truelight@9361: /* $Id$ */ truelight@9361: truebrain@9833: /** @file ai_object.cpp Implementation of AIObject. */ truelight@9361: rubidium@9430: #include "ai_object.hpp" truebrain@9851: #include "ai_log.hpp" rubidium@9863: #include "ai_error.hpp" truebrain@9844: #include "table/strings.h" rubidium@9723: #include "../../command_func.h" rubidium@9723: #include "../../network/network.h" rubidium@9724: #include "../../player_func.h" rubidium@9837: #include "../../signs_func.h" rubidium@9723: #include "../../vehicle_func.h" 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); truebrain@9862: GetDoCommandStruct(_current_player)->delay = ticks; truelight@9450: } truelight@9450: truelight@9450: uint AIObject::GetDoCommandDelay() truelight@9450: { truebrain@9862: return GetDoCommandStruct(_current_player)->delay; truelight@9450: } truelight@9450: truelight@9473: void AIObject::SetDoCommandMode(AIModeProc *proc, AIObject *instance) truelight@9450: { truebrain@9862: GetDoCommandStruct(_current_player)->mode = proc; truebrain@9862: GetDoCommandStruct(_current_player)->mode_instance = instance; truelight@9450: } truelight@9450: truelight@9450: AIModeProc *AIObject::GetDoCommandMode() truelight@9450: { truebrain@9862: return GetDoCommandStruct(_current_player)->mode; truelight@9450: } truelight@9450: truelight@9473: AIObject *AIObject::GetDoCommandModeInstance() truelight@9473: { truebrain@9862: return GetDoCommandStruct(_current_player)->mode_instance; truelight@9473: } truelight@9473: glx@9629: void AIObject::SetDoCommandCosts(Money value) truelight@9414: { truebrain@9862: GetDoCommandStruct(_current_player)->costs = CommandCost(value); truelight@9414: } truelight@9414: glx@9629: void AIObject::IncreaseDoCommandCosts(Money value) truelight@9414: { truebrain@9862: GetDoCommandStruct(_current_player)->costs.AddCost(value); truelight@9452: } truelight@9452: glx@9629: Money AIObject::GetDoCommandCosts() truelight@9452: { truebrain@9862: return GetDoCommandStruct(_current_player)->costs.GetCost(); truelight@9414: } truelight@9414: rubidium@9864: void AIObject::SetLastError(AIErrorType last_error) truebrain@9844: { truebrain@9862: GetDoCommandStruct(_current_player)->last_error = last_error; truebrain@9844: } truebrain@9844: rubidium@9864: AIErrorType AIObject::GetLastError() truebrain@9844: { truebrain@9862: return GetDoCommandStruct(_current_player)->last_error; truebrain@9844: } truebrain@9844: truebrain@9760: void AIObject::SetLastCommandRes(bool res) truebrain@9760: { truebrain@9862: GetDoCommandStruct(_current_player)->last_command_res = res; truebrain@9760: } truebrain@9760: truebrain@9760: bool AIObject::GetLastCommandRes() truebrain@9760: { truebrain@9862: return GetDoCommandStruct(_current_player)->last_command_res; truebrain@9760: } truebrain@9760: truebrain@9841: void AIObject::SetNewVehicleID(VehicleID vehicle_id) truelight@9496: { truebrain@9862: GetDoCommandStruct(_current_player)->new_vehicle_id = vehicle_id; truelight@9496: } truelight@9496: truelight@9496: VehicleID AIObject::GetNewVehicleID() truelight@9496: { truebrain@9862: return GetDoCommandStruct(_current_player)->new_vehicle_id; truelight@9496: } truelight@9496: truebrain@9841: void AIObject::SetNewSignID(SignID sign_id) rubidium@9511: { truebrain@9862: GetDoCommandStruct(_current_player)->new_sign_id = sign_id; rubidium@9511: } rubidium@9511: rubidium@9511: SignID AIObject::GetNewSignID() rubidium@9511: { truebrain@9862: return GetDoCommandStruct(_current_player)->new_sign_id; rubidium@9511: } rubidium@9511: truelight@9682: void *&AIObject::GetEventPointer() truelight@9680: { truebrain@9862: return GetDoCommandStruct(_current_player)->event_data; truelight@9680: } truelight@9680: truebrain@9851: void *&AIObject::GetLogPointer() truebrain@9851: { truebrain@9862: return GetDoCommandStruct(_current_player)->log_data; truebrain@9851: } truebrain@9851: truelight@9450: AIObject::AIDoCommandStruct *AIObject::GetDoCommandStruct(PlayerID player) truelight@9450: { truelight@9450: /* Storage for data on per-AI level */ truebrain@9862: static 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: { truebrain@9862: 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; truebrain@9851: if (command_struct->log_data != NULL) AILog::FreeLogPointer(); truebrain@9851: command_struct->log_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; truebrain@9748: const char *tmp_cmdtext; truelight@9361: truebrain@9844: /* Make sure the last error is reset, so we don't give faulty warnings */ rubidium@9863: SetLastError(AIError::ERR_NONE); truebrain@9844: 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 */ truebrain@9844: if (::CmdFailed(res)) { rubidium@9864: SetLastError(AIError::StringToError(_error_message)); truebrain@9844: return false; truebrain@9844: } 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 */ truebrain@9862: if (GetDoCommandMode() != NULL && !GetDoCommandMode()(tile, p1, p2, procc, res)) { truebrain@9862: 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_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 */ truebrain@9862: ::AI_SuspendPlayer(_current_player, -(int)GetDoCommandDelay()); truelight@9441: /* Check if the callback still agrees with us, else return error */ truebrain@9862: if (!GetLastCommandRes()) 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 */ truebrain@9862: SetNewVehicleID(_new_vehicle_id); truebrain@9862: SetNewSignID(_new_sign_id); truelight@9496: truelight@9441: /* Suspend the AI player for 1 tick, so it simulates MultiPlayer */ truebrain@9862: ::AI_SuspendPlayer(_current_player, GetDoCommandDelay()); truelight@9361: } truelight@9361: truebrain@9844: if (::CmdFailed(res)) { rubidium@9864: SetLastError(AIError::StringToError(_error_message)); truebrain@9844: return false; truebrain@9844: } truelight@9452: truebrain@9862: IncreaseDoCommandCosts(res.GetCost()); truelight@9452: return true; truelight@9361: }