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

Last change on this file since 494 was 494, checked in by Sam Hocevar, 11 years ago

style: remove trailing spaces, fix copyright statements.

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