source: abuse/trunk/src/cop.cpp @ 496

Last change on this file since 496 was 496, checked in by Sam Hocevar, 10 years ago

lisp: implement LObject::Eval.

File size: 27.3 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 "lisp.h"
14#include "lisp_gc.h"
15#include "compiled.h"
16#include "objects.h"
17#include "level.h"
18#include "game.h"
19#include "jrand.h"
20#include "clisp.h"
21#include "ant.h"
22#include "dev.h"
23
24enum { point_angle, fire_delay1 };
25
26#define SHOTGUN  10
27#define GRENADE  2
28#define ROCKET   3
29#define PLASMA   4
30#define FIREBOMB 5
31#define DFRIS    6
32#define LSABER   7
33
34signed char small_fire_off[24*2]=  // x & y offset from character to end of gun.
35  { 17,20,     // 1
36    17,23,     // 2
37    17,28,
38    15,33,
39    11,39,     // 5
40    7,43,
41    -3,44,     // 7
42    -10,42,
43    -16,39,
44    -20,34,
45    -20,28,
46    -20,25,
47    -19,20,
48    -19,16,
49    -16,14,
50    -14,11,
51    -11,9,
52    -7,8,
53    -3,8,
54    2,8,
55    6,9,
56    10,10,
57    14,13,
58    16,15 };
59
60signed char large_fire_off[24*2]=
61  { 18,25,
62    17,30,
63    15,34,
64    14,36,
65    10,39,
66    7,41,
67    4,42,
68    -3,41,
69    -8,39,
70    -11,37,
71    -14,33,
72    -16,30,
73    -18,25,
74    -17,21,
75    -14,17,
76    -11,15,
77    -7,13,
78    -4,12,
79    3,12,
80    9,12,
81    12,15,
82    14,16,
83    15,18,
84    16,21 };
85
86
87enum { in_climbing_area,
88    disable_top_draw,
89    just_hit,
90    ship_pan_x,
91    special_power,
92    used_special_power,
93    last1_x, last1_y,
94    last2_x, last2_y,
95    has_saved_this_level,
96    r_ramp, g_ramp, b_ramp,
97        is_teleporting,
98       just_fired};
99
100
101enum { sgb_speed,
102       sgb_angle,
103       sgb_lastx,
104       sgb_lasty,
105       sgb_bright_color,
106       sgb_medium_color,
107       sgb_lifetime };
108
109enum { NO_POWER,
110       FAST_POWER,
111       FLY_POWER,
112       SNEAKY_POWER,
113       HEALTH_POWER } ;
114
115enum { top_point_angle,
116       top_fire_delay1,
117       top_just_fired };
118
119inline int angle_diff(int a1, int a2)
120{
121  if (a1<a2)
122  { if ((a2-a1)<180)
123      return a2-a1;
124    else return 360-a2+a1;
125  } else
126  {
127    if ((a1-a2)<180)
128      return a1-a2;
129    else return 360-a1+a2;
130  }
131  return 0;
132}
133
134void *top_ai()
135{
136  game_object *o=current_object;
137  if (o->total_objects())            // make sure we are linked to the main character
138  {
139    game_object *q=o->get_object(0);
140
141    view *v=q->controller();
142    if (v)
143    {
144      if (!v->freeze_time)
145      {
146    o->direction=1;                 // always face right
147
148    if (q->direction<0)
149          q->x+=4;
150    int i;
151    signed char *fire_off=o->otype==S_DFRIS_TOP ? large_fire_off :
152                                    (o->otype==S_ROCKET_TOP ? large_fire_off :
153                     (o->otype==S_BFG_TOP ? large_fire_off : small_fire_off));
154    signed char *f=fire_off,*fb=NULL;
155    int best_diff=200,best_num=0;
156    int iy=f[1],ix=f[6*2];
157
158    int best_angle=lisp_atan2(q->y-iy-v->pointer_y,v->pointer_x-q->x-ix);
159    for (i=0; i<24; i++,f+=2)             // check all the angles to see which would best fit animation wise
160    {
161      int this_angle=lisp_atan2(f[1]-iy,f[0]-ix);
162      int this_diff=angle_diff(this_angle,best_angle);
163      if (this_diff<best_diff)
164      {
165        best_diff=this_diff;
166        best_num=i;
167        fb=f;
168      }
169    }
170
171
172    // if the pointer is too close to the player go with the angle shown, not the angle through the pointer
173    if (abs(q->y-fb[1]-v->pointer_y)<45 && abs(v->pointer_x-q->x+fb[0])<40)
174      o->lvars[point_angle]=lisp_atan2(fb[1]-iy,fb[0]-ix);
175    else
176      o->lvars[point_angle]=lisp_atan2(q->y-fb[1]-v->pointer_y,v->pointer_x-(q->x+fb[0]));
177
178
179    if (q->direction<0)
180          q->x-=4;
181
182    o->x=q->x;
183    o->y=q->y+29-q->picture()->height();
184
185    rand_on+=o->lvars[point_angle];
186    o->current_frame=best_num;
187
188
189    if (o->lvars[fire_delay1])
190      o->lvars[fire_delay1]--;
191
192    o->otype=weapon_types[v->current_weapon];  // switch to correct top part
193      }
194    }
195  }
196  return true_symbol;
197}
198
199
200static int player_fire_weapon(game_object *o, int type, game_object *target, int angle, signed char *fire_off)
201{
202
203  if (!o->total_objects()) return 0;
204  game_object *other=o->get_object(0);
205  int ox=other->x,oy=other->y;
206  if (other->direction<0) other->x+=4;
207
208  int firex=other->x+fire_off[o->current_frame*2];
209  int firey=other->y-fire_off[o->current_frame*2+1];
210
211
212
213  // fire try to move up to gun level
214
215  int32_t x2=o->x,y2=firey;
216//  current_level->foreground_intersect(other->x,other->y,x2,y2);      // find first location we can actuall "see"
217//  current_level->all_boundary_setback(o,other->x,other->y,x2,y2);       // to make we don't fire through walls
218  other->y=y2;
219
220  if (other->y==firey)             // now try to move out to end of gun if we were not blocked above
221  {
222    x2=firex;
223    current_level->foreground_intersect(other->x,other->y,x2,y2);      // find first location we can actuall "see"
224    current_level->all_boundary_setback(other,other->x,other->y,x2,y2);       // to make we don't fire through walls
225    o->x=x2;
226  }
227
228  void *list=NULL;
229  PtrRef r1(list);
230  push_onto_list(LPointer::Create(target),list);
231  push_onto_list(LNumber::Create(angle),list);
232  push_onto_list(LNumber::Create(y2),list);
233  push_onto_list(LNumber::Create(x2),list);
234  push_onto_list(LNumber::Create(type),list);
235  push_onto_list(LPointer::Create(o->get_object(0)),list);
236  eval_function((LSymbol *)l_fire_object,list);
237  o->lvars[top_just_fired]=1;
238  other->lvars[just_fired]=1;
239  other->x=ox;
240  other->y=oy;
241
242  return 1;
243}
244
245
246
247void *laser_ufun(void *args)
248{
249  game_object *o=current_object;
250  PtrRef r1(args);
251  void *signal=CAR(args);  args=CDR(args);
252  void *ret=NULL;
253
254  if (signal==l_FIRE)
255  {
256    if (!o->lvars[fire_delay1])                   // make sur we are not waiting of previous fire
257    {
258      int32_t value=lnumber_value(CAR(args)->Eval());
259      if (value)                                   // do we have ammo ?
260      {
261    o->lvars[fire_delay1]=3;
262    if (player_fire_weapon(o,SHOTGUN,NULL,o->lvars[point_angle],small_fire_off))
263          ret=LNumber::Create(-1);
264    else ret=LNumber::Create(0);
265      } else
266      {
267    o->lvars[fire_delay1]=5;                  // no ammo, set large fire delay for next shot
268    player_fire_weapon(o,SHOTGUN,NULL,o->lvars[point_angle],small_fire_off);
269    ret=LNumber::Create(0);
270      }
271    } else ret=LNumber::Create(0);                // can't fire yet, return 0 ammo subtract
272  }
273  return ret;
274}
275
276
277static int ammo_type(int otype)
278{
279  if (otype==S_GRENADE_TOP)
280    return GRENADE;
281  else if (otype==S_FIREBOMB_TOP)
282    return FIREBOMB;
283  else if (otype==S_DFRIS_TOP)
284    return DFRIS;
285  else return SHOTGUN;
286}
287
288
289void *top_ufun(void *args)                       // generic top character ai GRENADE && FIREBOMB
290{
291  game_object *o=current_object;
292  PtrRef r1(args);
293  void *signal=CAR(args);  args=CDR(args);
294  void *ret=NULL;
295
296  if (signal==l_FIRE)
297  {
298    if (!o->lvars[fire_delay1])                   // make sur we are not waiting of previous fire
299    {
300      int32_t value=lnumber_value(CAR(args)->Eval());
301      if (value)                                   // do we have ammo ?
302      {
303    o->lvars[fire_delay1]=6;
304    if (player_fire_weapon(o,ammo_type(o->otype),NULL,o->lvars[point_angle],
305                   o->otype==DFRIS ? large_fire_off : small_fire_off ))
306          ret=LNumber::Create(-1);
307    else ret=LNumber::Create(0);
308      } else ret=LNumber::Create(0);
309    } else ret=LNumber::Create(0);                // can't fire yet, return 0 ammo subtract
310  }
311  return ret;
312}
313
314static int climb_handler(game_object *, int xm, int ym, int but);
315
316void *plaser_ufun(void *args)
317{
318  game_object *o=current_object;
319  PtrRef r1(args);
320  void *signal=CAR(args);  args=CDR(args);
321  void *ret=NULL;
322
323  if (signal==l_FIRE)
324  {
325    if (!o->lvars[fire_delay1])                   // make sur we are not waiting of previous fire
326    {
327      int32_t value=lnumber_value(CAR(args)->Eval());
328      if (value)                                   // do we have ammo ?
329      {
330    o->lvars[fire_delay1]=2;
331    if (player_fire_weapon(o,PLASMA,NULL,o->lvars[point_angle],small_fire_off))
332          ret=LNumber::Create(-1);
333    else ret=LNumber::Create(0);
334      } else ret=LNumber::Create(0);
335    } else ret=LNumber::Create(0);                // can't fire yet, return 0 ammo subtract
336  }
337  return ret;
338}
339
340void *lsaber_ufun(void *args)
341{
342  game_object *o=current_object;
343  PtrRef r1(args);
344  void *signal=CAR(args);  args=CDR(args);
345  void *ret=NULL;
346
347  if (signal==l_FIRE)
348  {
349    if (!o->lvars[fire_delay1])                   // make sur we are not waiting of previous fire
350    {
351      int32_t value=lnumber_value(CAR(args)->Eval());
352      if (value)                                   // do we have ammo ?
353      {
354    o->lvars[fire_delay1]=1;
355    if (player_fire_weapon(o,LSABER,NULL,o->lvars[point_angle]+(current_level->tick_counter()&7)-8,
356                   small_fire_off))
357          ret=LNumber::Create(-1);
358    else ret=LNumber::Create(0);
359      } else ret=LNumber::Create(0);
360    } else ret=LNumber::Create(0);                // can't fire yet, return 0 ammo subtract
361  }
362  return ret;
363}
364
365
366
367void *player_rocket_ufun(void *args)
368{
369  game_object *o=current_object;
370  PtrRef r1(args);
371  void *signal=CAR(args);  args=CDR(args);
372  void *ret=NULL;
373  int xd,yd,cl=0xfffffff,d;
374  if (signal==l_FIRE)
375  {
376    if (!o->lvars[fire_delay1])                   // make sur we are not waiting of previous fire
377    {
378      int32_t value=lnumber_value(CAR(args)->Eval());
379      if (value)                                   // do we have ammo ?
380      {
381    o->lvars[fire_delay1]=6;
382    game_object *target=NULL,*p,*bot=o->total_objects() ? o->get_object(0) : 0;
383    if (bad_guy_array)
384    {
385      game_object *other=current_object->total_objects() ? current_object->get_object(0) : 0;
386      for (p=current_level->first_active_object(); p; p=p->next_active)
387      {
388        xd=abs(p->x-o->x);
389        yd=abs(p->y-o->y);
390        if (xd<160 && yd<130 && bad_guy_array[p->otype] && p!=other)
391        {
392          if (p->targetable() &&
393          !(p->otype==S_ROCKET && p->total_objects() && p->get_object(0)==bot))  // don't track onto own missles
394          {
395        d=xd*xd+yd*yd;
396        if (d<cl)
397        {
398          cl=d;
399          target=p;
400        }
401          }
402        }
403      }
404    }
405    if (player_fire_weapon(o,ROCKET,target,o->lvars[point_angle],large_fire_off))
406          ret=LNumber::Create(-1);
407    else ret=LNumber::Create(0);
408
409      } else ret=LNumber::Create(0);
410    } else ret=LNumber::Create(0);                // can't fire yet, return 0 ammo subtract
411  }
412  return ret;
413}
414
415static int player_move(game_object *o, int xm, int ym, int but)
416{
417  if (!o->lvars[in_climbing_area])
418  {
419    if (o->state==S_climbing)
420    {
421      o->set_gravity(1);
422      o->set_state(run_jump_fall);
423    }
424    o->next_picture();
425    return o->mover(xm,ym,but);
426  } else return climb_handler(o,xm,ym,but);
427
428}
429
430
431static void undo_special_power(game_object *o)
432{
433  switch (o->lvars[special_power])
434  {
435    case SNEAKY_POWER :
436    {
437      if (o->lvars[used_special_power]>0)
438        o->lvars[used_special_power]--;
439    } break;
440    case FAST_POWER :
441    {
442      o->lvars[used_special_power]=0;
443    } break;
444  }
445}
446
447static void do_special_power(game_object *o, int xm, int ym, int but, game_object *top)
448{
449  switch (o->lvars[special_power])
450  {
451    case FLY_POWER :
452    {
453      game_object *cloud=create(S_CLOUD,o->x+o->direction*-10,o->y+jrand()%5);
454      if (current_level)
455        current_level->add_object(cloud);
456      o->set_state(run_jump);
457      o->set_gravity(1);
458      o->set_yacel(0);
459      if (o->yvel()>0) o->set_yvel(o->yvel()/2);
460      if (ym<0)
461        o->set_yvel(o->yvel()-3);
462      else
463        o->set_yvel(o->yvel()-2);
464      the_game->play_sound(S_FLY_SND,32,o->x,o->y);
465    } break;
466    case FAST_POWER :
467    {
468      if ((current_level->tick_counter()%16)==0)
469      the_game->play_sound(S_SPEED_SND,100,o->x,o->y);
470
471      o->lvars[used_special_power]=1;
472      o->lvars[last1_x]=o->x;
473      o->lvars[last1_y]=o->y;
474      int32_t oyvel=o->yvel();
475      int in=o->lvars[in_climbing_area];
476
477      player_move(o,xm,ym,but);
478      if (ym<0 && !oyvel && o->yvel()<0)             // if they just jumped, make them go higher
479      o->set_yvel(o->yvel()+o->yvel()/3);
480      o->lvars[in_climbing_area]=in;
481
482      o->lvars[last2_x]=o->x;
483      o->lvars[last2_x]=o->y;
484    } break;
485    case SNEAKY_POWER :
486    {
487      if (o->lvars[used_special_power]<15)
488        o->lvars[used_special_power]++;
489    } break;
490  }
491}
492
493static int climb_off_handler(game_object *o)
494{
495  if (o->next_picture())
496    o->controller()->pan_y-=4;
497  else
498  {
499    o->y-=28;
500    o->controller()->pan_y+=28;
501    o->controller()->last_y-=28;
502    o->set_state(stopped);
503  }
504  return 0;
505}
506
507
508static int climb_on_handler(game_object *o)
509{
510  if (o->next_picture())
511    o->controller()->pan_y+=4;
512  else
513    o->set_state((character_state)S_climbing);
514  return 0;
515}
516
517static int climb_handler(game_object *o, int xm, int ym, int but)
518{
519  int yd=o->lvars[in_climbing_area];  // see how from the top we are
520  o->lvars[in_climbing_area]=0;          // set 0, ladders will set back to proper if still in area
521  if (o->state==S_climb_off)
522    climb_off_handler(o);
523  else if (o->state==S_climb_on)
524    climb_on_handler(o);
525  else
526  {
527    if (o->state==S_climbing)
528    {
529      if (ym>0)                       // going down
530      {
531
532    if (o->current_frame==0) o->current_frame=9;
533      o->current_frame--;
534
535/*    if (o->lvars[special_power]==FAST_POWER)
536    {
537      int32_t xv=0,yv=4;
538      o->try_move(o->x,o->y,xv,yv,1);
539      if (yv==4)
540        o->y+=3;
541      else
542      {
543        o->set_gravity(1);
544          o->set_state(run_jump_fall);
545      }
546    }
547    else */ o->y+=3;
548
549
550      } else if (ym<0)
551      {
552    if (yd<32)
553      o->set_state((character_state)S_climb_off);
554    else
555    {
556      if (!o->next_picture()) o->set_state((character_state)S_climbing);
557      o->y-=3;
558    }
559      }
560      if (xm)                     // trying to get off the ladder, check to see if that's ok
561      {
562    int32_t x2=0,y2=-20;
563    o->try_move(o->x,o->y,x2,y2,3);
564    if (y2==-20)
565    {
566      o->set_gravity(1);
567      if (ym>=0)
568        o->set_state(run_jump_fall);
569      else
570      { o->set_state(run_jump);
571        o->set_yvel(get_ability(o->otype,jump_yvel));
572      }
573    }
574      }
575    }  else if (ym>0 && yd<10)
576    {
577      o->y+=28;
578      o->controller()->pan_y-=28;
579      o->controller()->last_y+=28;
580      o->set_state((character_state)S_climb_on);
581    }
582    else if (o->yvel()>=0 && (ym>0 || (ym<0 && yd>8)))
583    {
584      o->set_state((character_state)S_climbing);
585      o->set_gravity(0);
586      o->set_xvel(0);
587      o->set_yvel(0);
588      o->set_xacel(0);
589      o->set_yacel(0);
590      return 0;
591    } else
592    {
593      o->next_picture();
594      return o->mover(xm,ym,but);
595    }
596  }
597  return 0;
598}
599
600
601void *cop_mover(int xm, int ym, int but)
602{
603
604  int ret=0;
605  game_object *o=current_object,*top;
606  if (o->controller() && o->controller()->freeze_time)
607  {
608    o->controller()->freeze_time--;
609    if (but || o->controller()->key_down(JK_SPACE) || o->controller()->key_down(JK_ENTER))
610      o->controller()->freeze_time=0;
611  }
612  else
613  {
614    if (!o->total_objects())                  // if no top create one
615    {
616      top=create(S_MGUN_TOP,o->x,o->y,0,0);
617      current_level->add_object_after(top,o);
618      o->add_object(top);
619      top->add_object(o);
620    } else top=o->get_object(0);
621
622    if (o->yvel()>10)
623    {
624      o->set_yacel(0);
625      o->set_yvel(o->yvel()-1);            // terminal velocity
626    }
627
628    if (o->aistate()==0)  // just started, wait for button
629    {
630      o->set_aistate(1);
631    } else if (o->aistate()==1)         // normal play
632    {
633      if (o->hp()==0)
634      {
635    o->set_aistate(2);                // go to deing state
636    o->set_state(dead);
637      }
638      else
639      {
640    if (o->hp()<40 && (current_level->tick_counter()%16)==0) // if low on health play heart beat
641      the_game->play_sound(S_LOW_HEALTH_SND,127,o->x,o->y);
642    else if (o->hp()<15 && (current_level->tick_counter()%8)==0) // if low on health play heart beat
643      the_game->play_sound(S_LOW_HEALTH_SND,127,o->x,o->y);
644    else if (o->hp()<7 && (current_level->tick_counter()%4)==0) // if low on health play heart beat
645      the_game->play_sound(S_LOW_HEALTH_SND,127,o->x,o->y);
646
647    if (but&1)
648        do_special_power(o,xm,ym,but,top);
649    else
650    undo_special_power(o);
651    ret=player_move(o,xm,ym,but);
652    top->x=o->x;
653    top->y=o->y+29-top->picture()->height();
654
655    if ((but&2) && !o->lvars[is_teleporting] && o->state!=S_climbing && o->state!=S_climb_off)
656    {
657      void *args=NULL;
658      PtrRef r1(args);
659      view *v=o->controller();
660
661      push_onto_list(LNumber::Create(v->weapon_total(v->current_weapon)),args);
662      push_onto_list(l_FIRE,args);
663
664      current_object=top;
665      void *ret=eval_function((LSymbol *)figures[top->otype]->get_fun(OFUN_USER_FUN),args);
666      current_object=o;
667      v->add_ammo(v->current_weapon,lnumber_value(ret));
668    }
669      }
670    } else if (o->aistate()==3)
671    {
672      if (!o->controller() || o->controller()->key_down(JK_SPACE))
673      {
674        // call the user function to reset the player
675    eval_function((LSymbol *)l_restart_player,NULL);
676    o->controller()->reset_player();
677    o->set_aistate(0);
678      } else if (o->controller() && o->controller()->local_player())
679        the_game->show_help(symbol_str("space_cont"));
680
681    } else o->set_aistate(o->aistate()+1);
682  }
683
684  return LNumber::Create(ret);
685}
686
687
688
689void *ladder_ai()
690{
691  view *f=player_list;
692  game_object *o=current_object;
693  if (o->total_objects())
694  {
695    game_object *other=o->get_object(0);
696    for (; f; f=f->next)
697    {
698      int mex=f->focus->x;
699      int mey=f->focus->y;
700
701      if (o->x<=mex && o->y<=mey && other->x>=mex && other->y>=mey)
702      {
703    if (f->focus->state==S_climbing)
704      f->focus->x=(o->x+other->x)/2;
705        f->focus->lvars[in_climbing_area]=mey-o->y;
706      }
707    }
708  }
709  return true_symbol;
710}
711
712
713
714void *player_draw(int just_fired_var, int num)
715{
716  game_object *o=current_object;
717  if (num==0)
718  {
719    if (o->lvars[just_fired_var])
720    {
721      o->draw_tint(S_bright_tint);
722      o->lvars[just_fired_var]=0;
723    } else
724      o->drawer();
725  }
726  else
727  {
728    if (o->lvars[just_fired_var])
729    {
730      o->draw_double_tint(lnumber_value(((LArray *)((LSymbol *)l_player_tints)->GetValue())->Get(num)), S_bright_tint);
731      o->lvars[just_fired_var]=0;
732    } else
733      o->draw_tint(lnumber_value(((LArray *)((LSymbol *)l_player_tints)->GetValue())->Get(num)));
734  }
735  return NULL;
736}
737
738
739void *top_draw()
740{
741  game_object *o=current_object;
742  if (o->total_objects())
743  {
744    game_object *bot=o->get_object(0);
745    if (bot->state==stopped  || bot->state==running ||
746    bot->state==run_jump || bot->state==run_jump_fall ||
747    bot->state==end_run_jump)
748    {
749      int oldy=o->y;
750      o->x=bot->x;
751      if (bot->direction<0)
752        o->x+=4;
753      o->y=bot->y+29-bot->picture()->height();
754
755      void *ret=NULL;
756      PtrRef r1(ret);
757
758      push_onto_list(LNumber::Create(bot->get_tint()),ret);
759
760      if (bot->lvars[special_power]==SNEAKY_POWER)
761      {
762    if (bot->lvars[used_special_power]==0)
763      player_draw(top_just_fired,bot->get_tint());
764    else if (bot->lvars[used_special_power]<15)
765      o->draw_trans(bot->lvars[used_special_power],16);
766    else
767      o->draw_predator();
768      } else
769        eval_function((LSymbol *)l_player_draw,ret);
770
771      o->y=oldy;
772      if (bot->direction<0)
773        o->x-=4;
774    }
775  }
776  return NULL;
777}
778
779
780
781void *bottom_draw()
782{
783  game_object *o=current_object;
784
785  if (o->lvars[r_ramp] || o->lvars[g_ramp] || o->lvars[b_ramp])
786  {
787    int r=o->lvars[r_ramp];
788    if (r>7) r-=7;
789    else r=0;
790    o->lvars[r_ramp]=r;
791
792    int g=o->lvars[g_ramp];
793    if (g>7) g-=7;
794    else g=0;
795    o->lvars[g_ramp]=g;
796
797    int b=o->lvars[b_ramp];
798    if (b>7) b-=7;
799    else b=0;
800    o->lvars[b_ramp]=b;
801
802    palette *p=pal->copy();
803    uint8_t *addr=(uint8_t *)p->addr();
804    int ra,ga,ba;
805
806    for (int i=0; i<256; i++)
807    {
808      ra=(int)*addr+r; if (ra>255) ra=255; else if (ra<0) r=0; *addr=(uint8_t)ra; addr++;
809      ga=(int)*addr+g; if (ga>255) ga=255; else if (ga<0) g=0; *addr=(uint8_t)ga; addr++;
810      ba=(int)*addr+b; if (ba>255) ba=255; else if (ba<0) b=0; *addr=(uint8_t)ba; addr++;
811    }
812    p->load();
813    delete p;
814  }
815
816  if (o->aistate()>0)
817  {
818    switch (o->lvars[special_power])
819    {
820      case NO_POWER :
821      { player_draw(just_fired,o->get_tint()); } break;
822
823      case HEALTH_POWER :
824      {
825    player_draw(just_fired,o->get_tint());
826    if (o->controller() && o->controller()->local_player())
827      cache.img(S_health_image)->put_image(screen,o->controller()->cx2-20,
828                        o->controller()->cy1+5,1);
829      } break;
830      case FAST_POWER :
831      {
832    eval_function((LSymbol *)l_draw_fast,NULL);
833    int old_state=o->state;
834    switch (o->state)
835    {
836      case stopped : o->state=(character_state)S_fast_stopped; break;
837      case running : o->state=(character_state)S_fast_running; break;
838      case start_run_jump : o->state=(character_state)S_fast_start_run_jump; break;
839      case run_jump : o->state=(character_state)S_fast_run_jump; break;
840      case run_jump_fall : o->state=(character_state)S_fast_run_jump_fall; break;
841      case end_run_jump : o->state=(character_state)S_fast_end_run_jump; break;
842      default: break;
843    }
844
845    player_draw(just_fired,o->get_tint());
846    o->state=(character_state)old_state;
847    if (o->controller() && o->controller()->local_player())
848      cache.img(S_fast_image)->put_image(screen,o->controller()->cx2-20,
849                        o->controller()->cy1+5,1);
850      } break;
851      case FLY_POWER :
852      {
853    int old_state=o->state;
854    switch (o->state)
855    {
856      case stopped : o->state=(character_state)S_fly_stopped; break;
857      case running : o->state=(character_state)S_fly_running; break;
858      case start_run_jump : o->state=(character_state)S_fly_start_run_jump; break;
859      case run_jump : o->state=(character_state)S_fly_run_jump; break;
860      case run_jump_fall : o->state=(character_state)S_fly_run_jump_fall; break;
861      case end_run_jump : o->state=(character_state)S_fly_end_run_jump; break;
862      default: break;
863    }
864
865    player_draw(just_fired,o->get_tint());
866    o->state=(character_state)old_state;
867
868    if (o->controller() && o->controller()->local_player())
869      cache.img(S_fly_image)->put_image(screen,o->controller()->cx2-20,
870                        o->controller()->cy1+5,1);
871      } break;
872      case SNEAKY_POWER :
873      {
874    if (o->lvars[used_special_power]==0)
875      player_draw(just_fired,o->get_tint());
876    else if (o->lvars[used_special_power]<15)
877      o->draw_trans(o->lvars[used_special_power],16);
878    else
879      o->draw_predator();
880
881    if (o->controller() && o->controller()->local_player())
882      cache.img(S_sneaky_image)->put_image(screen,o->controller()->cx2-20,
883                        o->controller()->cy1+5,1);
884      } break;
885    }
886  }
887  return NULL;
888}
889
890
891
892void *sgun_ai()
893{
894  game_object *o=current_object;
895
896  if (o->lvars[sgb_lifetime]==0)
897    return NULL;
898  o->lvars[sgb_lifetime]--;
899
900  o->lvars[sgb_lastx]=o->x;
901  o->lvars[sgb_lasty]=o->y;
902  o->lvars[sgb_speed]=o->lvars[sgb_speed]*6/5;
903
904  int32_t ang=o->lvars[sgb_angle];
905  int32_t mag=o->lvars[sgb_speed];
906
907  int32_t xvel=(lisp_cos(ang))*(mag);
908  current_object->set_xvel(xvel>>16);
909  current_object->set_fxvel((xvel&0xffff)>>8);
910  int32_t yvel=-(lisp_sin(ang))*(mag);
911  current_object->set_yvel(yvel>>16);
912  current_object->set_fyvel((yvel&0xffff)>>8);
913
914
915  int whit=0;
916  game_object *who=o->bmove(whit, o->total_objects() ? o->get_object(0) : 0);
917
918  if (whit || (who && figures[who->otype]->get_cflag(CFLAG_UNACTIVE_SHIELD) && who->total_objects() &&
919           who->get_object(0)->aistate()==0))
920  {
921    o->lvars[sgb_lifetime]=0;
922    game_object *n=create(S_EXPLODE5,o->x+jrand()%4,o->y+jrand()%4);
923    current_level->add_object(n);
924  } else if (who && figures[who->otype]->get_cflag(CFLAG_HURTABLE))
925  {
926    o->lvars[sgb_lifetime]=0;
927    game_object *n=create(S_EXPLODE3,o->x+jrand()%4,o->y+jrand()%4);
928    current_level->add_object(n);
929     who->do_damage(5,o,o->x,o->y,(lisp_cos(ang)*10)>>16,(lisp_sin(ang)*10)>>16);
930  }
931  return true_symbol;
932}
933
934
935
936void *mover_ai()
937{
938  game_object *o=current_object;
939  if (o->total_objects()==2)
940  {
941    if (o->aistate()<2)
942    {
943      game_object *obj=o->get_object(1);
944      o->remove_object(obj);
945      game_object *d=o->get_object(0);
946      d->add_object(obj);
947      d->set_aistate(d->aitype());
948    } else
949    {
950      o->set_aistate(o->aistate()-1);
951      game_object *d=o->get_object(0);
952      game_object *obj=o->get_object(1);
953
954      obj->x=d->x-(d->x-o->x)*o->aistate()/o->aitype();
955      obj->y=d->y-(d->y-o->y)*o->aistate()/o->aitype();
956    }
957  }
958  return true_symbol;
959}
960
961
962void *respawn_ai()
963{
964 game_object *o=current_object;
965 int x=o->total_objects();
966 if (x)
967 {
968   game_object *last=o->get_object(x-1);
969   if (last->x==o->x && last->y==o->y)
970   {
971     if (last->fade_count())
972       last->set_fade_count(last->fade_count()-1);
973     o->set_aistate_time(0);
974   } else if (o->aistate_time()>o->xvel())
975   {
976     int type=o->get_object(jrandom(x))->otype;
977     game_object *n=create(type,o->x,o->y);
978     current_level->add_object(n);
979     o->add_object(n);
980     n->set_fade_count(15);
981     o->set_aistate_time(0);
982   }
983 }
984 return true_symbol;
985}
986
987static int compare_players(const void *a, const void *b)
988{
989  if  ( ((view **)a)[0]->kills > ((view **)b)[0]->kills)
990    return -1;
991  else if  ( ((view **)a)[0]->kills < ((view **)b)[0]->kills)
992    return 1;
993  else if (((view **)a)[0]->player_number > ((view **)b)[0]->player_number)
994    return -1;
995  else if (((view **)a)[0]->player_number < ((view **)b)[0]->player_number)
996    return 1;
997  else return 0;
998}
999
1000void *score_draw()
1001{
1002  view *sorted_players[16],*local=NULL;
1003  int tp=0;
1004  view *f=player_list;
1005  for (; f; f=f->next)
1006  {
1007    sorted_players[tp]=f;
1008    tp++;
1009    if (f->local_player()) local=f;
1010  }
1011
1012  JCFont *fnt=wm->font();
1013  if (local)
1014  {
1015    qsort(sorted_players,tp,sizeof(view *),compare_players);
1016
1017    int x=local->cx1;
1018    int y=local->cy1;
1019    char msg[100];
1020
1021    int i;
1022    for (i=0; i<tp; i++)
1023    {
1024      int color=lnumber_value(((LArray *)((LSymbol *)l_player_text_color)->GetValue())->Get(sorted_players[i]->get_tint()));
1025      sprintf(msg,"%3ld %s",(long)sorted_players[i]->kills,sorted_players[i]->name);
1026      if (sorted_players[i]==local)
1027        strcat(msg," <<");
1028
1029      fnt->put_string(screen,x,y,msg,color);
1030      y+=fnt->height();
1031    }
1032  }
1033  return NULL;
1034}
1035
1036
1037extern void fade_in(image *im, int steps);
1038extern void fade_out(int steps);
1039
1040void *show_kills()
1041{
1042  fade_out(8);
1043  wm->set_mouse_position(0,0);
1044  screen->clear();
1045  image *im=cache.img(cache.reg("art/frame.spe","end_level_screen",SPEC_IMAGE,1));
1046  im->put_image(screen,0,0);
1047  int x1=im->width()+1,y1=0,y2=screen->height();
1048  JCFont *fnt=wm->font();
1049
1050  view *v=player_list; int tp=0,i;
1051  for (v=player_list; v; v=v->next) tp++;
1052
1053  int y=(y1+y2)/2-(tp+2)*fnt->height()/2,x=x1+10;
1054  char const *header_str = symbol_str("score_header");
1055  fnt->put_string(screen,x,y,header_str,wm->bright_color());
1056  y+=fnt->height();
1057
1058  screen->widget_bar(x,y+2,x+strlen(header_str)*fnt->width(),y+fnt->height()-3,
1059             wm->bright_color(),wm->medium_color(),wm->dark_color());
1060  y+=fnt->height();
1061  v=player_list;
1062  for (i=0; i<tp; i++)
1063  {
1064    enum { NAME_LEN=18 } ;
1065    int color=lnumber_value(((LArray *)((LSymbol *)l_player_text_color)->GetValue())->Get(v->get_tint()));
1066    char max_name[NAME_LEN];
1067    strncpy(max_name,v->name,NAME_LEN-1);
1068    max_name[NAME_LEN-1]=0;
1069    char msg[100];
1070
1071
1072    sprintf(msg,"%-17s %3ld  %3ld",max_name,(long)v->kills,(long)(v->tkills+v->kills));
1073    fnt->put_string(screen,x,y,msg,color);
1074
1075    y+=fnt->height();
1076    v=v->next;
1077  }
1078
1079  wm->flush_screen();
1080  milli_wait(4000);   // wait 4 seconds
1081
1082  return NULL;
1083}
1084
1085
Note: See TracBrowser for help on using the repository browser.