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

Last change on this file since 60 was 60, checked in by Sam Hocevar, 11 years ago
  • Make a few symbols static (Ref #7).
File size: 11.6 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.hpp"
15#include "lisp.hpp"
16#include "lisp_gc.hpp"
17#include "compiled.hpp"
18#include "objects.hpp"
19#include "level.hpp"
20#include "game.hpp"
21#include "jrand.hpp"
22#include "clisp.hpp"
23#include "dev.hpp"
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    eh->set_mouse_position(0,0);
446    screen->clear();
447    image *im=cash.img(cash.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=eh->font()->width()*strlen(msg),h=eh->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,eh->bright_color());
473    screen->bar(x-9,y-9,x+w+9,y+h+9,eh->medium_color());
474
475    eh->font()->put_string(screen,x+1,y+1,msg,eh->dark_color());   
476    eh->font()->put_string(screen,x,y,msg,eh->bright_color());
477    eh->flush_screen();
478    milli_wait(500);
479  }
480
481}
Note: See TracBrowser for help on using the repository browser.