1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <math.h>
4
5 #include "xtux.h"
6 #include "server.h"
7 #include "entity.h"
8 #include "clients.h"
9 #include "ai.h"
10
11 extern float sin_lookup[DEGREES];
12 extern float cos_lookup[DEGREES];
13 extern server_t server;
14 extern entity *root;
15
ai_move(entity * ent)16 void ai_move(entity *ent)
17 {
18 int accel;
19
20 /* Move forward */
21 if( ent->ai_moving && ent->mode >= ALIVE ) {
22 accel = ent->type_info->accel;
23 ent->x_v += sin_lookup[ ent->dir ] * accel;
24 ent->y_v += -cos_lookup[ ent->dir ] * accel;
25 }
26
27 }
28
29
30 /* Find appropriate threat and face it, setting ent->target appropriately.
31 true opposite is anything but targ_type */
ai_face_threat(entity * ent,int distance,int targ_type,int opposite)32 int ai_face_threat(entity *ent, int distance, int targ_type, int opposite)
33 {
34 int d, found;
35 entity *targ;
36
37 /* Check to see if existing target is within distance, if so, go for it first */
38 if( ent->target ) {
39 if( ent->target->visible && (d = entity_dist(ent, ent->target)) < distance ) {
40 ent->dir = calculate_dir(ent, ent->target);
41 return d;
42 }
43 }
44
45 found = 0;
46 for( targ = root ; targ != NULL ; targ = targ->next ) {
47 if( targ == ent || targ->id == ent->pid )
48 continue; /* Don't match self or parent */
49 if( ent->pid != 0 && targ->pid == ent->pid )
50 continue; /* Don't match siblings */
51
52 if( (opposite ? (targ->class != targ_type) : (targ->class == targ_type))) {
53 if( targ->visible && (d = entity_dist(ent, targ)) < distance ) {
54 found = 1;
55 distance = d;
56 ent->dir = calculate_dir(ent, targ);
57 ent->target = targ;
58 }
59 }
60 }
61
62 if( found )
63 return distance;
64 else
65 return -1; /* No threats near */
66
67 }
68
69
70 #define SCARED_DIST 200
71
72 /* AI for bunny (and critters).
73 * They look at threats that are near them and run away from them
74 * if they get too close.
75 * If nobody's around, they groom themselves and hop around.
76 */
ai_flee_think(entity * ai)77 void ai_flee_think(entity *ai)
78 {
79 int speed, sight;
80
81 sight = ai->type_info->sight;
82 speed = ai->type_info->speed;
83
84 if( ai_face_threat(ai, sight, NEUTRAL, 1) >= 0 ) {
85 ai->dir += DEGREES/2; /* Face AWAY from threat. */
86 ai->ai_moving = 1;
87 ai->mode = ALIVE; /* Stop Fidgeting */
88 ai->speed = speed;
89 } else if( ai->mode == ALIVE && (ai->x_v || ai->y_v) ) {
90 if( (rand()%(server.fps*5)) == 0 ) {
91 ai->mode = FIDGETING;
92 ai->ai_moving = 0;
93 }
94 } else if( ai->mode == ALIVE ) {
95 ai->speed = speed/2;
96 ai->ai_moving = 1;
97 }
98
99 if( ai->mode == FIDGETING ) {
100 /* Move around a bit */
101 if( ((rand() % (10*server.fps))) == 0 ) {
102 ai->mode = ALIVE;
103 ai->dir = rand()%256;
104 ai->ai_moving = 0;
105 }
106 }
107
108 }
109
110
111 /* FIXME: Todo */
ai_fight_think(entity * ai)112 void ai_fight_think(entity *ai)
113 {
114 int target;
115
116 ai->speed = ai->type_info->speed;
117
118 if( ai->class == GOODIE )
119 target = BADDIE;
120 else
121 target = GOODIE;
122
123
124 if( ai_face_threat(ai, ai->type_info->sight, target, 0) >= 0 ) {
125 ai->ai_moving = 1;
126 ai->mode = ALIVE;
127 ai->cliplevel = GROUNDCLIP;
128 } else if( ai->mode == PATROL ) {
129 ai->cliplevel = AICLIP;
130 ai->ai_moving = 1;
131 } else if( (ai->x_v || ai->y_v) == 0 ) { /* Stationary */
132 if( ai->mode != PATROL || !(rand() % (10*server.fps)) ) {
133 ai->mode = PATROL;
134 ai->dir = rand()%DEGREES;
135 ai->ai_moving = 1;
136 }
137 }
138
139 }
140
141
ai_shooter_think(entity * shooter)142 void ai_shooter_think(entity *shooter)
143 {
144 weap_type_t *wt;
145 int dist, target, effective_range;
146 int sight;
147
148 shooter->ai_moving = 1;
149 shooter->trigger = 0;
150 shooter->speed = shooter->type_info->speed;
151 sight = shooter->type_info->sight;
152
153 if( shooter->class == GOODIE )
154 target = BADDIE;
155 else
156 target = GOODIE;
157
158 dist = ai_face_threat(shooter, sight, target, 0);
159
160 if( dist >= 0 ) {
161 wt = weapon_type(shooter->weapon);
162 if( wt->max_length )
163 effective_range = wt->max_length;
164 else
165 effective_range = sight;
166
167 shooter->mode = ALIVE;
168 if( dist < effective_range ) {
169 shooter->ai_moving = 0;
170 shooter->trigger = 1;
171 } else {
172 shooter->trigger = 0;
173 shooter->ai_moving = 1;
174 shooter->cliplevel = GROUNDCLIP;
175 }
176 } else if( shooter->mode == PATROL ) {
177 shooter->cliplevel = AICLIP;
178 shooter->ai_moving = 1;
179 } else if( shooter->mode != PATROL || !(rand() % (10*server.fps)) ) {
180 shooter->mode = PATROL;
181 shooter->dir = rand()%DEGREES;
182 }
183
184 }
185
186
187
ai_seek_think(entity * ai)188 void ai_seek_think(entity *ai)
189 {
190
191 if( ai->target ) {
192 ai->dir = calculate_dir(ai, ai->target);
193 } else if( ai_face_threat(ai, ai->type_info->sight, ITEM, 1) >= 0 ) {
194 ai->ai_moving = 1;
195 } else {
196 ai->ai_moving = 0;
197 }
198
199 }
200
201
202
203 /* Find the dir ent must face to see target */
calculate_dir(entity * ent,entity * target)204 byte calculate_dir(entity *ent, entity *target)
205 {
206 float ex, ey;
207 float tx, ty;
208 vector_t U, V;
209
210 /* U = unit vector in dir 0 from origin */
211 U.x = 0;
212 U.y = 1;
213
214 /* (ex, ey) = midpoint of ent */
215 ex = ent->x + ent->type_info->width/2;
216 ey = ent->y + ent->type_info->height/2;
217
218 /* (tx, ty) = midpoint of target */
219 tx = target->x + target->type_info->width/2.0;
220 ty = target->y + target->type_info->height/2.0;
221
222 /* V = vector from (origin) entity -> target */
223 V.x = tx - ex;
224 V.y = -1 * (ty - ey);
225
226 return angle_between(U,V);
227
228 }
229
230 /* This is a terrible hack to make the weapons spin.... */
231
232 /* Offset from (0, (DIR) * 50) to the center of the gun, which
233 was found by using the co-ordinates in the gimp, I did say this was
234 a terrible hack... */
235 static int gun_pos[8][2] = {
236 { 41, 15 },
237 { 45, 24 },
238 { 38, 32 },
239 { 23, 34 },
240 { 12, 28 },
241 { 41, 34 },
242 { 27, 32 },
243 { 18, 25 }
244 };
245
246 #define MSECS_PER_ROTATION 1500
247
ai_rotate_think(entity * ai)248 void ai_rotate_think(entity *ai)
249 {
250 int olddir, dir;
251 int x = 0, y = 0;
252
253 olddir = (ai->dir + 16)/32;
254 ai->dir += (256 / ((float)server.fps / M_SEC)) / MSECS_PER_ROTATION;
255 dir = (ai->dir + 16)/32;
256
257 if( dir != olddir ) {
258 x = gun_pos[dir%8][0] - gun_pos[olddir%8][0];
259 y = gun_pos[dir%8][1] - gun_pos[olddir%8][1];
260 ai->x -= x;
261 ai->y -= y;
262 }
263
264 }
265