# ai_object.cpp

Go to the documentation of this file.

    00001 /* $Id: ai_object.cpp 16508 2009-06-03 13:33:58Z 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   Squirrel *squirrel = GetCompany(_current_company)->ai_instance->engine;
    00166   return GetStorage()->allow_do_command && squirrel->CanSuspend();
    00167 }
    00168
    00169 void *&AIObject::GetEventPointer()
    00170 {
    00171   return GetStorage()->event_data;
    00172 }
    00173
    00174 void *&AIObject::GetLogPointer()
    00175 {
    00176   return GetStorage()->log_data;
    00177 }
    00178
    00179 void AIObject::SetCallbackVariable(int index, int value)
    00180 {
    00181   if ((size_t)index >= GetStorage()->callback_value.size()) GetStorage()->callback_value.resize(index + 1);
    00182   GetStorage()->callback_value[index] = value;
    00183 }
    00184
    00185 int AIObject::GetCallbackVariable(int index)
    00186 {
    00187   return GetStorage()->callback_value[index];
    00188 }
    00189
    00190 bool AIObject::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text, AISuspendCallbackProc *callback)
    00191 {
    00192   if (AIObject::GetAllowDoCommand() == false) {
    00193     AILog::Error("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator.\n");
    00194     return false;
    00195   }
    00196
    00197   CommandCost res;
    00198
    00199   /* Set the default callback to return a true/false result of the DoCommand */
    00200   if (callback == NULL) callback = &AIInstance::DoCommandReturn;
    00201
    00202   /* Make sure the last error is reset, so we don't give faulty warnings */
    00203   SetLastError(AIError::ERR_NONE);
    00204
    00205   /* First, do a test-run to see if we can do this */
    00206   res = ::DoCommand(tile, p1, p2, CommandFlagsToDCFlags(GetCommandFlags(cmd)), cmd, text);
    00207   /* The command failed, so return */
    00208   if (::CmdFailed(res)) {
    00209     SetLastError(AIError::StringToError(_error_message));
    00210     return false;
    00211   }
    00212
    00213   /* Check what the callback wants us to do */
    00214   if (GetDoCommandMode() != NULL && !GetDoCommandMode()(tile, p1, p2, cmd, res)) {
    00215     IncreaseDoCommandCosts(res.GetCost());
    00216     return true;
    00217   }
    00218
    00219 #ifdef ENABLE_NETWORK
    00220   /* Send the command */
    00221   if (_networking) {
    00222     /* NetworkSend_Command needs _local_company to be set correctly, so
    00223      * adjust it, and put it back right after the function */
    00224     CompanyID old_company = _local_company;
    00225     _local_company = _current_company;
    00226     ::NetworkSend_Command(tile, p1, p2, cmd, CcAI, text);
    00227     _local_company = old_company;
    00228     SetLastCost(res.GetCost());
    00229
    00230     /* Suspend the AI till the command is really executed */
    00231     throw AI_VMSuspend(-(int)GetDoCommandDelay(), callback);
    00232   } else {
    00233 #else
    00234   {
    00235 #endif
    00236     /* For SinglePlayer we execute the command immediatly */
    00237     if (!::DoCommandP(tile, p1, p2, cmd, NULL, text)) res = CMD_ERROR;
    00238     SetLastCommandRes(!::CmdFailed(res));
    00239
    00240     if (::CmdFailed(res)) {
    00241       SetLastError(AIError::StringToError(_error_message));
    00242       return false;
    00243     }
    00244     SetLastCost(res.GetCost());
    00245     IncreaseDoCommandCosts(res.GetCost());
    00246
    00247     /* Suspend the AI player for 1+ ticks, so it simulates multiplayer. This
    00248      *  both avoids confusion when a developer launched his AI in a
    00249      *  multiplayer game, but also gives time for the GUI and human player
    00250      *  to interact with the game. */
    00251     throw AI_VMSuspend(GetDoCommandDelay(), callback);
    00252   }
    00253
    00254   NOT_REACHED();
    00255 }