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