source: abuse/trunk/src/ant.cpp @ 481

Last change on this file since 481 was 481, checked in by Sam Hocevar, 12 years ago

Fuck the history, I'm renaming all .hpp files to .h for my own sanity.

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