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

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

lisp: rename core classes to slightly shorter names (LispObject? -> LObject).

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    PtrRef r1(call_list);
114    push_onto_list(new_lisp_pointer(b),call_list);
115    push_onto_list(LNumber::Create(angle),call_list);
116    push_onto_list(LNumber::Create(firey),call_list);
117    push_onto_list(LNumber::Create(firex),call_list);
118    push_onto_list(LNumber::Create(o->aitype()),call_list);
119    push_onto_list(new_lisp_pointer(o),call_list);
120    eval_user_fun((LSymbol *)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.