예제 #1
0
// Give a group an order
bool scrOrderGroup(void)
{
	DROID_GROUP		*psGroup;
	DROID_ORDER		order;

	if (!stackPopParams(2, ST_GROUP, &psGroup, VAL_INT, &order))
	{
		return false;
	}

	ASSERT(psGroup != NULL,
	       "scrOrderGroup: Invalid group pointer");

	if (order != DORDER_STOP &&
	    order != DORDER_RETREAT &&
	    order != DORDER_DESTRUCT &&
	    order != DORDER_RTR &&
	    order != DORDER_RTB &&
	    order != DORDER_RUN)
	{
		ASSERT(false,
		       "scrOrderGroup: Invalid order");
		return false;
	}

	debug(LOG_NEVER, "group %p (%u) order %d", psGroup, psGroup->getNumMembers(), order);
	psGroup->orderGroup(order);

	return true;
}
예제 #2
0
// Add droids in an area to a group
bool scrGroupAddArea(void)
{
	DROID_GROUP		*psGroup;
	DROID			*psDroid;
	SDWORD			x1, y1, x2, y2, player;

	if (!stackPopParams(6, ST_GROUP, &psGroup, VAL_INT, &player,
	        VAL_INT, &x1, VAL_INT, &y1, VAL_INT, &x2, VAL_INT, &y2))
	{
		return false;
	}

	ASSERT(psGroup != NULL,
	       "scrGroupAdd: Invalid group pointer");

	if (player < 0 || player >= MAX_PLAYERS)
	{
		ASSERT(false, "scrGroupAddArea: invalid player");
		return false;
	}

	for (psDroid = apsDroidLists[player]; psDroid; psDroid = psDroid->psNext)
	{
		if (((SDWORD)psDroid->pos.x >= x1) && ((SDWORD)psDroid->pos.x <= x2) &&
		    ((SDWORD)psDroid->pos.y >= y1) && ((SDWORD)psDroid->pos.y <= y2) &&
		    psDroid->droidType != DROID_COMMAND &&
		    (psDroid->droidType != DROID_TRANSPORTER && psDroid->droidType != DROID_SUPERTRANSPORTER))

		{
			psGroup->add(psDroid);
		}
	}

	return true;
}
예제 #3
0
// Add a droid to a group
bool scrGroupAddDroid(void)
{
	DROID_GROUP		*psGroup;
	DROID			*psDroid;

	if (!stackPopParams(2, ST_GROUP, &psGroup, ST_DROID, &psDroid))
	{
		return false;
	}

	ASSERT(psGroup != NULL,
	       "scrGroupAdd: Invalid group pointer");
	ASSERT(psDroid != NULL,
	       "scrGroupAdd: Invalid droid pointer");
	if (psDroid == NULL)
	{
		return false;
	}
	if (psDroid->droidType == DROID_COMMAND)
	{
		debug(LOG_ERROR,
		      "scrGroupAdd: cannot add a command droid to a group");
		return false;
	}
	if (psDroid->droidType == DROID_TRANSPORTER || psDroid->droidType == DROID_SUPERTRANSPORTER)
	{
		debug(LOG_ERROR,
		      "scrGroupAdd: cannot add a transporter to a group");
		return false;
	}

	psGroup->add(psDroid);

	return true;
}
예제 #4
0
/** This function adds the droid to the command group commanded by psCommander.
 * It creates a group if it doesn't exist.
 * If the group is not full, it adds the droid to it and sets all the droid's states and orders to the group's.
 */
void cmdDroidAddDroid(DROID *psCommander, DROID *psDroid)
{
	DROID_GROUP	*psGroup;

	if (psCommander->psGroup == NULL)
	{
		psGroup = grpCreate();
		psGroup->add(psCommander);
		psDroid->group = UBYTE_MAX;
	}

	if (psCommander->psGroup->getNumMembers() < cmdDroidMaxGroup(psCommander))
	{
		psCommander->psGroup->add(psDroid);
		psDroid->group = UBYTE_MAX;

		// set the secondary states for the unit
		secondarySetState(psDroid, DSO_REPAIR_LEVEL, (SECONDARY_STATE)(psCommander->secondaryOrder & DSS_REPLEV_MASK), ModeImmediate);
		secondarySetState(psDroid, DSO_ATTACK_LEVEL, (SECONDARY_STATE)(psCommander->secondaryOrder & DSS_ALEV_MASK), ModeImmediate);

		orderDroidObj(psDroid, DORDER_GUARD, (BASE_OBJECT *)psCommander, ModeImmediate);
	}
	else
	{
		audio_PlayTrack( ID_SOUND_BUILD_FAIL );
		addConsoleMessage(_("Commander needs a higher level to command more units"), DEFAULT_JUSTIFY,  SYSTEM_MESSAGE);
	}
}
예제 #5
0
bool scrCBTransporterLandedB( void )
{
	SDWORD			player;
	DROID_GROUP		*psGroup;
	DROID			*psTransporter, *psDroid, *psNext;
	bool			retval;
	DROID			**ppsTransp;

	if (!stackPopParams(3, ST_GROUP, &psGroup, VAL_INT, &player,
		VAL_REF|ST_DROID, &ppsTransp))
	{
		debug(LOG_ERROR, "scrCBTransporterLandedB(): stack failed");
		return false;
	}

	psTransporter = transporterGetScriptCurrent();

	if ( (psTransporter == NULL) ||
		 (psTransporter->player != (UDWORD)player) )
	{
		retval = false;
	}
	else
	{
		*ppsTransp = psTransporter;		//return landed transporter

		/* if not selectedPlayer unload droids */
		//if ( (UDWORD)player != selectedPlayer )
		//{
			/* transfer droids from transporter group to current group */
			for(psDroid=psTransporter->psGroup->psList; psDroid; psDroid=psNext)
			{
				psNext = psDroid->psGrpNext;
				if ( psDroid != psTransporter )
				{
					psGroup->add(psDroid);
				}
			}
		//}

		retval = true;
	}

	scrFunctionResult.v.bval = retval;
	if (!stackPushResult(VAL_BOOL, &scrFunctionResult))
	{
		debug(LOG_ERROR, "scrCBTransporterLandedB: push landed");
		return false;
	}

	return true;
}
예제 #6
0
// release a ST_GROUP variable
void scrvReleaseGroup(INTERP_VAL *psVal)
{
	DROID_GROUP		*psGroup;

	psGroup = (DROID_GROUP*)psVal->v.oval;
	psGroup->removeAll();

	ASSERT( psGroup->refCount == 1,
		"scrvReleaseGroup: ref count is wrong" );

	// do a final Remove to free the group
	psGroup->remove(NULL);
}
예제 #7
0
// create a group structure for a ST_GROUP variable
bool scrvNewGroup(INTERP_VAL *psVal)
{
	DROID_GROUP		*psGroup;

	psGroup = grpCreate();

	// increment the refcount so the group doesn't get automatically freed when empty
	psGroup->add(NULL);

	psVal->v.oval = psGroup;

	return true;
}
예제 #8
0
static QScriptValue js_groupAddDroid(QScriptContext *context, QScriptEngine *engine)
{
	int groupId = context->argument(0).toInt32();
	DROID_GROUP *psGroup = grpFind(groupId);
	QScriptValue droidVal = context->argument(1);
	int droidId = droidVal.property("id").toInt32();
	int droidPlayer = droidVal.property("player").toInt32();
	DROID *psDroid = IdToDroid(droidId, droidPlayer);

	SCRIPT_ASSERT(context, psGroup, "Invalid group index %d", groupId);
	SCRIPT_ASSERT(context, psDroid, "Invalid droid index %d", droidId);
	psGroup->add(psDroid);
	return QScriptValue();
}
예제 #9
0
bool scrCBTransporterLanded( void )
{
	SDWORD			player;
	DROID_GROUP		*psGroup;
	DROID			*psTransporter, *psDroid, *psNext;
	bool			retval;

	if (!stackPopParams(2, ST_GROUP, &psGroup, VAL_INT, &player))
	{
		return false;
	}

	psTransporter = transporterGetScriptCurrent();

	if ( (psTransporter == NULL) ||
		 (psTransporter->player != (UDWORD)player) )
	{
		retval = false;
	}
	else
	{
		/* if not selectedPlayer unload droids */
		if ( (UDWORD)player != selectedPlayer )
		{
			/* transfer droids from transporter group to current group */
			for(psDroid=psTransporter->psGroup->psList; psDroid; psDroid=psNext)
			{
				psNext = psDroid->psGrpNext;
				if ( psDroid != psTransporter )
				{
					psGroup->add(psDroid);
				}
			}
		}

		retval = true;
	}

	scrFunctionResult.v.bval = retval;
	if (!stackPushResult(VAL_BOOL, &scrFunctionResult))
	{
		return false;
	}

	return true;
}
예제 #10
0
// set the secondary state for a droid
bool scrSetGroupSecondary(void)
{
	DROID_GROUP		*psGroup;
	SECONDARY_ORDER		sec;
	SECONDARY_STATE		state;

	if (!stackPopParams(3, ST_GROUP, &psGroup, VAL_INT, &sec, VAL_INT, &state))
	{
		return false;
	}

	ASSERT(psGroup != NULL,
	       "scrSetGroupSecondary: invalid group pointer");

	psGroup->setSecondary(sec, state);

	return true;
}
예제 #11
0
static QScriptValue js_groupAddArea(QScriptContext *context, QScriptEngine *engine)
{
	int groupId = context->argument(0).toInt32();
	int player = engine->globalObject().property("me").toInt32();
	int x1 = context->argument(1).toInt32();
	int y1 = context->argument(2).toInt32();
	int x2 = context->argument(3).toInt32();
	int y2 = context->argument(4).toInt32();
	DROID_GROUP *psGroup = grpFind(groupId);

	SCRIPT_ASSERT(context, psGroup, "Invalid group index %d", groupId);
	for (DROID *psDroid = apsDroidLists[player]; psGroup && psDroid; psDroid = psDroid->psNext)
	{
		if (psDroid->pos.x >= x1 && psDroid->pos.x <= x2 && psDroid->pos.y >= y1 && psDroid->pos.y <= y2
		    && psDroid->droidType != DROID_COMMAND && psDroid->droidType != DROID_TRANSPORTER)
		{
			psGroup->add(psDroid);
		}
	}
	return QScriptValue();
}
예제 #12
0
// Give a group an order to an object
bool scrOrderGroupObj(void)
{
	DROID_GROUP		*psGroup;
	DROID_ORDER		order;
	BASE_OBJECT		*psObj;

	if (!stackPopParams(3, ST_GROUP, &psGroup, VAL_INT, &order, ST_BASEOBJECT, &psObj))
	{
		return false;
	}

	ASSERT(psGroup != NULL,
	       "scrOrderGroupObj: Invalid group pointer");
	ASSERT(psObj != NULL,
	       "scrOrderGroupObj: Invalid object pointer");

	if (order != DORDER_ATTACK &&
	    order != DORDER_HELPBUILD &&
	    order != DORDER_DEMOLISH &&
	    order != DORDER_REPAIR &&
	    order != DORDER_OBSERVE &&
	    order != DORDER_EMBARK &&
	    order != DORDER_FIRESUPPORT &&
	    order != DORDER_DROIDREPAIR)
	{
		ASSERT(false,
		       "scrOrderGroupObj: Invalid order");
		return false;
	}

	debug(LOG_NEVER, "group %p (%u) order %d,  obj type %d player %d id %d",
	      psGroup, psGroup->getNumMembers(), order, psObj->type, psObj->player, psObj->id);

	psGroup->orderGroup(order, psObj);

	return true;
}
예제 #13
0
// Give a group an order to a location
bool scrOrderGroupLoc(void)
{
	DROID_GROUP		*psGroup;
	DROID_ORDER		order;
	SDWORD			x, y;

	if (!stackPopParams(4, ST_GROUP, &psGroup, VAL_INT, &order, VAL_INT, &x, VAL_INT, &y))
	{
		return false;
	}

	ASSERT(psGroup != NULL,
	       "scrOrderGroupLoc: Invalid group pointer");

	if (order != DORDER_MOVE &&
	    order != DORDER_SCOUT)
	{
		ASSERT(false,
		       "scrOrderGroupLoc: Invalid order");
		return false;
	}
	if (x < 0
	    || x > world_coord(mapWidth)
	    || y < 0
	    || y > world_coord(mapHeight))
	{
		ASSERT(false, "Invalid map location (%d, %d), max is (%d, %d)", x, y, world_coord(mapWidth), world_coord(mapHeight));
		return false;
	}

	debug(LOG_NEVER, "group %p (%u) order %d (%d,%d)",
	      psGroup, psGroup->getNumMembers(), order, x, y);
	psGroup->orderGroup(order, (UDWORD)x, (UDWORD)y);

	return true;
}
예제 #14
0
/// default value load routine
bool scrValDefLoad(INTERP_VAL *psVal, WzConfig &ini)
{
	DROID			*psCDroid;
	SDWORD			index, members;
	UDWORD			id;
	LEVEL_DATASET	*psLevel;
	DROID_GROUP		*psGroup = NULL;

	switch ((unsigned)psVal->type)  // Unsigned cast to suppress compiler warnings due to enum abuse.
	{
	case ST_INTMESSAGE:
		if (ini.contains("data"))
		{
			psVal->v.oval = (void*)getViewData(ini.value("data").toString().toAscii().constData());
		}
		else
		{
			psVal->v.oval = NULL;
		}
		break;
	case ST_BASEOBJECT:
	case ST_DROID:
	case ST_STRUCTURE:
	case ST_FEATURE:
		if (ini.contains("data"))
		{
			psVal->v.oval = (void*)getBaseObjFromId(ini.value("data").toInt());
		}
		else
		{
			psVal->v.oval = NULL;
		}
		break;
	case ST_BASESTATS:
	case ST_COMPONENT:
		break;
	case ST_STRUCTURESTAT:
		index = 0;
		if (ini.contains("data"))
		{
			index = getStructStatFromName(ini.value("data").toString().toAscii().constData());
			if (index == -1)
			{
				debug( LOG_FATAL, "Could not find stat");
				index = 0;
			}
		}
		psVal->v.ival = index;
		break;
	case ST_FEATURESTAT:
		index = 0;
		if (ini.contains("data"))
		{
			index = getFeatureStatFromName(ini.value("data").toString().toAscii().constData());
			if (index == -1)
			{
				debug( LOG_FATAL, "Could not find stat");
				index = 0;
			}
		}
		psVal->v.ival = index;
		break;
	case ST_BODY:
		index = getCompFromResName(COMP_BODY, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find body component");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_PROPULSION:
		index = getCompFromResName(COMP_PROPULSION, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find propulsion component");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_ECM:
		index = getCompFromResName(COMP_ECM, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find ECM component");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_SENSOR:
		index = getCompFromResName(COMP_SENSOR, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find sensor component");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_CONSTRUCT:
		index = getCompFromResName(COMP_CONSTRUCT, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find constructor component");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_WEAPON:
		index = getCompFromResName(COMP_WEAPON, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find weapon");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_REPAIR:
		index = getCompFromResName(COMP_REPAIRUNIT, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find repair component");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_BRAIN:
		index = getCompFromResName(COMP_BRAIN, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find repair brain");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_TEMPLATE:
		psVal->v.oval = NULL;
		if (ini.contains("data"))
		{
			// FIXME: Ugh. Find a better way to show full template info
			psVal->v.oval = (void*)IdToTemplate(ini.value("data").toInt(), ANYPLAYER);
			if ((DROID_TEMPLATE*)(psVal->v.oval) == NULL)
			{
				debug(LOG_FATAL, "Could not find template %d", ini.value("data").toInt());
			}
		}
		break;
	case ST_TEXTSTRING:
		psVal->v.sval = NULL;
		if (ini.contains("data"))
		{
			psVal->v.sval = strdup(ini.value("data").toString().toAscii().constData());
		}
		break;
	case ST_LEVEL:
		psVal->v.sval = NULL;
		if (ini.contains("data"))
		{
			psLevel = levFindDataSet(ini.value("data").toString().toAscii().constData());
			if (psLevel == NULL)
			{
				debug(LOG_FATAL, "Could not find level dataset");
			}
			psVal->v.sval = psLevel->pName;
		}
		break;
	case ST_RESEARCH:
		psVal->v.oval = NULL;
		if (ini.contains("data"))
		{
			QString research = ini.value("data").toString();
			if (!research.isEmpty())
			{
				psVal->v.oval = (void*)getResearch(research.toUtf8().constData());
				ASSERT_OR_RETURN(false, psVal->v.oval, "Could not find research %s", research.toUtf8().constData());
			}
		}
		break;
	case ST_GROUP:
		if (psVal->v.oval == NULL)
		{
			DROID_GROUP *tmp = grpCreate();
			tmp->add(NULL);
			psVal->v.oval = tmp;
		}
		psGroup = (DROID_GROUP *)(psVal->v.oval);
		members = ini.value("members", 0).toInt();
		if (psGroup && members > 0)
		{
			QStringList droids = ini.value("data").toStringList();

			// load the retreat data
			psGroup->sRunData.sPos = ini.vector2i("runpos");
			psGroup->sRunData.forceLevel = ini.value("forceLevel").toInt();
			psGroup->sRunData.leadership = ini.value("leadership").toInt();
			psGroup->sRunData.healthLevel = ini.value("healthLevel").toInt();

			// load the droids
			while (members > 0)
			{
				id = droids.takeLast().toInt();
				psCDroid = (DROID *)getBaseObjFromId(id);
				if (!psCDroid)
				{
					debug(LOG_ERROR, "Could not find object id %d", id);
				}
				else
				{
					((DROID_GROUP*)(psVal->v.oval))->add(psCDroid);
				}
				members--;
			}
		}
		break;
	case ST_SOUND:
		// find audio id

		// don't use sound if it's disabled
		if (audio_Disabled())
		{
			psVal->v.ival = NO_SOUND;
			break;
		}

		index = audio_GetTrackID(ini.value("data").toString().toAscii().constData());
		if (index == SAMPLE_NOT_FOUND)
		{
			// find empty id and set track vals
			QString soundname = ini.value("data").toString();
			index = audio_SetTrackVals(soundname.toAscii().constData(), false, 100, 1800);
			if (!index)			// this is a NON fatal error.
			{
				// We can't find filename of the sound for some reason.
				debug(LOG_ERROR, "Sound ID not available %s not found", soundname.toAscii().constData());
				break;
			}
		}
		psVal->v.ival = index;
		break;
	case ST_STRUCTUREID:
	case ST_DROIDID:
	default:
		// just set the contents directly
		psVal->v.ival = ini.value("data").toInt();
		break;
	}

	return true;
}
예제 #15
0
/// default value load routine
bool scrValDefLoad(SDWORD version, INTERP_VAL *psVal, char *pBuffer, UDWORD size)
{
	char			*pPos;
	DROID			*psCDroid;
	SDWORD			index, members, savedMembers;
	UDWORD			id;
	LEVEL_DATASET	*psLevel;
	DROID_GROUP		*psGroup = NULL;
	const char              *pName;
	bool			bObjectDefined;

	switch ((unsigned)psVal->type)  // Unsigned cast to suppress compiler warnings due to enum abuse.
	{
	case ST_INTMESSAGE:
		if ((size == 1) &&
			(*pBuffer == 0))
		{
			psVal->v.oval = NULL;
		}
		else
		{
			psVal->v.oval = (void*)getViewData(pBuffer);
			if (psVal->v.oval == NULL)
			{
				return false;
			}
		}
		break;
	case ST_BASEOBJECT:
	case ST_DROID:
	case ST_STRUCTURE:
	case ST_FEATURE:
		id = *((UDWORD *)pBuffer);
		endian_udword(&id);

		if (id == UDWORD_MAX)
		{
			psVal->v.oval = NULL;
		}
		else
		{
			psVal->v.oval = (void*)getBaseObjFromId(id);
			if (!psVal->v.oval)
			{
				debug(LOG_ERROR, "Could not find object id %d", id);
			}
		}
		break;
	case ST_BASESTATS:
	case ST_COMPONENT:
		break;
	case ST_STRUCTURESTAT:
		index = getStructStatFromName(pBuffer);
		if (index == -1)
		{
			debug( LOG_FATAL, "scrValDefLoad: couldn't find structure stat %s", pBuffer );
			abort();
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_FEATURESTAT:
		index = getFeatureStatFromName(pBuffer);
		if (index == -1)
		{
			debug( LOG_FATAL, "scrValDefLoad: couldn't find feature stat %s", pBuffer );
			abort();
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_BODY:
		index = getCompFromResName(COMP_BODY, pBuffer);
		if (index == -1)
		{
			debug( LOG_FATAL, "scrValDefLoad: couldn't find body component %s", pBuffer );
			abort();
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_PROPULSION:
		index = getCompFromResName(COMP_PROPULSION, pBuffer);
		if (index == -1)
		{
			debug( LOG_FATAL, "scrValDefLoad: couldn't find propulsion component %s", pBuffer );
			abort();
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_ECM:
		index = getCompFromResName(COMP_ECM, pBuffer);
		if (index == -1)
		{
			debug( LOG_FATAL, "scrValDefLoad: couldn't find ECM component %s", pBuffer );
			abort();
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_SENSOR:
		index = getCompFromResName(COMP_SENSOR, pBuffer);
		if (index == -1)
		{
			debug( LOG_FATAL, "scrValDefLoad: couldn't find sensor component %s", pBuffer );
			abort();
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_CONSTRUCT:
		index = getCompFromResName(COMP_CONSTRUCT, pBuffer);
		if (index == -1)
		{
			debug( LOG_FATAL, "scrValDefLoad: couldn't find constructor component %s", pBuffer );
			abort();
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_WEAPON:
		index = getCompFromResName(COMP_WEAPON, pBuffer);
		if (index == -1)
		{
			debug( LOG_FATAL, "scrValDefLoad: couldn't find weapon %s", pBuffer );
			abort();
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_REPAIR:
		index = getCompFromResName(COMP_REPAIRUNIT, pBuffer);
		if (index == -1)
		{
			debug( LOG_FATAL, "scrValDefLoad: couldn't find repair component %s", pBuffer );
			abort();
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_BRAIN:
		index = getCompFromResName(COMP_BRAIN, pBuffer);
		if (index == -1)
		{
			debug( LOG_FATAL, "scrValDefLoad: couldn't find repair brain %s", pBuffer );
			abort();
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_TEMPLATE:
		id = *((UDWORD *)pBuffer);
		endian_udword(&id);

		if (id == UDWORD_MAX)
		{
			psVal->v.oval = NULL;
		}
		else
		{
			psVal->v.oval = (void*)IdToTemplate(id, ANYPLAYER);
			if ((DROID_TEMPLATE*)(psVal->v.oval) == NULL)
			{
				debug( LOG_FATAL, "scrValDefLoad: couldn't find template id %d", id );
				abort();
			}
		}
		break;
	case ST_TEXTSTRING:
		{
			const char* str;
			char* idStr;
			uint16_t len;

			if (size < sizeof(len))
			{
				debug(LOG_ERROR, "Data size is too small, %u is expected, but %u is provided", (unsigned int)(sizeof(len)), (unsigned int)size);
				return false;
			}

			len = *((uint16_t*)pBuffer);
			endian_uword(&len);

			if (size < sizeof(len) + len)
			{
				debug(LOG_ERROR, "Data size is too small, %u is expected, but %u is provided", (unsigned int)(sizeof(len) + len), (unsigned int)size);
				return false;
			}

			if (len == 0)
			{
				psVal->v.sval = NULL;
				return true;
			}

			idStr = (char *)malloc(len);
			if (!idStr)
			{
				debug(LOG_ERROR, "Out of memory (tried to allocate %u bytes)", (unsigned int)len);
				// Don't abort() here, as this might be the result from a bad "len" field in the data
				return false;
			}

			memcpy(idStr, pBuffer + sizeof(len), len);

			if (idStr[len - 1] != '\0')
			{
				debug(LOG_WARNING, "Non-NUL terminated string encountered!");
			}
			idStr[len - 1] = '\0';

			str = strresGetString(psStringRes, idStr);
			if (!str)
			{
				debug(LOG_ERROR, "Couldn't find string with id \"%s\"", idStr);
				free(idStr);
				return false;
			}
			free(idStr);

			psVal->v.sval = strdup(str);
			if (!psVal->v.sval)
			{
				debug(LOG_FATAL, "Out of memory");
				abort();
				return false;
			}
		}
		break;
	case ST_LEVEL:
		if ((size == 1) &&
			(*pBuffer == 0))
		{
			psVal->v.sval = '\0';
		}
		else
		{
			psLevel = levFindDataSet(pBuffer);
			if (psLevel == NULL)
			{
				debug( LOG_FATAL, "scrValDefLoad: couldn't find level dataset %s", pBuffer );
				abort();
			}
			psVal->v.sval = psLevel->pName;
		}
		break;
	case ST_RESEARCH:
		if ((size == 1) &&
			(*pBuffer == 0))
		{
			psVal->v.oval = NULL;
		}
		else
		{
			psVal->v.oval = (void*)getResearch(pBuffer);
			if (psVal->v.oval == NULL)
			{
				debug( LOG_FATAL, "scrValDefLoad: couldn't find research %s", pBuffer );
				abort();
			}
		}
		break;
	case ST_GROUP:
		bObjectDefined = true;

		if (psVal->v.oval == NULL)
		{
			DROID_GROUP *tmp = grpCreate();
			tmp->add(NULL);
			psVal->v.oval = tmp;
		}

		pPos = pBuffer;

		if (version < 2)
		{
			members = size / sizeof(UDWORD);
		}
		else if (version < 3)
		{
			members = (size - sizeof(SDWORD)*4) / sizeof(UDWORD);
		}
		else
		{
			members = (size - sizeof(SDWORD)*6) / sizeof(UDWORD);

			// get saved group member count/nullpointer flag
			endian_sdword((SDWORD*)pPos);
			bObjectDefined = ( *((SDWORD *)pPos) != UNALLOCATED_OBJECT );

			if(bObjectDefined)
			{
				savedMembers = *((SDWORD *)pPos);	// get number of saved group members

				ASSERT(savedMembers == members, "scrValDefLoad: calculated and saved group member count did not match." );
			}
			pPos += sizeof(SDWORD);
		}

		// make sure group was allocated when it was saved (relevant starting from version 3)
		if( version < 3 || bObjectDefined )
		{
			if (version >= 2)
			{
				// load the retreat data
				psGroup = (DROID_GROUP*)(psVal->v.oval);
				endian_sdword((SDWORD*)pPos);
				psGroup->sRunData.sPos.x = *((SDWORD *)pPos);
				pPos += sizeof(SDWORD);
				endian_sdword((SDWORD*)pPos);
				psGroup->sRunData.sPos.y = *((SDWORD *)pPos);
				pPos += sizeof(SDWORD);
				endian_sdword((SDWORD*)pPos);
				psGroup->sRunData.forceLevel = (UBYTE)(*((SDWORD *)pPos));
				pPos += sizeof(SDWORD);
				endian_sdword((SDWORD*)pPos);
				psGroup->sRunData.leadership = (UBYTE)(*((SDWORD *)pPos));
				pPos += sizeof(SDWORD);
			}
			if (version >= 3)
			{
				endian_sdword((SDWORD*)pPos);
				psGroup->sRunData.healthLevel = (UBYTE)(*((SDWORD *)pPos));
				pPos += sizeof(SDWORD);
			}

			// load the droids
			while (members > 0)
			{
				endian_udword((UDWORD*)pPos);
				id = *((UDWORD *) pPos);
				psCDroid = (DROID *)getBaseObjFromId(id);
				if (!psCDroid)
				{
					debug(LOG_ERROR, "Could not find object id %d", id);
				}
				else
				{
					((DROID_GROUP*)(psVal->v.oval))->add(psCDroid);
				}

				pPos += sizeof(UDWORD);
				members -= 1;
			}
		}
		else		// a group var was unallocated during saving
		{
			pPos += sizeof(UWORD);
		}
		break;
	case ST_SOUND:
		// find audio id

		// don't use sound if it's disabled
		if (audio_Disabled())
		{
			psVal->v.ival = NO_SOUND;
			break;
		}

		pName = pBuffer;
		index = audio_GetTrackID( pName );
		if (index == SAMPLE_NOT_FOUND)
		{
			// find empty id and set track vals
			index = audio_SetTrackVals(pName, false, 100, 1800);
			if (!index)			//this is a NON fatal error.
			{
				// We can't find filename of the sound for some reason.
				debug(LOG_ERROR, "Sound ID not available %s not found", pName);
				break;
			}
		}
		psVal->v.ival = index;
		break;
	case ST_STRUCTUREID:
	case ST_DROIDID:
	default:
		// just set the contents directly
		psVal->v.ival = *((SDWORD *)pBuffer);
		endian_sdword(&psVal->v.ival);
		break;
	}

	return true;
}