truelight@9361: /* $Id$ */ truelight@9361: rubidium@9430: /** @file ai_object.cpp handles the commands-related functions of the AIObject class */ truelight@9361: rubidium@9430: #include "ai_object.hpp" truelight@9441: #include "../../command.h" rubidium@9430: #include "../../player.h" rubidium@9511: #include "table/strings.h" // for signs.h rubidium@9511: #include "../../signs.h" // for _new_sign_id truelight@9441: #include "../ai.h" rubidium@9444: #include "../ai_threads.h" truelight@9361: truelight@9450: void AIObject::SetDoCommandDelay(uint ticks) truelight@9450: { truelight@9450: assert(ticks > 0); truelight@9450: AIObject::GetDoCommandStruct(_current_player)->delay = ticks; truelight@9450: } truelight@9450: truelight@9450: uint AIObject::GetDoCommandDelay() truelight@9450: { truelight@9450: return AIObject::GetDoCommandStruct(_current_player)->delay; truelight@9450: } truelight@9450: truelight@9473: void AIObject::SetDoCommandMode(AIModeProc *proc, AIObject *instance) truelight@9450: { truelight@9450: AIObject::GetDoCommandStruct(_current_player)->mode = proc; truelight@9473: AIObject::GetDoCommandStruct(_current_player)->mode_instance = instance; truelight@9450: } truelight@9450: truelight@9450: AIModeProc *AIObject::GetDoCommandMode() truelight@9450: { truelight@9450: return AIObject::GetDoCommandStruct(_current_player)->mode; truelight@9450: } truelight@9450: truelight@9473: AIObject *AIObject::GetDoCommandModeInstance() truelight@9473: { truelight@9473: return AIObject::GetDoCommandStruct(_current_player)->mode_instance; truelight@9473: } truelight@9473: glx@9629: void AIObject::SetDoCommandCosts(Money value) truelight@9414: { glx@9629: AIObject::GetDoCommandStruct(_current_player)->costs = CommandCost(value); truelight@9414: } truelight@9414: glx@9629: void AIObject::IncreaseDoCommandCosts(Money value) truelight@9414: { glx@9629: AIObject::GetDoCommandStruct(_current_player)->costs.AddCost(value); truelight@9452: } truelight@9452: glx@9629: Money AIObject::GetDoCommandCosts() truelight@9452: { glx@9629: return AIObject::GetDoCommandStruct(_current_player)->costs.GetCost(); truelight@9414: } truelight@9414: truelight@9496: void AIObject::SetNewVehicleID(VehicleID vehicle) truelight@9496: { truelight@9496: AIObject::GetDoCommandStruct(_current_player)->new_vehicle_id = vehicle; truelight@9496: } truelight@9496: truelight@9496: VehicleID AIObject::GetNewVehicleID() truelight@9496: { truelight@9496: return AIObject::GetDoCommandStruct(_current_player)->new_vehicle_id; truelight@9496: } truelight@9496: rubidium@9511: void AIObject::SetNewSignID(SignID sign) rubidium@9511: { rubidium@9511: AIObject::GetDoCommandStruct(_current_player)->new_sign_id = sign; rubidium@9511: } rubidium@9511: rubidium@9511: SignID AIObject::GetNewSignID() rubidium@9511: { rubidium@9511: return AIObject::GetDoCommandStruct(_current_player)->new_sign_id; rubidium@9511: } rubidium@9511: truelight@9682: void *&AIObject::GetEventPointer() truelight@9680: { truelight@9682: return AIObject::GetDoCommandStruct(_current_player)->event_data; truelight@9680: } truelight@9680: truelight@9450: AIObject::AIDoCommandStruct *AIObject::GetDoCommandStruct(PlayerID player) truelight@9450: { truelight@9450: /* Storage for data on per-AI level */ truelight@9450: static AIObject::AIDoCommandStruct command_struct[MAX_PLAYERS]; truelight@9682: static bool initialized = false; truelight@9682: truelight@9682: /* Make sure all memory is NULL when we start */ truelight@9682: if (!initialized) { truelight@9682: initialized = true; truelight@9682: memset(&command_struct, 0, sizeof(command_struct)); truelight@9682: } truelight@9450: truelight@9454: return &command_struct[player]; truelight@9454: } truelight@9450: truelight@9454: void AIObject::ResetInternalPlayerData() truelight@9454: { truelight@9454: AIObject::AIDoCommandStruct *command_struct = GetDoCommandStruct(_current_player); truelight@9454: command_struct->mode = NULL; truelight@9454: command_struct->delay = 1; glx@9629: command_struct->costs = CommandCost(); truelight@9682: if (command_struct->event_data != NULL) AIEventController::FreeEventPointer(); truelight@9682: command_struct->event_data = NULL; truelight@9450: } truelight@9450: truelight@9695: bool AIObject::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint procc, bool water_protection) truelight@9361: { truelight@9486: uint32 flags = 0; truelight@9361: PlayerID old_lp; glx@9629: CommandCost res; truelight@9361: const char* tmp_cmdtext; truelight@9361: truelight@9486: if (procc != CMD_LANDSCAPE_CLEAR) flags |= DC_AUTO; truelight@9695: if (water_protection) flags |= DC_NO_WATER; truelight@9486: truelight@9361: /* The test already resets _cmd_text, so backup the pointer */ truelight@9361: tmp_cmdtext = _cmd_text; truelight@9361: truelight@9361: /* First, do a test-run to see if we can do this */ truelight@9486: res = ::DoCommand(tile, p1, p2, flags, procc); truelight@9450: /* The command failed, so return */ truelight@9452: if (::CmdFailed(res)) return false; truelight@9450: truelight@9473: /* Restore _cmd_text */ truelight@9473: _cmd_text = tmp_cmdtext; truelight@9473: truelight@9450: /* Check what the callback wants us to do */ truelight@9486: if (AIObject::GetDoCommandMode() != NULL && !AIObject::GetDoCommandMode()(tile, p1, p2, procc, res)) { glx@9629: AIObject::IncreaseDoCommandCosts(res.GetCost()); truelight@9452: return true; truelight@9452: } truelight@9361: truelight@9361: /* If we did a DC_EXEC, and the command did not return an error, execute it truelight@9361: * over the network */ truelight@9361: if (flags & DC_AUTO) procc |= CMD_AUTO; truelight@9361: if (flags & DC_NO_WATER) procc |= CMD_NO_WATER; truelight@9361: truelight@9361: #ifdef ENABLE_NETWORK truelight@9361: /* Send the command */ truelight@9361: if (_networking) { truelight@9406: /* NetworkSend_Command needs _local_player to be set correctly, so truelight@9406: * adjust it, and put it back right after the function */ truelight@9406: old_lp = _local_player; truelight@9406: _local_player = _current_player; truelight@9441: ::NetworkSend_Command(tile, p1, p2, procc, CcAI); truelight@9441: _local_player = old_lp; truelight@9406: truelight@9441: /* Suspend the AI till the command is really executed */ truelight@9508: AI_SuspendPlayer(_current_player, -(int)AIObject::GetDoCommandDelay()); truelight@9441: /* Check if the callback still agrees with us, else return error */ truelight@9441: if (!AI_GetCallbackResult(_current_player)) res = CMD_ERROR; truelight@9361: } else { truelight@9361: #else truelight@9361: { truelight@9361: #endif truelight@9361: /* For SinglePlayer we execute the command immediatly */ truelight@9441: ::DoCommandP(tile, p1, p2, NULL, procc); truelight@9496: /* Store some values inside the AIObject static memory */ truelight@9496: AIObject::SetNewVehicleID(_new_vehicle_id); rubidium@9511: AIObject::SetNewSignID(_new_sign_id); truelight@9496: truelight@9441: /* Suspend the AI player for 1 tick, so it simulates MultiPlayer */ truelight@9473: AI_SuspendPlayer(_current_player, AIObject::GetDoCommandDelay()); truelight@9361: } truelight@9361: truelight@9452: if (::CmdFailed(res)) return false; truelight@9452: glx@9629: AIObject::IncreaseDoCommandCosts(res.GetCost()); truelight@9452: return true; truelight@9361: }