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

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

imlib: use vec2i for image::size and unroll all necessary changes
everywhere else in the code.

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