/** * Unknown function 0C5A. * * Stack: *none* * * @param script The script engine to operate on. * @return unknown. */ uint16 Script_Structure_Unknown0C5A(ScriptEngine *script) { tile32 tile; Structure *s; Unit *u; uint16 position; VARIABLE_NOT_USED(script); s = g_scriptCurrentStructure; if (s->o.linkedID == 0xFF) return 0; u = Unit_Get_ByIndex(s->o.linkedID); if (g_table_unitInfo[u->o.type].movementType == MOVEMENT_WINGER && Unit_SetPosition(u, s->o.position)) { s->o.linkedID = u->o.linkedID; u->o.linkedID = 0xFF; if (s->o.linkedID == 0xFF) Structure_SetState(s, STRUCTURE_STATE_IDLE); Object_Script_Variable4_Clear(&s->o); if (s->o.houseID == g_playerHouseID) Sound_Output_Feedback(g_playerHouseID + 49); return 1; } position = Structure_FindFreePosition(s, u->o.type == UNIT_HARVESTER); if (position == 0) return 0; u->o.seenByHouses |= s->o.seenByHouses; tile = Tile_Center(Tile_UnpackTile(position)); if (!Unit_SetPosition(u, tile)) return 0; s->o.linkedID = u->o.linkedID; u->o.linkedID = 0xFF; Unit_SetOrientation(u, Tile_GetDirection(s->o.position, u->o.position) & 0xE0, true, 0); Unit_SetOrientation(u, u->orientation[0].current, true, 1); if (u->o.houseID == g_playerHouseID && u->o.type == UNIT_HARVESTER) { GUI_DisplayHint(STR_SEARCH_FOR_SPICE_FIELDS_TO_HARVEST, 0x6A); } if (s->o.linkedID == 0xFF) Structure_SetState(s, STRUCTURE_STATE_IDLE); Object_Script_Variable4_Clear(&s->o); if (s->o.houseID != g_playerHouseID) return 1; if (s->o.type == STRUCTURE_REPAIR) return 1; Sound_Output_Feedback(g_playerHouseID + ((u->o.type == UNIT_HARVESTER) ? 68 : 30)); return 1; }
/** * Refine spice in the current structure. * * Stack: *none* * * @param script The script engine to operate on. * @return 0 if there is no spice to refine, otherwise 1. */ uint16 Script_Structure_RefineSpice(ScriptEngine *script) { const StructureInfo *si; Structure *s; Unit *u; House *h; uint16 harvesterStep, creditsStep; VARIABLE_NOT_USED(script); s = g_scriptCurrentStructure; if (s->o.linkedID == 0xFF) { Structure_SetState(s, STRUCTURE_STATE_IDLE); return 0; } u = Unit_Get_ByIndex(s->o.linkedID); si = &g_table_structureInfo[s->o.type]; harvesterStep = (s->o.hitpoints * 256 / si->o.hitpoints) * 3 / 256; if (u->amount < harvesterStep) harvesterStep = u->amount; if (u->amount != 0 && harvesterStep < 1) harvesterStep = 1; if (harvesterStep == 0) return 0; creditsStep = 7; if (u->o.houseID != g_playerHouseID) { creditsStep += (Tools_Random_256() % 4) - 1; } creditsStep *= harvesterStep; if (House_AreAllied(g_playerHouseID, s->o.houseID)) { g_scenario.harvestedAllied += creditsStep; if (g_scenario.harvestedAllied > 65000) g_scenario.harvestedAllied = 65000; } else { g_scenario.harvestedEnemy += creditsStep; if (g_scenario.harvestedEnemy > 65000) g_scenario.harvestedEnemy = 65000; } h = House_Get_ByIndex(s->o.houseID); h->credits += creditsStep; u->amount -= harvesterStep; if (u->amount == 0) u->o.flags.s.inTransport = false; s->o.script.delay = 6; return 1; }
/** * Set in a safe way the new value for variable4. * @param o The Object to set variable4 for. * @param index The encoded index to set it to. */ void Object_Script_Variable4_Set(Object* o, uint16 encoded) { StructureInfo* si; Structure* s; if (o == NULL) return; o->script.variables[4] = encoded; if (o->flags.s.isUnit) return; si = &g_table_structureInfo[o->type]; if (!si->o.flags.busyStateIsIncoming) return; s = (Structure *)o; if (Structure_GetLinkedUnit(s) != NULL) return; Structure_SetState(s, (encoded == 0) ? STRUCTURE_STATE_IDLE : STRUCTURE_STATE_BUSY); }
/** * Set the state for the current structure. * * Stack: 1 - The state. * * @param script The script engine to operate on. * @return The value 0. Always. */ uint16 Script_Structure_SetState(ScriptEngine *script) { Structure *s; int16 state; s = g_scriptCurrentStructure; state = STACK_PEEK(1); if (state == STRUCTURE_STATE_DETECT) { if (s->o.linkedID == 0xFF) { state = STRUCTURE_STATE_IDLE; } else { if (s->countDown == 0) { state = STRUCTURE_STATE_READY; } else { state = STRUCTURE_STATE_BUSY; } } } Structure_SetState(s, state); return 0; }
/** * Prepare the map (after loading scenario or savegame). Does some basic * sanity-check and corrects stuff all over the place. */ void Game_Prepare(void) { PoolFindStruct find; uint16 oldSelectionType; Tile *t; int i; g_validateStrictIfZero++; oldSelectionType = g_selectionType; g_selectionType = SELECTIONTYPE_MENTAT; Structure_Recount(); Unit_Recount(); Team_Recount(); t = &g_map[0]; for (i = 0; i < 64 * 64; i++, t++) { Structure *s; Unit *u; u = Unit_Get_ByPackedTile(i); s = Structure_Get_ByPackedTile(i); if (u == NULL || !u->o.flags.s.used) t->hasUnit = false; if (s == NULL || !s->o.flags.s.used) t->hasStructure = false; if (t->isUnveiled) Map_UnveilTile(i, g_playerHouseID); } find.houseID = HOUSE_INVALID; find.index = 0xFFFF; find.type = 0xFFFF; while (true) { Unit *u; u = Unit_Find(&find); if (u == NULL) break; if (u->o.flags.s.isNotOnMap) continue; Unit_RemoveFog(u); Unit_UpdateMap(1, u); } find.houseID = HOUSE_INVALID; find.index = 0xFFFF; find.type = 0xFFFF; while (true) { Structure *s; s = Structure_Find(&find); if (s == NULL) break; if (s->o.type == STRUCTURE_SLAB_1x1 || s->o.type == STRUCTURE_SLAB_2x2 || s->o.type == STRUCTURE_WALL) continue; if (s->o.flags.s.isNotOnMap) continue; Structure_RemoveFog(s); if (s->o.type == STRUCTURE_STARPORT && s->o.linkedID != 0xFF) { Unit *u = Unit_Get_ByIndex(s->o.linkedID); if (!u->o.flags.s.used || !u->o.flags.s.isNotOnMap) { s->o.linkedID = 0xFF; s->countDown = 0; } else { Structure_SetState(s, STRUCTURE_STATE_READY); } } Script_Load(&s->o.script, s->o.type); if (s->o.type == STRUCTURE_PALACE) { House_Get_ByIndex(s->o.houseID)->palacePosition = s->o.position; } if ((House_Get_ByIndex(s->o.houseID)->palacePosition.x != 0) || (House_Get_ByIndex(s->o.houseID)->palacePosition.y != 0)) continue; House_Get_ByIndex(s->o.houseID)->palacePosition = s->o.position; } find.houseID = HOUSE_INVALID; find.index = 0xFFFF; find.type = 0xFFFF; while (true) { House *h; h = House_Find(&find); if (h == NULL) break; h->structuresBuilt = Structure_GetStructuresBuilt(h); House_UpdateCreditsStorage((uint8)h->index); House_CalculatePowerAndCredit(h); } GUI_Palette_CreateRemap(g_playerHouseID); Map_SetSelection(g_selectionPosition); if (g_structureActiveType != 0xFFFF) { Map_SetSelectionSize(g_table_structureInfo[g_structureActiveType].layout); } else { Structure *s = Structure_Get_ByPackedTile(g_selectionPosition); if (s != NULL) Map_SetSelectionSize(g_table_structureInfo[s->o.type].layout); } Voice_LoadVoices(g_playerHouseID); g_tickHousePowerMaintenance = max(g_timerGame + 70, g_tickHousePowerMaintenance); g_viewport_forceRedraw = true; g_playerCredits = 0xFFFF; g_selectionType = oldSelectionType; g_validateStrictIfZero--; }
/** * Pickup a unit (either from structure or on the map). The unit that does the * picking up returns the unit to his last position. * * Stack: *none*. * * @param script The script engine to operate on. * @return The value 0. Always. */ uint16 Script_Unit_Pickup(ScriptEngine *script) { Unit *u; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; if (u->o.linkedID != 0xFF) return 0; switch (Tools_Index_GetType(u->targetMove)) { case IT_STRUCTURE: { Structure *s; Unit *u2; s = Tools_Index_GetStructure(u->targetMove); /* There was nothing to pickup here */ if (s->state != STRUCTURE_STATE_READY) { Object_Script_Variable4_Clear(&u->o); u->targetMove = 0; return 0; } u->o.flags.s.inTransport = true; Object_Script_Variable4_Clear(&u->o); u->targetMove = 0; u2 = Unit_Get_ByIndex(s->o.linkedID); /* Pickup the unit */ u->o.linkedID = u2->o.index & 0xFF; s->o.linkedID = u2->o.linkedID; u2->o.linkedID = 0xFF; if (s->o.linkedID == 0xFF) Structure_SetState(s, STRUCTURE_STATE_IDLE); /* Check if the unit has a return-to position or try to find spice in case of a harvester */ if (u2->targetLast.tile != 0) { u->targetMove = Tools_Index_Encode(Tile_PackTile(u2->targetLast), IT_TILE); } else if (u2->o.type == UNIT_HARVESTER && Unit_GetHouseID(u2) != g_playerHouseID) { u->targetMove = Tools_Index_Encode(Map_SearchSpice(Tile_PackTile(u->o.position), 20), IT_TILE); } Unit_UpdateMap(2, u); return 1; } case IT_UNIT: { Unit *u2; Structure *s = NULL; PoolFindStruct find; int16 minDistance = 0; u2 = Tools_Index_GetUnit(u->targetMove); if (!u2->o.flags.s.allocated) return 0; find.houseID = Unit_GetHouseID(u); find.index = 0xFFFF; find.type = 0xFFFF; /* Find closest refinery / repair station */ while (true) { Structure *s2; int16 distance; s2 = Structure_Find(&find); if (s2 == NULL) break; distance = Tile_GetDistanceRoundedUp(s2->o.position, u->o.position); if (u2->o.type == UNIT_HARVESTER) { if (s2->o.type != STRUCTURE_REFINERY || s2->state != STRUCTURE_STATE_IDLE || s2->o.script.variables[4] != 0) continue; if (minDistance != 0 && distance >= minDistance) break; minDistance = distance; s = s2; break; } if (s2->o.type != STRUCTURE_REPAIR || s2->state != STRUCTURE_STATE_IDLE || s2->o.script.variables[4] != 0) continue; if (minDistance != 0 && distance >= minDistance) continue; minDistance = distance; s = s2; } if (s == NULL) return 0; /* Deselect the unit as it is about to be picked up */ if (u2 == g_unitSelected) Unit_Select(NULL); /* Pickup the unit */ u->o.linkedID = u2->o.index & 0xFF; u->o.flags.s.inTransport = true; Unit_UpdateMap(0, u2); Unit_Hide(u2); /* Set where we are going to */ Object_Script_Variable4_Link(Tools_Index_Encode(u->o.index, IT_UNIT), Tools_Index_Encode(s->o.index, IT_STRUCTURE)); u->targetMove = u->o.script.variables[4]; Unit_UpdateMap(2, u); if (u2->o.type != UNIT_HARVESTER) return 0; /* Check if we want to return to this spice field later */ if (Map_SearchSpice(Tile_PackTile(u2->o.position), 2) == 0) { u2->targetPreLast.tile = 0; u2->targetLast.tile = 0; } return 0; } default: return 0; } }
/** * Delivery of transport, either to structure or to a tile. * * Stack: *none*. * * @param script The script engine to operate on. * @return One if delivered, zero otherwise.. */ uint16 Script_Unit_TransportDeliver(ScriptEngine *script) { Unit *u; Unit *u2; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; if (u->o.linkedID == 0xFF) return 0; if (Tools_Index_GetType(u->targetMove) == IT_UNIT) return 0; if (Tools_Index_GetType(u->targetMove) == IT_STRUCTURE) { const StructureInfo *si; Structure *s; s = Tools_Index_GetStructure(u->targetMove); si = &g_table_structureInfo[s->o.type]; if (s->o.type == STRUCTURE_STARPORT) { uint16 ret = 0; if (s->state == STRUCTURE_STATE_BUSY) { s->o.linkedID = u->o.linkedID; u->o.linkedID = 0xFF; u->o.flags.s.inTransport = false; u->amount = 0; Unit_UpdateMap(2, u); Voice_PlayAtTile(24, u->o.position); Structure_SetState(s, STRUCTURE_STATE_READY); ret = 1; } Object_Script_Variable4_Clear(&u->o); u->targetMove = 0; return ret; } if ((s->state == STRUCTURE_STATE_IDLE || (si->o.flags.busyStateIsIncoming && s->state == STRUCTURE_STATE_BUSY)) && s->o.linkedID == 0xFF) { Voice_PlayAtTile(24, u->o.position); Unit_EnterStructure(Unit_Get_ByIndex(u->o.linkedID), s); Object_Script_Variable4_Clear(&u->o); u->targetMove = 0; u->o.linkedID = 0xFF; u->o.flags.s.inTransport = false; u->amount = 0; Unit_UpdateMap(2, u); return 1; } Object_Script_Variable4_Clear(&u->o); u->targetMove = 0; return 0; } if (!Map_IsValidPosition(Tile_PackTile(Tile_Center(u->o.position)))) return 0; u2 = Unit_Get_ByIndex(u->o.linkedID); if (!Unit_SetPosition(u2, Tile_Center(u->o.position))) return 0; if (u2->o.houseID == g_playerHouseID) { Voice_PlayAtTile(24, u->o.position); } Unit_SetOrientation(u2, u->orientation[0].current, true, 0); Unit_SetOrientation(u2, u->orientation[0].current, true, 1); Unit_SetSpeed(u2, 0); u->o.linkedID = u2->o.linkedID; u2->o.linkedID = 0xFF; if (u->o.linkedID != 0xFF) return 1; u->o.flags.s.inTransport = false; Object_Script_Variable4_Clear(&u->o); u->targetMove = 0; return 1; }