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

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