Пример #1
0
// Build a list of orders available for the selected structure.
static std::vector<AVORDER> buildStructureOrderList(STRUCTURE *psStructure)
{
	ASSERT_OR_RETURN(std::vector<AVORDER>(), StructIsFactory(psStructure), "BuildStructureOrderList: structure is not a factory");

	//this can be hard-coded!
	std::vector<AVORDER> orders(2);
	orders[0].OrderIndex = 0;//DSO_REPAIR_LEVEL;
	orders[1].OrderIndex = 1;//DSO_ATTACK_LEVEL;

	return orders;
}
Пример #2
0
// Build a list of orders available for the selected structure.
static std::vector<AVORDER> buildStructureOrderList(STRUCTURE *psStructure)
{
	//only valid for Factories (at the moment)
	ASSERT_OR_RETURN(std::vector<AVORDER>(), StructIsFactory(psStructure), "BuildStructureOrderList: structure is not a factory");

	//this can be hard-coded!
	std::vector<AVORDER> orders(4);
	orders[0].OrderIndex = 1;//DSO_REPAIR_LEVEL;
	orders[1].OrderIndex = 2;//DSO_ATTACK_LEVEL;
	orders[2].OrderIndex = 5;//DSO_HALTTYPE;

	return orders;
}
Пример #3
0
// ********************************************************************************************
bool scrSkGetFactoryCapacity(void)
{
	SDWORD count = 0;
	STRUCTURE *psStructure;

	if (!stackPopParams(1, ST_STRUCTURE, &psStructure))
	{
		return false;
	}

	if (psStructure && StructIsFactory(psStructure))
	{
		count = psStructure->capacity;
	}

	scrFunctionResult.v.ival = count;
	if (!stackPushResult(VAL_INT, &scrFunctionResult))
	{
		return false;
	}
	return true;
}
Пример #4
0
// ********************************************************************************************
BOOL scrSkGetFactoryCapacity(void)
{	
	SDWORD count=0,structure;
	STRUCTURE *psStructure;

	if (!stackPopParams(1,ST_STRUCTURE, &structure))
	{
		return FALSE;
	}
	psStructure = (STRUCTURE *) structure;

	if(psStructure && StructIsFactory(psStructure))
	{
		count = ((FACTORY *)psStructure->pFunctionality)->capacity;
	}

	if (!stackPushResult(VAL_INT, count))
	{
		return FALSE;
	}
	return TRUE;
}
Пример #5
0
/*called when a Template is deleted in the Design screen*/
void deleteTemplateFromProduction(DROID_TEMPLATE *psTemplate, unsigned player, QUEUE_MODE mode)
{
	STRUCTURE   *psStruct;
	STRUCTURE	*psList;

	//see if any factory is currently using the template
	for (unsigned i = 0; i < 2; ++i)
	{
		psList = NULL;
		switch (i)
		{
		case 0:
			psList = apsStructLists[player];
			break;
		case 1:
			psList = mission.apsStructLists[player];
			break;
		}
		for (psStruct = psList; psStruct != NULL; psStruct = psStruct->psNext)
		{
			if (StructIsFactory(psStruct))
			{
				FACTORY             *psFactory = &psStruct->pFunctionality->factory;

				if (psFactory->psAssemblyPoint->factoryInc < asProductionRun[psFactory->psAssemblyPoint->factoryType].size())
				{
					ProductionRun &productionRun = asProductionRun[psFactory->psAssemblyPoint->factoryType][psFactory->psAssemblyPoint->factoryInc];
					for (unsigned inc = 0; inc < productionRun.size(); ++inc)
					{
						if (productionRun[inc].psTemplate->multiPlayerID == psTemplate->multiPlayerID && mode == ModeQueue)
						{
							//just need to erase this production run entry
							productionRun.erase(productionRun.begin() + inc);
							--inc;
						}
					}
				}

				if (psFactory->psSubject == NULL)
				{
					continue;
				}

				// check not being built in the factory for the template player
				if (psTemplate->multiPlayerID == psFactory->psSubject->multiPlayerID && mode == ModeImmediate)
				{
					syncDebugStructure(psStruct, '<');
					syncDebug("Clearing production");

					// Clear the factory's subject, and returns power.
					cancelProduction(psStruct, ModeImmediate, false);
					// Check to see if anything left to produce. (Also calls cancelProduction again, if nothing left to produce, which is a no-op. But if other things are left to produce, doesn't call cancelProduction, so wouldn't return power without the explicit cancelProduction call above.)
					doNextProduction(psStruct, NULL, ModeImmediate);

					//tell the interface
					intManufactureFinished(psStruct);

					syncDebugStructure(psStruct, '>');
				}
			}
		}
	}
}
Пример #6
0
// Add the droid order screen.
// Returns true if the form was displayed ok.
//
//changed to a BASE_OBJECT to accomodate the factories - AB 21/04/99
bool intAddOrder(BASE_OBJECT *psObj)
{
	bool Animate = true;
	SECONDARY_STATE State;
	UWORD OrdIndex;
	UWORD Height, NumDisplayedOrders;
	UWORD NumButs;
	UWORD NumJustifyButs, NumCombineButs, NumCombineBefore;
	bool  bLastCombine, bHidden;
	DROID *Droid;
	STRUCTURE *psStructure;

	if (bInTutorial)
	{
		// No RMB orders in tutorial!!
		return (false);
	}

	// Is the form already up?
	if (widgGetFromID(psWScreen, IDORDER_FORM) != NULL)
	{
		intRemoveOrderNoAnim();
		Animate = false;
	}
	// Is the stats window up?
	if (widgGetFromID(psWScreen, IDSTAT_FORM) != NULL)
	{
		intRemoveStatsNoAnim();
		Animate = false;
	}

	if (psObj)
	{
		if (psObj->type == OBJ_DROID)
		{
			Droid = (DROID *)psObj;
			psStructure =  NULL;
		}
		else if (psObj->type == OBJ_STRUCTURE)
		{
			Droid = NULL;
			psStructure = (STRUCTURE *)psObj;
			psSelectedFactory = psStructure;
			ASSERT_OR_RETURN(false, StructIsFactory(psSelectedFactory), "Trying to select a %s as a factory!",
			                 objInfo((BASE_OBJECT *)psSelectedFactory));
		}
		else
		{
			ASSERT(false, "Invalid object type");
			Droid = NULL;
			psStructure =  NULL;
		}
	}
	else
	{
		Droid = NULL;
		psStructure =  NULL;
	}

	setWidgetsStatus(true);

	AvailableOrders.clear();
	SelectedDroids.clear();

	// Selected droid is a command droid?
	if ((Droid != NULL) && (Droid->droidType == DROID_COMMAND))
	{
		// displaying for a command droid - ignore any other droids
		SelectedDroids.push_back(Droid);
	}
	else if (psStructure != NULL)
	{
		AvailableOrders = buildStructureOrderList(psStructure);
		if (AvailableOrders.empty())
		{
			return false;
		}
	}
	// Otherwise build a list of selected droids.
	else if (!BuildSelectedDroidList())
	{
		// If no droids selected then see if we were given a specific droid.
		if (Droid != NULL)
		{
			// and put it in the list.
			SelectedDroids.push_back(Droid);
		}
	}

	// Build a list of orders available for the list of selected droids. - if a factory has not been selected
	if (psStructure == NULL)
	{
		AvailableOrders = buildDroidOrderList();
		if (AvailableOrders.empty())
		{
			// If no orders then return;
			return false;
		}
	}

	WIDGET *parent = psWScreen->psForm;

	/* Create the basic form */
	IntFormAnimated *orderForm = new IntFormAnimated(parent, Animate);  // Do not animate the opening, if the window was already open.
	orderForm->id = IDORDER_FORM;
	orderForm->setGeometry(ORDER_X, ORDER_Y, ORDER_WIDTH, ORDER_HEIGHT);

	// Add the close button.
	W_BUTINIT sButInit;
	sButInit.formID = IDORDER_FORM;
	sButInit.id = IDORDER_CLOSE;
	sButInit.x = ORDER_WIDTH - CLOSE_WIDTH;
	sButInit.y = 0;
	sButInit.width = CLOSE_WIDTH;
	sButInit.height = CLOSE_HEIGHT;
	sButInit.pTip = _("Close");
	sButInit.pDisplay = intDisplayImageHilight;
	sButInit.UserData = PACKDWORD_TRI(0, IMAGE_CLOSEHILIGHT , IMAGE_CLOSE);
	if (!widgAddButton(psWScreen, &sButInit))
	{
		return false;
	}

	sButInit = W_BUTINIT();
	sButInit.formID = IDORDER_FORM;
	sButInit.id = IDORDER_CLOSE + 1;
	sButInit.pDisplay = intDisplayButtonHilight;
	sButInit.y = ORDER_BUTY;

	Height = 0;
	NumDisplayedOrders = 0;

	for (unsigned j = 0; j < AvailableOrders.size() && NumDisplayedOrders < MAX_DISPLAYABLE_ORDERS; ++j)
	{
		OrdIndex = AvailableOrders[j].OrderIndex;

		// Get current order state.
		State = GetSecondaryStates(OrderButtons[OrdIndex].Order);

		// Get number of buttons.
		NumButs = OrderButtons[OrdIndex].NumButs;
		// Set actual number of buttons.
		OrderButtons[OrdIndex].AcNumButs = NumButs;

		// Handle special case for factory -> command droid assignment buttons.
		switch (OrderButtons[OrdIndex].Class)
		{
		case ORDBUTCLASS_FACTORY:
			NumButs = countAssignableFactories((UBYTE)selectedPlayer, FACTORY_FLAG);
			break;
		case ORDBUTCLASS_CYBORGFACTORY:
			NumButs = countAssignableFactories((UBYTE)selectedPlayer, CYBORG_FLAG);
			break;
		case ORDBUTCLASS_VTOLFACTORY:
			NumButs = countAssignableFactories((UBYTE)selectedPlayer, VTOL_FLAG);
			break;
		default:
			break;
		}

		sButInit.id = OrderButtons[OrdIndex].ButBaseID;

		NumJustifyButs = NumButs;
		bLastCombine = false;

		switch (OrderButtons[OrdIndex].ButJustify & ORD_JUSTIFY_MASK)
		{
		case ORD_JUSTIFY_LEFT:
			sButInit.x = ORDER_BUTX;
			break;

		case ORD_JUSTIFY_RIGHT:
			sButInit.x = orderForm->width() - ORDER_BUTX -
			             (NumJustifyButs * GetImageWidth(IntImages, OrderButtons[OrdIndex].ButImageID[0]) +
			              (NumJustifyButs - 1) * ORDER_BUTGAP);
			break;

		case ORD_JUSTIFY_CENTER:
			sButInit.x = (orderForm->width() -
			              (NumJustifyButs * GetImageWidth(IntImages, OrderButtons[OrdIndex].ButImageID[0]) +
			               (NumJustifyButs - 1) * ORDER_BUTGAP)) / 2;
			break;

		case ORD_JUSTIFY_COMBINE:
			// see how many are on this line before the button
			NumCombineBefore = 0;
			for (unsigned i = 0; i < j; ++i)
			{
				if ((OrderButtons[AvailableOrders[i].OrderIndex].ButJustify & ORD_JUSTIFY_MASK)
				    == ORD_JUSTIFY_COMBINE)
				{
					NumCombineBefore += 1;
				}
			}
			NumCombineButs = (UWORD)(NumCombineBefore + 1);

			// now see how many in total
			for (unsigned i = j + 1; i < AvailableOrders.size(); ++i)
			{
				if ((OrderButtons[AvailableOrders[i].OrderIndex].ButJustify & ORD_JUSTIFY_MASK)
				    == ORD_JUSTIFY_COMBINE)
				{
					NumCombineButs += 1;
				}
			}

			// get position on line
			NumCombineButs = (UWORD)(NumCombineButs - (NumCombineBefore - (NumCombineBefore % ORD_MAX_COMBINE_BUTS)));

			if (NumCombineButs >= ORD_MAX_COMBINE_BUTS)
			{
				// the buttons will fill the line
				sButInit.x = (SWORD)(ORDER_BUTX +
				                     (GetImageWidth(IntImages, OrderButtons[OrdIndex].ButImageID[0]) + ORDER_BUTGAP) * NumCombineBefore);
			}
			else
			{
				// center the buttons
				sButInit.x = orderForm->width() / 2 -
				             (NumCombineButs * GetImageWidth(IntImages, OrderButtons[OrdIndex].ButImageID[0]) +
				              (NumCombineButs - 1) * ORDER_BUTGAP) / 2;
				sButInit.x = (SWORD)(sButInit.x +
				                     (GetImageWidth(IntImages, OrderButtons[OrdIndex].ButImageID[0]) + ORDER_BUTGAP) * NumCombineBefore);
			}

			// see if need to start a new line of buttons
			if ((NumCombineBefore + 1) == (NumCombineButs % ORD_MAX_COMBINE_BUTS))
			{
				bLastCombine = true;
			}

			break;
		}

		for (unsigned i = 0; i < OrderButtons[OrdIndex].AcNumButs; ++i)
		{
			sButInit.pTip = getDORDDescription(OrderButtons[OrdIndex].ButTips[i]);
			sButInit.width = (UWORD)GetImageWidth(IntImages, OrderButtons[OrdIndex].ButImageID[i]);
			sButInit.height = (UWORD)GetImageHeight(IntImages, OrderButtons[OrdIndex].ButImageID[i]);
			sButInit.UserData = PACKDWORD_TRI(OrderButtons[OrdIndex].ButGreyID[i],
			                                  OrderButtons[OrdIndex].ButHilightID[i],
			                                  OrderButtons[OrdIndex].ButImageID[i]);
			if (!widgAddButton(psWScreen, &sButInit))
			{
				return false;
			}

			// Set the default state for the button.
			switch (OrderButtons[OrdIndex].ButType)
			{
			case ORD_BTYPE_RADIO:
			case ORD_BTYPE_BOOLEAN:
				if ((State & OrderButtons[OrdIndex].StateMask) == (UDWORD)OrderButtons[OrdIndex].States[i])
				{
					widgSetButtonState(psWScreen, sButInit.id, WBUT_CLICKLOCK);
				}
				else
				{
					widgSetButtonState(psWScreen, sButInit.id, 0);
				}
				break;

			case ORD_BTYPE_BOOLEAN_DEPEND:
				if ((State & OrderButtons[OrdIndex].StateMask) == (UDWORD)OrderButtons[OrdIndex].States[i])
				{
					widgSetButtonState(psWScreen, sButInit.id, WBUT_CLICKLOCK);
				}
				else
				{
					if (i == 0)
					{
						widgSetButtonState(psWScreen, sButInit.id, 0);
					}
					else
					{
						widgSetButtonState(psWScreen, sButInit.id, WBUT_DISABLE);
					}
				}
				break;
			case ORD_BTYPE_BOOLEAN_COMBINE:
				if (State & (UDWORD)OrderButtons[OrdIndex].States[i])
				{
					widgSetButtonState(psWScreen, sButInit.id, WBUT_CLICKLOCK);
				}
				break;
			}

			// may not add a button if the factory doesn't exist
			bHidden = false;
			switch (OrderButtons[OrdIndex].Class)
			{
			case ORDBUTCLASS_FACTORY:
				if (!checkFactoryExists(selectedPlayer, FACTORY_FLAG, i))
				{
					widgHide(psWScreen, sButInit.id);
					bHidden = true;
				}
				break;
			case ORDBUTCLASS_CYBORGFACTORY:
				if (!checkFactoryExists(selectedPlayer, CYBORG_FLAG, i))
				{
					widgHide(psWScreen, sButInit.id);
					bHidden = true;
				}
				break;
			case ORDBUTCLASS_VTOLFACTORY:
				if (!checkFactoryExists(selectedPlayer, VTOL_FLAG, i))
				{
					widgHide(psWScreen, sButInit.id);
					bHidden = true;
				}
				break;
			default:
				break;
			}

			if (!bHidden)
			{

				sButInit.x = (SWORD)(sButInit.x + sButInit.width + ORDER_BUTGAP);
			}
			sButInit.id++;
		}

		if (((OrderButtons[OrdIndex].ButJustify & ORD_JUSTIFY_MASK) != ORD_JUSTIFY_COMBINE) ||
		    bLastCombine)
		{
			sButInit.y = (SWORD)(sButInit.y + sButInit.height + ORDER_BUTGAP);
			Height = (UWORD)(Height + sButInit.height + ORDER_BUTGAP);
		}
		NumDisplayedOrders ++;
	}

	// Now we know how many orders there are we can resize the form accordingly.
	int newHeight = Height + CLOSE_HEIGHT + ORDER_BUTGAP;
	orderForm->setGeometry(orderForm->x(), ORDER_BOTTOMY - newHeight, orderForm->width(), newHeight);

	OrderUp = true;

	return true;
}
Пример #7
0
void recvStructureInfo(NETQUEUE queue)
{
	uint8_t         player = 0;
	uint32_t        structId = 0;
	uint32_t        templateId = 0;
	uint8_t         structureInfo;
	STRUCTURE *     psStruct;
	DROID_TEMPLATE *psTempl = NULL;

	NETbeginDecode(queue, GAME_STRUCTUREINFO);
		NETuint8_t(&player);
		NETuint32_t(&structId);
		NETuint8_t(&structureInfo);
		if (structureInfo == STRUCTUREINFO_MANUFACTURE)
		{
			NETuint32_t(&templateId);
			if (templateId != 0)
			{
				psTempl = IdToTemplate(templateId, player);
				if (psTempl == NULL)
				{
					debug(LOG_SYNC, "Synch error, don't have tempate id %u, so can't change production of factory %u!", templateId, structId);
				}
			}
		}
	NETend();

	psStruct = IdToStruct(structId, player);

	syncDebug("player%d,structId%u%c,structureInfo%u,templateId%u%c", player, structId, psStruct == NULL? '^' : '*', structureInfo, templateId, psTempl == NULL? '^' : '*');

	if (psStruct == NULL)
	{
		debug(LOG_SYNC, "Couldn't find structure %u to change production.", structId);
		return;
	}

	CHECK_STRUCTURE(psStruct);

	if (StructIsFactory(psStruct))
	{
		if (psStruct->pFunctionality->factory.pendingCount == 0)
		{
			++psStruct->pFunctionality->factory.pendingCount;
		}
		if (--psStruct->pFunctionality->factory.pendingCount == 0)
		{
			// Subject is now synchronised, remove pending.
			psStruct->pFunctionality->factory.psSubjectPending = NULL;
			psStruct->pFunctionality->factory.statusPending = FACTORY_NOTHING_PENDING;
		}
	}

	syncDebugStructure(psStruct, '<');

	switch (structureInfo)
	{
		case STRUCTUREINFO_MANUFACTURE:       structSetManufacture(psStruct, psTempl, ModeImmediate); break;
		case STRUCTUREINFO_CANCELPRODUCTION:  cancelProduction(psStruct, ModeImmediate);              break;
		case STRUCTUREINFO_HOLDPRODUCTION:    holdProduction(psStruct, ModeImmediate);                break;
		case STRUCTUREINFO_RELEASEPRODUCTION: releaseProduction(psStruct, ModeImmediate);             break;
		case STRUCTUREINFO_HOLDRESEARCH:      holdResearch(psStruct, ModeImmediate);                  break;
		case STRUCTUREINFO_RELEASERESEARCH:   releaseResearch(psStruct, ModeImmediate);               break;
		default:
			debug(LOG_ERROR, "Invalid structureInfo %d", structureInfo);
	}

	syncDebugStructure(psStruct, '>');

	CHECK_STRUCTURE(psStruct);
}
Пример #8
0
// ////////////////////////////////////////////////////////////////////////////
// throw a party when you win!
bool multiplayerWinSequence(bool firstCall)
{
	static Position pos;
	Position pos2;
	static UDWORD last=0;
	float		rotAmount;
	STRUCTURE	*psStruct;

	if(firstCall)
	{
		pos  = cameraToHome(selectedPlayer,true);			// pan the camera to home if not already doing so
		last =0;

		// stop all research
		CancelAllResearch(selectedPlayer);

		// stop all manufacture.
		for(psStruct=apsStructLists[selectedPlayer];psStruct;psStruct = psStruct->psNext)
		{
			if (StructIsFactory(psStruct))
			{
				if (((FACTORY *)psStruct->pFunctionality)->psSubject)//check if active
				{
					cancelProduction(psStruct, ModeQueue);
				}
			}
		}
	}

	// rotate world
	if (MissionResUp && !getWarCamStatus())
	{
		rotAmount = graphicsTimeAdjustedIncrement(MAP_SPIN_RATE / 12);
		player.r.y += rotAmount;
	}

	if(last > gameTime)last= 0;
	if((gameTime-last) < 500 )							// only  if not done recently.
	{
		return true;
	}
	last = gameTime;

	if(rand()%3 == 0)
	{
		pos2=pos;
		pos2.x +=  (rand() % world_coord(8)) - world_coord(4);
		pos2.z +=  (rand() % world_coord(8)) - world_coord(4);

		if (pos2.x < 0)
			pos2.x = 128;

		if ((unsigned)pos2.x > world_coord(mapWidth))
			pos2.x = world_coord(mapWidth);

		if (pos2.z < 0)
			pos2.z = 128;

		if ((unsigned)pos2.z > world_coord(mapHeight))
			pos2.z = world_coord(mapHeight);

		addEffect(&pos2,EFFECT_FIREWORK,FIREWORK_TYPE_LAUNCHER,false,NULL,0);	// throw up some fire works.
	}

	// show the score..


	return true;
}
Пример #9
0
/*called when a Template is deleted in the Design screen*/
void deleteTemplateFromProduction(DROID_TEMPLATE *psTemplate, unsigned player, QUEUE_MODE mode)
{
	STRUCTURE   *psStruct;
	STRUCTURE	*psList;

	//see if any factory is currently using the template
	for (unsigned i = 0; i < 2; ++i)
	{
		psList = NULL;
		switch (i)
		{
		case 0:
			psList = apsStructLists[player];
			break;
		case 1:
			psList = mission.apsStructLists[player];
			break;
		}
		for (psStruct = psList; psStruct != NULL; psStruct = psStruct->psNext)
		{
			if (StructIsFactory(psStruct))
			{
				FACTORY             *psFactory = &psStruct->pFunctionality->factory;

				if (psFactory->psAssemblyPoint->factoryInc < asProductionRun[psFactory->psAssemblyPoint->factoryType].size())
				{
					ProductionRun &productionRun = asProductionRun[psFactory->psAssemblyPoint->factoryType][psFactory->psAssemblyPoint->factoryInc];
					for (unsigned inc = 0; inc < productionRun.size(); ++inc)
					{
						if (productionRun[inc].psTemplate->multiPlayerID == psTemplate->multiPlayerID && mode == ModeQueue)
						{
							//just need to erase this production run entry
							productionRun.erase(productionRun.begin() + inc);
							--inc;
						}
					}
				}

				if (psFactory->psSubject == NULL)
				{
					continue;
				}

				// check not being built in the factory for the template player
				if (psTemplate->multiPlayerID == psFactory->psSubject->multiPlayerID && mode == ModeImmediate)
				{
					syncDebugStructure(psStruct, '<');
					syncDebug("Clearing production");

					// Clear the factory's subject.
					psFactory->psSubject = NULL;

					if (player == productionPlayer)
					{
						//check to see if anything left to produce
						DROID_TEMPLATE *psNextTemplate = factoryProdUpdate(psStruct, NULL);
						//power is returned by factoryProdAdjust()
						if (psNextTemplate)
						{
							structSetManufacture(psStruct, psNextTemplate, ModeQueue);  // ModeQueue because production lists aren't synchronised.
						}
					}

					//tell the interface
					intManufactureFinished(psStruct);

					syncDebugStructure(psStruct, '>');
				}
			}
		}
	}
}
Пример #10
0
void recvStructureInfo(NETQUEUE queue)
{
	uint8_t         player = 0;
	uint32_t        structId = 0;
	uint32_t        templateId = 0;
	uint8_t         structureInfo;
	STRUCTURE      *psStruct;
	DROID_TEMPLATE *psTempl = NULL;

	NETbeginDecode(queue, GAME_STRUCTUREINFO);
	NETuint8_t(&player);
	NETuint32_t(&structId);
	NETuint8_t(&structureInfo);
	if (structureInfo == STRUCTUREINFO_MANUFACTURE)
	{
		NETuint32_t(&templateId);
		if (templateId != 0)
		{
			// For autogames, where we want the AI to take us over, our templates are not setup... so let's use any AI's templates.
			if (!NetPlay.players[player].autoGame)
			{
				psTempl = IdToTemplate(templateId, player);
			}
			else
			{
				psTempl = IdToTemplate(templateId, ANYPLAYER);
			}
			if (psTempl == NULL)
			{
				debug(LOG_SYNC, "Synch error, don't have tempate id %u, so can't change production of factory %u!", templateId, structId);
			}
		}
	}
	NETend();

	psStruct = IdToStruct(structId, player);

	syncDebug("player%d,structId%u%c,structureInfo%u,templateId%u%c", player, structId, psStruct == NULL ? '^' : '*', structureInfo, templateId, psTempl == NULL ? '^' : '*');

	if (psStruct == NULL)
	{
		debug(LOG_SYNC, "Couldn't find structure %u to change production.", structId);
		return;
	}
	if (!canGiveOrdersFor(queue.index, psStruct->player))
	{
		syncDebug("Wrong player.");
		return;
	}

	CHECK_STRUCTURE(psStruct);

	if (StructIsFactory(psStruct))
	{
		popStatusPending(psStruct->pFunctionality->factory);
	}
	else if (psStruct->pStructureType->type == REF_RESEARCH)
	{
		popStatusPending(psStruct->pFunctionality->researchFacility);
	}

	syncDebugStructure(psStruct, '<');

	switch (structureInfo)
	{
	case STRUCTUREINFO_MANUFACTURE:       structSetManufacture(psStruct, psTempl, ModeImmediate); break;
	case STRUCTUREINFO_CANCELPRODUCTION:  cancelProduction(psStruct, ModeImmediate, false);       break;
	case STRUCTUREINFO_HOLDPRODUCTION:    holdProduction(psStruct, ModeImmediate);                break;
	case STRUCTUREINFO_RELEASEPRODUCTION: releaseProduction(psStruct, ModeImmediate);             break;
	case STRUCTUREINFO_HOLDRESEARCH:      holdResearch(psStruct, ModeImmediate);                  break;
	case STRUCTUREINFO_RELEASERESEARCH:   releaseResearch(psStruct, ModeImmediate);               break;
	default:
		debug(LOG_ERROR, "Invalid structureInfo %d", structureInfo);
	}

	syncDebugStructure(psStruct, '>');

	CHECK_STRUCTURE(psStruct);
}