# ai_object.cpp

Go to the documentation of this file.

    00001 /* $Id: ai_object.cpp 17517 2009-09-12 20:59:34Z rubidium $ */
    00002
    00005 #include "../../stdafx.h"
    00006 #include <squirrel.h>
    00007 #include "../../script/squirrel.hpp"
    00008 #include "../../company_base.h"
    00009
    00010 #include "ai_log.hpp"
    00011 #include "table/strings.h"
    00012 #include "../ai.hpp"
    00013 #include "../ai_storage.hpp"
    00014 #include "../ai_instance.hpp"
    00015
    00016 static AIStorage *GetStorage()
    00017 {
    00018   return AIInstance::GetStorage();
    00019 }
    00020
    00021 void AIObject::SetDoCommandDelay(uint ticks)
    00022 {
    00023   assert(ticks > 0);
    00024   GetStorage()->delay = ticks;
    00025 }
    00026
    00027 uint AIObject::GetDoCommandDelay()
    00028 {
    00029   return GetStorage()->delay;
    00030 }
    00031
    00032 void AIObject::SetDoCommandMode(AIModeProc *proc, AIObject *instance)
    00033 {
    00034   GetStorage()->mode = proc;
    00035   GetStorage()->mode_instance = instance;
    00036 }
    00037
    00038 AIModeProc *AIObject::GetDoCommandMode()
    00039 {
    00040   return GetStorage()->mode;
    00041 }
    00042
    00043 AIObject *AIObject::GetDoCommandModeInstance()
    00044 {
    00045   return GetStorage()->mode_instance;
    00046 }
    00047
    00048 void AIObject::SetDoCommandCosts(Money value)
    00049 {
    00050   GetStorage()->costs = CommandCost(value);
    00051 }
    00052
    00053 void AIObject::IncreaseDoCommandCosts(Money value)
    00054 {
    00055   GetStorage()->costs.AddCost(value);
    00056 }
    00057
    00058 Money AIObject::GetDoCommandCosts()
    00059 {
    00060   return GetStorage()->costs.GetCost();
    00061 }
    00062
    00063 void AIObject::SetLastError(AIErrorType last_error)
    00064 {
    00065   GetStorage()->last_error = last_error;
    00066 }
    00067
    00068 AIErrorType AIObject::GetLastError()
    00069 {
    00070   return GetStorage()->last_error;
    00071 }
    00072
    00073 void AIObject::SetLastCost(Money last_cost)
    00074 {
    00075   GetStorage()->last_cost = last_cost;
    00076 }
    00077
    00078 Money AIObject::GetLastCost()
    00079 {
    00080   return GetStorage()->last_cost;
    00081 }
    00082
    00083 void AIObject::SetRoadType(RoadType road_type)
    00084 {
    00085   GetStorage()->road_type = road_type;
    00086 }
    00087
    00088 RoadType AIObject::GetRoadType()
    00089 {
    00090   return GetStorage()->road_type;
    00091 }
    00092
    00093 void AIObject::SetRailType(RailType rail_type)
    00094 {
    00095   GetStorage()->rail_type = rail_type;
    00096 }
    00097
    00098 RailType AIObject::GetRailType()
    00099 {
    00100   return GetStorage()->rail_type;
    00101 }
    00102
    00103 void AIObject::SetLastCommandRes(bool res)
    00104 {
    00105   GetStorage()->last_command_res = res;
    00106   /* Also store the results of various global variables */
    00107   SetNewVehicleID(_new_vehicle_id);
    00108   SetNewSignID(_new_sign_id);
    00109   SetNewTunnelEndtile(_build_tunnel_endtile);
    00110   SetNewGroupID(_new_group_id);
    00111 }
    00112
    00113 bool AIObject::GetLastCommandRes()
    00114 {
    00115   return GetStorage()->last_command_res;
    00116 }
    00117
    00118 void AIObject::SetNewVehicleID(VehicleID vehicle_id)
    00119 {
    00120   GetStorage()->new_vehicle_id = vehicle_id;
    00121 }
    00122
    00123 VehicleID AIObject::GetNewVehicleID()
    00124 {
    00125   return GetStorage()->new_vehicle_id;
    00126 }
    00127
    00128 void AIObject::SetNewSignID(SignID sign_id)
    00129 {
    00130   GetStorage()->new_sign_id = sign_id;
    00131 }
    00132
    00133 SignID AIObject::GetNewSignID()
    00134 {
    00135   return GetStorage()->new_sign_id;
    00136 }
    00137
    00138 void AIObject::SetNewTunnelEndtile(TileIndex tile)
    00139 {
    00140   GetStorage()->new_tunnel_endtile = tile;
    00141 }
    00142
    00143 TileIndex AIObject::GetNewTunnelEndtile()
    00144 {
    00145   return GetStorage()->new_tunnel_endtile;
    00146 }
    00147
    00148 void AIObject::SetNewGroupID(GroupID group_id)
    00149 {
    00150   GetStorage()->new_group_id = group_id;
    00151 }
    00152
    00153 GroupID AIObject::GetNewGroupID()
    00154 {
    00155   return GetStorage()->new_group_id;
    00156 }
    00157
    00158 void AIObject::SetAllowDoCommand(bool allow)
    00159 {
    00160   GetStorage()->allow_do_command = allow;
    00161 }
    00162
    00163 bool AIObject::GetAllowDoCommand()
    00164 {
    00165   return GetStorage()->allow_do_command;
    00166 }
    00167
    00168 bool AIObject::CanSuspend()
    00169 {
    00170   Squirrel *squirrel = GetCompany(_current_company)->ai_instance->engine;
    00171   return GetStorage()->allow_do_command && squirrel->CanSuspend();
    00172 }
    00173
    00174 void *&AIObject::GetEventPointer()
    00175 {
    00176   return GetStorage()->event_data;
    00177 }
    00178
    00179 void *&AIObject::GetLogPointer()
    00180 {
    00181   return GetStorage()->log_data;
    00182 }
    00183
    00184 void AIObject::SetCallbackVariable(int index, int value)
    00185 {
    00186   if ((size_t)index >= GetStorage()->callback_value.size()) GetStorage()->callback_value.resize(index + 1);
    00187   GetStorage()->callback_value[index] = value;
    00188 }
    00189
    00190 int AIObject::GetCallbackVariable(int index)
    00191 {
    00192   return GetStorage()->callback_value[index];
    00193 }
    00194
    00195 bool AIObject::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text, AISuspendCallbackProc *callback)
    00196 {
    00197   if (!AIObject::CanSuspend()) {
    00198     throw AI_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator.");
    00199   }
    00200
    00201   CommandCost res;
    00202
    00203   /* Set the default callback to return a true/false result of the DoCommand */
    00204   if (callback == NULL) callback = &AIInstance::DoCommandReturn;
    00205
    00206   /* Make sure the last error is reset, so we don't give faulty warnings */
    00207   SetLastError(AIError::ERR_NONE);
    00208
    00209   /* First, do a test-run to see if we can do this */
    00210   res = ::DoCommand(tile, p1, p2, CommandFlagsToDCFlags(GetCommandFlags(cmd)), cmd, text);
    00211   /* The command failed, so return */
    00212   if (::CmdFailed(res)) {
    00213     SetLastError(AIError::StringToError(_error_message));
    00214     return false;
    00215   }
    00216
    00217   /* Check what the callback wants us to do */
    00218   if (GetDoCommandMode() != NULL && !GetDoCommandMode()(tile, p1, p2, cmd, res)) {
    00219     IncreaseDoCommandCosts(res.GetCost());
    00220     return true;
    00221   }
    00222
    00223 #ifdef ENABLE_NETWORK
    00224   /* Send the command */
    00225   if (_networking) {
    00226     /* NetworkSend_Command needs _local_company to be set correctly, so
    00227      * adjust it, and put it back right after the function */
    00228     CompanyID old_company = _local_company;
    00229     _local_company = _current_company;
    00230     ::NetworkSend_Command(tile, p1, p2, cmd, CcAI, text);
    00231     _local_company = old_company;
    00232     SetLastCost(res.GetCost());
    00233
    00234     /* Suspend the AI till the command is really executed */
    00235     throw AI_VMSuspend(-(int)GetDoCommandDelay(), callback);
    00236   } else {
    00237 #else
    00238   {
    00239 #endif
    00240     /* For SinglePlayer we execute the command immediatly */
    00241     if (!::DoCommandP(tile, p1, p2, cmd, NULL, text)) res = CMD_ERROR;
    00242     SetLastCommandRes(!::CmdFailed(res));
    00243
    00244     if (::CmdFailed(res)) {
    00245       SetLastError(AIError::StringToError(_error_message));
    00246       return false;
    00247     }
    00248     SetLastCost(res.GetCost());
    00249     IncreaseDoCommandCosts(res.GetCost());
    00250
    00251     /* Suspend the AI player for 1+ ticks, so it simulates multiplayer. This
    00252      *  both avoids confusion when a developer launched his AI in a
    00253      *  multiplayer game, but also gives time for the GUI and human player
    00254      *  to interact with the game. */
    00255     throw AI_VMSuspend(GetDoCommandDelay(), callback);
    00256   }
    00257
    00258   NOT_REACHED();
    00259 }