/** ** Cast a spell at position or unit. ** ** @param unit Pointer to unit. ** @param pos map position to spell cast on. ** @param dest Spell cast on unit (if exist). ** @param spell Spell type pointer. ** @param flush If true, flush command queue. */ void CommandSpellCast(CUnit &unit, const Vec2i &pos, CUnit *dest, const SpellType &spell, int flush, bool isAutocast) { DebugPrint(": %d casts %s at %d %d on %d\n" _C_ UnitNumber(unit) _C_ spell.Ident.c_str() _C_ pos.x _C_ pos.y _C_ dest ? UnitNumber(*dest) : 0); Assert(unit.Type->CanCastSpell[spell.Slot]); Assert(Map.Info.IsPointOnMap(pos)); if (IsUnitValidForNetwork(unit) == false) { return ; } //Wyrmgus start CMapField &mf = *Map.Field(unit.tilePos); if ((mf.Flags & MapFieldBridge) && !unit.Type->BoolFlag[BRIDGE_INDEX].value && unit.Type->UnitType == UnitTypeLand) { std::vector<CUnit *> table; Select(unit.tilePos, unit.tilePos, table); for (size_t i = 0; i != table.size(); ++i) { if (!table[i]->Removed && table[i]->Type->BoolFlag[BRIDGE_INDEX].value && table[i]->CanMove()) { CommandStopUnit(*table[i]); //always stop the raft if a new command is issued } } } //Wyrmgus end COrderPtr *order = GetNextOrder(unit, flush); if (order == NULL) { return; } *order = COrder::NewActionSpellCast(spell, pos, dest, true); ClearSavedAction(unit); }
/** ** Prepare send of command message. ** ** Convert arguments into network format and place it into output queue. ** ** @param command Command (Move,Attack,...). ** @param unit Unit that receive the command. ** @param x optional X map position. ** @param y optional y map position. ** @param dest optional destination unit. ** @param type optional unit-type argument. ** @param status Append command or flush old commands. ** ** @warning Destination and unit-type shares the same network slot. */ void NetworkSendCommand(int command, const CUnit &unit, int x, int y, const CUnit *dest, const CUnitType *type, int status) { CNetworkCommandQueue ncq; ncq.Time = GameCycle; ncq.Type = command; if (status) { ncq.Type |= 0x80; } CNetworkCommand nc; nc.Unit = UnitNumber(unit); nc.X = x; nc.Y = y; Assert(!dest || !type); // Both together isn't allowed if (dest) { nc.Dest = UnitNumber(*dest); } else if (type) { nc.Dest = type->Slot; } else { nc.Dest = 0xFFFF; // -1 } ncq.Data.resize(nc.Size()); nc.Serialize(&ncq.Data[0]); // Check for duplicate command in queue if (std::find(CommandsIn.begin(), CommandsIn.end(), ncq) != CommandsIn.end()) { return; } CommandsIn.push_back(ncq); }
bool operator()(const CUnit *c1, const CUnit *c2) { int d1 = c1->MapDistanceTo(*referenceunit); int d2 = c2->MapDistanceTo(*referenceunit); if (d1 == d2) { return UnitNumber(*c1) < UnitNumber(*c2); } else { return d1 < d2; } }
static bool IsPiercedUnit(const Missile &missile, const CUnit &unit) { for (std::vector<CUnit *>::const_iterator it = missile.PiercedUnits.begin(); it != missile.PiercedUnits.end(); ++it) { CUnit &punit = **it; if (UnitNumber(unit) == UnitNumber(punit)) { return true; } } return false; }
int AiForceManager::GetForce(const CUnit &unit) { for (unsigned int i = 0; i < forces.size(); ++i) { AiForce &force = forces[i]; for (unsigned int j = 0; j < force.Units.size(); ++j) { CUnit &aiunit = *force.Units[j]; if (UnitNumber(unit) == UnitNumber(aiunit)) { return i; } } } return -1; }
/** ** Call a lua callback to make user actions in Lua script ** ** @param caster Unit that casts the spell ** @param spell Spell-type pointer ** @param target Target ** @param goalPos coord of target spot when/if target does not exist ** ** @return =!0 if spell should be repeated, 0 if not */ /* virtual */ int Spell_LuaCallback::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &goalPos) { if (this->Func) { this->Func->pushPreamble(); this->Func->pushString(spell.Ident); this->Func->pushInteger(UnitNumber(caster)); this->Func->pushInteger(goalPos.x); this->Func->pushInteger(goalPos.y); this->Func->pushInteger((target && target->IsAlive()) ? UnitNumber(*target) : -1); this->Func->run(1); bool result = this->Func->popBoolean(); return result; } return 0; }
/** ** Cast a spell at position or unit. ** ** @param unit Pointer to unit. ** @param x X map position to spell cast on. ** @param y Y map position to spell cast on. ** @param dest Spell cast on unit (if exist). ** @param spell Spell type pointer. ** @param flush If true, flush command queue. */ void CommandSpellCast(CUnit *unit, int x, int y, CUnit *dest, SpellType *spell, int flush) { COrder *order; Assert(x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight); DebugPrint(": %d casts %s at %d %d on %d\n" _C_ UnitNumber(unit) _C_ spell->Ident.c_str() _C_ x _C_ y _C_ dest ? UnitNumber(dest) : 0); Assert(unit->Type->CanCastSpell[spell->Slot]); // // Check if unit is still valid? (NETWORK!) // if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) { // FIXME: should I check here, if there is still enough mana? if (!(order = GetNextOrder(unit, flush))) { return; } order->Init(); order->Action = UnitActionSpellCast; order->Range = spell->Range; if (dest) { // // Destination could be killed. // Should be handled in action, but is not possible! // Unit::Refs is used as timeout counter. // if (dest->Destroyed) { // FIXME: where check if spell needs an unit as destination? // FIXME: dest->Type is now set to 0. maybe we shouldn't bother. order->X = dest->X /*+ dest->Type->TileWidth / 2*/ - order->Range; order->Y = dest->Y /*+ dest->Type->TileHeight / 2*/ - order->Range; order->Range <<= 1; } else { order->Goal = dest; dest->RefsIncrease(); } } else { order->X = x; order->Y = y; } order->Arg1.Spell = spell; } ClearSavedAction(unit); }
/** ** Sends my selections to teammates ** ** @param units Units to send ** @param count Number of units to send */ void NetworkSendSelection(CUnit **units, int count) { // Check if we have any teammates to send to bool hasteammates = false; for (int i = 0; i < HostsCount; ++i) { if (Players[Hosts[i].PlyNr].Team == ThisPlayer->Team) { hasteammates = true; break; } } if (!hasteammates) { return; } // Build and send packets to cover all units. CNetworkSelection ns; for (int i = 0; i != count; ++i) { ns.Units.push_back(UnitNumber(*units[i])); } CNetworkCommandQueue ncq; ncq.Time = GameCycle; ncq.Type = MessageSelection; ncq.Data.resize(ns.Size()); ns.Serialize(&ncq.Data[0]); CommandsIn.push_back(ncq); }
/** ** Unit upgrades unit! ** ** @param unit Pointer to unit. */ global void HandleActionUpgradeTo(Unit* unit) { Player* player; UnitType* type; const UnitStats* stats; DebugLevel3Fn(" %d\n" _C_ UnitNumber(unit)); player=unit->Player; if( !unit->SubAction ) { // first entry unit->Data.UpgradeTo.Ticks=0; unit->SubAction=1; } type=unit->Orders[0].Type; stats=&type->Stats[player->Player]; UnitMarkSeen(unit); // FIXME: Should count down here unit->Data.UpgradeTo.Ticks+=SpeedUpgrade; if( unit->Data.UpgradeTo.Ticks>=stats->Costs[TimeCost] ) { unit->HP+=stats->HitPoints-unit->Type->Stats[player->Player].HitPoints; // don't have such unit now player->UnitTypesCount[unit->Type->Type]--; unit->Type=type; unit->Stats=(UnitStats*)stats; // and we have new one... player->UnitTypesCount[unit->Type->Type]++; UpdateForNewUnit(unit,1); NotifyPlayer(player,NotifyGreen,unit->X,unit->Y, "Upgrade to %s complete",unit->Type->Name ); if( unit->Player->Ai ) { AiUpgradeToComplete(unit,type); } unit->Reset=unit->Wait=1; unit->Orders[0].Action=UnitActionStill; unit->SubAction=0; // // Update possible changed buttons. // if( IsOnlySelected(unit) ) { UpdateButtonPanel(); MustRedraw|=RedrawPanels; } else if( player==ThisPlayer ) { UpdateButtonPanel(); MustRedraw|=RedrawInfoPanel; } return; } if( IsOnlySelected(unit) ) { MustRedraw|=RedrawInfoPanel; } unit->Reset=1; unit->Wait=CYCLES_PER_SECOND/6; }
/** ** Ask to the sound server to play a sound attached to a unit. The ** sound server may discard the sound if needed (e.g., when the same ** unit is already speaking). ** ** @param unit Sound initiator, unit speaking ** @param voice Type of sound wanted (Ready,Die,Yes,...) */ void PlayUnitSound(const CUnit &unit, UnitVoiceGroup voice) { CSound *sound = ChooseUnitVoiceSound(unit, voice); if (!sound) { return; } bool selection = (voice == VoiceSelected || voice == VoiceBuilding); Origin source = {&unit, unsigned(UnitNumber(unit))}; //Wyrmgus start // if (UnitSoundIsPlaying(&source)) { if (UnitSoundIsPlaying(&source) && voice != VoiceHit && voice != VoiceMiss && voice != VoiceStep) { //Wyrmgus end return; } int channel = PlaySample(ChooseSample(sound, selection, source), &source); if (channel == -1) { return; } //Wyrmgus start // SetChannelVolume(channel, CalculateVolume(false, ViewPointDistanceToUnit(unit), sound->Range)); SetChannelVolume(channel, CalculateVolume(false, ViewPointDistanceToUnit(unit), sound->Range) * sound->VolumePercent / 100); //Wyrmgus end SetChannelStereo(channel, CalculateStereo(unit)); //Wyrmgus start SetChannelVoiceGroup(channel, voice); //Wyrmgus end }
/** ** Get a player's units in rectangle box specified with 2 coordinates ** ** @param l Lua state. ** ** @return Array of units. */ static int CclGetUnitsAroundUnit(lua_State *l) { const int nargs = lua_gettop(l); if (nargs != 2 && nargs != 3) { LuaError(l, "incorrect argument\n"); } const int slot = LuaToNumber(l, 1); const CUnit &unit = UnitManager.GetSlotUnit(slot); const int range = LuaToNumber(l, 2); bool allUnits = false; if (nargs == 3) { allUnits = LuaToBoolean(l, 3); } lua_newtable(l); std::vector<CUnit *> table; if (allUnits) { SelectAroundUnit(unit, range, table, HasNotSamePlayerAs(Players[PlayerNumNeutral])); } else { SelectAroundUnit(unit, range, table, HasSamePlayerAs(*unit.Player)); } size_t n = 0; for (size_t i = 0; i < table.size(); ++i) { if (table[i]->IsAliveOnMap()) { lua_pushnumber(l, UnitNumber(*table[i])); lua_rawseti(l, -2, ++n); } } return 1; }
/** ** Generate a unit reference, a printable unique string for unit. */ std::string UnitReference(const CUnit &unit) { std::ostringstream ss; ss << "U" << std::setfill('0') << std::setw(4) << std::uppercase << std::hex << UnitNumber(unit); return ss.str(); }
/** ** Called if upgrading of an unit is completed. ** ** @param unit Pointer to unit working. ** @param what Pointer to the new unit-type. */ void AiUpgradeToComplete(CUnit &unit, const CUnitType &what) { DebugPrint("%d: %d(%s) upgrade-to %s at %d,%d completed\n" _C_ unit.Player->Index _C_ UnitNumber(unit) _C_ unit.Type->Ident.c_str() _C_ what.Ident.c_str() _C_ unit.tilePos.x _C_ unit.tilePos.y); Assert(unit.Player->Type != PlayerPerson); }
CUnit* GetUnitByID(int unitID) { int i; for (i = 0; i < NumUnits; i++) if (UnitNumber(Units[i]) == unitID) return Units[i]; return NoUnitP; }
/** ** Called if a member of Group is Attacked ** ** @param attacker Pointer to attacker unit. ** @param defender Pointer to unit that is being attacked. */ void GroupHelpMe(CUnit *attacker, CUnit &defender) { /* Freandly Fire - typical splash */ if (!attacker || attacker->Player->Index == defender.Player->Index) { return; } DebugPrint("%d: GroupHelpMe %d(%s) attacked at %d,%d\n" _C_ defender.Player->Index _C_ UnitNumber(defender) _C_ defender.Type->Ident.c_str() _C_ defender.tilePos.x _C_ defender.tilePos.y); // // Don't send help to scouts (zeppelin,eye of vision). // if (!defender.Type->CanAttack && defender.Type->UnitType == UnitTypeFly) { return; } if (defender.GroupId) { int mask = 0; CUnitGroup *group; for (int num = 0; num < NUM_GROUPS; ++num) { // Unit belongs to an group, check if brothers in arms can help if (defender.GroupId & (1<<num)) { mask |= (1<<num); group = &Groups[num]; for (int i = 0; i < group->NumUnits; ++i) { CUnit &gunit = *group->Units[i]; if (&defender == &gunit) { continue; } // if brother is idle or attack no-agressive target and // can attack our attacker then ask for help if (gunit.IsAgressive() && (gunit.IsIdle() || !(gunit.CurrentAction() == UnitActionAttack && gunit.CurrentOrder()->HasGoal() && gunit.CurrentOrder()->GetGoal()->IsAgressive())) && CanTarget(gunit.Type, attacker->Type)) { if (gunit.SavedOrder.Action == UnitActionStill) { // FIXME: should rewrite command handling CommandAttack(gunit, gunit.tilePos, NoUnitP, FlushCommands); gunit.SavedOrder = *gunit.Orders[1]; } CommandAttack(gunit, attacker->tilePos, attacker, FlushCommands); } } if (!(defender.GroupId & ~mask)) { return; } } } } }
/** ** Called if a Unit is Attacked ** ** @param attacker Pointer to attacker unit. ** @param defender Pointer to unit that is being attacked. */ void AiHelpMe(const CUnit *attacker, CUnit *defender) { PlayerAi *pai; CUnit *aiunit; int force; int destx, desty; DebugPrint("%d: %d(%s) attacked at %d,%d\n" _C_ defender->Player->Index _C_ UnitNumber(defender) _C_ defender->Type->Ident.c_str() _C_ defender->X _C_ defender->Y); AiPlayer = pai = defender->Player->Ai; if (pai->Force[0].Attacking) { // Force 0 busy return; } // // If unit belongs to an attacking force, don't defend it. // for (force = 0; force < AI_MAX_ATTACKING_FORCES; ++force) { if (!pai->Force[force].Attacking) { // none attacking // FIXME, send the force for help continue; } for (size_t i = 0; i < pai->Force[force].Units.size(); ++i) { aiunit = pai->Force[force].Units[i]; if (defender == aiunit) { return; } } } // // Send forces // destx = attacker ? attacker->X : defender->X; desty = attacker ? attacker->Y : defender->Y; // Send force 0 defending AiAttackWithForceAt(0, destx, desty); pai->Force[0].Defending = true; // Also send force 1 if not already attacking if (!pai->Force[1].Attacking) { pai->Force[1].Defending = true; AiAttackWithForceAt(1, destx, desty); } }
/** ** Called if building can't be build. ** ** @param unit Pointer to unit what builds the building. ** @param what Pointer to unit-type. */ void AiCanNotBuild(const CUnit &unit, const CUnitType &what) { DebugPrint("%d: %d(%s) Can't build %s at %d,%d\n" _C_ unit.Player->Index _C_ UnitNumber(unit) _C_ unit.Type->Ident.c_str() _C_ what.Ident.c_str() _C_ unit.tilePos.x _C_ unit.tilePos.y); Assert(unit.Player->Type != PlayerPerson); AiReduceMadeInBuilt(*unit.Player->Ai, what); }
/** ** Called if building can't be built. ** ** @param unit The unit trying to build. ** @param unitType Unit type trying to be built. */ void AiCanNotBuild(CUnit *unit, const CUnitType *unitType) { DebugPrint("%d: %d(%s) Can't build %s at %d,%d\n" _C_ unit->Player->Index _C_ UnitNumber(unit) _C_ unit->Type->Ident.c_str() _C_ unitType->Ident.c_str() _C_ unit->X _C_ unit->Y); Assert(unit->Player->Type != PlayerPerson); AiReduceMadeInBuilt(unit->Player->Ai, unitType); }
/** Called when unit is killed. ** warn the AI module. */ void COrder_Build::AiUnitKilled(CUnit &unit) { DebugPrint("%d: %d(%s) killed, with order %s!\n" _C_ unit.Player->Index _C_ UnitNumber(unit) _C_ unit.Type->Ident.c_str() _C_ this->Type->Ident.c_str()); if (this->BuildingUnit == NULL) { AiReduceMadeInBuilt(*unit.Player->Ai, *this->Type); } }
/** ** Generate a unit reference, a printable unique string for unit. */ std::string UnitReference(const CUnitPtr &unit) { Assert(unit != NULL); std::ostringstream ss; ss << "U" << std::setfill('0') << std::setw(4) << std::uppercase << std::hex << UnitNumber(*unit); return ss.str(); }
/** ** Cast a spell at position or unit. ** ** @param unit Pointer to unit. ** @param pos map position to spell cast on. ** @param dest Spell cast on unit (if exist). ** @param spell Spell type pointer. ** @param flush If true, flush command queue. */ void CommandSpellCast(CUnit &unit, const Vec2i &pos, CUnit *dest, const SpellType &spell, int flush) { DebugPrint(": %d casts %s at %d %d on %d\n" _C_ UnitNumber(unit) _C_ spell.Ident.c_str() _C_ pos.x _C_ pos.y _C_ dest ? UnitNumber(*dest) : 0); Assert(unit.Type->CanCastSpell[spell.Slot]); Assert(Map.Info.IsPointOnMap(pos)); if (IsUnitValidForNetwork(unit) == false) { return ; } COrderPtr *order = GetNextOrder(unit, flush); if (order == NULL) { return; } *order = COrder::NewActionSpellCast(spell, pos, dest); ClearSavedAction(unit); }
/** ** Called if reseaching of an unit is completed. ** ** @param unit Pointer to unit working. ** @param what Pointer to the new upgrade. */ void AiResearchComplete(CUnit &unit, const CUpgrade *what) { DebugPrint("%d: %d(%s) research %s at %d,%d completed\n" _C_ unit.Player->Index _C_ UnitNumber(unit) _C_ unit.Type->Ident.c_str() _C_ what->Ident.c_str() _C_ unit.tilePos.x _C_ unit.tilePos.y); Assert(unit.Player->Type != PlayerPerson); // FIXME: upgrading knights -> paladins, must rebuild lists! }
/** ** Save the viewports. ** ** @param file Save file handle ** @param ui User interface to save */ static void SaveViewports(CFile &file, const CUserInterface &ui) { // FIXME: don't save the number file.printf("DefineViewports(\"mode\", %d", ui.ViewportMode); for (int i = 0; i < ui.NumViewports; ++i) { const CViewport &vp = ui.Viewports[i]; file.printf(",\n \"viewport\", {%d, %d, %d}", vp.MapPos.x, vp.MapPos.y, vp.Unit ? UnitNumber(*vp.Unit) : -1); } file.printf(")\n\n"); }
/** ** Ask to the sound server to play a sound attached to a unit. The ** sound server may discard the sound if needed (e.g., when the same ** unit is already speaking). ** ** @param unit Sound initiator, unit speaking ** @param sound Sound to be generated */ void PlayUnitSound(const CUnit &unit, CSound *sound) { Origin source = {&unit, UnitNumber(unit)}; int channel = PlaySample(ChooseSample(sound, false, source)); if (channel == -1) { return; } SetChannelVolume(channel, CalculateVolume(false, ViewPointDistanceToUnit(unit), sound->Range)); SetChannelStereo(channel, CalculateStereo(unit)); }
/** ** Get a player's units ** ** @param l Lua state. ** ** @return Array of units. */ static int CclGetUnits(lua_State *l) { LuaCheckArgs(l, 1); const int plynr = TriggerGetPlayer(l); lua_newtable(l); if (plynr == -1) { int i = 0; for (CUnitManager::Iterator it = UnitManager.begin(); it != UnitManager.end(); ++it, ++i) { const CUnit &unit = **it; lua_pushnumber(l, UnitNumber(unit)); lua_rawseti(l, -2, i + 1); } } else { for (int i = 0; i < Players[plynr].GetUnitCount(); ++i) { lua_pushnumber(l, UnitNumber(Players[plynr].GetUnit(i))); lua_rawseti(l, -2, i + 1); } } return 1; }
void HandleGet() { int i; char buf[256]; sprintf(buf, "Units: %d\n", NumUnits); SendResponseMessage(buf, 1); for (i = 0; i < NumUnits; ++i) { if (Units[i]->Orders[0]->Goal) { sprintf(buf, "Unit %d, Slot %d, Player %d: %s (%d, %d) HP: %d/%d ACTION: (%d Goal: %d (%d, %d))\n", UnitNumber(Units[i]), Units[i]->Slot, Units[i]->Player->Index, Units[i]->Type->Ident.c_str(), Units[i]->X, Units[i]->Y, Units[i]->Variable[HP_INDEX].Value, Units[i]->Stats->Variables[HP_INDEX].Value, Units[i]->Orders[0]->Action, UnitNumber(Units[i]->Orders[0]->Goal), Units[i]->Orders[0]->Goal->X, Units[i]->Orders[0]->Goal->Y); } else { sprintf(buf, "Unit %d, Slot %d, Player %d: %s (%d, %d) HP: %d/%d ACTION: %d\n", UnitNumber(Units[i]), Units[i]->Slot, Units[i]->Player->Index, Units[i]->Type->Ident.c_str(), Units[i]->X, Units[i]->Y, Units[i]->Variable[HP_INDEX].Value, Units[i]->Stats->Variables[HP_INDEX].Value, Units[i]->Orders[0]->Action); } SendResponseMessage(buf, 0); } sprintf(buf, "Map Size: %dx%d\n", Map.Info.MapWidth, Map.Info.MapHeight); SendResponseMessage(buf, 2); }
/** ** Called when a unit is killed. ** ** @param unit Pointer to unit. */ void AiUnitKilled(CUnit *unit) { DebugPrint("%d: %d(%s) killed\n" _C_ unit->Player->Index _C_ UnitNumber(unit) _C_ unit->Type->Ident.c_str()); Assert(unit->Player->Type != PlayerPerson); // FIXME: must handle all orders... switch (unit->Orders[0]->Action) { case UnitActionStill: case UnitActionAttack: case UnitActionMove: break; case UnitActionBuilt: DebugPrint("%d: %d(%s) killed, under construction!\n" _C_ unit->Player->Index _C_ UnitNumber(unit) _C_ unit->Type->Ident.c_str()); AiReduceMadeInBuilt(unit->Player->Ai, unit->Type); break; case UnitActionBuild: DebugPrint("%d: %d(%s) killed, with order %s!\n" _C_ unit->Player->Index _C_ UnitNumber(unit) _C_ unit->Type->Ident.c_str() _C_ unit->Orders[0]->Type->Ident.c_str()); if (!unit->Orders[0]->Goal) { AiReduceMadeInBuilt(unit->Player->Ai, unit->Orders[0]->Type); } break; default: DebugPrint("FIXME: %d: %d(%s) killed, with order %d!\n" _C_ unit->Player->Index _C_ UnitNumber(unit) _C_ unit->Type->Ident.c_str() _C_ unit->Orders[0]->Action); break; } }
/** ** Called when training of a unit is completed. ** ** @param unit Unit that trained the new unit. ** @param newUnit The new unit. */ void AiTrainingComplete(CUnit *unit, CUnit *newUnit) { DebugPrint("%d: %d(%s) training %s at %d,%d completed\n" _C_ unit->Player->Index _C_ UnitNumber(unit) _C_ unit->Type->Ident.c_str() _C_ newUnit->Type->Ident.c_str() _C_ unit->X _C_ unit->Y); Assert(unit->Player->Type != PlayerPerson); AiRemoveFromBuilt(unit->Player->Ai, newUnit->Type); AiPlayer = unit->Player->Ai; AiCleanForces(); AiAssignToForce(newUnit); }
/** ** Called if work complete (Buildings). ** ** @param unit Pointer to unit that builds the building. ** @param what Pointer to unit building that was built. */ void AiWorkComplete(CUnit *unit, CUnit &what) { if (unit) { DebugPrint("%d: %d(%s) build %s at %d,%d completed\n" _C_ what.Player->Index _C_ UnitNumber(*unit) _C_ unit->Type->Ident.c_str() _C_ what.Type->Ident.c_str() _C_ unit->tilePos.x _C_ unit->tilePos.y); } else { DebugPrint("%d: building %s at %d,%d completed\n" _C_ what.Player->Index _C_ what.Type->Ident.c_str() _C_ what.tilePos.x _C_ what.tilePos.y); } Assert(what.Player->Type != PlayerPerson); AiRemoveFromBuilt(what.Player->Ai, *what.Type); }
/** ** Called if training of a unit is completed. ** ** @param unit Pointer to unit making. ** @param what Pointer to new ready trained unit. */ void AiTrainingComplete(CUnit &unit, CUnit &what) { DebugPrint("%d: %d(%s) training %s at %d,%d completed\n" _C_ unit.Player->Index _C_ UnitNumber(unit) _C_ unit.Type->Ident.c_str() _C_ what.Type->Ident.c_str() _C_ unit.tilePos.x _C_ unit.tilePos.y); Assert(unit.Player->Type != PlayerPerson); AiRemoveFromBuilt(unit.Player->Ai, *what.Type); unit.Player->Ai->Force.RemoveDeadUnit(); unit.Player->Ai->Force.Assign(what); }