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

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

style: remove trailing spaces, fix copyright statements.

File size: 75.2 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#if (defined(__MACH__) || !defined(__APPLE__))
14#include <sys/stat.h>
15#endif
16
17#include <string.h>
18#include <limits.h>
19#include <time.h>
20
21#include "light.h"
22#include "level.h"
23#include "game.h"
24#include "intsect.h"
25#include "lisp.h"
26#include "dprint.h"
27#include "particle.h"
28#include "objects.h"
29#include "jrand.h"
30#include "macs.h"
31#include "clisp.h"
32#include "status.h"
33#include "dev.h"
34#include "demo.h"
35#include "pcxread.h"
36#include "profile.h"
37#include "sbar.h"
38#include "cop.h"
39#include "nfserver.h"
40#include "lisp_gc.h"
41
42level *current_level;
43
44game_object *level::attacker(game_object *who)
45{
46  int32_t d=0x7fffffff;
47  game_object *c=NULL;
48  view *f=the_game->first_view;
49  for (; f; f=f->next)
50  {
51    if (f->focus)
52    {
53      int32_t tmp_d=abs(f->focus->x-who->x)+abs(f->focus->y-who->y);
54      if (tmp_d<d)
55      {
56    d=tmp_d;
57    c=f->focus;
58      }
59    }
60  }
61  CONDITION(c,"no attacker found");
62  return c;
63}
64
65
66
67int level::is_attacker(game_object *who)
68{
69  return who->controller()!=NULL;
70}
71
72
73game_object *level::main_character()
74{
75  return the_game->first_view->focus;
76}
77
78void level::load_fail()
79{
80  if (map_fg)    free(map_fg);   map_fg=NULL;
81  if (map_bg)    free(map_bg);   map_bg=NULL;
82  if (Name)      free(Name);     Name=NULL;
83
84  first_active=NULL;
85  view *f=player_list;
86  for (; f; f=f->next)
87    if (f->focus)
88      current_level->remove_object(f->focus);
89
90  while (first)
91  {
92    first_active=first;
93    first=first->next;
94    if (dev_cont)
95      dev_cont->notify_deleted_object(first_active);
96    delete first_active;
97  }
98
99  while (area_list)
100  {
101    area_controller *l=area_list;
102    area_list=area_list->next;
103    delete l;
104  }
105
106  last=NULL;
107  delete_panims();
108  delete_all_lights();
109
110}
111
112level::~level()
113{
114  load_fail();
115  if (attack_list) free(attack_list);
116  if (target_list) free(target_list);
117  if (block_list) free(block_list);
118  if (all_block_list) free(all_block_list);
119  if (first_name) free(first_name);
120}
121
122void level::restart()
123{
124  view *f;
125  game_object *found=NULL,*o;
126  f=the_game->first_view;
127  for (o=first; f && o; o=o->next)
128  {
129    while (f && !f->focus) f=f->next;
130    if (f)
131    {
132      if (!strcmp(object_names[o->otype],"START"))
133      {
134    if (!found) found=o;
135    f->focus->x=o->x;
136    f->focus->y=o->y;
137    f->focus->set_hp(get_ability(f->focus->otype,start_hp));
138    f->focus->set_state(stopped);
139    f=f->next;
140      }
141    }
142  }
143  while (f)
144  {
145    if (f->focus)
146    {
147      f->focus->x=found->x;
148      f->focus->y=found->y;
149      f->focus->set_hp(get_ability(f->focus->otype,start_hp));
150      f->focus->set_state(stopped);
151    }
152    f=f->next;
153  }
154}
155
156
157void level::next_focus()
158{
159/*  int i;
160  for (i=0; i<total_objs; i++)
161    if (obj[i]==the_game->first_view->focus)
162    {
163      int tries=total_objs;
164      do
165      {
166    i++;
167    if (i==total_objs)
168      i=0;
169    the_game->first_view->focus=obj[i];
170      }  while ((!the_game->first_view->focus->is_playable() ||
171         the_game->first_view->focus->hp<=0) && tries--);
172      return ;
173    }            */
174}
175
176void level::unactivate_all()
177{
178  first_active=NULL;
179  game_object *o=first;
180  attack_total=0;  // reset the attack list
181  target_total=0;
182  block_total=0;
183  all_block_total=0;
184
185  for (; o; o=o->next)
186    o->active=0;
187}
188
189
190void level::pull_actives(game_object *o, game_object *&last_active, int &t)
191{
192  int i=o->total_objects();
193  for (; i; i--)        // pull any linked object into active list
194  {
195    game_object *other=o->get_object(i-1);
196    if (!other->active)
197    {
198      other->active=1;
199      if (other->can_block())              // if object can block other player, keep a list for fast testing
200      {
201    add_block(other);
202    add_all_block(other);
203      } else if (other->hurtable())
204        add_all_block(other);
205
206      t++;
207      last_active->next_active=other;
208      last_active=other;
209      pull_actives(o,last_active,t);
210    }
211  }
212}
213
214int level::add_actives(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
215{
216  int t=0;
217  game_object *last_active=NULL;
218  if (first_active)
219    for (last_active=first_active; last_active->next_active; last_active=last_active->next_active);
220
221  game_object *o=first;
222  for (; o; o=o->next)
223  {
224    if (!o->active)
225    {
226      int32_t xr=figures[o->otype]->rangex,
227           yr=figures[o->otype]->rangey;
228
229      if (o->x+xr>=x1 && o->x-xr<=x2 && o->y+yr>=y1 && o->y-yr<=y2)
230      {
231
232    if (o->can_block())              // if object can block other player, keep a list for fast testing
233    {
234      add_block(o);
235      add_all_block(o);
236    } else if (o->hurtable())
237          add_all_block(o);
238
239
240    o->active=1;
241    t++;
242    if (!first_active)
243      first_active=o;
244    else
245          last_active->next_active=o;
246    last_active=o;
247
248    pull_actives(o,last_active,t);
249      }
250    }
251  }
252  if (last_active)
253    last_active->next_active=NULL;
254  return t;
255}
256
257
258int level::add_drawables(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
259{
260  int t=0,ft=0;
261  game_object *last_active=NULL;
262  if (first_active)
263  {
264    for (last_active=first_active; last_active->next_active; last_active=last_active->next_active);
265  } else ft=1;
266
267  game_object *o=first;
268  for (; o; o=o->next)
269  {
270    if (ft || !o->active)
271    {
272      int32_t xr=figures[o->otype]->draw_rangex,
273      yr=figures[o->otype]->draw_rangey;
274
275      if (o->x+xr>=x1 && o->x-xr<=x2 && o->y+yr>=y1 && o->y-yr<=y2)
276      {
277    t++;
278    if (!first_active)
279    first_active=o;
280    else
281    last_active->next_active=o;
282    last_active=o;
283    o->active=1;
284      } else if (ft) o->active=0;  // if this is the first pass, then mark objects not in this ranges as not active
285    }
286  }
287  if (last_active)
288    last_active->next_active=NULL;
289  return t;
290}
291
292
293view *level::make_view_list(int nplayers)
294{
295  int startable;
296  CONDITION(nplayers>0,"make_view_list with <=0 players!\n");
297  view *f=NULL;
298  int j,use_type=current_start_type;
299  figures[use_type]->cache_in();
300  game_object *o,*last_start=NULL;
301  int num=0;
302
303  for (j=0,o=first; o && j<nplayers; o=o->next)
304  {
305    if (!strcmp(object_names[o->otype],"START"))
306    {
307      f=new view(create(use_type,o->x,o->y),f,num); num++;
308      f->focus->set_controller(f);
309      add_object_after(f->focus,o);
310      j++;
311      last_start=o;
312    }
313  }
314
315  // if we couldn't find enough starts then create the rest of the players at the original start
316  startable=j;  // if we haven't created anyone yet, it's because we can't
317
318  for (; j<nplayers; j++)
319  {
320    if (startable)
321    {
322      game_object *o=create(use_type,f->focus->x,f->focus->y);
323      f=new view(o,f,num); num++;
324      f->focus->set_controller(f);
325      add_object_after(o,last_start);
326    }
327    else
328    {
329      f=new view(NULL,f,num);
330      num++;
331    }
332  }
333  return f;
334}
335
336void level::wall_push()
337{
338  int32_t sx1,sy1,sx2,sy2,xv,yv;
339  game_object *o=first_active;
340  for (; o; o=o->next_active)
341  {
342    if (o->pushable())
343    {
344      o->picture_space(sx1,sy1,sx2,sy2);
345      xv=sx1-o->x;
346      yv=0;
347      o->try_move(o->x,o->y-1,xv,yv,1);         // check for wall pushes on the left using feet
348      if (xv!=sx1-o->x)                         // is the character in the wall?
349      {
350    xv=-xv;
351    o->try_move(o->x,o->y-1,xv,yv,1);       // see how far to the right we can push the character
352    o->x+=xv;
353      } else
354      {
355    xv=sx2-o->x;
356    o->try_move(o->x,o->y-1,xv,yv,1);      // now check the right of the character for a wall
357    if (xv!=sx2-o->x)
358    {
359      xv=-xv;
360      o->try_move(o->x,o->y-1,xv,yv,1);
361      o->x+=xv;
362    }
363      }
364    }
365  }
366}
367
368
369void level::try_pushback(game_object *subject,game_object *target)
370{
371  if (subject->pushable() && target->pushable() &&
372      subject->state!=dead && target->state!=dead &&
373      subject->state!=dieing && target->state!=dieing)
374  {
375    int b1=subject->push_range(),b2=target->push_range();
376    if (abs(subject->x-target->x)<b1+b2)
377    {
378      int32_t tmove=b1+b2-abs(subject->x-target->x),xv,yv=0,xv2;
379      if (subject->x>target->x)
380        xv=tmove/2;
381      else xv=-tmove/2;
382      xv2=-xv;
383
384      subject->try_move(subject->x,subject->y,xv,yv,3);
385      subject->x+=xv;
386
387      yv=0;
388      target->try_move(target->x,target->y,xv2,yv,3);
389      target->x+=xv2;
390    }
391  }
392}
393
394/*
395void level::check_collisions()
396{
397  game_object *target,*reciever=NULL;
398  int32_t sx1,sy1,sx2,sy2,tx1,ty1,tx2,ty2,hitx,hity,
399      s_centerx,t_centerx;
400
401  for (game_object *subject=first_active; subject; subject=subject->next_active)
402  {
403    subject->picture_space(sx1,sy1,sx2,sy2);
404    s_centerx=subject->x_center();
405
406    int hit=0;
407    reciever=NULL;
408    for (target=first_active; target; target=target->next_active)
409    {
410      if (target!=subject)
411      {
412    target->picture_space(tx1,ty1,tx2,ty2);
413
414        if (!(sx2<tx1 || sx1>tx2 || sy1>ty2 || sy2<ty1))  // are they semi/overlapping?
415        {
416      try_pushback(subject,target);
417      if (subject->can_hurt(target))    // see if we can hurt him before calculating
418      {
419        t_centerx=target->x_center();
420        point_list *s_hit,*t_damage;
421
422        s_hit=subject->current_figure()->hit;
423        t_damage=target->current_figure()->damage;
424
425        unsigned char *s_dat=s_hit->data,
426        *t_dat;
427        int i,j;
428        for (i=(int)s_hit->tot-1; i>0 && !hit; i--)
429        {
430          for (t_dat=t_damage->data,j=(int)t_damage->tot-1; j>0 && !hit; j--)
431          {
432        int32_t x1,y1,x2,y2,          // define the two line segments to check
433        xp1,yp1,xp2,yp2;
434
435        xp1=target->x+target->tx(*t_dat);  t_dat++;
436        yp1=target->y+target->ty(*t_dat);  t_dat++;
437        xp2=target->x+target->tx(*t_dat);
438        yp2=target->y+target->ty(t_dat[1]);
439
440        x1=subject->x+subject->tx(s_dat[0]);
441        y1=subject->y+subject->ty(s_dat[1]);
442        x2=subject->x+subject->tx(s_dat[2]);
443        y2=subject->y+subject->ty(s_dat[3]);
444
445
446        // ok, now we know which line segemnts to check for intersection
447        // now check to see if (x1,y1-x2,y2) intercest with (xp1,yp1-xp2,yp2)
448        int _x2=x2,_y2=y2;
449        setback_intersect(x1, y1, x2, y2, xp1, yp1, xp2, yp2,0);
450
451
452        if (x2!=_x2 || _y2!=y2)
453        {
454          reciever=target;
455          hitx=((x1+x2)/2+(xp1+xp2)/2)/2;
456          hity=((y1+y1)/2+(yp1+yp2)/2)/2;
457        }
458          }
459          s_dat+=2;
460        }
461      }
462    }
463      }
464    }
465    if (reciever)
466    {
467      reciever->do_damage((int)subject->current_figure()->hit_damage,subject,hitx,hity,0,0);
468      subject->note_attack(reciever);
469      hit=1;
470    }
471  }
472}
473*/
474
475game_object *level::boundary_setback(game_object *subject, int32_t x1, int32_t y1, int32_t &x2, int32_t &y2)
476{
477  game_object *l=NULL;
478  int32_t tx1,ty1,tx2,ty2,t_centerx;
479  game_object *target=first_active;
480  game_object **blist=block_list;
481  int t=block_total;
482  for (; t; t--,blist++)
483  {
484    target=*blist;
485    if (target!=subject && (target->total_objects()==0 || target->get_object(0)!=subject))
486    {
487      target->picture_space(tx1,ty1,tx2,ty2);
488      if (!((x2<tx1 && x1<tx1) || (x1>tx2 && x2>tx2) ||
489        (y1>ty2 && y2>ty2) || (y1<ty1 && y2<ty1)))  // are they semi/overlapping?
490      {
491    t_centerx=target->x_center();
492    boundary *t_damage;
493    if (target->direction>0)
494    t_damage=target->current_figure()->f_damage;
495    else
496    t_damage=target->current_figure()->b_damage;
497    unsigned char *t_dat=t_damage->data,*ins=t_damage->inside;
498    int iter=t_damage->tot-1;
499    while(iter-->0)
500    {
501      int32_t xp1=target->x+target->tx(*t_dat);  t_dat++;
502      int32_t yp1=target->y+target->ty(*t_dat);  t_dat++;
503      int32_t xp2=target->x+target->tx(*t_dat);
504      int32_t yp2=target->y+target->ty(t_dat[1]);
505
506      // now check to see if (x1,y1-x2,y2) intercest with (xp1,yp1-xp2,yp2)
507      if (*ins)
508      {
509        if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,1))
510        l=target;
511      }
512      else
513      {
514        if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,-1))
515        l=target;
516      }
517      ins++;
518
519    }
520      }
521    }
522  }
523  return l;       // return the last person we intersected
524}
525
526
527game_object *level::all_boundary_setback(game_object *subject, int32_t x1, int32_t y1, int32_t &x2, int32_t &y2)
528{
529  game_object *l=NULL;
530  int32_t tx1,ty1,tx2,ty2,t_centerx;
531  game_object *target=first_active;
532  game_object **blist=all_block_list;
533  int t=all_block_total;
534  for (; t; t--,blist++)
535  {
536    target=*blist;
537    if (target!=subject && (target->total_objects()==0 || target->get_object(0)!=subject))
538    {
539      target->picture_space(tx1,ty1,tx2,ty2);
540      if (!((x2<tx1 && x1<tx1) || (x1>tx2 && x2>tx2) ||
541        (y1>ty2 && y2>ty2) || (y1<ty1 && y2<ty1)))  // are they semi/overlapping?
542      {
543    t_centerx=target->x_center();
544    boundary *t_damage;
545    if (target->direction>0)
546    t_damage=target->current_figure()->f_damage;
547    else
548    t_damage=target->current_figure()->b_damage;
549    unsigned char *t_dat=t_damage->data,*ins=t_damage->inside;
550    int iter=t_damage->tot-1;
551    while(iter-->0)
552    {
553      int32_t xp1=target->x+target->tx(*t_dat);  t_dat++;
554      int32_t yp1=target->y+target->ty(*t_dat);  t_dat++;
555      int32_t xp2=target->x+target->tx(*t_dat);
556      int32_t yp2=target->y+target->ty(t_dat[1]);
557
558      // now check to see if (x1,y1-x2,y2) intercest with (xp1,yp1-xp2,yp2)
559      if (*ins)
560      {
561        if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,1))
562        l=target;
563      }
564      else
565      {
566        if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,-1))
567        l=target;
568      }
569      ins++;
570    }
571      }
572    }
573  }
574  return l;       // return the last person we intersected
575}
576
577
578//bFILE *rcheck=NULL,*rcheck_lp=NULL;
579
580void level::interpolate_draw_objects(view *v)
581{
582  int32_t old_x,old_y;
583  current_view=v;
584
585  game_object *o=first_active;
586  for (; o; o=o->next_active)
587  {
588    old_x=o->x;
589    old_y=o->y;
590    o->x=(o->last_x+o->x)/2;
591    o->y=(o->last_y+o->y)/2;
592    o->last_x=old_x;
593    o->last_y=old_y;
594  }
595
596  for (o=first_active; o; o=o->next_active)
597    o->draw();
598
599  for (o=first_active; o; o=o->next_active)
600  {
601    o->x=o->last_x;
602    o->y=o->last_y;
603  }
604}
605
606bFILE *rcheck=NULL,*rcheck_lp=NULL;
607
608extern int sshot_fcount,screen_shot_on;
609
610int level::tick()
611{
612  game_object *o,*l=NULL,  // l is last, used for delete
613              *cur;        // cur is current object, NULL if object deletes it's self
614  int ret=1;
615
616  if (profiling())
617    profile_reset();
618
619/*  // test to see if demo is in sync
620  if (current_demo_mode()==DEMO_PLAY)
621  {
622    if (!rcheck) rcheck=open_file("rcheck","rb");
623    int32_t x=rcheck->read_uint32();
624    if (x!=rand_on)
625      dprintf("off!\n");
626  } else if (current_demo_mode()==DEMO_RECORD)
627  {
628    if (!rcheck)
629    {
630      rcheck=open_file("rcheck","wb");
631      rcheck_lp=open_file("rcheck.lp","wb");
632    }
633    rcheck->write_uint32(rand_on);
634  } else
635  {
636    if (rcheck)
637    {
638      delete rcheck;
639      rcheck=NULL;
640    }
641    if (rcheck_lp)
642    {
643      delete rcheck_lp;
644      rcheck_lp=NULL;
645    }
646  }*/
647
648  for (o=first_active; o; )
649  {
650    o->last_x=o->x;
651    o->last_y=o->y;
652    cur=o;
653    view *c=o->controller();
654    if (!(dev&SUSPEND_MODE) || c)
655    {
656      o->set_flags(o->flags()&(0xff-FLAG_JUST_HIT-FLAG_JUST_BLOCKED));
657
658      if (c)
659      {
660    area_controller *a,*smallest=NULL;
661    int32_t smallest_size=0xffffffff;
662    for (a=area_list; a; a=a->next)
663      if (o->x>=a->x && o->y>=a->y && o->x<=a->x+a->w && o->y<=a->y+a->h)
664      {
665        int32_t size=a->w*a->h;
666        if (size<smallest_size)
667        {
668          smallest=a;
669          smallest_size=size;
670        }
671      }
672
673    if (c->local_player())
674    {
675      if (!shutdown_lighting)       // should we initiate a lighting shutdown?
676      {
677        if (massive_frame_panic>30)
678        {
679          shutdown_lighting=100;
680          shutdown_lighting_value=c->ambient;
681        }
682      } else if (massive_frame_panic)  // do we need brighten towards 63?
683      {
684        if (shutdown_lighting_value<63)
685          shutdown_lighting_value++;
686      } else if (shutdown_lighting>1)        // delay for some time before turning back on
687        shutdown_lighting--;
688      else if (shutdown_lighting_value!=c->ambient) // do we need to lower light toward real ambient?
689      {
690        if (abs(shutdown_lighting_value-c->ambient)<4)
691          shutdown_lighting_value=c->ambient;
692        else
693          if (shutdown_lighting_value<c->ambient)
694              shutdown_lighting_value+=4;
695        else if (shutdown_lighting_value>c->ambient)
696          shutdown_lighting_value-=4;
697      } else shutdown_lighting=0;                    // back to normal
698    }
699
700    if (smallest)
701      c->configure_for_area(smallest);
702
703
704    o->move(c->x_suggestion,c->y_suggestion,c->b1_suggestion|(c->b2_suggestion<<1)|
705        (c->b3_suggestion<<2));
706
707    if (o->otype!=current_start_type)
708    {
709      int32_t fmp=o->fmp();
710      int reduce=figures[o->otype]->morph_power;
711      if (reduce)
712      {
713        fmp-=reduce;
714        o->add_power(fmp>>16);
715        o->set_fmp(fmp&0xffff);
716        if (o->mp()<=0)
717        o->morph_into(current_start_type,NULL,-1,9);
718      }
719    }
720
721    l=o;
722    o=o->next_active;
723      }
724      else if (!o->decide())      // if object returns 0, delete it... I don't like 0's :)
725      {
726    game_object *p=o;
727    o=o->next_active;
728    delete_object(p);
729    cur=NULL;
730      } else
731      {
732    o=o->next_active;
733    l=o;
734      }
735    } else
736    {
737      o=o->next_active;
738      l=o;
739    }
740
741    clear_tmp();
742
743    if (cur)
744    {
745      point_list *p=cur->current_figure()->hit;  // see if this character is on an attack frame
746      if (p && p->tot)
747        add_attacker(cur);               // if so add him to attack list for later collision detect
748
749      if (cur->hurtable())                    // add to target list if is hurtable
750        add_target(cur);
751
752    }
753
754  }
755  tick_panims();
756
757  check_collisions();
758//  wall_push();
759
760  set_tick_counter(tick_counter()+1);
761
762  if (sshot_fcount!=-1)
763  {
764    sshot_fcount++;
765    if ((sshot_fcount%70)==0)
766    {
767      char name[100];
768      sprintf(name,"shot%04d.pcx",screen_shot_on++);
769      write_PCX(screen,pal,name);
770    }
771  }
772
773  return ret;
774}
775
776void level::set_tick_counter(uint32_t x)
777{
778  ctick=x;
779}
780
781void level::draw_areas(view *v)
782{
783  int32_t sx1,sy1,sx2,sy2;
784  area_controller *a=area_list;
785  for (; a; a=a->next)
786  {
787    int c1,c2;
788    if (a->active)
789    {
790      c1=morph_sel_frame_color;
791      c2=wm->bright_color();
792    } else
793    {
794      c2=morph_sel_frame_color;
795      c1=wm->bright_color();
796    }
797
798    the_game->game_to_mouse(a->x,a->y,v,sx1,sy1);
799    the_game->game_to_mouse(a->x+a->w,a->y+a->h,v,sx2,sy2);
800    screen->rectangle(sx1,sy1,sx2,sy2,c1);
801    screen->bar(sx1-1,sy1-1,sx1+1,sy1+1,c2);
802    screen->bar(sx2-1,sy2-1,sx2+1,sy2+1,c2);
803  }
804}
805
806void level::draw_objects(view *v)
807{
808  current_view=v;
809  game_object *o=first_active;
810  if (dev&MAP_MODE)
811  {
812    for (; o; o=o->next_active)
813      o->map_draw();
814  } else
815  {
816    for (; o; o=o->next_active)
817      o->draw();
818  }
819
820  clear_tmp();
821}
822
823void calc_bgsize(uint16_t fgw, uint16_t  fgh, uint16_t  &bgw, uint16_t  &bgh)
824{
825  bgw=fgw/ASPECT+8;
826  bgh=fgh/ASPECT+8;
827}
828
829
830void level::set_size(int w, int h)
831{
832  if (w*h>200000)
833  {
834    the_game->show_help(symbol_str("too_big"));
835    return ;
836  }
837
838  uint16_t *new_fg,*new_bg;
839  new_fg=(uint16_t *)malloc(w*h*sizeof(int16_t));
840  memset(new_fg,0,w*h*sizeof(int16_t));
841
842  int x,y,miny=(h<fg_height)? h : fg_height,minx=(w<fg_width)? w : fg_width;
843
844  uint16_t nbw,nbh;
845  calc_bgsize(w,h,nbw,nbh);
846
847  new_bg=(uint16_t *)malloc((int)nbw*(int)nbh*sizeof(int16_t));
848  memset(new_bg,0,(int)nbw*(int)nbh*sizeof(int16_t));
849
850  for (y=0; y<miny; y++)
851    for (x=0; x<minx; x++)
852      new_fg[x+y*w]=get_fg(x,y);
853
854  miny=(nbh<bg_height) ? nbh : bg_height;
855  minx=(nbw<bg_width) ? nbw : bg_width;
856
857  for (y=0; y<miny; y++)
858    for (x=0; x<minx; x++)
859      new_bg[x+y*nbw]=get_bg(x,y);
860
861  free(map_fg);
862  free(map_bg);
863  map_fg=new_fg;
864  map_bg=new_bg;
865  fg_width=w;
866  fg_height=h;
867  bg_height=nbh;
868  bg_width=nbw;
869
870  char msg[80];
871  sprintf(msg,"Level %s size now %d %d\n",name(),foreground_width(),foreground_height());
872  the_game->show_help(msg);
873}
874
875
876int locate_var(bFILE *fp, spec_directory *sd, char *str, int size)
877{
878  spec_entry *se=sd->find(str);
879  if (se)
880  {
881    fp->seek(se->offset,0);
882    if (RC_type_size(fp->read_uint8())!=size)
883      return 0;
884    else return 1;
885  }
886  return 0;
887}
888
889
890// load objects assumes current objects have already been disposed of
891void level::old_load_objects(spec_directory *sd, bFILE *fp)
892{
893  spec_entry *se=sd->find("objects");
894  total_objs=0;
895  first=last=first_active=NULL;
896  int i,j;
897  if (se)
898  {
899    fp->seek(se->offset,0);
900    /******************************* Read debug info ******************************/
901    int16_t old_tot=fp->read_uint16();
902    uint16_t *o_remap=(uint16_t *)malloc(old_tot * 2);
903    char old_name[150];
904    for (i=0; i<old_tot; i++)
905    {
906      fp->read(old_name,fp->read_uint8());    // read the name
907      for (o_remap[i]=0xffff,j=0; j<total_objects; j++)  // check for matching current name
908      {
909    if (!strcmp(old_name,object_names[j]))
910          o_remap[i]=j;
911      }
912    }
913
914
915    /***************************** Read state names *********************************/
916    int old_stot=fp->read_uint16();
917    unsigned char *s_remap=(unsigned char *)malloc(old_stot);
918    for (i=0; i<old_stot; i++)
919    {
920      fp->read(old_name,fp->read_uint8());
921      s_remap[i]=stopped;           // non exsitant states get mapped into stopped state
922      for (j=0; j<MAX_STATE; j++)                  // see if old state exist now
923    if (!strcmp(state_names[j],old_name))
924         s_remap[i]=j;
925    }
926    total_objs=fp->read_uint32();
927
928    se=sd->find("type");
929    if (se)
930    {
931      fp->seek(se->offset,0);
932      last=NULL;
933      if (fp->read_uint8()==RC_16)    //  read type array, this should be type RC_16
934      {
935    for (i=0; i<total_objs; i++)
936    {
937      uint16_t t=fp->read_uint16();
938      game_object *p=new game_object(o_remap[t],1);
939      clear_tmp();
940      if (!first) first=p; else last->next=p;
941      last=p; p->next=NULL;
942    }
943
944
945    se=sd->find("state");
946    if (se)
947    {
948      fp->seek(se->offset,0);
949      if (fp->read_uint8()==RC_16)    //  read state array, this should be type RC_16
950      {
951        game_object *l=first;
952        for (i=0; i<total_objs; i++,l=l->next)
953        {
954          character_state s=(character_state)s_remap[fp->read_uint16()];
955          if (l->otype!=0xffff)
956          {
957        if (l->has_sequence((character_state)s))
958          l->state=s;
959        else l->state=stopped;
960        l->current_frame=0;
961          }
962        }
963      }
964    }
965
966    int frame_var=0;
967    int i=0;
968    for (; i<TOTAL_OBJECT_VARS; i++)
969      if (!strcmp(object_descriptions[i].name,"cur_frame"))
970        frame_var=i;
971
972    int j=0;
973    for (; j<default_simple.total_vars(); j++)
974    {
975      spec_entry *se=sd->find(object_descriptions[j].name);
976      if (se)
977      {
978        fp->seek(se->offset,0);
979        int t=object_descriptions[j].type;
980        if (fp->read_uint8()!=t)
981          dprintf("Warning : load level -> var '%s' size changed\n");
982        else
983        {
984          game_object *f=first;
985          for (; f; f=f->next)
986          {
987        switch (t)
988        {
989          case RC_8 : f->set_var(j,fp->read_uint8()); break;
990          case RC_16 : f->set_var(j,fp->read_uint16()); break;
991          case RC_32 : f->set_var(j,fp->read_uint32()); break;
992        }
993
994        // check to make sure the frame number is not out of bounds from the time
995        // it was last saved
996        if (j==frame_var)
997        {
998          if (f->otype!=0xffff && f->current_frame>=
999              figures[f->otype]->get_sequence(f->state)->length())
1000            f->current_frame=0;
1001        }
1002          }
1003        }
1004      } else dprintf("Warning : load level -> no previous var %s\n",default_simple.var_name(j));
1005    }
1006      }
1007    }
1008
1009    free(o_remap);
1010    free(s_remap);
1011  }
1012
1013}
1014
1015
1016// load objects assumes current objects have already been disposed of
1017void level::load_objects(spec_directory *sd, bFILE *fp)
1018{
1019  spec_entry *se=sd->find("object_descripitions");
1020  total_objs=0;
1021  first=last=first_active=NULL;
1022  int i,j;
1023  if (!se)
1024  {
1025    old_load_objects(sd,fp);
1026    return ;
1027  }
1028  else if (se)
1029  {
1030    fp->seek(se->offset,0);
1031    int16_t old_tot=fp->read_uint16();
1032    se=sd->find("describe_names");
1033    if (!se || !old_tot)
1034      return ;
1035
1036    uint16_t *o_remap=(uint16_t *)malloc(old_tot * 2);
1037    uint16_t *o_backmap=(uint16_t *)malloc(total_objects * 2);
1038    memset(o_backmap,0xff,total_objects*2);
1039    char old_name[150];
1040    for (i=0; i<old_tot; i++)
1041    {
1042      fp->read(old_name,fp->read_uint8());    // read the name
1043      for (o_remap[i]=0xffff,j=0; j<total_objects; j++)  // check for matching current name
1044      {
1045    if (!strcmp(old_name,object_names[j]))
1046    {
1047          o_remap[i]=j;
1048      o_backmap[j]=i;
1049    }
1050      }
1051    }
1052
1053    se=sd->find("describe_states");
1054    if (!se) { free(o_remap); free(o_backmap); return ; }
1055    int16_t **s_remap=(int16_t **)malloc(old_tot*sizeof(int16_t *));
1056    int16_t *s_remap_totals=(int16_t *)malloc(old_tot*sizeof(int16_t));
1057    fp->seek(se->offset,0);
1058    int i=0;
1059    for (; i<old_tot; i++)
1060    {
1061      int16_t t=fp->read_uint16();
1062      s_remap_totals[i]=t;
1063      if (t)
1064      {
1065        s_remap[i]=(int16_t *)malloc(t*sizeof(int16_t));
1066    int j=0;
1067    for (; j<t; j++)
1068      *(s_remap[i]+j)=stopped;    // if no remap found, then go to stopped state
1069      }
1070      else s_remap[i]=0;
1071
1072      int j=0;
1073      for (; j<t; j++)
1074      {
1075    fp->read(old_name,fp->read_uint8());
1076    int new_type=o_remap[i];
1077    if (new_type<total_objects)     // make sure old object still exsist
1078    {
1079      int k=0;
1080      for (; k<figures[new_type]->ts; k++)
1081      {
1082        if (figures[new_type]->seq[k] &&
1083           !strcmp(lstring_value(((LSymbol *)figures[new_type]->seq_syms[k])->GetName()),old_name))
1084        *(s_remap[i]+j)=k;
1085      }
1086    }
1087      }
1088    }
1089
1090    int16_t **v_remap=NULL;
1091    int16_t *v_remap_totals=NULL;
1092    int load_vars=1;
1093    se=sd->find("describe_lvars");
1094    if (se)
1095    {
1096      v_remap=(int16_t **)malloc(old_tot*sizeof(int16_t *));
1097      v_remap_totals=(int16_t *)malloc(old_tot*sizeof(int16_t));
1098
1099      fp->seek(se->offset,0);
1100      int i=0;
1101      for (; i<old_tot; i++)
1102      {
1103    int16_t t=fp->read_uint16();
1104    v_remap_totals[i]=t;
1105    if (t)
1106    {
1107      v_remap[i]=(int16_t *)malloc(t*sizeof(int16_t));
1108      memset(v_remap[i],0xff,t*sizeof(int16_t));
1109    } else { v_remap[i]=NULL; }
1110    int j=0;
1111    for (; j<t; j++)
1112    {
1113      fp->read(old_name,fp->read_uint8());
1114      int new_type=o_remap[i];
1115      if (new_type!=0xffff)        // make sure old object still exsist
1116      {
1117        int k=0;
1118        for (; k<figures[new_type]->tiv; k++)
1119        {
1120          if (figures[new_type]->vars[k])
1121          {
1122        if (!strcmp(lstring_value(((LSymbol *)figures[new_type]->vars[k])->GetName()),old_name))
1123          *(v_remap[i]+j)=figures[new_type]->var_index[k];
1124          }
1125        }
1126      }
1127    }
1128      }
1129      load_vars=1;
1130    }
1131
1132    se=sd->find("object_list");
1133    if (se)
1134    {
1135      total_objs=fp->read_uint32();
1136
1137      se=sd->find("type");
1138      if (se)
1139      {
1140    fp->seek(se->offset,0);
1141    last=NULL;
1142    if (fp->read_uint8()==RC_16)    //  read type array, this should be type RC_16
1143    {
1144      int i=0;
1145      for (; i<total_objs; i++)
1146      {
1147        uint16_t t=fp->read_uint16();
1148        game_object *p=new game_object(o_remap[t],1);
1149        clear_tmp();
1150        if (!first) first=p; else last->next=p;
1151        last=p; p->next=NULL;
1152      }
1153
1154      se=sd->find("state");
1155      if (se)
1156      {
1157        fp->seek(se->offset,0);
1158        if (fp->read_uint8()==RC_16)    //  read state array, this should be type RC_16
1159        {
1160          game_object *l=first;
1161          for (i=0; i<total_objs; i++,l=l->next)
1162          {
1163        int st=fp->read_uint16();
1164        if (l->otype==0xffff)
1165          l->state=stopped;
1166        else
1167        {
1168          character_state s=(character_state)(*(s_remap[o_backmap[l->otype]]+st));
1169          if (l->has_sequence((character_state)s))
1170                l->state=s;
1171          else l->state=stopped;
1172          l->current_frame=0;
1173        }
1174          }
1175        }
1176      }
1177
1178      se=sd->find("lvars");
1179      if (se && load_vars)
1180      {
1181        fp->seek(se->offset,0);
1182        int abort=0;
1183        game_object *o=first;
1184        for (; o && !abort; o=o->next)
1185        {
1186          int16_t ot=fp->read_uint16();
1187          int k=0;
1188          for (; k<ot; k++)
1189          {
1190        if (fp->read_uint8()!=RC_32) abort=1;
1191        else
1192        {
1193          int32_t v=fp->read_uint32();
1194          if (o->otype!=0xffff)     // non-exstant object
1195          {
1196            int remap=*(v_remap[o_backmap[o->otype]]+k);
1197            if (remap!=-1 && figures[o->otype]->tiv>=k)
1198            {
1199              o->lvars[remap]=v;
1200            }
1201          }
1202        }
1203          }
1204        }
1205      }
1206
1207      int frame_var=0;
1208      for (i=0; i<TOTAL_OBJECT_VARS; i++)
1209        if (!strcmp(object_descriptions[i].name,"cur_frame"))
1210          frame_var=i;
1211
1212
1213      int j=0;
1214      for (; j<default_simple.total_vars(); j++)
1215      {
1216        spec_entry *se=sd->find(object_descriptions[j].name);
1217        if (se)
1218        {
1219          fp->seek(se->offset,0);
1220          int t=object_descriptions[j].type;
1221          if (fp->read_uint8()!=t)
1222            dprintf("Warning : load level -> var '%s' size changed\n");
1223          else
1224          {
1225        game_object *f=first;
1226        for (; f; f=f->next)
1227        {
1228          switch (t)
1229          {
1230            case RC_8 :
1231            { f->set_var(j,fp->read_uint8()); } break;
1232            case RC_16 :
1233            { f->set_var(j,fp->read_uint16()); } break;
1234            case RC_32 :
1235            { f->set_var(j,fp->read_uint32()); } break;
1236          }
1237
1238          // check to make sure the frame number is not out of bounds from the time
1239          // it was last saved
1240          if (j==frame_var)
1241          {
1242            if (f->otype!=0xffff && f->current_frame>=
1243            figures[f->otype]->get_sequence(f->state)->length())
1244            f->current_frame=0;
1245          }
1246        }
1247          }
1248        } else dprintf("Warning : load level -> no previous var %s\n",default_simple.var_name(j));
1249      }
1250    }
1251      }
1252    }
1253
1254    int k=0;
1255    for (; k<old_tot; k++)
1256    {
1257      if (s_remap_totals[k])
1258        free(s_remap[k]);
1259    }
1260
1261    int l=0;
1262    for (; l<old_tot; l++)
1263    {
1264      if (v_remap_totals[l])
1265        free(v_remap[l]);
1266    }
1267    free(v_remap_totals);
1268    free(s_remap_totals);
1269    free(o_remap);
1270    free(o_backmap);
1271    free(s_remap);
1272    free(v_remap);
1273  }
1274
1275}
1276
1277level::level(spec_directory *sd, bFILE *fp, char const *lev_name)
1278{
1279  spec_entry *e;
1280  area_list=NULL;
1281
1282  attack_list=NULL;
1283  attack_list_size=attack_total=0;
1284
1285  target_list=NULL;
1286  target_list_size=target_total=0;
1287
1288  block_list=NULL;
1289  block_list_size=block_total=0;
1290
1291  all_block_list=NULL;
1292  all_block_list_size=all_block_total=0;
1293  first_name=NULL;
1294
1295  the_game->need_refresh();
1296
1297  char cmd[100];
1298  sprintf(cmd,symbol_str("loading"),lev_name);
1299  stack_stat stat(cmd);
1300  Name = strdup(lev_name);
1301
1302  e=sd->find("first name");
1303  if (e)
1304  {
1305    fp->seek(e->offset,0);
1306    int len=fp->read_uint8();   // read the length of the string
1307    first_name=(char *)malloc(len);
1308    fp->read(first_name,len);    // read the string
1309  } else
1310  {
1311    first_name = strdup(Name);
1312  }
1313
1314  e=sd->find("fgmap");
1315  int no_fg=0,no_bg=0;
1316
1317  if (e)
1318  {
1319    fp->seek(e->offset,0);
1320    fg_width=fp->read_uint32();
1321    fg_height=fp->read_uint32();
1322    map_fg=(uint16_t *)malloc(2*fg_width*fg_height);
1323    fp->read((char *)map_fg,2*fg_width*fg_height);
1324    int t=fg_width*fg_height;
1325    uint16_t *map=map_fg;
1326    while (t) { *map=lstl(*map); map++; t--; }
1327  } else
1328  {
1329    the_game->show_help("Warning foreground map missing");
1330    no_fg=1;
1331  }
1332  stat_man->update(5);
1333
1334  e=sd->find("bgmap");
1335  if (e)
1336  {
1337    fp->seek(e->offset,0);
1338    bg_width=fp->read_uint32();
1339    bg_height=fp->read_uint32();
1340    map_bg=(uint16_t *)malloc(2*bg_width*bg_height);
1341    fp->read((char *)map_bg,2*bg_width*bg_height);
1342    int t=bg_width*bg_height;
1343    uint16_t *map=map_bg;
1344    while (t) { *map=lstl(*map); map++; t--; }
1345  } else
1346  {
1347    the_game->show_help("Warning background map missing");
1348    no_bg=1;
1349  }
1350
1351  if (no_fg && !no_bg)
1352  {
1353    fg_width=bg_width;
1354    fg_height=bg_height;
1355    map_fg=(uint16_t *)malloc(2*fg_width*fg_height);
1356    memset(map_fg,0,2*fg_width*fg_height);
1357  }
1358
1359  if (no_bg)
1360  {
1361    bg_width=fg_width/8+8;
1362    bg_height=fg_height/8+8;
1363    map_bg=(uint16_t *)malloc(2*bg_width*bg_height);
1364    memset(map_bg,0,2*bg_width*bg_height);
1365  }
1366  stat_man->update(10);
1367
1368  /***************** Check map for non exsistant tiles **************************/
1369  int32_t i,w;
1370  uint16_t *m;
1371  spec_entry *load_all=sd->find("player_info");
1372  for (i=0,w=fg_width*fg_height,m=map_fg; i<w; i++,m++)
1373  {
1374    if (!load_all)
1375      (*m)=(*m)&(~0x8000);    // clear the has-seen bit on the tile
1376
1377    if (fgvalue(*m)>=nforetiles || foretiles[fgvalue(*m)]<0)
1378      *m=0;
1379  }
1380
1381  for (i=0,w=bg_width*bg_height,m=map_bg; i<w; i++,m++)
1382  {
1383    if ( (bgvalue(*m)>=nbacktiles) || backtiles[bgvalue(*m)]<0)
1384       *m=0;
1385  }
1386
1387  load_options(sd,fp);
1388  stat_man->update(15);
1389
1390//  first=first_active=last=NULL;
1391  load_objects(sd,fp);
1392  stat_man->update(25);
1393
1394  object_node *players,*objs;
1395  players=make_player_onodes();
1396  objs=make_not_list(players);
1397
1398
1399
1400  read_lights(sd,fp,lev_name);
1401  load_links(fp,sd,objs,players);
1402  int players_got_loaded=load_player_info(fp,sd,objs);
1403
1404
1405  game_object *l=first;
1406  for (; l; )
1407  {
1408    game_object *p=l;
1409    l=l->next;
1410    if (p->otype==0xffff || p->x<0 || p->y<0)
1411      delete_object(p);
1412  }
1413
1414  load_cache_info(sd,fp);
1415
1416  if (!players_got_loaded)
1417  {
1418    level *old=current_level;
1419    current_level=this;
1420
1421    object_node *list=NULL;
1422    list=make_not_list(list);     // create a list of the object list in case objects change positions
1423
1424    object_node *ln=list;
1425    for (; ln; ln=ln->next)
1426      ln->me->reload_notify();
1427    delete_object_list(list);
1428
1429    current_level=old;
1430
1431    insert_players();
1432  }
1433
1434  delete_object_list(players);
1435  delete_object_list(objs);
1436
1437}
1438
1439
1440/*
1441   [object_descriptions] 2 total_type
1442   for(1..total_types)
1443   {
1444     ["object_names"]  1,(name)
1445
1446     ["object_states"]  2(total),<2=number,1,name>
1447
1448     ["object_lvars"]   2(total),<1(type),1,name>
1449   }
1450
1451  [object_list]
1452   4 total_objects
1453   for(1..total_objects)
1454   {
1455     ["type"]
1456     ["state"]
1457     ["lvars"]
1458     ...
1459   }
1460
1461*/
1462
1463
1464void get_prof_assoc_filename(char *filename, char *prof_filename)
1465{
1466  char *s1,*s2,*dot=NULL;
1467  for (s1=filename,s2=prof_filename,dot=NULL; *s1; s1++,s2++)
1468  {
1469    *s2=*s1;
1470    if (*s1=='.') dot=s2;
1471  }
1472  if (dot) s2=dot+1;
1473
1474  *(s2++)='c';
1475  *(s2++)='p';
1476  *(s2++)='f';
1477  *s2=0;
1478}
1479
1480void level::level_loaded_notify()
1481{
1482  char *n;
1483  if (first_name)
1484    n=first_name;
1485  else
1486    n=name();
1487  if (strstr(n,"levels/level"))
1488  {
1489    char nm[100];
1490    sprintf(nm,"music/abuse%c%c.hmi",n[12],n[13]);
1491    bFILE *fp=open_file(nm,"rb");
1492    if (fp->open_failure())
1493    {
1494      delete fp;
1495    }
1496    else
1497    {
1498      if (current_song) { current_song->stop(); delete current_song; }
1499
1500      delete fp;
1501      current_song=new song(nm);
1502      current_song->play(music_volume);
1503    }
1504  }
1505
1506/*  if (DEFINEDP(symbol_function(l_level_loaded)))
1507  {
1508    int sp=current_space;
1509    current_space=PERM_SPACE;
1510
1511    void *arg_list=NULL;
1512    PtrRef r1(arg_list);
1513    push_onto_list(LString::Create(n),arg_list);
1514    eval_function((LSymbol *)l_level_loaded,arg_list);
1515
1516    current_space=sp;
1517  } */
1518}
1519
1520
1521bFILE *level::create_dir(char *filename, int save_all,
1522             object_node *save_list, object_node *exclude_list)
1523{
1524  spec_directory sd;
1525  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"Copyright 1995 Crack dot Com, All Rights reserved",NULL,0,0));
1526  if (first_name)
1527    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"first name",NULL,strlen(first_name)+2,0));
1528
1529
1530
1531  sd.add_by_hand(new spec_entry(SPEC_GRUE_FGMAP,"fgmap",NULL,4+4+fg_width*fg_height*2,0));
1532  sd.add_by_hand(new spec_entry(SPEC_GRUE_BGMAP,"bgmap",NULL,4+4+bg_width*bg_height*2,0));
1533  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"bg_scroll_rate",NULL,1+4*4,0));
1534
1535  int ta=0;
1536  area_controller *a=area_list;
1537  for (; a; a=a->next) ta++;
1538
1539  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"area_list.v1",NULL,1+ta*(4*11)+4,0));
1540
1541  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"tick_counter",NULL,1+4,0));
1542
1543
1544
1545  // how many object types are we goint to save, use a short to specify how many
1546  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"object_descripitions",NULL,2,0));
1547
1548
1549  int size=0;
1550  int i=0;
1551  for (; i<total_objects; i++)       // now save the names of the objects so if ordering
1552    size+=1+strlen(object_names[i])+1;    // changes in future versions we can adjust in load
1553  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"describe_names",NULL,size,0));
1554
1555
1556  size=0;
1557  for (i=0; i<total_objects; i++)
1558  {
1559    size+=2;  // total number of states
1560    int j=0;
1561    for (; j<figures[i]->ts; j++)
1562      if (figures[i]->seq[j])
1563        size+=1+strlen(lstring_value(((LSymbol *)figures[i]->seq_syms[j])->GetName()))+1;
1564  }
1565  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"describe_states",NULL,size,0));
1566
1567
1568
1569  size=0;
1570  for (i=0; i<total_objects; i++)
1571  {
1572    size+=2;  // total number of variables
1573    int j=0;
1574    for (; j<figures[i]->tiv; j++)
1575      if (figures[i]->vars[j])
1576        size+=1+strlen(lstring_value(((LSymbol *)figures[i]->vars[j])->GetName()))+1;
1577  }
1578  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"describe_lvars",NULL,size,0));
1579
1580
1581
1582  // how many objects are we goint to save, use a int32_t to specify how many
1583  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"object_list",NULL,4,0));
1584
1585  int32_t t=0;
1586  object_node *o=save_list;
1587  for (; o; o=o->next)
1588    t++;
1589
1590  // type and state aren't normal records because they will be remapped on loading
1591  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"type",NULL,1+2*t,0));
1592  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"state",NULL,1+2*t,0));
1593
1594
1595  // now save all the lvars for each object
1596  for (size=0,o=save_list; o; o=o->next)
1597    size+=figures[o->me->otype]->tv*5+2;
1598  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"lvars",NULL,size,0));
1599
1600
1601  for (i=0; i<TOTAL_OBJECT_VARS; i++)
1602    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,object_descriptions[i].name,NULL,1+
1603              RC_type_size(object_descriptions[i].type)*t,0));
1604
1605  add_light_spec(&sd,Name);
1606
1607
1608  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"object_links",NULL,1+4+total_object_links(save_list)*8,0));
1609  sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"light_links",NULL,1+4+total_light_links(save_list)*8,0));
1610
1611  if (save_all)
1612  {
1613    t=0;
1614    view *v=player_list;
1615    for (; v; v=v->next) t++;
1616    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"player_info",NULL,t*4+4,0));
1617
1618    int tv=total_view_vars();
1619    int i=0;
1620    for (; i<tv; i++)
1621      sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,get_view_var_name(i),NULL,1+4*t,0));
1622    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"random_start",NULL,5,0));
1623
1624    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"weapon_array",NULL,1+4+total_weapons*4*t,0));
1625
1626    int name_len=0;
1627    for (v=player_list; v; v=v->next)
1628      name_len+=strlen(v->name)+2;
1629    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"player_names",NULL,name_len,0));
1630
1631    sd.add_by_hand(new spec_entry(SPEC_IMAGE,"thumb nail",NULL,4+160*(100+wm->font()->height()*2),0));
1632  }
1633
1634  sd.calc_offsets();
1635
1636  return sd.write(filename);
1637}
1638
1639void scale_put(image *im, image *screen, int x, int y, short new_width, short new_height);
1640
1641void level::write_thumb_nail(bFILE *fp, image *im)
1642{
1643  image *i=new image(160,100+wm->font()->height()*2);
1644  i->clear();
1645  scale_put(im,i,0,0,160,100);
1646  if (first_name)
1647    wm->font()->put_string(i,80-strlen(first_name)*wm->font()->width()/2,100,first_name);
1648
1649  time_t t;
1650  t=time(NULL);
1651  char buf[80];
1652
1653  strftime(buf,80,"%T %A %B %d",localtime(&t));
1654  wm->font()->put_string(i,80-strlen(buf)*wm->font()->width()/2,100+wm->font()->height(),buf);
1655
1656  fp->write_uint16(i->width());
1657  fp->write_uint16(i->height());
1658
1659  i->lock();
1660  for(int y = 0; y < i->height(); y++)
1661    fp->write(i->scan_line(y),i->width());
1662  i->unlock();
1663
1664  delete i;
1665}
1666
1667void level::write_player_info(bFILE *fp, object_node *save_list)
1668{
1669  int32_t t=0;
1670  view *v=player_list;
1671  for (; v; v=v->next) t++;
1672  fp->write_uint32(t);
1673
1674  for (v=player_list; v; v=v->next)
1675    fp->write_uint32(object_to_number_in_list(v->focus,save_list));
1676
1677  int tv=total_view_vars();
1678  int i=0;
1679  for (; i<tv; i++)
1680  {
1681    fp->write_uint8(RC_32);
1682    for (v=player_list; v; v=v->next)
1683      fp->write_uint32(v->get_view_var_value(i));
1684  }
1685
1686  fp->write_uint8(RC_32);
1687  fp->write_uint32(rand_on);
1688
1689  fp->write_uint8(RC_32);
1690  fp->write_uint32(total_weapons);
1691  for (v=player_list; v; v=v->next)
1692    for (i=0; i<total_weapons; i++)
1693      fp->write_uint32(v->weapons[i]);
1694
1695  for (v=player_list; v; v=v->next)
1696  {
1697    int len=strlen(v->name)+1;
1698    fp->write_uint8(len);
1699    fp->write(v->name,len);
1700  }
1701}
1702
1703
1704int level::load_player_info(bFILE *fp, spec_directory *sd, object_node *save_list)
1705{
1706  int ret;
1707  spec_entry *se=sd->find("player_info");
1708  if (se)
1709  {
1710    fp->seek(se->offset,0);
1711
1712    int set_first_view=0;
1713    if (the_game->first_view==player_list) set_first_view=1;
1714    int my_player_number=-1;
1715
1716    view *v=player_list;
1717    for (; v; v=v->next)
1718    { v->suggest.send_view=0;
1719      v->suggest.send_weapon_change=0;
1720    }
1721
1722    for (v=player_list; v; v=v->next)
1723      if (v->local_player())
1724         my_player_number=v->player_number;
1725
1726    while (player_list)    // delete all of the views (they will get recreated)
1727    {
1728      v=player_list;
1729      if (v->focus)
1730      {
1731        if (v->focus->controller())
1732         v->focus->set_controller(NULL);
1733    delete v->focus;
1734      }
1735
1736      player_list=player_list->next;
1737      delete v;
1738    }
1739
1740    int32_t total_players=fp->read_uint32();
1741    view *last=NULL;
1742    int i=0;
1743    for (; i<total_players; i++)
1744    {
1745      game_object *o=number_to_object_in_list(fp->read_uint32(),save_list);
1746      v=new view(o,NULL,0);
1747      if (o) o->set_controller(v);
1748      if (player_list)
1749        last->next=v;
1750      else player_list=v;
1751      last=v;
1752    }
1753    if (set_first_view)
1754      the_game->first_view=player_list;
1755
1756    for (i=0; i<total_view_vars(); i++)
1757    {
1758      char const *find_name = get_view_var_name(i);
1759      se=sd->find(find_name);
1760
1761      if (se)
1762      {
1763    fp->seek(se->offset,0);
1764    if (fp->read_uint8()==RC_32)
1765    {
1766      for (v=player_list; v; v=v->next)
1767            v->set_view_var_value(i,fp->read_uint32());
1768    }
1769      } else
1770      {
1771    for (v=player_list; v; v=v->next)
1772        v->set_view_var_value(i,0);
1773      }
1774    }
1775
1776    se=sd->find("random_start");      // start of index into random table
1777    if (se)
1778    {
1779      fp->seek(se->offset,0);
1780      if (fp->read_uint8()==RC_32)
1781        rand_on=fp->read_uint32();
1782    } else rand_on=0;
1783
1784    se=sd->find("weapon_array");
1785    if (se)
1786    {
1787      fp->seek(se->offset,0);
1788      if (fp->read_uint8()==RC_32)
1789      {
1790    int32_t m=fp->read_uint32();  // read how many weapons exsisted when last saved
1791    int i;
1792    for (v=player_list; v; v=v->next)
1793    {
1794      for (i=0; i<m; i++)
1795      {
1796        int32_t x=fp->read_uint32();
1797        if (i<total_weapons)
1798        {
1799          v->weapons[i]=x;
1800          v->last_weapons[i]=x;
1801        }
1802      }
1803    }
1804      }
1805    }  else
1806    {
1807      for (v=player_list; v; v=v->next)
1808      {
1809    memset(v->last_weapons,0xff,total_weapons*sizeof(int32_t));
1810    memset(v->weapons,0xff,total_weapons*sizeof(int32_t));
1811      }
1812    }
1813
1814    se=sd->find("player_names");
1815    if (se)
1816    {
1817      fp->seek(se->offset,0);
1818      for (v=player_list; v; v=v->next)
1819      {
1820    uint8_t len=fp->read_uint8();
1821    fp->read(v->name,len);
1822      }
1823    }
1824
1825    ret=1;
1826    recalc_local_view_space();
1827
1828  } else
1829  {
1830    LSymbol *fun = LSymbol::FindOrCreate("set_player_defaults");
1831    if (DEFINEDP(fun->GetFunction()))
1832    {
1833      view *f;
1834      game_object *o=current_object;
1835      for (f=player_list; f; f=f->next)
1836      {
1837    if (f->focus)
1838    {
1839      current_object=f->focus;
1840      void *m=mark_heap(TMP_SPACE);
1841      eval_function(fun,NULL);
1842      restore_heap(m,TMP_SPACE);
1843    }
1844      }
1845      current_object=o;
1846    }
1847    ret=0;
1848  }
1849
1850  view *vw;
1851  for (vw=player_list; vw; vw=vw->next)
1852  {
1853    if (total_weapons && !vw->has_weapon(vw->current_weapon))
1854    {
1855      vw->suggest.send_weapon_change=1;
1856      vw->suggest.new_weapon=0;
1857    }
1858  }
1859
1860  return ret;
1861}
1862
1863
1864void level::write_objects(bFILE *fp, object_node *save_list)
1865{
1866  // record information in the file about what the data structures look like
1867  // right now, so if they change later, they don't get get screwed up
1868  fp->write_uint16(total_objects);   // mark how many objects we know about right now
1869
1870  int i=0;
1871  for (; i<total_objects; i++)   // loop through all the object types we know of
1872  {
1873    fp->write_uint8(strlen(object_names[i])+1);                    // sizeof name
1874    fp->write(object_names[i],strlen(object_names[i])+1);      // write object name
1875  }
1876
1877
1878  // write state numbers and names for each object
1879  for (i=0; i<total_objects; i++)
1880  {
1881    int total=0;
1882    int j=0;
1883    for (; j<figures[i]->ts; j++)
1884      if (figures[i]->seq[j]) total++;
1885    fp->write_uint16(total);
1886
1887    for (j=0; j<figures[i]->ts; j++)
1888      if (figures[i]->seq[j])
1889      {
1890    char *state_name=lstring_value(((LSymbol *)figures[i]->seq_syms[j])->GetName());
1891    fp->write_uint8(strlen(state_name)+1);
1892    fp->write(state_name,strlen(state_name)+1);
1893      }
1894  }
1895
1896
1897  // write object lvar names
1898  for (i=0; i<total_objects; i++)
1899  {
1900    fp->write_uint16(figures[i]->tv);
1901    int j,x;
1902
1903    for (x=0; x<figures[i]->tv; x++)
1904    {
1905      for (j=0; j<figures[i]->tiv; j++)
1906      {
1907        if (figures[i]->vars[j] && figures[i]->var_index[j]==x)
1908    {
1909      char *var_name=lstring_value(((LSymbol *)figures[i]->vars[j])->GetName());
1910      fp->write_uint8(strlen(var_name)+1);
1911      fp->write(var_name,strlen(var_name)+1);
1912    }
1913      }
1914    }
1915  }
1916
1917  int32_t t=0;
1918  object_node *o=save_list;
1919  for (; o; o=o->next) t++;
1920  fp->write_uint32(t);
1921
1922
1923  fp->write_uint8(RC_16);                                    // save type info for each record
1924  for (o=save_list; o; o=o->next) fp->write_uint16(o->me->type());
1925
1926  fp->write_uint8(RC_16);                                    // save state info for each record
1927  for (o=save_list; o; o=o->next) fp->write_uint16(o->me->reduced_state());
1928
1929  for (o=save_list; o; o=o->next)                            // save lvars
1930  {
1931    fp->write_uint16(figures[o->me->otype]->tv);
1932    for (i=0; i<figures[o->me->otype]->tv; i++)
1933    {
1934      fp->write_uint8(RC_32);                           // for now the only type allowed is int32_t
1935      fp->write_uint32(o->me->lvars[i]);
1936    }
1937  }
1938
1939  for (i=0; i<default_simple.total_vars(); i++)
1940  {
1941    int t=object_descriptions[i].type;
1942    fp->write_uint8(t);
1943    for (o=save_list; o; o=o->next)
1944    {
1945      switch (t)
1946      {
1947    case RC_8 :
1948    { fp->write_uint8(o->me->get_var(i)); } break;
1949    case RC_16 :
1950    { fp->write_uint16(o->me->get_var(i)); } break;
1951    case RC_32 :
1952    { fp->write_uint32(o->me->get_var(i)); } break;
1953      }
1954    }
1955  }
1956}
1957
1958
1959int32_t level::total_object_links(object_node *list)
1960{
1961  int32_t tl=0;
1962  for (object_node *o=list; o; o=o->next)
1963    tl+=o->me->total_objects();
1964  return tl;
1965}
1966
1967int32_t level::total_light_links(object_node *list)
1968{
1969  int32_t tl=0;
1970  for (object_node *o=list; o; o=o->next)
1971    tl+=o->me->total_lights();
1972  return tl;
1973}
1974
1975void level::write_links(bFILE *fp, object_node *save_list, object_node *exclude_list)
1976{
1977  fp->write_uint8(RC_32);
1978  fp->write_uint32(total_object_links(save_list));
1979
1980  int x=1;
1981  object_node *o=save_list;
1982
1983  for (; o; o=o->next,x++)
1984  {
1985    int i=0;
1986    for (; i<o->me->total_objects(); i++)
1987    {
1988      fp->write_uint32(x);
1989      int32_t x=object_to_number_in_list(o->me->get_object(i),save_list);
1990      if (x)
1991        fp->write_uint32(x);
1992      else                            // save links to excluded items as negative
1993        fp->write_uint32((int32_t)(-(object_to_number_in_list(o->me,exclude_list))));
1994    }
1995  }
1996
1997  fp->write_uint8(RC_32);
1998  fp->write_uint32(total_light_links(save_list));
1999
2000  x=1;
2001  for (o=save_list; o; o=o->next,x++)
2002  {
2003    int i=0;
2004    for (; i<o->me->total_lights(); i++)
2005    {
2006      fp->write_uint32(x);
2007      fp->write_uint32(light_to_number(o->me->get_light(i)));
2008    }
2009  }
2010
2011}
2012
2013
2014void level::load_links(bFILE *fp, spec_directory *sd,
2015               object_node *save_list, object_node *exclude_list)
2016{
2017  spec_entry *se=sd->find("object_links");
2018  if (se)
2019  {
2020    fp->seek(se->offset,0);
2021    if (fp->read_uint8()==RC_32)
2022    {
2023      int32_t t=fp->read_uint32();
2024      while (t)
2025      {
2026    int32_t x1=fp->read_uint32();
2027    CONDITION(x1>=0,"expected x1 for object link to be > 0\n");
2028    int32_t x2=fp->read_uint32();
2029    game_object *p,*q=number_to_object_in_list(x1,save_list);
2030    if (x2>0)
2031      p=number_to_object_in_list(x2,save_list);
2032    else p=number_to_object_in_list(-x2,exclude_list);
2033    if (q)
2034      q->add_object(p);
2035    else dprintf("bad object link\n");
2036
2037    t--;
2038      }
2039    }
2040  }
2041
2042  se=sd->find("light_links");
2043  if (se)
2044  {
2045    fp->seek(se->offset,0);
2046    if (fp->read_uint8()==RC_32)
2047    {
2048      int32_t t=fp->read_uint32();
2049      while (t)
2050      {
2051    int32_t x1=fp->read_uint32();
2052    int32_t x2=fp->read_uint32();
2053    game_object *p=number_to_object_in_list(x1,save_list);
2054    if (p)
2055      p->add_light(number_to_light(x2));
2056    else dprintf("bad object/light link\n");
2057    t--;
2058      }
2059    }
2060  }
2061
2062}
2063
2064
2065void level::write_options(bFILE *fp)
2066{
2067  // save background scroll rate
2068  fp->write_uint8(RC_32);
2069  fp->write_uint32(bg_xmul);
2070  fp->write_uint32(bg_xdiv);
2071  fp->write_uint32(bg_ymul);
2072  fp->write_uint32(bg_ydiv);
2073
2074  fp->write_uint8(RC_32);
2075  int ta=0;
2076  area_controller *a=area_list;
2077  for (; a; a=a->next) ta++;
2078  fp->write_uint32(ta);
2079  for (a=area_list; a; a=a->next)
2080  {
2081    fp->write_uint32(a->x);
2082    fp->write_uint32(a->y);
2083    fp->write_uint32(a->w);
2084    fp->write_uint32(a->h);
2085    fp->write_uint32(a->active);
2086
2087    fp->write_uint32(a->ambient);
2088    fp->write_uint32(a->view_xoff);
2089    fp->write_uint32(a->view_yoff);
2090    fp->write_uint32(a->ambient_speed);
2091    fp->write_uint32(a->view_xoff_speed);
2092    fp->write_uint32(a->view_yoff_speed);
2093  }
2094  fp->write_uint8(RC_32);
2095  fp->write_uint32(tick_counter());
2096}
2097
2098void level::load_options(spec_directory *sd, bFILE *fp)
2099{
2100  spec_entry *se=sd->find("bg_scroll_rate");
2101  if (se)
2102  {
2103    fp->seek(se->offset,0);
2104    if (fp->read_uint8()!=RC_32)
2105    { bg_xmul=bg_ymul=1; bg_xdiv=bg_ydiv=8; }
2106    else
2107    {
2108      bg_xmul=fp->read_uint32();
2109      bg_xdiv=fp->read_uint32();
2110      bg_ymul=fp->read_uint32();
2111      bg_ydiv=fp->read_uint32();
2112    }
2113  } else { bg_xmul=bg_ymul=1; bg_xdiv=bg_ydiv=8; }
2114
2115  se=sd->find("area_list.v1");
2116  if (se)
2117  {
2118    fp->seek(se->offset,0);
2119    if (fp->read_uint8()==RC_32)
2120    {
2121      area_controller *l=NULL,*p;
2122      int32_t ta=fp->read_uint32();
2123      int i=0;
2124      for (; i<ta; i++)
2125      {
2126    int32_t x,y,w,h;
2127    x=fp->read_uint32();
2128    y=fp->read_uint32();
2129    w=fp->read_uint32();
2130    h=fp->read_uint32();
2131    p=new area_controller(x,y,w,h,NULL);
2132    if (l) l->next=p;
2133    else area_list=p;
2134    l=p;
2135    p->active=fp->read_uint32();
2136    p->ambient=fp->read_uint32();
2137    p->view_xoff=fp->read_uint32();
2138    p->view_yoff=fp->read_uint32();
2139    p->ambient_speed=fp->read_uint32();
2140    p->view_xoff_speed=fp->read_uint32();
2141    p->view_yoff_speed=fp->read_uint32();
2142      }
2143    }
2144  }
2145
2146  se=sd->find("tick_counter");
2147  if (se)
2148  {
2149    fp->seek(se->offset,0);
2150    if (fp->read_uint8()==RC_32)
2151      set_tick_counter(fp->read_uint32());
2152    else set_tick_counter(0);
2153  } else set_tick_counter(0);
2154}
2155
2156
2157void level::write_cache_prof_info()
2158{
2159  if (cache.prof_is_on())
2160  {
2161    char pf_name[100];
2162    if (first_name)
2163      get_prof_assoc_filename(first_name,pf_name);
2164    else
2165      get_prof_assoc_filename(Name,pf_name);
2166
2167
2168    spec_directory sd;
2169    sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"cache profile info",NULL,cache.prof_size(),0));
2170    sd.calc_offsets();
2171    jFILE *fp2=sd.write(pf_name);
2172    if (!fp2)
2173      the_game->show_help("Unable to open cache profile output file");
2174    else
2175    {
2176      cache.prof_write(fp2);
2177      delete fp2;
2178    }
2179    sd.delete_entries();
2180  }
2181
2182}
2183
2184void level::load_cache_info(spec_directory *sd, bFILE *fp)
2185{
2186  if (!DEFINEDP(symbol_value(l_empty_cache)) || !symbol_value(l_empty_cache))
2187  {
2188    char pf_name[100];
2189    if (first_name)
2190      get_prof_assoc_filename(first_name,pf_name);  // get cache info from orignal filename if this is a savegame
2191    else
2192      get_prof_assoc_filename(Name,pf_name);
2193
2194
2195    cache.load_cache_prof_info(pf_name,this);
2196  }
2197}
2198
2199
2200int level::save(char const *filename, int save_all)
2201{
2202    char name[255], bkname[255];
2203
2204    sprintf( name, "%s%s", get_save_filename_prefix(), filename );
2205    sprintf( bkname, "%slevsave.bak", get_save_filename_prefix() );
2206    if( !save_all && DEFINEDP( symbol_value( l_keep_backup ) ) &&
2207        symbol_value( l_keep_backup ) )   // make a backup
2208    {
2209        bFILE *fp = open_file( name, "rb" );    // does file already exist?
2210        if( !fp->open_failure() )
2211        {
2212            unlink( bkname );
2213            bFILE *bk = open_file( bkname, "wb" );
2214            if( bk->open_failure() )
2215                dprintf("unable to open backup file %s\n", bkname );
2216            else
2217            {
2218                uint8_t buf[0x1000];
2219                int32_t size = fp->file_size();
2220                int tr = 1;
2221                while( size && tr )
2222                {
2223                    int tr = fp->read(buf,0x1000);
2224                    if( tr )
2225                    tr = bk->write(buf,tr);
2226                    size -= tr;
2227                }
2228            }
2229            delete bk;
2230#if (defined(__MACH__) || !defined(__APPLE__))
2231            chmod( bkname, S_IRWXU | S_IRWXG | S_IRWXO );
2232#endif
2233        }
2234        delete fp;
2235    }
2236
2237    // if we are not doing a savegame then change the first_name to this name
2238    if( !save_all )
2239    {
2240        if( first_name )
2241            free(first_name);
2242        first_name = strdup(name);
2243    }
2244
2245    object_node *players, *objs;
2246    if( save_all )
2247        players = NULL;
2248    else
2249        players = make_player_onodes();
2250
2251    objs = make_not_list(players);     // negate the above list
2252
2253    bFILE *fp = create_dir( name, save_all, objs, players);
2254    if( fp != NULL )
2255    {
2256        if( !fp->open_failure() )
2257        {
2258            if( first_name )
2259            {
2260                fp->write_uint8( strlen( first_name ) + 1 );
2261                fp->write( first_name, strlen( first_name ) + 1 );
2262            }
2263            else
2264            {
2265                fp->write_uint8( 1 );
2266                fp->write_uint8( 0 );
2267            }
2268
2269            fp->write_uint32( fg_width );
2270            fp->write_uint32( fg_height );
2271
2272            int t  = fg_width * fg_height;
2273            uint16_t *rm = map_fg;
2274            for (; t; t--,rm++)
2275            {
2276                uint16_t x = *rm;
2277                x = lstl(x);            // convert to intel endianess
2278                *rm = x;
2279            }
2280
2281            fp->write( (char *)map_fg, 2 * fg_width * fg_height );
2282            t = fg_width * fg_height;
2283            rm = map_fg;
2284            for (; t; t--,rm++)
2285            {
2286                uint16_t x = *rm;
2287                x = lstl( x );            // convert to intel endianess
2288                *rm = x;
2289            }
2290
2291            fp->write_uint32( bg_width );
2292            fp->write_uint32( bg_height );
2293            t = bg_width * bg_height;
2294            rm = map_bg;
2295
2296            for (; t; t--,rm++)
2297            {
2298                uint16_t x=*rm;
2299                x = lstl( x );        // convert to intel endianess
2300                *rm = x;
2301            }
2302
2303            fp->write( (char *)map_bg, 2 * bg_width * bg_height );
2304            rm = map_bg;
2305            t = bg_width*bg_height;
2306
2307            for (; t; t--,rm++)
2308            {
2309                uint16_t x = *rm;
2310                x = lstl( x );        // convert to intel endianess
2311                *rm = x;
2312            }
2313
2314            write_options( fp );
2315            write_objects( fp, objs );
2316            write_lights( fp );
2317            write_links( fp, objs, players );
2318            if( save_all )
2319            {
2320                write_player_info( fp, objs );
2321                write_thumb_nail( fp,screen );
2322            }
2323
2324            delete fp;
2325#if (defined(__MACH__) || !defined(__APPLE__))
2326            chmod( name, S_IRWXU | S_IRWXG | S_IRWXO );
2327#endif
2328            write_cache_prof_info();
2329        }
2330        else
2331        {
2332            the_game->show_help( "Unable to open file for saving\n" );
2333            delete fp;
2334            return 0;
2335        }
2336    }
2337    else
2338    {
2339        the_game->show_help( "Unable to open file for saving.\n" );
2340        printf( "\nFailed to save game.\n" );
2341        printf( "I was trying to save to: '%s'\n\tPath: '%s'\n\tFile: '%s'\n", name, get_save_filename_prefix(), filename );
2342        printf( "\nPlease send an email to:\n\ttrandor@labyrinth.net.au\nwith these details.\nThanks.\n" );
2343        return 0;
2344    }
2345
2346    delete_object_list(players);
2347    delete_object_list(objs);
2348
2349    return 1;
2350}
2351
2352level::level(int width, int height, char const *name)
2353{
2354  the_game->need_refresh();
2355  area_list=NULL;
2356  set_tick_counter(0);
2357
2358  attack_list=NULL;
2359  attack_list_size=attack_total=0;
2360
2361  target_list=NULL;
2362  target_list_size=target_total=0;
2363
2364  block_list=NULL;
2365  block_list_size=block_total=0;
2366
2367  all_block_list=NULL;
2368  all_block_list_size=all_block_total=0;
2369
2370  Name=NULL;
2371  first_name=NULL;
2372
2373  set_name(name);
2374  first=first_active=NULL;
2375
2376  fg_width=width;
2377  fg_height=height;
2378  calc_bgsize(fg_width,fg_height,bg_width,bg_height);
2379
2380  map_bg=(uint16_t *)malloc(sizeof(int16_t)*bg_width*bg_height);
2381  map_fg=(uint16_t *)malloc(sizeof(int16_t)*fg_width*fg_height);
2382
2383
2384
2385  memset(map_bg,0,sizeof(int16_t)*bg_width*bg_height);
2386  memset(map_fg,0,sizeof(int16_t)*fg_width*fg_height);
2387
2388  int i;
2389  for (i=0; i<fg_width; i++)
2390  {
2391    map_fg[i]=1;
2392    map_fg[fg_width*(fg_height-1)+i]=1;
2393  }
2394  for (i=0; i<fg_height; i++)
2395  {
2396    map_fg[fg_width*i]=1;
2397    map_fg[fg_width*i+fg_width-1]=1;
2398  }
2399
2400  total_objs=0;
2401  insert_players();
2402}
2403
2404
2405void level::add_object(game_object *new_guy)
2406{
2407  total_objs++;
2408  new_guy->next=NULL;
2409  if (figures[new_guy->otype]->get_cflag(CFLAG_ADD_FRONT))
2410  {
2411    if (!first)
2412      first=new_guy;
2413    else
2414      last->next=new_guy;
2415    last=new_guy;
2416  } else
2417  {
2418    if (!first)
2419      last=first=new_guy;
2420    else
2421    {
2422      new_guy->next=first;
2423      first=new_guy;
2424    }
2425  }
2426}
2427
2428void level::add_object_after(game_object *new_guy,game_object *who)
2429{
2430  if (!who) add_object(new_guy);
2431  else
2432  {
2433    total_objs++;
2434    if (who==last) last=new_guy;
2435    new_guy->next=who->next;
2436    who->next=new_guy;
2437  }
2438}
2439
2440void level::delete_object(game_object *who)
2441{
2442  remove_object(who);
2443  delete who;
2444}
2445
2446void level::remove_block(game_object *who)
2447{
2448  int i=0,j;
2449  game_object **o=block_list;
2450  for (; i<block_total; i++)
2451  {
2452    if (*o==who)        // is this object in the block list?
2453    {
2454      block_total--;    // squish the block list in
2455      o++;
2456      for (j=i; j<block_total; j++)
2457        block_list[j]=block_list[j+1];
2458    } else o++;
2459  }
2460}
2461
2462
2463// searches through the all_block list for who and if it finds it deletes it
2464void level::remove_all_block(game_object *who)
2465{
2466  int i=0,j;
2467  game_object **o=all_block_list;
2468  for (; i<all_block_total; i++)
2469  {
2470    if (*o==who)        // is this object in the block list?
2471    {
2472      all_block_total--;    // squish the block list in
2473      o++;
2474      for (j=i; j<all_block_total; j++)
2475        all_block_list[j]=all_block_list[j+1];
2476    } else o++;
2477  }
2478}
2479
2480void level::remove_object(game_object *who)
2481{
2482  if (dev_cont)
2483    dev_cont->notify_deleted_object(who);
2484
2485  if (who==first)
2486  {
2487    if (who==last) last=NULL;
2488    first=first->next;
2489  }
2490  else
2491  {
2492    game_object *o=first;
2493    for (; o && o->next!=who; o=o->next);
2494    if (o)
2495    {
2496      o->next=who->next;
2497      if (!o->next) last=o;
2498    }
2499    else return ;     // if object is not in level, don't try to do anything else
2500  }
2501  total_objs--;
2502
2503
2504  if (first_active==who)
2505    first_active=who->next_active;
2506  else
2507  {
2508    game_object *o=first_active;
2509    for (; o && o->next_active!=who; o=o->next_active);
2510    if (o)
2511      o->next_active=who->next_active;
2512  }
2513
2514  if (who->flags()&KNOWN_FLAG)
2515  {
2516    game_object *o=first;
2517    for (; o; o=o->next)
2518    {
2519      int t=o->total_objects();
2520      int i=0;
2521      for (; i<t; i++)
2522        if (o->get_object(i)==who)
2523    {
2524      o->remove_object(who);
2525      t=o->total_objects();
2526    }
2527    }
2528  }
2529
2530  if (who->otype<0xffff)
2531  {
2532    if (who->can_block())  // remove object from block list and all_block if nessasary
2533    {
2534      remove_block(who);
2535      remove_all_block(who);
2536    } else if (who->hurtable())
2537      remove_all_block(who);
2538  }
2539
2540
2541  int t=who->total_objects();
2542  while (t) { who->remove_object(who->get_object(0)); t--; }
2543
2544  t=who->total_lights();
2545  while (t) { who->remove_light(who->get_light(0)); t--; }
2546}
2547
2548void level::to_front(game_object *o)  // move to end of list, so we are drawn last, therefore top
2549{
2550  if (o==last) return ;
2551  first_active=NULL;     // make sure nothing goes screwy with the active list
2552
2553  if (o==first)
2554    first=first->next;
2555  else
2556  {
2557    game_object *w=first;
2558    for (; w && w->next!=o; w=w->next);
2559    if (!w) return ;
2560    w->next=o->next;
2561  }
2562
2563  last->next=o;
2564  o->next=NULL;
2565  last=o;
2566}
2567
2568void level::to_back(game_object *o)   // to make the character drawn in back, put at front of list
2569{
2570  if (o==first) return;
2571  first_active=NULL;     // make sure nothing goes screwy with the active list
2572
2573  game_object *w=first;
2574  for (; w && w->next!=o; w=w->next);
2575  if (!w) return;
2576  if (last==o)
2577    last=w;
2578  w->next=o->next;
2579  o->next=first;
2580  first=o;
2581}
2582
2583
2584game_object *level::find_self(game_object *me)
2585{
2586  return me;
2587}
2588
2589game_object *level::find_object(int32_t x, int32_t y)
2590{
2591  int32_t x1,y1,x2,y2;
2592  game_object *o=first;
2593  for (; o; o=o->next)
2594  {
2595    o->picture_space(x1,y1,x2,y2);
2596    if (x<x2 && x>=x1 && y<y2 && y>=y1)
2597      return o;
2598  }
2599  return NULL;
2600}
2601
2602int32_t last_tile_hit_x,last_tile_hit_y;
2603
2604#define remapx(x) (x==0 ? -1 : x==tl-1 ? tl+1 : x)
2605#define remapy(y) (y==0 ? -1 : y==th-1 ? th+1 : y)
2606
2607void level::foreground_intersect(int32_t x1, int32_t y1, int32_t &x2, int32_t &y2)
2608{
2609/*  if (x1==x2)
2610  { vforeground_intersect(x1,y1,y2);
2611    return ;
2612  }  */
2613
2614  int32_t tl=the_game->ftile_width(),th=the_game->ftile_height(),
2615    j,
2616    xp1,yp1,xp2,yp2,    // starting and ending points of block line segment
2617    swap;               // temp var
2618  int32_t blockx1,blocky1,blockx2,blocky2,block,bx,by;
2619  point_list *block_list;
2620  unsigned char *bdat;
2621
2622  blockx1=x1;
2623  blocky1=y1;
2624  blockx2=x2;
2625  blocky2=y2;
2626  if (blockx1>blockx2) { swap=blockx1; blockx1=blockx2; blockx2=swap; }
2627  if (blocky1>blocky2) { swap=blocky1; blocky1=blocky2; blocky2=swap; }
2628  blockx1=(blockx1-2)/tl-1;
2629  blockx2=(blockx2+tl+2)/tl+1;
2630  blocky1=(blocky1-2)/th-1;
2631  blocky2=(blocky2+th+2)/th+1;
2632
2633
2634  if (blockx2>=foreground_width()) { x2=tl*foreground_width()-1; }
2635  if (blocky2>=foreground_height()) { y2=th*foreground_height()-1; }
2636  blockx1=Max(blockx1,0);
2637  blocky1=Max(blocky1,0);
2638
2639  if ((blockx1>blockx2) || (blocky1>blocky2)) return ;
2640
2641  // now check all the map positions this line could intersect
2642  for (bx=blockx1; bx<=blockx2; bx++)
2643  {
2644    for (by=blocky1; by<=blocky2; by++)
2645    {
2646      block=the_game->get_map_fg(bx,by);
2647      if (block>BLACK)        // don't check BLACK, should be no points in it
2648      {
2649        // now check the all the line segments in the block
2650        foretile *f=the_game->get_fg(block);
2651        block_list=f->points;
2652        unsigned char total=block_list->tot;
2653        bdat=block_list->data;
2654        unsigned char *ins=f->points->inside;
2655    int32_t xo=bx*tl,yo=by*th;
2656        for (j=0; j<total-1; j++,ins++)
2657        {
2658          // find the starting and ending points for this segment
2659      xp1=xo+remapx(*bdat);
2660      bdat++;
2661
2662      yp1=yo+remapy(*bdat);
2663      bdat++;
2664
2665      xp2=xo+remapx(*bdat);
2666      yp2=yo+remapy(bdat[1]);
2667
2668
2669      int32_t ox2=x2,oy2=y2;
2670          if (*ins)
2671            setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,1);
2672          else
2673            setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,-1);
2674      if (ox2!=x2 || oy2!=y2)
2675      {
2676        last_tile_hit_x=bx;
2677        last_tile_hit_y=by;
2678      }
2679
2680        }
2681      }
2682    }
2683  }
2684}
2685
2686
2687void level::vforeground_intersect(int32_t x1, int32_t y1, int32_t &y2)
2688{
2689  int32_t tl=f_wid,th=f_hi,
2690    j,
2691    xp1,yp1,xp2,yp2;    // starting and ending points of block line segment temp var
2692  int32_t blocky1,blocky2,block,bx,by,checkx;
2693  point_list *block_list;
2694  unsigned char *bdat;
2695
2696  int y_addback;
2697  if (y1>y2)
2698  {
2699    blocky1=y2/th;
2700    blocky2=y1/th;
2701    y_addback=blocky2*f_hi;
2702  } else
2703  {
2704    blocky1=y1/th;
2705    blocky2=y2/th;
2706    y_addback=blocky1*f_hi;
2707  }
2708
2709  y1-=y_addback;
2710  y2-=y_addback;
2711
2712  bx=x1/f_wid;
2713  checkx=x1-bx*f_wid;
2714
2715
2716  // now check all the map positions this line could intersect
2717
2718  for (by=blocky1; by<=blocky2; by++,y1-=f_hi,y2-=f_hi,y_addback+=f_hi)
2719  {
2720    block=the_game->get_map_fg(bx,by);
2721
2722    // now check the all the line segments in the block
2723    foretile *f=the_game->get_fg(block);
2724    block_list=f->points;
2725
2726    unsigned char total=block_list->tot;
2727    bdat=block_list->data;
2728    unsigned char *ins=f->points->inside;
2729
2730//    int32_t xo=bx*tl,yo=by*th;
2731    for (j=0; j<total-1; j++,ins++)
2732    {
2733      // find the starting and ending points for this segment
2734      xp1=remapx(*bdat);
2735      bdat++;
2736
2737      yp1=remapy(*bdat);
2738      bdat++;
2739
2740      xp2=remapx(*bdat);
2741      yp2=remapy(bdat[1]);
2742
2743
2744      int32_t oy2=y2;
2745      if (*ins)
2746        setback_intersect(checkx,y1,checkx,y2,xp1,yp1,xp2,yp2,1);
2747      else
2748        setback_intersect(checkx,y1,checkx,y2,xp1,yp1,xp2,yp2,-1);
2749      if (oy2!=y2)
2750      {
2751    last_tile_hit_x=bx;
2752    last_tile_hit_y=by;
2753      }
2754    }
2755  }
2756  y2+=y_addback;
2757}
2758
2759
2760
2761void level::send_signal(int32_t signal)
2762{
2763  if (signal)   // signal 0 is never sent!
2764  {
2765    game_object *o=first_active;
2766    for (; o; o=o->next_active)
2767      o->recieve_signal(signal);
2768  }
2769}
2770
2771
2772int level::crush(game_object *by_who, int xamount, int yamount)
2773{
2774  int32_t xv,yv,crushed=0;
2775  game_object *o=first_active;
2776  for (; o; o=o->next_active)
2777  {
2778    if (o->hurtable() && o!=by_who)
2779    {
2780      xv=-xamount;
2781      yv=-yamount;
2782      if (o->try_move(o->x,o->y,xv,yv,3)==by_who)
2783      {
2784    xv=xamount;
2785    yv=yamount;
2786    o->try_move(o->x,o->y,xv,yv,3);
2787    if (xv==0 && yv==0)
2788    {
2789      if (o->state!=dead && o->state!=dieing)
2790        o->do_damage(by_who->current_figure()->hit_damage,by_who,o->x,o->y,0,0);
2791
2792/*      {
2793        if (o->has_sequence(dieing))
2794          o->set_state(dieing);
2795        else o->set_state(dead);
2796          o->hp=0;
2797      }        */
2798      crushed=1;
2799    }
2800      }
2801    }
2802  }
2803
2804  return crushed;
2805}
2806
2807
2808int level::platform_push(game_object *by_who, int xamount, int yamount)
2809{
2810  int failed=0;
2811  int32_t xv,yv;
2812  game_object *o=first_active;
2813  for (; o; o=o->next_active)
2814  {
2815    if (o->is_playable() && o->state!=dieing && o->state!=dead)
2816    {
2817      // check to see if the platform is going up and will run into us.
2818      int32_t tvx,tvy;
2819      if (yamount<0)
2820      {
2821    tvx=-xamount;
2822    tvy=-yamount;
2823    if (o->try_move(o->x,o->y,tvx,tvy,1)==by_who)
2824    {
2825      o->x+=tvx;
2826      o->y+=tvy;
2827    }
2828      }
2829
2830/*      xv=xamount;
2831      yv=yamount;
2832      tvx,tvy;
2833      if (xv>0) tvx=xv+1; else if (xv<0) tvx=xv-1; else tvx=0;
2834      if (yv>0) tvy=yv+1; else if (yv<0) tvx=yv-1; else tvy=0;
2835      if (o->try_move(o->x,o->y,tvx,tvy,1)==by_who)  // we the platform hit us?
2836      {
2837    o->x+=tvx;
2838    o->y+=tvy;
2839      }*/
2840
2841      xv=0;
2842      yv=2;
2843      if (o->try_move(o->x,o->y,xv,yv,1)==by_who)  // are we standing on the platform?
2844      {
2845    by_who->x=-by_who->x;
2846    xv=xamount;
2847    yv=yamount;
2848    o->try_move(o->x,o->y,xv,yv,3);
2849    if (xv!=xamount || yv!=yamount) failed=1;
2850    o->x+=xv;
2851    o->y+=yv;
2852    by_who->x=-by_who->x;
2853      }
2854    }
2855  }
2856  return !failed;
2857}
2858
2859int level::push_characters(game_object *by_who, int xamount, int yamount)
2860{
2861  int32_t xv,yv;
2862  int failed=0;
2863  game_object *o=first_active;
2864  for (; o; o=o->next_active)
2865  {
2866    if ((o->is_playable() || o->pushable()) && o->state!=dieing && o->state!=dead)
2867    {
2868      xv=-xamount;
2869      yv=-yamount;
2870      int32_t tvx,tvy;
2871      if (xv>0) tvx=xv+1; else if (xv<0) tvx=xv-1; else tvx=0;
2872      if (yv>0) tvy=yv+1; else if (yv<0) tvx=yv-1; else tvy=0;
2873      if (o->try_move(o->x+xamount,o->y+yamount,tvx,tvy,3)==by_who)
2874      {
2875    xv=(xamount-tvx);
2876    yv=(yamount-tvy);
2877    o->try_move(o->x,o->y,xv,yv,3);
2878    o->x+=xv;
2879    o->y+=yv;
2880    if (xv!=xamount-tvx || yv!=yamount-tvy)
2881      failed=1;
2882      }
2883    }
2884  }
2885  return !failed;
2886}
2887
2888game_object *level::find_xrange(int x, int y, int type, int xd)
2889{
2890  int32_t find_ydist=100000;
2891  game_object *find=NULL;
2892  game_object *o=first_active;
2893  for (; o; o=o->next_active)
2894  {
2895    if (o->otype==type)
2896    {
2897      int x_dist=abs(x-o->x);
2898      int y_dist=abs(y-o->y);
2899
2900      if (x_dist<xd  && y_dist<find_ydist)
2901      {
2902    find_ydist=y_dist;
2903    find=o;
2904      }
2905    }
2906  }
2907  return find;
2908}
2909
2910
2911game_object *level::find_xclosest(int x, int y, int type, game_object *who)
2912{
2913  int32_t find_ydist=100000,find_xdist=0xffffff;
2914  game_object *find=NULL;
2915  game_object *o=first_active;
2916  for (; o; o=o->next_active)
2917  {
2918    if (o->otype==type && o!=who)
2919    {
2920      int x_dist=abs(x-o->x);
2921      if (x_dist<find_xdist)
2922      {
2923    find_xdist=x_dist;
2924    find_ydist=abs(y-o->y);
2925    find=o;
2926      }
2927      else if (x_dist==find_xdist)
2928      {
2929    int y_dist=abs(y-o->y);
2930    if (y_dist<find_ydist)
2931    {
2932      find_ydist=y_dist;
2933      find=o;
2934    }
2935      }
2936    }
2937  }
2938  return find;
2939}
2940
2941game_object *level::find_closest(int x, int y, int type, game_object *who)
2942{
2943  int32_t find_dist=100000;
2944  game_object *find=NULL;
2945  game_object *o=first_active;
2946  for (; o; o=o->next_active)
2947  {
2948    if (o->otype==type && o!=who)
2949    {
2950      int d=(x-o->x)*(x-o->x)+(y-o->y)*(y-o->y);
2951      if (d<find_dist)
2952      {
2953    find=o;
2954    find_dist=d;
2955      }
2956    }
2957  }
2958  return find;
2959}
2960
2961
2962
2963void level::remove_light(light_source *which)
2964{
2965  if (which->known)
2966  {
2967    game_object *o=first;
2968    for (; o; o=o->next)
2969    {
2970      int t=o->total_lights();
2971      int i=0;
2972      for (; i<t; i++)
2973        if (o->get_light(i)==which)
2974      o->remove_light(o->get_light(i));
2975    }
2976  }
2977  delete_light(which);
2978}
2979
2980
2981game_object *level::find_type(int type, int skip)
2982{
2983  game_object *l=NULL;
2984  game_object *o=first;
2985  for (; o; o=o->next)
2986  {
2987    if (o->otype==type)
2988    {
2989      if (!skip)
2990        return o;
2991      skip--;
2992      l=o;
2993    }
2994  }
2995  return l;
2996}
2997
2998void level::hurt_radius(int32_t x, int32_t y,int32_t r, int32_t m, game_object *from, game_object *exclude,
2999            int max_push)
3000{
3001  if (r<1) return ;   // avoid dev vy zero
3002  game_object *o=first_active;
3003  for (; o; o=o->next_active)
3004  {
3005    if (o!=exclude && o->hurtable())
3006    {
3007      int32_t y1=o->y,y2=o->y-o->picture()->height();
3008      int32_t cx=abs(o->x-x),cy1=abs(y1-y),d1,d2,cy2=abs(y2-y);
3009      if (cx<cy1)
3010        d1=cx+cy1-(cx>>1);
3011      else d1=cx+cy1-(cy1>>1);
3012
3013      if (cx<cy2)
3014        d2=cx+cy2-(cx>>1);
3015      else d2=cx+cy2-(cy2>>1);
3016      if (d2<d1)
3017        d1=d2;
3018
3019
3020
3021      if (d1<r)
3022      {
3023
3024    int px=(r-cx)*max_push/r,py=(r-cy1)*max_push/r;
3025    if (o->x<x)
3026          px=-px;
3027    if (o->y<y)
3028          py=-py;
3029    o->do_damage((r-d1)*m/r,from,x,y1,px,py);
3030      }
3031
3032
3033    }
3034  }
3035
3036}
3037
3038
3039
3040game_object *level::get_random_start(int min_player_dist, view *exclude)
3041{
3042  int t=0;
3043  game_object *o=first;
3044  for (; o; o=o->next)
3045    if (o->otype==start_position_type) t++;    // count how many starts there are in the level
3046
3047  if (t==0) return NULL;                       // there aren't any starts in level!
3048
3049  int retries=t;
3050  do
3051  {
3052    int ctry=jrandom(t)+1;
3053    game_object *n=first;
3054    for (n=first; ctry && n; n=n->next)
3055    {
3056      if (n->otype==start_position_type)
3057      {
3058    o=n;
3059        ctry--;
3060      }
3061    }
3062
3063    int too_close=0;
3064    view *v=player_list;
3065    for (; v; v=v->next)
3066    {
3067      if (v!=exclude)
3068      {
3069    int32_t cx=abs(v->x_center()-o->x),cy=abs(v->y_center()-o->y),d;
3070    if (cx<cy)
3071          d=cx+cy-(cx>>1);
3072    else d=cx+cy-(cy>>1);
3073    if (d<min_player_dist) too_close=1;
3074      }
3075    }
3076    if (too_close) retries--;
3077    else retries=0;
3078  } while (retries);
3079
3080  return o;
3081}
3082
3083
3084
3085
3086
3087void level::insert_players()
3088{
3089
3090  int start=0;
3091  int i=0;
3092  for (; i<total_objects; i++)
3093    if (!strcmp(object_names[i],"START"))
3094      start=i;
3095
3096  view *f=player_list;
3097  for (; f; f=f->next)
3098  {
3099    game_object *st=find_type(start,f->player_number);
3100    if (st)
3101    {
3102      f->focus->x=st->x;
3103      f->focus->y=st->y;
3104    }
3105    add_object_after(f->focus,st);
3106  }
3107
3108}
3109
3110
3111void level::add_attacker(game_object *who)
3112{
3113  if (attack_total>=attack_list_size)  // see if we need to grow the list size..
3114  {
3115    attack_list_size++;
3116    attack_list=(game_object **)realloc(attack_list,sizeof(game_object *)*attack_list_size);
3117  }
3118  attack_list[attack_total]=who;
3119  attack_total++;
3120}
3121
3122
3123
3124void level::add_target(game_object *who)
3125{
3126  if (target_total>=target_list_size)  // see if we need to grow the list size..
3127  {
3128    target_list_size++;
3129    target_list=(game_object **)realloc(target_list,sizeof(game_object *)*target_list_size);
3130  }
3131  target_list[target_total]=who;
3132  target_total++;
3133}
3134
3135
3136
3137void level::add_block(game_object *who)
3138{
3139  if (block_total>=block_list_size)  // see if we need to grow the list size..
3140  {
3141    block_list_size++;
3142    block_list=(game_object **)realloc(block_list,sizeof(game_object *)*block_list_size);
3143  }
3144  block_list[block_total]=who;
3145  block_total++;
3146}
3147
3148
3149void level::add_all_block(game_object *who)
3150{
3151  if (all_block_total>=all_block_list_size)  // see if we need to grow the list size..
3152  {
3153    all_block_list_size++;
3154    all_block_list=(game_object **)realloc(all_block_list,sizeof(game_object *)*all_block_list_size);
3155  }
3156  all_block_list[all_block_total]=who;
3157  all_block_total++;
3158}
3159
3160
3161game_object *level::find_object_in_area(int32_t x, int32_t y, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
3162                     Cell *list, game_object *exclude)
3163{
3164  game_object *closest=NULL;
3165  int32_t closest_distance=0xfffffff,distance,xo,yo;
3166  game_object *o=first_active;
3167  for (; o; o=o->next_active)
3168  {
3169    int32_t xp1,yp1,xp2,yp2;
3170    o->picture_space(xp1,yp1,xp2,yp2);
3171
3172
3173    if (!(xp1>x2 || xp2<x1 || yp1>y2 || yp2<y1) && o!=exclude)
3174    {
3175      // check to see if the type is in the list
3176      Cell *v=list;
3177      for (; !NILP(v) && lnumber_value(CAR(v))!=o->otype; v=CDR(v));
3178      if (!NILP(v))
3179      {
3180    xo=abs(o->x-x);
3181    yo=abs(o->y-y);
3182    distance=xo*xo+yo*yo;
3183    if (distance<closest_distance)
3184    {
3185      closest_distance=distance;
3186      closest=o;
3187    }
3188      }
3189    }
3190  }
3191  return closest;
3192}
3193
3194
3195
3196
3197game_object *level::find_object_in_angle(int32_t x, int32_t y, int32_t start_angle, int32_t end_angle,
3198                    void *list, game_object *exclude)
3199{
3200  game_object *closest=NULL;
3201  int32_t closest_distance=0xfffffff,distance,xo,yo;
3202  game_object *o=first_active;
3203  for (; o; o=o->next_active)
3204  {
3205    int32_t angle=lisp_atan2(o->y-y,o->x-x);
3206    if (((start_angle<=end_angle && (angle>=start_angle && angle<=end_angle))
3207    || (start_angle>end_angle && (angle>=start_angle || angle<=end_angle)))
3208    && o!=exclude)
3209    {
3210      // check to see if the type is in the list
3211      Cell *v=(Cell *)list;
3212      for (; !NILP(v) && lnumber_value(CAR(v))!=o->otype; v=CDR(v));
3213      if (!NILP(v))
3214      {
3215    xo=abs(o->x-x);
3216    yo=abs(o->y-y);
3217    distance=xo*xo+yo*yo;
3218    if (distance<closest_distance)
3219    {
3220      closest_distance=distance;
3221      closest=o;
3222    }
3223      }
3224    }
3225  }
3226  return closest;
3227}
3228
3229
3230object_node *level::make_not_list(object_node *list)
3231{
3232  object_node *f=NULL,*l=NULL;
3233  game_object *o=first;
3234  for (; o; o=o->next)
3235  {
3236    if (!object_to_number_in_list(o,list))
3237    {
3238      object_node *q=new object_node(o,NULL);
3239      if (f)
3240        l->next=q;
3241      else f=q;
3242      l=q;
3243    }
3244  }
3245  return f;
3246}
3247
3248void level::write_object_info(char *filename)
3249{
3250  FILE *fp=open_FILE(filename,"wb");
3251  if (fp)
3252  {
3253    int i=0;
3254    game_object *o=first;
3255    for (; o; o=o->next)
3256    {
3257      fprintf(fp,"%3d %s %4ld %4ld %4ld %4ld %04d\n",i++,object_names[o->otype],(long)o->x,(long)o->y,
3258          (long)o->xvel(),(long)o->yvel(),o->current_frame);
3259    }
3260    fclose(fp);
3261  }
3262}
3263
3264
3265area_controller::area_controller(int32_t X, int32_t Y, int32_t W, int32_t H, area_controller *Next)
3266{
3267  x=X; y=Y; w=W; h=H;
3268  next=Next; active=0;
3269
3270  ambient=-1;
3271  view_xoff=-1;
3272  view_yoff=-1;
3273  ambient_speed=2;
3274  view_xoff_speed=4;
3275  view_yoff_speed=4;
3276}
Note: See TracBrowser for help on using the repository browser.