source: abuse/branches/pd/macabuse/src/ant.c @ 98

Last change on this file since 98 was 49, checked in by Sam Hocevar, 15 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 14.0 KB
Line 
1#include "ant.hpp"
2#include "lisp.hpp"
3#include "lisp_gc.hpp"
4#include "compiled.hpp"
5#include "objects.hpp"
6#include "level.hpp"
7#include "game.hpp"
8#include "jrand.hpp"
9#include "clisp.hpp"
10#include "dev.hpp"
11#include "key_cfg.hpp"
12#include "status.hpp"
13#include <ctype.h>
14
15
16enum {  ANT_need_to_dodge,     // ant vars
17        ANT_no_see_time,
18        ANT_hide_flag };
19
20void *ant_ai();
21
22int can_see(game_object *o, long x1, long y1, long x2, long y2)
23{
24  long nx2=x2,ny2=y2;
25  current_level->vforeground_intersect(x1,y1,y2);
26  if (y2!=ny2) return 0;
27
28  current_level->boundary_setback(o,x1,y1,x2,y2);
29  return (x2==nx2 && y2==ny2);
30}
31
32
33// if we first saw the player or it's been a while since we've seen the player then do a scream
34static void scream_check(game_object *o, game_object *b)
35{
36  if (can_see(o,o->x,o->y,b->x,b->y))
37  {
38    if (o->lvars[ANT_no_see_time]==0 || o->lvars[ANT_no_see_time]>20)
39      the_game->play_sound(S_ASCREAM_SND,127,o->x,o->y);     
40    o->lvars[ANT_no_see_time]=1;
41  } else o->lvars[ANT_no_see_time]++;
42}
43
44int ant_congestion(game_object *o)
45{
46  for (game_object *d=current_level->first_active_object();d;d=d->next_active)
47  {
48    if (d->otype==o->otype && abs(o->x-d->x)<30 && abs(o->x-d->y)<20) return 1;
49  }
50  return 0;
51}
52
53int ant_dodge(game_object *o)
54{
55  if (o->lvars[ANT_need_to_dodge]==1)
56  {
57    o->lvars[ANT_need_to_dodge]=0;
58    if ((jrand()%2)==0)
59    {
60      o->set_state(stopped);
61      o->set_aistate(ANT_JUMP);
62      if (!can_see(o,o->x,o->y,o->x,o->y-120))   // is there a roof above?
63      {
64        o->set_yvel(-17);
65        o->set_xvel(0);
66        o->set_aistate(ANT_JUMP_ROOF);
67        ant_ai();
68      } else
69      {
70        o->set_yvel(-12);
71        if (o->direction>0)
72          o->set_xvel(22);
73        else o->set_xvel(-22);
74        o->set_aistate(ANT_JUMP);
75      }
76    }
77    return 1;
78  } else return 0;
79}
80
81static int alien_wait_time()
82{
83  void *v=symbol_value(l_difficulty);
84  if (v==l_easy)
85    return 6;
86  else if (v==l_medium)
87   return 4;
88  else if (v==l_hard)
89    return 2;
90  else return 1;
91}
92
93static int can_hit_player(game_object *o, game_object *b)
94
95  return can_see(o,o->x+(o->direction>0?15:-15),o->y-15,b->x,b->y-15);
96}
97
98static void fire_at_player(game_object *o, game_object *b)
99{
100  long firex=o->x+(o->direction>0?15:-15),firey=o->y-15,
101       playerx=b->x+b->xvel()*8,playery=b->y-15+b->yvel()*2;
102  if (can_see(o,o->x,o->y,firex,firey) && can_see(o,firex,firey,playerx,playery))
103  {
104    int angle=lisp_atan2(firey-playery,playerx-firex);
105    void *call_list=NULL;
106    p_ref r1(call_list);
107    push_onto_list(new_lisp_pointer(b),call_list);
108    push_onto_list(new_lisp_number(angle),call_list);
109    push_onto_list(new_lisp_number(firey),call_list);
110    push_onto_list(new_lisp_number(firex),call_list);
111    push_onto_list(new_lisp_number(o->aitype()),call_list);
112    push_onto_list(new_lisp_pointer(o),call_list);
113    eval_user_fun((lisp_symbol *)l_fire_object,call_list);
114    o->set_state((character_state)S_weapon_fire);
115  }
116}
117
118void *ant_ai()
119{
120  game_object *o=current_object,*b;
121
122  if (o->hp()==0)    // if we are dead return NULL and get deleted
123  {
124    if (o->state==dead)
125    {
126      current_level->attacker(current_object)->controller()->kills++;
127      return NULL;
128    }
129    else o->set_state(dead);
130    return true_symbol;
131  }
132
133
134  if (o->state==flinch_up || o->state==flinch_down)
135  {
136    o->next_picture();
137    return true_symbol;
138  }
139
140
141  switch (o->aistate())
142  {
143    case ANT_START :
144    {
145      o->set_state((character_state)S_hanging);
146      if (o->lvars[ANT_hide_flag])
147        o->set_aistate(ANT_HIDING);
148
149      else o->set_aistate(ANT_HANGING);
150    } break;
151    case ANT_HIDING :
152    {
153      if ((jrand()%128)==0) the_game->play_sound(S_SCARE_SND,127,o->x,o->y);
154      if (o->otype!=S_HIDDEN_ANT)
155      {
156        o->change_type(S_HIDDEN_ANT);      // switch types so noone hurts us.
157        o->set_state(stopped);
158        o->set_aistate(ANT_HIDING);
159      }
160
161      int fall=0;
162      if (o->total_objects()==0)
163      {
164        if (player_list->next)
165          b=current_level->attacker(current_object);
166        else b=player_list->focus;
167        if (abs(b->x-o->x)<130 && (o->y<b->y))
168          fall=1;
169      }     
170      else if (o->get_object(0)->aistate()!=0)
171        fall=1;
172     
173      if (fall)
174      {
175        o->change_type(S_ANT_ROOF);
176        o->set_state((character_state)S_falling);
177        o->set_aistate(ANT_FALL_DOWN);
178        o->set_targetable(1);
179      } else o->set_targetable(0);
180    } break;
181    case ANT_HANGING :
182    {
183      int fall=0;
184      if ((jrand()%128)==0) the_game->play_sound(S_SCARE_SND,127,o->x,o->y);
185      if (o->lvars[ANT_hide_flag])
186        o->set_aistate(ANT_HIDING);
187      else
188      {
189        o->set_state((character_state)S_hanging);
190        if (o->total_objects())
191        {
192          if (o->get_object(0)->aistate()!=0)
193          fall=1;
194        } else
195        {
196          if (player_list->next)
197            b=current_level->attacker(current_object);
198          else b=player_list->focus;
199          if (abs(b->x-o->x)<130 && (o->y<b->y))
200          fall=1;
201        }
202        if (fall)
203        {
204          o->set_state((character_state)S_fall_start);
205          o->set_aistate(ANT_FALL_DOWN);
206          o->set_targetable(1);
207        } else o->set_targetable(0);
208      }
209     
210    } break;
211    case ANT_FALL_DOWN :
212    {
213      o->set_state((character_state)S_falling);
214       
215      if (player_list->next)
216      b=current_level->attacker(current_object);
217      else b=player_list->focus;
218     
219      scream_check(o,b);
220      int ret=o->mover(0,0,0);
221      if ((ret&BLOCKED_DOWN) || !can_see(o,o->x,o->y,o->x,o->y+1))
222      {
223        o->set_state((character_state)S_landing);
224        the_game->play_sound(S_ALAND_SND,127,o->x,o->y);
225        o->set_aistate(ANT_LANDING);
226      }
227    } break;
228    case ANT_LANDING :
229    {
230      if (!o->next_picture())
231      {
232        long xv=0,yv=2;
233        o->try_move(o->x,o->y,xv,yv,1);
234        if (yv!=0)
235        {
236          o->set_gravity(1);
237          o->set_aistate(ANT_FALL_DOWN);
238        }
239        else
240        {
241          o->set_state(stopped);
242          o->set_aistate(ANT_RUNNING);
243          return ant_ai;
244        }
245      }
246    } break;
247    case ANT_RUNNING :
248    {
249      if (player_list->next)
250      b=current_level->attacker(current_object);
251      else b=player_list->focus;
252      scream_check(o,b);
253     
254     
255      if ((jrand()%16)==0) 
256      o->lvars[ANT_need_to_dodge]=1;
257      if (!ant_dodge(o))
258      {
259        if ((o->x>b->x && o->direction==-1) || (o->x<b->x && o->direction==1))
260        {
261          o->next_picture();
262          if ((jrand()%4)==0 && abs(o->x-b->x)<180 && abs(o->y-b->y)<100 && can_hit_player(o,b))
263          {
264            o->set_state((character_state)S_weapon_fire);
265            o->set_aistate(ANT_FIRE);
266          } else if (abs(o->x-b->x)<100 && abs(o->y-b->y)<10 && (jrand()%4)==0)
267            o->set_aistate(ANT_POUNCE_WAIT);
268          else if (abs(o->x-b->x)>140 && !ant_congestion(o))
269            o->set_aistate(ANT_JUMP);
270          else
271          {
272            long xm=o->direction>0 ? get_ability(o->otype,run_top_speed) : -get_ability(o->otype,run_top_speed);
273            long ym=0,new_xm=xm;
274            if (o->state!=running) o->set_state(running);
275
276            o->try_move(o->x,o->y,new_xm,ym,3);
277            if (new_xm!=xm)    // blocked, see if we can climb ramp
278            {
279              new_xm=xm;
280              ym=-abs(xm);
281              o->try_move(o->x,o->y,new_xm,ym,3);
282              if (new_xm==xm)
283              {
284                o->x+=new_xm;
285                o->y+=ym;
286                new_xm=0;
287                ym=abs(xm);      // now get back on the ground
288                o->try_move(o->x,o->y,new_xm,ym,3);
289                o->x+=new_xm;
290                o->y+=ym;
291              } else
292              {
293                o->direction=0-o->direction;
294                o->set_aistate(ANT_JUMP);
295              }
296            } else
297              o->x+=new_xm;
298            new_xm=0;
299            ym=10;       // see if we should fall
300            o->try_move(o->x,o->y,new_xm,ym,3);
301            if (ym==10)
302              o->set_aistate(ANT_FALL_DOWN);
303            else o->y+=ym;
304          }
305        } else
306        {
307          o->direction=o->x>b->x ? -1 : 1;
308          o->set_aistate(ANT_LANDING);
309        }
310      }
311    } break;
312   
313    case ANT_POUNCE_WAIT :
314    {
315      if (!ant_dodge(o))
316      {
317        o->set_state((character_state)S_pounce_wait);
318        if (o->aistate_time()>alien_wait_time())
319        {
320          the_game->play_sound(S_ASLASH_SND,127,o->x,o->y);
321          o->set_state(stopped);
322          o->set_aistate(ANT_JUMP);
323        }
324      }
325    } break;
326
327    case ANT_JUMP :
328    {
329      o->lvars[ANT_need_to_dodge]=0;
330      if (o->move(o->direction,-1,0)&BLOCKED_DOWN)
331      o->set_aistate(ANT_RUNNING);     
332    } break;
333    case ANT_FIRE :
334    {
335      if (!ant_dodge(o))
336      {
337        if (o->state==S_fire_wait)
338        {
339          if (!o->next_picture() || symbol_value(l_difficulty)==l_extreme)
340          {
341            if (player_list->next)
342            b=current_level->attacker(current_object);
343            else b=player_list->focus;
344            fire_at_player(o,b);
345            o->set_state(stopped);
346            o->set_aistate(ANT_RUNNING);
347          }
348        } else o->set_state((character_state)S_fire_wait);
349      }
350    } break;
351    case ANT_JUMP_ROOF :
352    {
353      o->lvars[ANT_need_to_dodge]=0;
354      o->set_state((character_state)S_jump_up);
355//      o->set_yvel(o->yvel()+1);
356      o->set_xacel(0);
357      long xv=0,yv=o->yvel();
358      o->y-=31;
359      o->try_move(o->x,o->y,xv,yv,1);
360      o->y+=31+yv;
361      if (yv!=o->yvel())
362      {
363        if (o->yvel()>0)
364        {
365          o->set_state(stopped);
366          o->set_aistate(ANT_RUNNING);
367        } else
368        {
369          o->set_state((character_state)S_top_walk);
370          o->set_aistate(ANT_ROOF_WALK);
371        }
372        o->set_yvel(0);
373      }
374    } break;
375    case ANT_ROOF_WALK :
376    {
377      if (player_list->next)
378      b=current_level->attacker(current_object);
379      else b=player_list->focus;
380      scream_check(o,b);     
381      if (((jrand()%8)==0 && abs(o->x-b->x)<10 && o->y<b->y) ||
382          o->lvars[ANT_need_to_dodge]==1)
383      {
384        o->set_gravity(1);
385        o->set_state(run_jump);
386        o->set_aistate(ANT_JUMP);
387        ant_ai();
388      }
389      else
390      {
391        if ((o->x>b->x && o->direction>0) || (o->x<b->x && o->direction<0))
392        o->direction=-o->direction;
393        else if (abs(o->x-b->x)<120 && (jrand()%4)==0)
394        {
395          o->set_state((character_state)S_ceil_fire);
396          o->set_aistate(ANT_CEIL_SHOOT);
397          ant_ai();
398        } else
399        {
400          int speed=o->direction>0 ? get_ability(o->otype,run_top_speed) :
401                    -get_ability(o->otype,run_top_speed);
402          if (can_see(o,o->x,o->y-31,o->x+speed,o->y-31) &&
403              !can_see(o,o->x+speed,o->y-31,o->x+speed,o->y-32))
404          {
405            o->x+=speed;
406            if (!o->next_picture()) o->set_state((character_state)S_top_walk);
407           
408          } else o->set_aistate(ANT_FALL_DOWN);
409        }
410      }
411    } break;
412    case ANT_CEIL_SHOOT :
413    {
414      if (!o->next_picture())
415      {
416        if (player_list->next)
417          b=current_level->attacker(current_object);
418        else b=player_list->focus;
419        fire_at_player(o,b);
420        o->set_state((character_state)S_top_walk);
421        o->set_aistate(ANT_ROOF_WALK);
422      }
423    } break;
424  }
425 
426 
427 
428  return true_symbol;
429}
430
431
432
433void fade_in(image *im, int steps);
434void fade_out(int steps);
435
436time_marker stat_show_start;
437static status_manager *old_stat;
438
439class next_level_status_manager : public status_manager
440{
441  int level;
442  int x1,y1,x2,y2,color,last;
443  public :
444  next_level_status_manager(int x1, int y1, int x2, int y2, int color) : x1(x1),y1(y1),x2(x2),y2(y2),color(color)
445  {
446    level=0;
447    last=-1;
448  }
449
450  virtual void push(char *name, visual_object *show)
451  {
452    level++;
453  }
454
455  virtual void update(int percentage)
456  {
457    if (percentage!=last)
458    {
459      last=percentage;
460
461      if (level==1)
462      {
463        int w=x1+(x2-x1)*percentage/100;
464        screen->bar(x1,y1,w,y2,color);
465        if (w<x2)
466          screen->bar(w,y1,x2,y2,0);
467      }
468      eh->flush_screen();
469    }
470
471  }
472
473  virtual void pop() { level--; }
474  virtual void force_display() { ; }
475} ;
476
477void show_stats()
478{
479  if (current_level)
480  {
481    int xp,yp;
482
483    if (!player_list->next)
484    {
485      fade_out(8);
486      eh->set_mouse_position(0,0);
487      screen->clear();
488
489      switch_mode(VMODE_640x480);
490
491      load_image_into_screen("art/frame.spe","end_level_screen",xp,yp);
492      fade_in(NULL,16);
493    } else
494    {
495      xp=screen->width()/2-640/2;
496      yp=screen->height()/2-480/2;
497    }
498
499
500
501    char name[50];
502    strcpy(name,current_level->original_name());
503    char dig1=name[strlen(name)-strlen(".spe")-2];
504    char dig2=name[strlen(name)-strlen(".spe")-1];
505
506   
507    char msg[50];
508    int lev_num;
509
510
511    if (isdigit(dig1) && isdigit(dig2))
512      lev_num=(dig1-'0')*10+dig2-'0';
513    else
514      lev_num=dig2-'0';
515
516    sprintf(msg,symbol_str("lev_complete"),lev_num);   
517
518    int w=eh->font()->width()*strlen(msg),h=eh->font()->height();   
519    int x1=0,y1=0,x2=xres,y2=yres;
520    //    int x=(x1+x2)/2-w/2,y=(y1+y2)/2-h/2;
521    int x=444+xp,y=293+yp;   
522   
523    eh->font()->put_string(screen,x+1,y+1,msg,eh->dark_color());   
524    eh->font()->put_string(screen,x,y,msg,eh->bright_color());
525   
526    y+=eh->font()->height();
527    sprintf(msg,"Time taken.. %0.1f minutes",current_level->time_taken()/60.0);
528    eh->font()->put_string(screen,x+1,y+1,msg,eh->dark_color());   
529    eh->font()->put_string(screen,x,y,msg,eh->bright_color());
530
531    y+=eh->font()->height();
532    sprintf(msg,"Kills....... %d",player_list->kills);
533    eh->font()->put_string(screen,x+1,y+1,msg,eh->dark_color());   
534    eh->font()->put_string(screen,x,y,msg,eh->bright_color());
535
536
537
538    eh->flush_screen();
539    stat_show_start.get_time();
540
541    old_stat=stat_man;
542    stat_man=new next_level_status_manager(xp+443,yp+424,xp+589,yp+443,93); 
543  }
544}
545
546
547
548void end_stats()
549{
550  time_marker now;
551  while (now.diff_time(&stat_show_start)<2)
552    now.get_time();
553
554  view *f=player_list;
555  for (;f;f=f->next)
556    f->kills=0;
557
558  fade_out(8);
559  switch_mode(VMODE_320x200);
560  pal->load();
561  stat_man=old_stat;
562}
563
564
565
566void scatter_line(int x1, int y1, int x2, int y2, int c, int s)
567{
568  short cx1,cy1,cx2,cy2;
569  screen->get_clip(cx1,cy1,cx2,cy2);
570 
571  int t=abs(x2-x1)>abs(y2-y1) ? abs(x2-x1)+1 : abs(y2-y1)+1;
572  long xo=x1<<16,yo=y1<<16,dx=((x2-x1)<<16)/t,dy=((y2-y1)<<16)/t,count=0,x,y;
573  uchar *sl;
574
575  int xm=(1<<s);
576  int ym=(1<<s);
577  s=(15-s);
578
579
580  while (t--)
581  {
582    x=(xo>>16)+(jrand()>>s)-xm;
583    y=(yo>>16)+(jrand()>>s)-ym;
584    if (!(x<cx1 || y<cy1 || x>cx2 || y>cy2))
585      *(screen->scan_line(y)+x)=c;
586    xo+=dx; yo+=dy;
587  }
588
589}
590
591
592
593void ascatter_line(int x1, int y1, int x2, int y2, int c1, int c2, int s)
594{
595  short cx1,cy1,cx2,cy2;
596  screen->get_clip(cx1,cy1,cx2,cy2);
597
598
599  int t=abs(x2-x1)>abs(y2-y1) ? abs(x2-x1)+1 : abs(y2-y1)+1;
600  long xo=x1<<16,yo=y1<<16,dx=((x2-x1)<<16)/t,dy=((y2-y1)<<16)/t,count=0,x,y;
601  uchar *sl;
602
603  int xm=(1<<s);
604  int ym=(1<<s);
605  s=(15-s);
606
607  int w=screen->width();
608  uchar *addr;
609
610
611  while (t--)
612  {
613    x=(xo>>16)+(jrand()>>s)-xm;
614    y=(yo>>16)+(jrand()>>s)-ym;
615    if (!(x<=cx1 || y<=cy1 || x>=cx2 || y>=cy2))
616    {
617      addr=screen->scan_line(y)+x;
618      *addr=c1;
619      *(addr+w)=c2;
620      *(addr-w)=c2;
621      *(addr-1)=c2;
622      *(addr+1)=c2;
623    }
624    xo+=dx; yo+=dy;
625  }
626
627}
628
629
Note: See TracBrowser for help on using the repository browser.