summaryrefslogtreecommitdiff
path: root/ai/ai.h
blob: 3258854104f0ae9668b0c56795fdebf592ed81da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#ifndef AI_H
#define AI_H

#include "../functions.h"
#include "../network.h"
#include "../player.h"
#ifdef GPMI
#include <gpmi.h>
#endif /* GPMI */

/* How DoCommands look like for an AI */
typedef struct AICommand {
	uint32 tile;
	uint32 p1;
	uint32 p2;
	uint32 procc;

	char *text;
	uint uid;

	struct AICommand *next;
} AICommand;

/* The struct for an AIScript Player */
typedef struct AIPlayer {
	bool active;            //! Is this AI active?
	AICommand *queue;       //! The commands that he has in his queue
	AICommand *queue_tail;  //! The tail of this queue
#ifdef GPMI
	gpmi_module *module;    //! The link to the GPMI module
#endif /* GPMI */
} AIPlayer;

/* The struct to keep some data about the AI in general */
typedef struct AIStruct {
	/* General */
	bool enabled;           //! Is AI enabled?
	uint tick;              //! The current tick (something like _frame_counter, only for AIs)

	/* For network-clients (a OpenTTD client who acts as an AI connected to a server) */
	bool network_client;    //! Are we a network_client?
	uint8 network_playas;   //! The current network player we are connected as

	bool gpmi;              //! True if we want GPMI AIs
#ifdef GPMI
	gpmi_module *gpmi_mod;  //! The module controller for GPMI based AIs (Event-handling)
	gpmi_package *gpmi_pkg; //! The package controller for GPMI based AIs (Functions)
	char gpmi_param[128];   //! The params given to the gpmi_mod
#endif /* GPMI */
} AIStruct;

VARDEF AIStruct _ai;
VARDEF AIPlayer _ai_player[MAX_PLAYERS];
VARDEF uint _ai_current_uid; //! Keeps track of the current UID, if any (0 means none)
VARDEF TileIndex _ai_current_tile; //! Keeps track of the current Tile.

// ai.c
void AI_StartNewAI(PlayerID player);
void AI_PlayerDied(PlayerID player);
void AI_RunGameLoop(void);
void AI_Initialize(void);
void AI_Uninitialize(void);
int32 AI_DoCommand(uint tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
int32 AI_DoCommandChecked(uint tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
void AI_GetCommandUID(uint32 cmd, uint32 p1, uint32 p2, TileIndex tile);
void AI_CommandResult(bool failed);

/** Is it allowed to start a new AI.
 * This function checks some boundries to see if we should launch a new AI.
 * @return True if we can start a new AI.
 */
static inline bool AI_AllowNewAI(void)
{
	/* If disabled, no AI */
	if (!_ai.enabled)
		return false;

	/* If in network, but no server, no AI */
	if (_networking && !_network_server)
		return false;

	/* If in network, and server, possible AI */
	if (_networking && _network_server) {
		/* Do we want AIs in multiplayer? */
		if (!_patches.ai_in_multiplayer)
			return false;

		/* Only the NewAI is allowed... sadly enough the old AI just doesn't support this
		 *  system, because all commands are delayed by at least 1 tick, which causes
		 *  a big problem, because it uses variables that are only set AFTER the command
		 *  is really executed... */
		if (!_patches.ainew_active && !_ai.gpmi)
			return false;
	}

	return true;
}

#define AI_CHANCE16(a,b)    ((uint16)     AI_Random()  <= (uint16)((65536 * a) / b))
#define AI_CHANCE16R(a,b,r) ((uint16)(r = AI_Random()) <= (uint16)((65536 * a) / b))

/**
 * The random-function that should be used by ALL AIs.
 */
static inline uint AI_RandomRange(uint max)
{
	/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
	 *   but we pick InteractiveRandomRange if we are a network_server or network-client.
	 */
	if (_networking)
		return InteractiveRandomRange(max);
	else
		return RandomRange(max);
}

/**
 * The random-function that should be used by ALL AIs.
 */
static inline uint32 AI_Random(void)
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
	 *   but we pick InteractiveRandomRange if we are a network_server or network-client.
	 */
	if (_networking)
		return InteractiveRandom();
	else
		return Random();
}

#endif /* AI_H */