source: abuse/branches/lol/src/cop.cpp @ 732

Last change on this file since 732 was 732, checked in by Sam Hocevar, 8 years ago

build: SDL2 compilation fixes.

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