source: abuse/tags/0.7.0/src/ant.cpp @ 608

Last change on this file since 608 was 2, checked in by Sam Hocevar, 17 years ago
  • imported original 0.7.0 tarball
File size: 11.2 KB
Line 
1#include "ant.hpp"
2#include "lisp.hpp"
3#include "lisp_gc.hpp"
4#include "compiled.hpp"
5#include "objects.hpp"
6#include "level.hpp"
7#include "game.hpp"
8#include "jrand.hpp"
9#include "clisp.hpp"
10#include "dev.hpp"
11#include <ctype.h>
12
13enum {  ANT_need_to_dodge,     // ant vars
14        ANT_no_see_time,
15        ANT_hide_flag };
16
17void *ant_ai();
18
19int can_see(game_object *o, long x1, long y1, long x2, long y2)
20{
21  long nx2=x2,ny2=y2;
22  current_level->foreground_intersect(x1,y1,x2,y2);
23  if (x2!=nx2 || y2!=ny2) return 0;
24
25  current_level->boundary_setback(o,x1,y1,x2,y2);
26  return (x2==nx2 && y2==ny2);
27}
28
29
30// if we first saw the player or it's been a while since we've seen the player then do a scream
31static void scream_check(game_object *o, game_object *b)
32{
33  if (can_see(o,o->x,o->y,b->x,b->y))
34  {
35    if (o->lvars[ANT_no_see_time]==0 || o->lvars[ANT_no_see_time]>20)
36      the_game->play_sound(S_ASCREAM_SND,127,o->x,o->y);     
37    o->lvars[ANT_no_see_time]=1;
38  } else o->lvars[ANT_no_see_time]++;
39}
40
41int ant_congestion(game_object *o)
42{
43  for (game_object *d=current_level->first_active_object();d;d=d->next_active)
44  {
45    if (d->otype==o->otype && abs(o->x-d->x)<30 && abs(o->x-d->y)<20) return 1;
46  }
47  return 0;
48}
49
50int ant_dodge(game_object *o)
51{
52  if (o->lvars[ANT_need_to_dodge]==1)
53  {
54    o->lvars[ANT_need_to_dodge]=0;
55    if ((jrand()%2)==0)
56    {
57      o->set_state(stopped);
58      o->set_aistate(ANT_JUMP);
59      if (!can_see(o,o->x,o->y,o->x,o->y-120))   // is there a roof above?
60      {
61        o->set_yvel(-17);
62        o->set_xvel(0);
63        o->set_aistate(ANT_JUMP_ROOF);
64        ant_ai();
65      } else
66      {
67        o->set_yvel(-12);
68        if (o->direction>0)
69          o->set_xvel(22);
70        else o->set_xvel(-22);
71        o->set_aistate(ANT_JUMP);
72      }
73    }
74    return 1;
75  } else return 0;
76}
77
78static int alien_wait_time()
79{
80  void *v=symbol_value(l_difficulty);
81  if (v==l_easy)
82    return 6;
83  else if (v==l_medium)
84   return 4;
85  else if (v==l_hard)
86    return 2;
87  else return 1;
88}
89
90static int can_hit_player(game_object *o, game_object *b)
91
92  return can_see(o,o->x+(o->direction>0?15:-15),o->y-15,b->x,b->y-15);
93}
94
95static void fire_at_player(game_object *o, game_object *b)
96{
97  long firex=o->x+(o->direction>0?15:-15),firey=o->y-15,
98       playerx=b->x+b->xvel()*8,playery=b->y-15+b->yvel()*2;
99  if (can_see(o,o->x,o->y,firex,firey) && can_see(o,firex,firey,playerx,playery))
100  {
101    int angle=lisp_atan2(firey-playery,playerx-firex);
102    void *call_list=NULL;
103    p_ref r1(call_list);
104    push_onto_list(new_lisp_pointer(b),call_list);
105    push_onto_list(new_lisp_number(angle),call_list);
106    push_onto_list(new_lisp_number(firey),call_list);
107    push_onto_list(new_lisp_number(firex),call_list);
108    push_onto_list(new_lisp_number(o->aitype()),call_list);
109    push_onto_list(new_lisp_pointer(o),call_list);
110    eval_user_fun((lisp_symbol *)l_fire_object,call_list);
111    o->set_state((character_state)S_weapon_fire);
112  }
113}
114
115void *ant_ai()
116{
117  game_object *o=current_object,*b;
118
119  if (o->hp()==0)    // if we are dead return NULL and get deleted
120  {
121    if (o->state==dead)
122      return NULL;
123    else o->set_state(dead);
124    return true_symbol;
125  }
126
127
128  if (o->state==flinch_up || o->state==flinch_down)
129  {
130    o->next_picture();
131    return true_symbol;
132  }
133
134
135  switch (o->aistate())
136  {
137    case ANT_START :
138    {
139      o->set_state((character_state)S_hanging);
140      if (o->lvars[ANT_hide_flag])
141        o->set_aistate(ANT_HIDING);
142
143      else o->set_aistate(ANT_HANGING);
144    } break;
145    case ANT_HIDING :
146    {
147      if ((jrand()%128)==0) the_game->play_sound(S_SCARE_SND,127,o->x,o->y);
148      if (o->otype!=S_HIDDEN_ANT)
149      {
150        o->change_type(S_HIDDEN_ANT);      // switch types so noone hurts us.
151        o->set_state(stopped);
152        o->set_aistate(ANT_HIDING);
153      }
154
155      int fall=0;
156      if (o->total_objects()==0)
157      {
158        if (player_list->next)
159          b=current_level->attacker(current_object);
160        else b=player_list->focus;
161        if (abs(b->x-o->x)<130 && (o->y<b->y))
162          fall=1;
163      }     
164      else if (o->get_object(0)->aistate()!=0)
165        fall=1;
166     
167      if (fall)
168      {
169        o->change_type(S_ANT_ROOF);
170        o->set_state((character_state)S_falling);
171        o->set_aistate(ANT_FALL_DOWN);
172        o->set_targetable(1);
173      } else o->set_targetable(0);
174    } break;
175    case ANT_HANGING :
176    {
177      int fall=0;
178      if ((jrand()%128)==0) the_game->play_sound(S_SCARE_SND,127,o->x,o->y);
179      if (o->lvars[ANT_hide_flag])
180        o->set_aistate(ANT_HIDING);
181      else
182      {
183        o->set_state((character_state)S_hanging);
184        if (o->total_objects())
185        {
186          if (o->get_object(0)->aistate()!=0)
187          fall=1;
188        } else
189        {
190          if (player_list->next)
191            b=current_level->attacker(current_object);
192          else b=player_list->focus;
193          if (abs(b->x-o->x)<130 && (o->y<b->y))
194          fall=1;
195        }
196        if (fall)
197        {
198          o->set_state((character_state)S_fall_start);
199          o->set_aistate(ANT_FALL_DOWN);
200          o->set_targetable(1);
201        } else o->set_targetable(0);
202      }
203     
204    } break;
205    case ANT_FALL_DOWN :
206    {
207      o->set_state((character_state)S_falling);
208       
209      if (player_list->next)
210      b=current_level->attacker(current_object);
211      else b=player_list->focus;
212     
213      scream_check(o,b);
214      int ret=o->mover(0,0,0);
215      if ((ret&BLOCKED_DOWN) || !can_see(o,o->x,o->y,o->x,o->y+1))
216      {
217        o->set_state((character_state)S_landing);
218        the_game->play_sound(S_ALAND_SND,127,o->x,o->y);
219        o->set_aistate(ANT_LANDING);
220      }
221    } break;
222    case ANT_LANDING :
223    {
224      if (!o->next_picture())
225      {
226        long xv=0,yv=2;
227        o->try_move(o->x,o->y,xv,yv,1);
228        if (yv!=0)
229        {
230          o->set_gravity(1);
231          o->set_aistate(ANT_FALL_DOWN);
232        }
233        else
234        {
235          o->set_state(stopped);
236          o->set_aistate(ANT_RUNNING);
237          return (void *)ant_ai;
238        }
239      }
240    } break;
241    case ANT_RUNNING :
242    {
243      if (player_list->next)
244      b=current_level->attacker(current_object);
245      else b=player_list->focus;
246      scream_check(o,b);
247     
248     
249      if ((jrand()%16)==0) 
250      o->lvars[ANT_need_to_dodge]=1;
251      if (!ant_dodge(o))
252      {
253        if ((o->x>b->x && o->direction==-1) || (o->x<b->x && o->direction==1))
254        {
255          o->next_picture();
256          if ((jrand()%4)==0 && abs(o->x-b->x)<180 && abs(o->y-b->y)<100 && can_hit_player(o,b))
257          {
258            o->set_state((character_state)S_weapon_fire);
259            o->set_aistate(ANT_FIRE);
260          } else if (abs(o->x-b->x)<100 && abs(o->y-b->y)<10 && (jrand()%4)==0)
261            o->set_aistate(ANT_POUNCE_WAIT);
262          else if (abs(o->x-b->x)>140 && !ant_congestion(o))
263            o->set_aistate(ANT_JUMP);
264          else
265          {
266            long xm=o->direction>0 ? get_ability(o->otype,run_top_speed) : -get_ability(o->otype,run_top_speed);
267            long ym=0,new_xm=xm;
268            if (o->state!=running) o->set_state(running);
269
270            o->try_move(o->x,o->y,new_xm,ym,3);
271            if (new_xm!=xm)    // blocked, see if we can climb ramp
272            {
273              new_xm=xm;
274              ym=-abs(xm);
275              o->try_move(o->x,o->y,new_xm,ym,3);
276              if (new_xm==xm)
277              {
278                o->x+=new_xm;
279                o->y+=ym;
280                new_xm=0;
281                ym=abs(xm);      // now get back on the ground
282                o->try_move(o->x,o->y,new_xm,ym,3);
283                o->x+=new_xm;
284                o->y+=ym;
285              } else
286              {
287                o->direction=0-o->direction;
288                o->set_aistate(ANT_JUMP);
289              }
290            } else
291              o->x+=new_xm;
292            new_xm=0;
293            ym=10;       // see if we should fall
294            o->try_move(o->x,o->y,new_xm,ym,3);
295            if (ym==10)
296              o->set_aistate(ANT_FALL_DOWN);
297            else o->y+=ym;
298          }
299        } else
300        {
301          o->direction=o->x>b->x ? -1 : 1;
302          o->set_aistate(ANT_LANDING);
303        }
304      }
305    } break;
306   
307    case ANT_POUNCE_WAIT :
308    {
309      if (!ant_dodge(o))
310      {
311        o->set_state((character_state)S_pounce_wait);
312        if (o->aistate_time()>alien_wait_time())
313        {
314          the_game->play_sound(S_ASLASH_SND,127,o->x,o->y);
315          o->set_state(stopped);
316          o->set_aistate(ANT_JUMP);
317        }
318      }
319    } break;
320
321    case ANT_JUMP :
322    {
323      o->lvars[ANT_need_to_dodge]=0;
324      if (o->move(o->direction,-1,0)&BLOCKED_DOWN)
325      o->set_aistate(ANT_RUNNING);     
326    } break;
327    case ANT_FIRE :
328    {
329      if (!ant_dodge(o))
330      {
331        if (o->state==S_fire_wait)
332        {
333          if (!o->next_picture() || symbol_value(l_difficulty)==l_extreme)
334          {
335            if (player_list->next)
336            b=current_level->attacker(current_object);
337            else b=player_list->focus;
338            fire_at_player(o,b);
339            o->set_state(stopped);
340            o->set_aistate(ANT_RUNNING);
341          }
342        } else o->set_state((character_state)S_fire_wait);
343      }
344    } break;
345    case ANT_JUMP_ROOF :
346    {
347      o->lvars[ANT_need_to_dodge]=0;
348      o->set_state((character_state)S_jump_up);
349//      o->set_yvel(o->yvel()+1);
350      o->set_xacel(0);
351      long xv=0,yv=o->yvel();
352      o->y-=31;
353      o->try_move(o->x,o->y,xv,yv,1);
354      o->y+=31+yv;
355      if (yv!=o->yvel())
356      {
357        if (o->yvel()>0)
358        {
359          o->set_state(stopped);
360          o->set_aistate(ANT_RUNNING);
361        } else
362        {
363          o->set_state((character_state)S_top_walk);
364          o->set_aistate(ANT_ROOF_WALK);
365        }
366        o->set_yvel(0);
367      }
368    } break;
369    case ANT_ROOF_WALK :
370    {
371      if (player_list->next)
372      b=current_level->attacker(current_object);
373      else b=player_list->focus;
374      scream_check(o,b);     
375      if (((jrand()%8)==0 && abs(o->x-b->x)<10 && o->y<b->y) ||
376          o->lvars[ANT_need_to_dodge]==1)
377      {
378        o->set_gravity(1);
379        o->set_state(run_jump);
380        o->set_aistate(ANT_JUMP);
381        ant_ai();
382      }
383      else
384      {
385        if ((o->x>b->x && o->direction>0) || (o->x<b->x && o->direction<0))
386        o->direction=-o->direction;
387        else if (abs(o->x-b->x)<120 && (jrand()%4)==0)
388        {
389          o->set_state((character_state)S_ceil_fire);
390          o->set_aistate(ANT_CEIL_SHOOT);
391          ant_ai();
392        } else
393        {
394          int speed=o->direction>0 ? get_ability(o->otype,run_top_speed) :
395                    -get_ability(o->otype,run_top_speed);
396          if (can_see(o,o->x,o->y-31,o->x+speed,o->y-31) &&
397              !can_see(o,o->x+speed,o->y-31,o->x+speed,o->y-32))
398          {
399            o->x+=speed;
400            if (!o->next_picture()) o->set_state((character_state)S_top_walk);
401           
402          } else o->set_aistate(ANT_FALL_DOWN);
403        }
404      }
405    } break;
406    case ANT_CEIL_SHOOT :
407    {
408      if (!o->next_picture())
409      {
410        if (player_list->next)
411          b=current_level->attacker(current_object);
412        else b=player_list->focus;
413        fire_at_player(o,b);
414        o->set_state((character_state)S_top_walk);
415        o->set_aistate(ANT_ROOF_WALK);
416      }
417    } break;
418  }
419 
420 
421 
422  return true_symbol;
423}
424
425
426
427void fade_in(image *im, int steps);
428void fade_out(int steps);
429
430void show_stats()
431{
432  if (current_level)
433  {
434    fade_out(8);
435    eh->set_mouse_position(0,0);
436    screen->clear();
437    image *im=cash.img(cash.reg("art/frame.spe","end_level_screen",SPEC_IMAGE,1));
438    im->put_image(screen,0,0);
439
440
441    int x1=im->width()+1,y1=0,x2=xres,y2=screen->height();
442    fade_in(NULL,16);
443
444    char name[50];
445    strcpy(name,current_level->original_name());
446    char dig1=name[strlen(name)-strlen(".spe")-2];
447    char dig2=name[strlen(name)-strlen(".spe")-1];
448
449   
450    char msg[50];
451
452    if (isdigit(dig1) && isdigit(dig2))
453    {
454      if (dig1!='0')
455        sprintf(msg,"%s : %c%c",symbol_str("lev_complete"),dig1,dig2);
456      else
457        sprintf(msg,"%s : %c",symbol_str("lev_complete"),dig2);
458    } else sprintf(msg,"%s : %s",symbol_str("lev_complete"),current_level->original_name());
459
460    int w=eh->font()->width()*strlen(msg),h=eh->font()->height();   
461    int x=(x1+x2)/2-w/2,y=(y1+y2)/2-h/2;
462    screen->bar(x-10,y-10,x+w+10,y+h+10,eh->bright_color());
463    screen->bar(x-9,y-9,x+w+9,y+h+9,eh->medium_color());
464
465    eh->font()->put_string(screen,x+1,y+1,msg,eh->dark_color());   
466    eh->font()->put_string(screen,x,y,msg,eh->bright_color());
467    eh->flush_screen();
468    milli_wait(500);
469  }
470
471}
Note: See TracBrowser for help on using the repository browser.