v50 Steam/Premium information for editors
  • v50 information can now be added to pages in the main namespace. v0.47 information can still be found in the DF2014 namespace. See here for more details on the new versioning policy.
  • Use this page to report any issues related to the migration.
This notice may be cached—the current version can be found here.

User:Quietust/parsebody.php

From Dwarf Fortress Wiki
Jump to navigation Jump to search
<?
$verbose = 0;
$filter = 'all';
array_shift($argv);
while (count($argv) > 0)
{
	$arg = array_shift($argv);
	if ($arg == '-verbose')
		$verbose = 1;
	else	$filter = $arg;
}

function verbose ($text)
{
	global $verbose;
	if ($verbose)
		echo "$text\n";
}
function notice ($text)
{
	echo "$text\n";
}
function warning ($text)
{
	echo "WARNING - $text\n";
}
function error ($text)
{
	echo "ERROR - $text\n";
	exit;
}

function readToken ($file)
{
	$token = '';
	while (1)
	{
		$c = fgetc($file);
		if (feof($file))
			return 0;
		if ($c == '[')
			break;
	}
	while (1)
	{
		$c = fgetc($file);
		if (feof($file))
			return 0;
		if ($c == '[')
			warning("Unterminated token '$token' found!");
		if ($c == ']')
			break;
		$token .= $c;
	}
	return explode(':', $token);
}

function readBodies (&$bodies, $in)
{
	$partname = $partdata = 0;
	$bodyname = $bodydata = 0;
	while (1)
	{
		$token = readToken($in);
		if (!$token)
		{
			if ($partname)
			{
				$bodydata[$partname] = $partdata;
				$partname = $partdata = 0;
			}
			if ($bodyname)
			{
				$bodies[$bodyname] = $bodydata;
				$bodyname = $bodydata = 0;
			}
			break;
		}
		switch ($token[0])
		{
		case 'BODY':
			if ($partname)
			{
				$bodydata[$partname] = $partdata;
				$partname = $partdata = 0;
			}
			if ($bodyname)
			{
				$bodies[$bodyname] = $bodydata;
				$bodyname = $bodydata = 0;
			}
			$bodyname = $token[1];
			$bodydata = array();
			break;
		case 'BP':
			if ($partname)
			{
				$bodydata[$partname] = $partdata;
				$partname = $partdata = 0;
			}
			$partname = $token[1];
			$partdata = array('id' => $partname, 'name' => $token[2]);
			break;
		case 'UPPERBODY':
		case 'LOWERBODY':
		case 'HEAD':
		case 'GRASP':
		case 'STANCE':
			$partdata[$token[0]] = 1;
			break;
		case 'CON':
		case 'CON_CAT':
		case 'CATEGORY':
		case 'CONTYPE':
			$partdata[$token[0]] = $token[1];
			break;
		// ignore other tokens
		}
	}
}

function tracePart ($body, $part)
{
	if (isset($part['UPPERBODY']))
	{
		verbose("The $part[name] bone IS the upper body - all done");
		return TRUE;
	}
	$types = 0;
	$numcon = $numcat = $numtype = 0;
	if (isset($part['CON']))
	{
		$types++;
		if (!isset($body[$part['CON']]))
		{
			warning("Body part $part[id] connects to nonexistent part $part[CON]!");
			return FALSE;
		}
		$bp = $body[$part['CON']];
		verbose("The $part[name] bone's connected to the $bp[name] bone");
		if (tracePart($body, $bp))
			$numcon++;
	}
	if (isset($part['CON_CAT']))
	{
		$types++;
		$found = FALSE;
		foreach ($body as $bp)
		{
			if (isset($bp['CATEGORY']))
			{
				if ($part['CON_CAT'] == $bp['CATEGORY'])
				{
					$found = TRUE;
					if ($numcat)
						verbose("...and the $part[name] bone's connected to the $bp[name] bone");
					else	verbose("The $part[name] bone's connected to the $bp[name] bone");
					if (tracePart($body, $bp))
						$numcat++;
				}
			}
		}
		if (!$found)
			warning("Body part $part[id] could not find [CATEGORY:$part[CON_CAT]] body part to connect to!");
	}
	if (isset($part['CONTYPE']))
	{
		$types++;
		$found = FALSE;
		foreach ($body as $bp)
		{
			if (isset($bp[$part['CONTYPE']]))
			{
				$found = TRUE;
				if ($numtype)
					verbose("...and the $part[name] bone's connected to the $bp[name] bone");
				else	verbose("The $part[name] bone's connected to the $bp[name] bone");
				if (tracePart($body, $bp))
					$numtype++;
			}
		}
		if (!$found)
			warning("Body part $part[id] could not find [$part[CONTYPE]] body part to connect to!");
	}
	if ($types > 1)
		warning("Body part $part[id] has multiple connections?");
	return ($numcon + $numcat + $numtype) > 0;
}

function parseBody ($name, $body)
{
	global $bodies;
	verbose("Parsing body of creature $name");
	array_shift($body);
	$parts = array();
	foreach ($body as $b)
	{
		if (!isset($bodies[$b]))
		{
			warning("Creature $name attempting to add nonexistent body $b!");
			continue;
		}
		verbose("Creature $name uses the BODY group '$b'");
		foreach ($bodies[$b] as $part)
		{
			verbose("That includes the '$part[name]' ($part[id])");
			if (isset($parts[$part['id']]))
			{
				$dup = $parts[$part['id']];
				verbose("...but that's got the same ID as the $dup[name]!");
				warning("Creature $name includes multiple instances of body part $part[id]!");
			}
		}
		$parts = array_merge($parts, $bodies[$b]);
	}
	$upper = array();
	foreach ($parts as $id => $part)
	{
		if (isset($part['UPPERBODY']))
			$upper[] = $id;
	}
	if (count($upper) == 0)
	{
		notice("Creature $name has no upper body, skipping.");
		return;
	}
	if (count($upper) > 1)
	{
		notice("Creature $name has more than one upper body, skipping.");
		return;
	}
	verbose("Creature $name has ". count($parts) ." body parts, starting at $upper[0].");
	foreach ($parts as $id => $part)
	{
		if (!tracePart($parts, $part))
			notice("Creature $name body part '$part[name]' is unconnected!");
	}
	verbose('');
}

$bodies = array();
foreach (glob("raw/objects/*.txt") as $filename)
{
	$in = fopen($filename, "r");
	if (!$in)
		continue;
	$token = readToken($in);
	if (($token) && ($token[0] == 'OBJECT') && ($token[1] == 'BODY'))
		readBodies($bodies, $in);
	fclose($in);
}

if (!count($bodies))
	error("unable to locate any body part definitions - please run this from the game's root folder (or from a region folder)");

foreach (glob("raw/objects/*.txt") as $filename)
{
	$in = fopen($filename, "r");
	if (!$in)
		continue;
	$token = readToken($in);
	if (($token) && ($token[0] == 'OBJECT') && ($token[1] == 'CREATURE'))
	{
		$creature = '';
		while (1)
		{
			$token = readToken($in);
			if (!$token)
				break;
			if ($token[0] == 'CREATURE')
				$creature = $token[1];
			if (($creature != '') && ($token[0] == 'BODY'))
			{
				if (in_array($filter, array($creature, 'all')))
					parseBody($creature, $token);
			}
		}
	}
	fclose($in);
}
?>