/** ** Show the current order of a unit. ** ** @param unit Pointer to the unit. */ void ShowOrder(const CUnit &unit) { if (unit.Destroyed || unit.Removed) { return; } #ifndef DEBUG if (!ThisPlayer->IsAllied(unit) && unit.Player != ThisPlayer) { return; } #endif // Get current position const PixelPos mapPos = unit.GetMapPixelPosCenter(); PixelPos screenStartPos = CurrentViewport->MapToScreenPixelPos(mapPos); const bool flushed = unit.Orders[0]->Finished; COrderPtr order; // If the current order is cancelled show the next one if (unit.Orders.size() > 1 && flushed) { order = unit.Orders[1]; } else { order = unit.Orders[0]; } PixelPos screenPos = order->Show(*CurrentViewport, screenStartPos); // Show the rest of the orders for (size_t i = 1 + (flushed ? 1 : 0); i < unit.Orders.size(); ++i) { screenPos = unit.Orders[i]->Show(*CurrentViewport, screenPos); } // Show order for new trained units if (unit.NewOrder) { unit.NewOrder->Show(*CurrentViewport, screenStartPos); } }
/** ** Get the location of a unit's order. ** ** @param unit Pointer to unit. ** @param order Pointer to order. ** @param x Resulting screen X cordinate. ** @param y Resulting screen Y cordinate. */ static void GetOrderPosition(const CUnit &unit, const COrderPtr order, int *x, int *y) { CUnit *goal; // FIXME: n0body: Check for goal gone? if ((goal = order->GetGoal()) && (!goal->Removed)) { // Order has a goal, get it's location. *x = CurrentViewport->Map2ViewportX(goal->tilePos.x) + goal->IX + goal->Type->TileWidth * TileSizeX / 2; *y = CurrentViewport->Map2ViewportY(goal->tilePos.y) + goal->IY + goal->Type->TileHeight * TileSizeY / 2; } else { if (order->goalPos.x >= 0 && order->goalPos.y >= 0) { // Order is for a location, show that. *x = CurrentViewport->Map2ViewportX(order->goalPos.x) + TileSizeX / 2; *y = CurrentViewport->Map2ViewportY(order->goalPos.y) + TileSizeY / 2; } else { // Some orders ignore x,y (like StandStill). // Use the unit's position instead. *x = CurrentViewport->Map2ViewportX(unit.tilePos.x) + unit.IX + unit.Type->TileWidth * TileSizeX / 2; *y = CurrentViewport->Map2ViewportY(unit.tilePos.y) + unit.IY + unit.Type->TileHeight * TileSizeY / 2; } if (order->Action == UnitActionBuild) { *x += (order->Arg1.Type->TileWidth - 1) * TileSizeX / 2; *y += (order->Arg1.Type->TileHeight - 1) * TileSizeY / 2; } } }
/** ** Check if there's a unit that should be repaired. */ static void AiCheckRepair() { int i; int j; int k; int n; bool repair_flag; n = AiPlayer->Player->TotalNumUnits; k = 0; // Selector for next unit for (i = n - 1; i >= 0; --i) { CUnit *unit = AiPlayer->Player->Units[i]; if (unit && UnitNumber(*unit) == AiPlayer->LastRepairBuilding) { k = i + 1; } } for (i = k; i < n; ++i) { CUnit &unit = *AiPlayer->Player->Units[i]; repair_flag = true; if (!unit.IsAliveOnMap()) { continue; } // Unit damaged? // Don't repair attacked unit (wait 5 sec before repairing) if (unit.Type->RepairHP && unit.CurrentAction() != UnitActionBuilt && unit.CurrentAction() != UnitActionUpgradeTo && unit.Variable[HP_INDEX].Value < unit.Variable[HP_INDEX].Max && unit.Attacked + 5 * CYCLES_PER_SECOND < GameCycle) { // // FIXME: Repair only units under control // if (AiEnemyUnitsInDistance(unit, unit.Stats->Variables[SIGHTRANGE_INDEX].Max)) { continue; } // // Must check, if there are enough resources // for (j = 1; j < MaxCosts; ++j) { if (unit.Stats->Costs[j] && AiPlayer->Player->Resources[j] < 99) { repair_flag = false; break; } } // // Find a free worker, who can build this building can repair it? // if (repair_flag) { AiRepairUnit(unit); AiPlayer->LastRepairBuilding = UnitNumber(unit); return; } } // Building under construction but no worker if (unit.CurrentAction() == UnitActionBuilt) { int j; for (j = 0; j < AiPlayer->Player->TotalNumUnits; ++j) { COrderPtr order = AiPlayer->Player->Units[j]->CurrentOrder(); if (order->Action == UnitActionRepair && order->GetGoal() == &unit) { break; } } if (j == AiPlayer->Player->TotalNumUnits) { // Make sure we have enough resources first for (j = 0; j < MaxCosts; ++j) { // FIXME: the resources don't necessarily have to be in storage if (AiPlayer->Player->Resources[j] < unit.Stats->Costs[j]) { break; } } if (j == MaxCosts) { AiRepairUnit(unit); AiPlayer->LastRepairBuilding = UnitNumber(unit); return; } } } } AiPlayer->LastRepairBuilding = 0; }
/** ** Save an order. ** ** @param order Order who should be saved. ** @param file Output file. */ void SaveOrder(const COrderPtr order, CFile *file) { file->printf("{"); switch (order->Action) { case UnitActionNone: file->printf("\"action-none\","); break; case UnitActionStill: file->printf("\"action-still\","); break; case UnitActionStandGround: file->printf("\"action-stand-ground\","); break; case UnitActionFollow: file->printf("\"action-follow\","); break; case UnitActionMove: file->printf("\"action-move\","); break; case UnitActionAttack: file->printf("\"action-attack\","); break; case UnitActionAttackGround: file->printf("\"action-attack-ground\","); break; case UnitActionDie: file->printf("\"action-die\","); break; case UnitActionSpellCast: file->printf("\"action-spell-cast\","); break; case UnitActionTrain: file->printf("\"action-train\","); break; case UnitActionUpgradeTo: file->printf("\"action-upgrade-to\","); break; case UnitActionResearch: file->printf("\"action-research\","); break; case UnitActionBuilt: file->printf("\"action-built\","); break; case UnitActionBoard: file->printf("\"action-board\","); break; case UnitActionUnload: file->printf("\"action-unload\","); break; case UnitActionPatrol: file->printf("\"action-patrol\","); break; case UnitActionBuild: file->printf("\"action-build\","); break; case UnitActionRepair: file->printf("\"action-repair\","); break; case UnitActionResource: file->printf("\"action-resource\","); break; case UnitActionReturnGoods: file->printf("\"action-return-goods\","); break; case UnitActionTransformInto: file->printf("\"action-transform-into\","); break; default: DebugPrint("Unknown action in order\n"); } file->printf(" \"range\", %d,", order->Range); file->printf(" \"width\", %d,", order->Width); file->printf(" \"height\", %d,", order->Height); file->printf(" \"min-range\", %d,", order->MinRange); if (order->HasGoal()) { CUnit &goal = *order->GetGoal(); if (goal.Destroyed) { /* this unit is destroyed so it's not in the global unit * array - this means it won't be saved!!! */ printf ("FIXME: storing destroyed Goal - loading will fail.\n"); } file->printf(" \"goal\", \"%s\",", UnitReference(goal).c_str()); } file->printf(" \"tile\", {%d, %d}", order->goalPos.x, order->goalPos.y); // Extra arg. switch (order->Action) { case UnitActionTrain: case UnitActionUpgradeTo: case UnitActionBuild: case UnitActionTransformInto: file->printf(", \"type\", \"%s\"", order->Arg1.Type->Ident.c_str()); break; case UnitActionPatrol: file->printf(", \"patrol\", {%d, %d}", order->Arg1.Patrol.x, order->Arg1.Patrol.y); break; case UnitActionSpellCast: if (order->Arg1.Spell) { file->printf(", \"spell\", \"%s\"", order->Arg1.Spell->Ident.c_str()); } break; case UnitActionResearch: if (order->Arg1.Upgrade) { file->printf(", \"upgrade\", \"%s\"", order->Arg1.Upgrade->Ident.c_str()); } break; case UnitActionResource : case UnitActionReturnGoods : if (order->CurrentResource) { file->printf(", \"current-resource\", \"%s\",", DefaultResourceNames[order->CurrentResource].c_str()); if(order->CurrentResource == WoodCost) { file->printf(" \"resource-pos\", {%d, %d}", order->Arg1.Resource.Pos.x, order->Arg1.Resource.Pos.y); } else { if (order->Arg1.Resource.Mine->Destroyed) { /* this unit is destroyed so it's not in the global unit * array - this means it won't be saved!!! */ printf ("FIXME: storing destroyed Mine - loading will fail.\n"); } file->printf(" \"resource-mine\", \"%s\"", UnitReference(*order->Arg1.Resource.Mine).c_str()); } } break; default: break; } file->printf("}"); }