mirror of https://github.com/OpenTTD/OpenTTD
(svn r5092) -Fix: There was a gross race condition in the AI code which made it pretty random if the AI could give a new vehicle its orders
parent
7dff47b7f0
commit
877c7e34a5
18
ai/ai.c
18
ai/ai.c
|
@ -32,7 +32,7 @@ static void AI_DequeueCommands(PlayerID player)
|
||||||
|
|
||||||
/* Copy the DP back in place */
|
/* Copy the DP back in place */
|
||||||
_cmd_text = com->text;
|
_cmd_text = com->text;
|
||||||
DoCommandP(com->tile, com->p1, com->p2, NULL, com->procc);
|
DoCommandP(com->tile, com->p1, com->p2, com->callback, com->procc);
|
||||||
|
|
||||||
/* Free item */
|
/* Free item */
|
||||||
entry_com = com->next;
|
entry_com = com->next;
|
||||||
|
@ -45,7 +45,7 @@ static void AI_DequeueCommands(PlayerID player)
|
||||||
* Needed for SP; we need to delay DoCommand with 1 tick, because else events
|
* Needed for SP; we need to delay DoCommand with 1 tick, because else events
|
||||||
* will make infinite loops (AIScript).
|
* will make infinite loops (AIScript).
|
||||||
*/
|
*/
|
||||||
static void AI_PutCommandInQueue(PlayerID player, TileIndex tile, uint32 p1, uint32 p2, uint procc)
|
static void AI_PutCommandInQueue(PlayerID player, TileIndex tile, uint32 p1, uint32 p2, uint procc, CommandCallback* callback)
|
||||||
{
|
{
|
||||||
AICommand *com;
|
AICommand *com;
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ static void AI_PutCommandInQueue(PlayerID player, TileIndex tile, uint32 p1, uin
|
||||||
com->p1 = p1;
|
com->p1 = p1;
|
||||||
com->p2 = p2;
|
com->p2 = p2;
|
||||||
com->procc = procc;
|
com->procc = procc;
|
||||||
|
com->callback = callback;
|
||||||
com->next = NULL;
|
com->next = NULL;
|
||||||
com->text = NULL;
|
com->text = NULL;
|
||||||
|
|
||||||
|
@ -80,7 +81,7 @@ static void AI_PutCommandInQueue(PlayerID player, TileIndex tile, uint32 p1, uin
|
||||||
/**
|
/**
|
||||||
* Executes a raw DoCommand for the AI.
|
* Executes a raw DoCommand for the AI.
|
||||||
*/
|
*/
|
||||||
int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
|
int32 AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback* callback)
|
||||||
{
|
{
|
||||||
PlayerID old_lp;
|
PlayerID old_lp;
|
||||||
int32 res = 0;
|
int32 res = 0;
|
||||||
|
@ -120,12 +121,12 @@ int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint proc
|
||||||
/* Send the command */
|
/* Send the command */
|
||||||
if (_networking)
|
if (_networking)
|
||||||
/* Network is easy, send it to his handler */
|
/* Network is easy, send it to his handler */
|
||||||
NetworkSend_Command(tile, p1, p2, procc, NULL);
|
NetworkSend_Command(tile, p1, p2, procc, callback);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
/* If we execute BuildCommands directly in SP, we have a big problem with events
|
/* If we execute BuildCommands directly in SP, we have a big problem with events
|
||||||
* so we need to delay is for 1 tick */
|
* so we need to delay is for 1 tick */
|
||||||
AI_PutCommandInQueue(_current_player, tile, p1, p2, procc);
|
AI_PutCommandInQueue(_current_player, tile, p1, p2, procc, callback);
|
||||||
|
|
||||||
/* Set _local_player back */
|
/* Set _local_player back */
|
||||||
_local_player = old_lp;
|
_local_player = old_lp;
|
||||||
|
@ -135,6 +136,13 @@ int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint proc
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
|
||||||
|
{
|
||||||
|
return AI_DoCommandCc(tile, p1, p2, flags, procc, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run 1 tick of the AI. Don't overdo it, keep it realistic.
|
* Run 1 tick of the AI. Don't overdo it, keep it realistic.
|
||||||
*/
|
*/
|
||||||
|
|
2
ai/ai.h
2
ai/ai.h
|
@ -11,6 +11,7 @@ typedef struct AICommand {
|
||||||
uint32 p1;
|
uint32 p1;
|
||||||
uint32 p2;
|
uint32 p2;
|
||||||
uint32 procc;
|
uint32 procc;
|
||||||
|
CommandCallback* callback;
|
||||||
|
|
||||||
char *text;
|
char *text;
|
||||||
uint uid;
|
uint uid;
|
||||||
|
@ -46,6 +47,7 @@ void AI_RunGameLoop(void);
|
||||||
void AI_Initialize(void);
|
void AI_Initialize(void);
|
||||||
void AI_Uninitialize(void);
|
void AI_Uninitialize(void);
|
||||||
int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
|
int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
|
||||||
|
int32 AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback* callback);
|
||||||
|
|
||||||
/** Is it allowed to start a new AI.
|
/** Is it allowed to start a new AI.
|
||||||
* This function checks some boundries to see if we should launch a new AI.
|
* This function checks some boundries to see if we should launch a new AI.
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "../../map.h"
|
#include "../../map.h"
|
||||||
#include "../../road_map.h"
|
#include "../../road_map.h"
|
||||||
#include "../../tile.h"
|
#include "../../tile.h"
|
||||||
|
#include "../../vehicle.h"
|
||||||
#include "../../command.h"
|
#include "../../command.h"
|
||||||
#include "trolly.h"
|
#include "trolly.h"
|
||||||
#include "../../engine.h"
|
#include "../../engine.h"
|
||||||
|
@ -249,6 +250,20 @@ EngineID AiNew_PickVehicle(Player *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2)
|
||||||
|
{
|
||||||
|
Player* p = GetPlayer(_current_player);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
p->ainew.state = AI_STATE_GIVE_ORDERS;
|
||||||
|
p->ainew.veh_id = _new_vehicle_id;
|
||||||
|
} else {
|
||||||
|
/* XXX this should be handled more gracefully */
|
||||||
|
p->ainew.state = AI_STATE_NOTHING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Builds the best vehicle possible
|
// Builds the best vehicle possible
|
||||||
int AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag)
|
int AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag)
|
||||||
{
|
{
|
||||||
|
@ -257,7 +272,11 @@ int AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag)
|
||||||
if (i == INVALID_ENGINE) return CMD_ERROR;
|
if (i == INVALID_ENGINE) return CMD_ERROR;
|
||||||
if (p->ainew.tbt == AI_TRAIN) return CMD_ERROR;
|
if (p->ainew.tbt == AI_TRAIN) return CMD_ERROR;
|
||||||
|
|
||||||
return AI_DoCommand(tile, i, 0, flag, CMD_BUILD_ROAD_VEH);
|
if (flag & DC_EXEC) {
|
||||||
|
return AI_DoCommandCc(tile, i, 0, flag, CMD_BUILD_ROAD_VEH, CcAI);
|
||||||
|
} else {
|
||||||
|
return AI_DoCommand(tile, i, 0, flag, CMD_BUILD_ROAD_VEH);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag)
|
int AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag)
|
||||||
|
|
|
@ -1155,7 +1155,7 @@ static void AiNew_State_BuildVehicle(Player *p)
|
||||||
// Decrease the total counter
|
// Decrease the total counter
|
||||||
p->ainew.amount_veh--;
|
p->ainew.amount_veh--;
|
||||||
// Go give some orders!
|
// Go give some orders!
|
||||||
p->ainew.state = AI_STATE_GIVE_ORDERS;
|
p->ainew.state = AI_STATE_WAIT_FOR_BUILD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1167,18 +1167,6 @@ static void AiNew_State_GiveOrders(Player *p)
|
||||||
|
|
||||||
assert(p->ainew.state == AI_STATE_GIVE_ORDERS);
|
assert(p->ainew.state == AI_STATE_GIVE_ORDERS);
|
||||||
|
|
||||||
// Get the new ID
|
|
||||||
/* XXX -- Because this AI isn't using any event-system, this is VERY dangerous!
|
|
||||||
* There is no way telling if the vehicle is already bought (or delayed by the
|
|
||||||
* network), and if bought, if not an other vehicle is bought in between.. in
|
|
||||||
* other words, there is absolutely no way knowing if this id is the true
|
|
||||||
* id.. soon this will all change, but for now, we needed something to test
|
|
||||||
* on ;) -- TrueLight -- 21-11-2005 */
|
|
||||||
if (p->ainew.tbt == AI_TRAIN) {
|
|
||||||
} else {
|
|
||||||
p->ainew.veh_id = _new_roadveh_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p->ainew.veh_main_id != INVALID_VEHICLE) {
|
if (p->ainew.veh_main_id != INVALID_VEHICLE) {
|
||||||
AI_DoCommand(0, p->ainew.veh_id + (p->ainew.veh_main_id << 16), 0, DC_EXEC, CMD_CLONE_ORDER);
|
AI_DoCommand(0, p->ainew.veh_id + (p->ainew.veh_main_id << 16), 0, DC_EXEC, CMD_CLONE_ORDER);
|
||||||
|
|
||||||
|
@ -1323,6 +1311,7 @@ static AiNew_StateFunction* const _ainew_state[] = {
|
||||||
AiNew_State_BuildPath,
|
AiNew_State_BuildPath,
|
||||||
AiNew_State_BuildDepot,
|
AiNew_State_BuildDepot,
|
||||||
AiNew_State_BuildVehicle,
|
AiNew_State_BuildVehicle,
|
||||||
|
NULL,
|
||||||
AiNew_State_GiveOrders,
|
AiNew_State_GiveOrders,
|
||||||
AiNew_State_StartVehicle,
|
AiNew_State_StartVehicle,
|
||||||
AiNew_State_RepayMoney,
|
AiNew_State_RepayMoney,
|
||||||
|
|
|
@ -187,6 +187,7 @@ enum {
|
||||||
AI_STATE_BUILD_PATH,
|
AI_STATE_BUILD_PATH,
|
||||||
AI_STATE_BUILD_DEPOT,
|
AI_STATE_BUILD_DEPOT,
|
||||||
AI_STATE_BUILD_VEHICLE,
|
AI_STATE_BUILD_VEHICLE,
|
||||||
|
AI_STATE_WAIT_FOR_BUILD,
|
||||||
AI_STATE_GIVE_ORDERS,
|
AI_STATE_GIVE_ORDERS,
|
||||||
AI_STATE_START_VEHICLE,
|
AI_STATE_START_VEHICLE,
|
||||||
AI_STATE_REPAY_MONEY,
|
AI_STATE_REPAY_MONEY,
|
||||||
|
|
|
@ -53,6 +53,8 @@ CommandCallback CcBuildWagon;
|
||||||
CommandCallback CcBuildLoco;
|
CommandCallback CcBuildLoco;
|
||||||
CommandCallback CcCloneTrain;
|
CommandCallback CcCloneTrain;
|
||||||
|
|
||||||
|
CommandCallback CcAI;
|
||||||
|
|
||||||
CommandCallback *_callback_table[] = {
|
CommandCallback *_callback_table[] = {
|
||||||
/* 0x00 */ NULL,
|
/* 0x00 */ NULL,
|
||||||
/* 0x01 */ CcBuildAircraft,
|
/* 0x01 */ CcBuildAircraft,
|
||||||
|
@ -79,6 +81,7 @@ CommandCallback *_callback_table[] = {
|
||||||
/* 0x16 */ CcCloneRoadVeh,
|
/* 0x16 */ CcCloneRoadVeh,
|
||||||
/* 0x17 */ CcCloneShip,
|
/* 0x17 */ CcCloneShip,
|
||||||
/* 0x18 */ CcCloneTrain,
|
/* 0x18 */ CcCloneTrain,
|
||||||
|
/* 0x19 */ CcAI
|
||||||
};
|
};
|
||||||
|
|
||||||
const int _callback_table_count = lengthof(_callback_table);
|
const int _callback_table_count = lengthof(_callback_table);
|
||||||
|
|
Loading…
Reference in New Issue