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

Last change on this file since 481 was 481, checked in by Sam Hocevar, 7 years ago

Fuck the history, I'm renaming all .hpp files to .h for my own sanity.

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