Fandom

Wikihack

Source:SLASH'EM 0.0.7E7F2/region.c

2,035pages on
this wiki
Add New Page
Talk0

Below is the full text to region.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/region.c#line123]], for example.

The latest source code for vanilla NetHack is at Source code.


The NetHack General Public License applies to screenshots, source code and other content from NetHack.
1.    /*	SCCS Id: @(#)region.c	3.4	2002/10/15	*/
2.    /* Copyright (c) 1996 by Jean-Christophe Collet	 */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
5.    #include "hack.h"
6.    #include "lev.h"
7.    
8.    /*
9.     * This should really go into the level structure, but
10.    * I'll start here for ease. It *WILL* move into the level
11.    * structure eventually.
12.    */
13.   
14.   static NhRegion **regions;
15.   static int n_regions = 0;
16.   static int max_regions = 0;
17.   
18.   #define NO_CALLBACK (-1)
19.   
20.   boolean FDECL(inside_gas_cloud, (genericptr,genericptr));
21.   boolean FDECL(expire_gas_cloud, (genericptr,genericptr));
22.   boolean FDECL(revive_cthulhu, (genericptr, genericptr));
23.   boolean FDECL(inside_rect, (NhRect *,int,int));
24.   boolean FDECL(inside_region, (NhRegion *,int,int));
25.   NhRegion *FDECL(create_region, (NhRect *,int));
26.   void FDECL(add_rect_to_reg, (NhRegion *,NhRect *));
27.   void FDECL(add_mon_to_reg, (NhRegion *,struct monst *));
28.   void FDECL(remove_mon_from_reg, (NhRegion *,struct monst *));
29.   boolean FDECL(mon_in_region, (NhRegion *,struct monst *));
30.   
31.   #if 0
32.   NhRegion *FDECL(clone_region, (NhRegion *));
33.   #endif
34.   void FDECL(free_region, (NhRegion *));
35.   void FDECL(add_region, (NhRegion *));
36.   void FDECL(remove_region, (NhRegion *));
37.   
38.   #if 0
39.   void FDECL(replace_mon_regions, (struct monst *,struct monst *));
40.   void FDECL(remove_mon_from_regions, (struct monst *));
41.   NhRegion *FDECL(create_msg_region, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,
42.   				    const char *,const char *));
43.   boolean FDECL(enter_force_field, (genericptr,genericptr));
44.   NhRegion *FDECL(create_force_field, (XCHAR_P,XCHAR_P,int,int));
45.   #endif
46.   
47.   static void FDECL(reset_region_mids, (NhRegion *));
48.   
49.   static callback_proc callbacks[] = {
50.   #define INSIDE_GAS_CLOUD 0
51.       inside_gas_cloud,
52.   #define EXPIRE_GAS_CLOUD 1
53.       expire_gas_cloud,
54.   #define REVIVE_CTHULHU 2	/* Cthulhu comes back... */
55.       revive_cthulhu
56.   };
57.   
58.   /* Should be inlined. */
59.   boolean
60.   inside_rect(r, x, y)
61.   NhRect *r;
62.   int x, y;
63.   {
64.       return (x >= r->lx && x <= r->hx && y >= r->ly && y <= r->hy);
65.   }
66.   
67.   /*
68.    * Check if a point is inside a region.
69.    */
70.   boolean
71.   inside_region(reg, x, y)
72.   NhRegion *reg;
73.   int x, y;
74.   {
75.       int i;
76.   
77.       if (reg == NULL || !inside_rect(&(reg->bounding_box), x, y))
78.   	return FALSE;
79.       for (i = 0; i < reg->nrects; i++)
80.   	if (inside_rect(&(reg->rects[i]), x, y))
81.   	    return TRUE;
82.       return FALSE;
83.   }
84.   
85.   /*
86.    * Create a region. It does not activate it.
87.    */
88.   NhRegion *
89.   create_region(rects, nrect)
90.   NhRect *rects;
91.   int nrect;
92.   {
93.       int i;
94.       NhRegion *reg;
95.   
96.       reg = (NhRegion *) alloc(sizeof (NhRegion));
97.       /* Determines bounding box */
98.       if (nrect > 0) {
99.   	reg->bounding_box = rects[0];
100.      } else {
101.  	reg->bounding_box.lx = 99;
102.  	reg->bounding_box.ly = 99;
103.  	reg->bounding_box.hx = 0;
104.  	reg->bounding_box.hy = 0;
105.      }
106.      reg->nrects = nrect;
107.      reg->rects = nrect > 0 ? (NhRect *)alloc((sizeof (NhRect)) * nrect) : NULL;
108.      for (i = 0; i < nrect; i++) {
109.  	if (rects[i].lx < reg->bounding_box.lx)
110.  	    reg->bounding_box.lx = rects[i].lx;
111.  	if (rects[i].ly < reg->bounding_box.ly)
112.  	    reg->bounding_box.ly = rects[i].ly;
113.  	if (rects[i].hx > reg->bounding_box.hx)
114.  	    reg->bounding_box.hx = rects[i].hx;
115.  	if (rects[i].hy > reg->bounding_box.hy)
116.  	    reg->bounding_box.hy = rects[i].hy;
117.  	reg->rects[i] = rects[i];
118.      }
119.      reg->ttl = -1;		/* Defaults */
120.      reg->attach_2_u = FALSE;
121.      reg->attach_2_m = 0;
122.      /* reg->attach_2_o = NULL; */
123.      reg->enter_msg = NULL;
124.      reg->leave_msg = NULL;
125.      reg->expire_f = NO_CALLBACK;
126.      reg->enter_f = NO_CALLBACK;
127.      reg->can_enter_f = NO_CALLBACK;
128.      reg->leave_f = NO_CALLBACK;
129.      reg->can_leave_f = NO_CALLBACK;
130.      reg->inside_f = NO_CALLBACK;
131.      clear_hero_inside(reg);
132.      clear_heros_fault(reg);
133.      reg->n_monst = 0;
134.      reg->max_monst = 0;
135.      reg->monsters = NULL;
136.      reg->arg = NULL;
137.      return reg;
138.  }
139.  
140.  /*
141.   * Add rectangle to region.
142.   */
143.  void
144.  add_rect_to_reg(reg, rect)
145.  NhRegion *reg;
146.  NhRect *rect;
147.  {
148.      NhRect *tmp_rect;
149.  
150.      tmp_rect = (NhRect *) alloc(sizeof (NhRect) * (reg->nrects + 1));
151.      if (reg->nrects > 0) {
152.  	(void) memcpy((genericptr_t) tmp_rect, (genericptr_t) reg->rects,
153.  		      (sizeof (NhRect) * reg->nrects));
154.  	free((genericptr_t) reg->rects);
155.      }
156.      tmp_rect[reg->nrects] = *rect;
157.      reg->nrects++;
158.      reg->rects = tmp_rect;
159.      /* Update bounding box if needed */
160.      if (reg->bounding_box.lx > rect->lx)
161.  	reg->bounding_box.lx = rect->lx;
162.      if (reg->bounding_box.ly > rect->ly)
163.  	reg->bounding_box.ly = rect->ly;
164.      if (reg->bounding_box.hx < rect->hx)
165.  	reg->bounding_box.hx = rect->hx;
166.      if (reg->bounding_box.hy < rect->hy)
167.  	reg->bounding_box.hy = rect->hy;
168.  }
169.  
170.  /*
171.   * Add a monster to the region
172.   */
173.  void
174.  add_mon_to_reg(reg, mon)
175.  NhRegion *reg;
176.  struct monst *mon;
177.  {
178.      int i;
179.      unsigned *tmp_m;
180.  
181.      if (reg->max_monst <= reg->n_monst) {
182.  	tmp_m = (unsigned *)
183.  		    alloc(sizeof (unsigned) * (reg->max_monst + MONST_INC));
184.  	if (reg->max_monst > 0) {
185.  	    for (i = 0; i < reg->max_monst; i++)
186.  		tmp_m[i] = reg->monsters[i];
187.  	    free((genericptr_t) reg->monsters);
188.  	}
189.  	reg->monsters = tmp_m;
190.  	reg->max_monst += MONST_INC;
191.      }
192.      reg->monsters[reg->n_monst++] = mon->m_id;
193.  }
194.  
195.  /*
196.   * Remove a monster from the region list (it left or died...)
197.   */
198.  void
199.  remove_mon_from_reg(reg, mon)
200.  NhRegion *reg;
201.  struct monst *mon;
202.  {
203.      register int i;
204.  
205.      for (i = 0; i < reg->n_monst; i++)
206.  	if (reg->monsters[i] == mon->m_id) {
207.  	    reg->n_monst--;
208.  	    reg->monsters[i] = reg->monsters[reg->n_monst];
209.  	    return;
210.  	}
211.  }
212.  
213.  /*
214.   * Check if a monster is inside the region.
215.   * It's probably quicker to check with the region internal list
216.   * than to check for coordinates.
217.   */
218.  boolean
219.  mon_in_region(reg, mon)
220.  NhRegion *reg;
221.  struct monst *mon;
222.  {
223.      int i;
224.  
225.      for (i = 0; i < reg->n_monst; i++)
226.  	if (reg->monsters[i] == mon->m_id)
227.  	    return TRUE;
228.      return FALSE;
229.  }
230.  
231.  #if 0
232.  /* not yet used */
233.  
234.  /*
235.   * Clone (make a standalone copy) the region.
236.   */
237.  NhRegion *
238.  clone_region(reg)
239.  NhRegion *reg;
240.  {
241.      NhRegion *ret_reg;
242.  
243.      ret_reg = create_region(reg->rects, reg->nrects);
244.      ret_reg->ttl = reg->ttl;
245.      ret_reg->attach_2_u = reg->attach_2_u;
246.      ret_reg->attach_2_m = reg->attach_2_m;
247.   /* ret_reg->attach_2_o = reg->attach_2_o; */
248.      ret_reg->expire_f = reg->expire_f;
249.      ret_reg->enter_f = reg->enter_f;
250.      ret_reg->can_enter_f = reg->can_enter_f;
251.      ret_reg->leave_f = reg->leave_f;
252.      ret_reg->can_leave_f = reg->can_leave_f;
253.      ret_reg->player_flags = reg->player_flags;	/* set/clear_hero_inside,&c*/
254.      ret_reg->n_monst = reg->n_monst;
255.      if (reg->n_monst > 0) {
256.  	ret_reg->monsters = (unsigned *)
257.  				alloc((sizeof (unsigned)) * reg->n_monst);
258.  	(void) memcpy((genericptr_t) ret_reg->monsters, (genericptr_t) reg->monsters,
259.  		      sizeof (unsigned) * reg->n_monst);
260.      } else
261.  	ret_reg->monsters = NULL;
262.      return ret_reg;
263.  }
264.  
265.  #endif	/*0*/
266.  
267.  /*
268.   * Free mem from region.
269.   */
270.  void
271.  free_region(reg)
272.  NhRegion *reg;
273.  {
274.      if (reg) {
275.  	if (reg->rects)
276.  	    free((genericptr_t) reg->rects);
277.  	if (reg->monsters)
278.  	    free((genericptr_t) reg->monsters);
279.  	free((genericptr_t) reg);
280.      }
281.  }
282.  
283.  /*
284.   * Add a region to the list.
285.   * This actually activates the region.
286.   */
287.  void
288.  add_region(reg)
289.  NhRegion *reg;
290.  {
291.      NhRegion **tmp_reg;
292.      int i, j;
293.  
294.      if (max_regions <= n_regions) {
295.  	tmp_reg = regions;
296.  	regions = (NhRegion **)alloc(sizeof (NhRegion *) * (max_regions + 10));
297.  	if (max_regions > 0) {
298.  	    (void) memcpy((genericptr_t) regions, (genericptr_t) tmp_reg,
299.  			  max_regions * sizeof (NhRegion *));
300.  	    free((genericptr_t) tmp_reg);
301.  	}
302.  	max_regions += 10;
303.      }
304.      regions[n_regions] = reg;
305.      n_regions++;
306.      /* Check for monsters inside the region */
307.      for (i = reg->bounding_box.lx; i <= reg->bounding_box.hx; i++)
308.  	for (j = reg->bounding_box.ly; j <= reg->bounding_box.hy; j++) {
309.  	    /* Some regions can cross the level boundaries */
310.  	    if (!isok(i,j))
311.  		continue;
312.  	    if (MON_AT(i, j) && inside_region(reg, i, j))
313.  		add_mon_to_reg(reg, level.monsters[i][j]);
314.  	    if (reg->visible && cansee(i, j))
315.  		newsym(i, j);
316.  	}
317.      /* Check for player now... */
318.      if (inside_region(reg, u.ux, u.uy)) 
319.  	set_hero_inside(reg);
320.      else
321.  	clear_hero_inside(reg);
322.  }
323.  
324.  /*
325.   * Remove a region from the list & free it.
326.   */
327.  void
328.  remove_region(reg)
329.  NhRegion *reg;
330.  {
331.      register int i, x, y;
332.  
333.      for (i = 0; i < n_regions; i++)
334.  	if (regions[i] == reg)
335.  	    break;
336.      if (i == n_regions)
337.  	return;
338.  
339.      /* Update screen if necessary */
340.      if (reg->visible)
341.  	for (x = reg->bounding_box.lx; x <= reg->bounding_box.hx; x++)
342.  	    for (y = reg->bounding_box.ly; y <= reg->bounding_box.hy; y++)
343.  		if (isok(x,y) && inside_region(reg, x, y) && cansee(x, y))
344.  		    newsym(x, y);
345.  
346.      free_region(reg);
347.      regions[i] = regions[n_regions - 1];
348.      regions[n_regions - 1] = (NhRegion *) 0;
349.      n_regions--;
350.  }
351.  
352.  /*
353.   * Remove all regions and clear all related data (This must be down
354.   * when changing level, for instance).
355.   */
356.  void
357.  clear_regions()
358.  {
359.      register int i;
360.  
361.      for (i = 0; i < n_regions; i++)
362.  	free_region(regions[i]);
363.      n_regions = 0;
364.      if (max_regions > 0)
365.  	free((genericptr_t) regions);
366.      max_regions = 0;
367.      regions = NULL;
368.  }
369.  
370.  /*
371.   * This function is called every turn.
372.   * It makes the regions age, if necessary and calls the appropriate
373.   * callbacks when needed.
374.   */
375.  void
376.  run_regions()
377.  {
378.      register int i, j, k;
379.      int f_indx;
380.  
381.      /* End of life ? */
382.      /* Do it backward because the array will be modified */
383.      for (i = n_regions - 1; i >= 0; i--) {
384.  	if (regions[i]->ttl == 0) {
385.  	    if ((f_indx = regions[i]->expire_f) == NO_CALLBACK ||
386.  		(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
387.  		remove_region(regions[i]);
388.  	}
389.      }
390.  
391.      /* Process remaining regions */
392.      for (i = 0; i < n_regions; i++) {
393.  	/* Make the region age */
394.  	if (regions[i]->ttl > 0)
395.  	    regions[i]->ttl--;
396.  	/* Check if player is inside region */
397.  	f_indx = regions[i]->inside_f;
398.  	if (f_indx != NO_CALLBACK && hero_inside(regions[i]))
399.  	    (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
400.  	/* Check if any monster is inside region */
401.  	if (f_indx != NO_CALLBACK) {
402.  	    for (j = 0; j < regions[i]->n_monst; j++) {
403.  		struct monst *mtmp = find_mid(regions[i]->monsters[j], FM_FMON);
404.  
405.  		if (!mtmp || mtmp->mhp <= 0 ||
406.  				(*callbacks[f_indx])(regions[i], mtmp)) {
407.  		    /* The monster died, remove it from list */
408.  		    k = (regions[i]->n_monst -= 1);
409.  		    regions[i]->monsters[j] = regions[i]->monsters[k];
410.  		    regions[i]->monsters[k] = 0;
411.  		    --j;    /* current slot has been reused; recheck it next */
412.  		}
413.  	    }
414.  	}
415.      }
416.  }
417.  
418.  /*
419.   * check whether player enters/leaves one or more regions.
420.   */
421.  boolean
422.  in_out_region(x, y)
423.  xchar
424.      x, y;
425.  {
426.      int i, f_indx;
427.  
428.      /* First check if we can do the move */
429.      for (i = 0; i < n_regions; i++) {
430.  	if (inside_region(regions[i], x, y)
431.  	    && !hero_inside(regions[i]) && !regions[i]->attach_2_u) {
432.  	    if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK)
433.  		if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
434.  		    return FALSE;
435.  	} else
436.  	    if (hero_inside(regions[i])
437.  		&& !inside_region(regions[i], x, y)
438.  		&& !regions[i]->attach_2_u) {
439.  	    if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK)
440.  		if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
441.  		    return FALSE;
442.  	}
443.      }
444.  
445.      /* Callbacks for the regions we do leave */
446.      for (i = 0; i < n_regions; i++)
447.  	if (hero_inside(regions[i]) &&
448.  		!regions[i]->attach_2_u && !inside_region(regions[i], x, y)) {
449.  	    clear_hero_inside(regions[i]);
450.  	    if (regions[i]->leave_msg != NULL)
451.  		pline(regions[i]->leave_msg);
452.  	    if ((f_indx = regions[i]->leave_f) != NO_CALLBACK)
453.  		(void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
454.  	}
455.  
456.      /* Callbacks for the regions we do enter */
457.      for (i = 0; i < n_regions; i++)
458.  	if (!hero_inside(regions[i]) &&
459.  		!regions[i]->attach_2_u && inside_region(regions[i], x, y)) {
460.  	    set_hero_inside(regions[i]);
461.  	    if (regions[i]->enter_msg != NULL)
462.  		pline(regions[i]->enter_msg);
463.  	    if ((f_indx = regions[i]->enter_f) != NO_CALLBACK)
464.  		(void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
465.  	}
466.      return TRUE;
467.  }
468.  
469.  /*
470.   * check wether a monster enters/leaves one or more region.
471.  */
472.  boolean
473.  m_in_out_region(mon, x, y)
474.  struct monst *mon;
475.  xchar x, y;
476.  {
477.      int i, f_indx;
478.  
479.      /* First check if we can do the move */
480.      for (i = 0; i < n_regions; i++) {
481.  	if (inside_region(regions[i], x, y) &&
482.  		!mon_in_region(regions[i], mon) &&
483.  		regions[i]->attach_2_m != mon->m_id) {
484.  	    if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK)
485.  		if (!(*callbacks[f_indx])(regions[i], mon))
486.  		    return FALSE;
487.  	} else if (mon_in_region(regions[i], mon) &&
488.  		!inside_region(regions[i], x, y) &&
489.  		regions[i]->attach_2_m != mon->m_id) {
490.  	    if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK)
491.  		if (!(*callbacks[f_indx])(regions[i], mon))
492.  		    return FALSE;
493.  	}
494.      }
495.  
496.      /* Callbacks for the regions we do leave */
497.      for (i = 0; i < n_regions; i++)
498.  	if (mon_in_region(regions[i], mon) &&
499.  		regions[i]->attach_2_m != mon->m_id &&
500.  		!inside_region(regions[i], x, y)) {
501.  	    remove_mon_from_reg(regions[i], mon);
502.  	    if ((f_indx = regions[i]->leave_f) != NO_CALLBACK)
503.  		(void) (*callbacks[f_indx])(regions[i], mon);
504.  	}
505.  
506.      /* Callbacks for the regions we do enter */
507.      for (i = 0; i < n_regions; i++)
508.  	if (!hero_inside(regions[i]) &&
509.  		!regions[i]->attach_2_u && inside_region(regions[i], x, y)) {
510.  	    add_mon_to_reg(regions[i], mon);
511.  	    if ((f_indx = regions[i]->enter_f) != NO_CALLBACK)
512.  		(void) (*callbacks[f_indx])(regions[i], mon);
513.  	}
514.      return TRUE;
515.  }
516.  
517.  /*
518.   * Checks player's regions after a teleport for instance.
519.   */
520.  void
521.  update_player_regions()
522.  {
523.      register int i;
524.  
525.      for (i = 0; i < n_regions; i++)
526.  	if (!regions[i]->attach_2_u && inside_region(regions[i], u.ux, u.uy))
527.  	    set_hero_inside(regions[i]);
528.  	else
529.  	    clear_hero_inside(regions[i]);
530.  }
531.  
532.  /*
533.   * Ditto for a specified monster.
534.   */
535.  void
536.  update_monster_region(mon)
537.  struct monst *mon;
538.  {
539.      register int i;
540.  
541.      for (i = 0; i < n_regions; i++) {
542.  	if (inside_region(regions[i], mon->mx, mon->my)) {
543.  	    if (!mon_in_region(regions[i], mon))
544.  		add_mon_to_reg(regions[i], mon);
545.  	} else {
546.  	    if (mon_in_region(regions[i], mon))
547.  		remove_mon_from_reg(regions[i], mon);
548.  	}
549.      }
550.  }
551.  
552.  #if 0
553.  /* not yet used */
554.  
555.  /*
556.   * Change monster pointer in regions
557.   * This happens, for instance, when a monster grows and
558.   * need a new structure (internally that is).
559.   */
560.  void
561.  replace_mon_regions(monold, monnew)
562.  struct monst *monold, *monnew;
563.  {
564.      register int i;
565.  
566.      for (i = 0; i < n_regions; i++)
567.  	if (mon_in_region(regions[i], monold)) {
568.  	    remove_mon_from_reg(regions[i], monold);
569.  	    add_mon_to_reg(regions[i], monnew);
570.  	}
571.  }
572.  
573.  /*
574.   * Remove monster from all regions it was in (ie monster just died)
575.   */
576.  void
577.  remove_mon_from_regions(mon)
578.  struct monst *mon;
579.  {
580.      register int i;
581.  
582.      for (i = 0; i < n_regions; i++)
583.  	if (mon_in_region(regions[i], mon))
584.  	    remove_mon_from_reg(regions[i], mon);
585.  }
586.  
587.  #endif	/*0*/
588.  
589.  /*
590.   * Check if a spot is under a visible region (eg: gas cloud).
591.   * Returns NULL if not, otherwise returns region.
592.   */
593.  NhRegion *
594.  visible_region_at(x, y)
595.  xchar x, y;
596.  {
597.      register int i;
598.  
599.      for (i = 0; i < n_regions; i++)
600.  	if (inside_region(regions[i], x, y) && regions[i]->visible &&
601.  		regions[i]->ttl != 0)
602.  	    return regions[i];
603.      return (NhRegion *) 0;
604.  }
605.  
606.  void
607.  show_region(reg, x, y)
608.  NhRegion *reg;
609.  xchar x, y;
610.  {
611.      show_glyph(x, y, reg->glyph);
612.  }
613.  
614.  /**
615.   * save_regions :
616.   */
617.  void
618.  save_regions(fd, mode)
619.  int fd;
620.  int mode;
621.  {
622.      int i, j;
623.      unsigned n;
624.  
625.      if (!perform_bwrite(mode)) goto skip_lots;
626.  
627.      bwrite(fd, (genericptr_t) &moves, sizeof (moves));	/* timestamp */
628.      bwrite(fd, (genericptr_t) &n_regions, sizeof (n_regions));
629.      for (i = 0; i < n_regions; i++) {
630.  	bwrite(fd, (genericptr_t) &regions[i]->bounding_box, sizeof (NhRect));
631.  	bwrite(fd, (genericptr_t) &regions[i]->nrects, sizeof (short));
632.  	for (j = 0; j < regions[i]->nrects; j++)
633.  	    bwrite(fd, (genericptr_t) &regions[i]->rects[j], sizeof (NhRect));
634.  	bwrite(fd, (genericptr_t) &regions[i]->attach_2_u, sizeof (boolean));
635.  	n = 0;
636.  	bwrite(fd, (genericptr_t) &regions[i]->attach_2_m, sizeof (unsigned));
637.  	n = regions[i]->enter_msg != NULL ? strlen(regions[i]->enter_msg) : 0;
638.  	bwrite(fd, (genericptr_t) &n, sizeof n);
639.  	if (n > 0)
640.  	    bwrite(fd, (genericptr_t) regions[i]->enter_msg, n);
641.  	n = regions[i]->leave_msg != NULL ? strlen(regions[i]->leave_msg) : 0;
642.  	bwrite(fd, (genericptr_t) &n, sizeof n);
643.  	if (n > 0)
644.  	    bwrite(fd, (genericptr_t) regions[i]->leave_msg, n);
645.  	bwrite(fd, (genericptr_t) &regions[i]->ttl, sizeof (short));
646.  	bwrite(fd, (genericptr_t) &regions[i]->expire_f, sizeof (short));
647.  	bwrite(fd, (genericptr_t) &regions[i]->can_enter_f, sizeof (short));
648.  	bwrite(fd, (genericptr_t) &regions[i]->enter_f, sizeof (short));
649.  	bwrite(fd, (genericptr_t) &regions[i]->can_leave_f, sizeof (short));
650.  	bwrite(fd, (genericptr_t) &regions[i]->leave_f, sizeof (short));
651.  	bwrite(fd, (genericptr_t) &regions[i]->inside_f, sizeof (short));
652.  	bwrite(fd, (genericptr_t) &regions[i]->player_flags, sizeof (boolean));
653.  	bwrite(fd, (genericptr_t) &regions[i]->n_monst, sizeof (short));
654.  	for (j = 0; j < regions[i]->n_monst; j++)
655.  	    bwrite(fd, (genericptr_t) &regions[i]->monsters[j],
656.  	     sizeof (unsigned));
657.  	bwrite(fd, (genericptr_t) &regions[i]->visible, sizeof (boolean));
658.  	bwrite(fd, (genericptr_t) &regions[i]->glyph, sizeof (int));
659.  	bwrite(fd, (genericptr_t) &regions[i]->arg, sizeof (genericptr_t));
660.      }
661.  
662.  skip_lots:
663.      if (release_data(mode))
664.  	clear_regions();
665.  }
666.  
667.  void
668.  rest_regions(fd, ghostly)
669.  int fd;
670.  boolean ghostly; /* If a bones file restore */
671.  {
672.      int i, j;
673.      unsigned n;
674.      long tmstamp;
675.      char *msg_buf;
676.  
677.      clear_regions();		/* Just for security */
678.      mread(fd, (genericptr_t) &tmstamp, sizeof (tmstamp));
679.      if (ghostly) tmstamp = 0;
680.      else tmstamp = (moves - tmstamp);
681.      mread(fd, (genericptr_t) &n_regions, sizeof (n_regions));
682.      max_regions = n_regions;
683.      if (n_regions > 0)
684.  	regions = (NhRegion **) alloc(sizeof (NhRegion *) * n_regions);
685.      for (i = 0; i < n_regions; i++) {
686.  	regions[i] = (NhRegion *) alloc(sizeof (NhRegion));
687.  	mread(fd, (genericptr_t) &regions[i]->bounding_box, sizeof (NhRect));
688.  	mread(fd, (genericptr_t) &regions[i]->nrects, sizeof (short));
689.  
690.  	if (regions[i]->nrects > 0)
691.  	    regions[i]->rects = (NhRect *)
692.  				  alloc(sizeof (NhRect) * regions[i]->nrects);
693.  	for (j = 0; j < regions[i]->nrects; j++)
694.  	    mread(fd, (genericptr_t) &regions[i]->rects[j], sizeof (NhRect));
695.  	mread(fd, (genericptr_t) &regions[i]->attach_2_u, sizeof (boolean));
696.  	mread(fd, (genericptr_t) &regions[i]->attach_2_m, sizeof (unsigned));
697.  
698.  	mread(fd, (genericptr_t) &n, sizeof n);
699.  	if (n > 0) {
700.  	    msg_buf = (char *) alloc(n + 1);
701.  	    mread(fd, (genericptr_t) msg_buf, n);
702.  	    msg_buf[n] = '\0';
703.  	    regions[i]->enter_msg = (const char *) msg_buf;
704.  	} else
705.  	    regions[i]->enter_msg = NULL;
706.  
707.  	mread(fd, (genericptr_t) &n, sizeof n);
708.  	if (n > 0) {
709.  	    msg_buf = (char *) alloc(n + 1);
710.  	    mread(fd, (genericptr_t) msg_buf, n);
711.  	    msg_buf[n] = '\0';
712.  	    regions[i]->leave_msg = (const char *) msg_buf;
713.  	} else
714.  	    regions[i]->leave_msg = NULL;
715.  
716.  	mread(fd, (genericptr_t) &regions[i]->ttl, sizeof (short));
717.  	/* check for expired region */
718.  	if (regions[i]->ttl >= 0)
719.  	    regions[i]->ttl =
720.  		(regions[i]->ttl > tmstamp) ? regions[i]->ttl - tmstamp : 0;
721.  	mread(fd, (genericptr_t) &regions[i]->expire_f, sizeof (short));
722.  	mread(fd, (genericptr_t) &regions[i]->can_enter_f, sizeof (short));
723.  	mread(fd, (genericptr_t) &regions[i]->enter_f, sizeof (short));
724.  	mread(fd, (genericptr_t) &regions[i]->can_leave_f, sizeof (short));
725.  	mread(fd, (genericptr_t) &regions[i]->leave_f, sizeof (short));
726.  	mread(fd, (genericptr_t) &regions[i]->inside_f, sizeof (short));
727.  	mread(fd, (genericptr_t) &regions[i]->player_flags, sizeof (boolean));
728.  	if (ghostly) {	/* settings pertained to old player */
729.  	    clear_hero_inside(regions[i]);
730.  	    clear_heros_fault(regions[i]);
731.  	}
732.  	mread(fd, (genericptr_t) &regions[i]->n_monst, sizeof (short));
733.  	if (regions[i]->n_monst > 0)
734.  	    regions[i]->monsters =
735.  		(unsigned *) alloc(sizeof (unsigned) * regions[i]->n_monst);
736.  	else
737.  	    regions[i]->monsters = NULL;
738.  	regions[i]->max_monst = regions[i]->n_monst;
739.  	for (j = 0; j < regions[i]->n_monst; j++)
740.  	    mread(fd, (genericptr_t) &regions[i]->monsters[j],
741.  		  sizeof (unsigned));
742.  	mread(fd, (genericptr_t) &regions[i]->visible, sizeof (boolean));
743.  	mread(fd, (genericptr_t) &regions[i]->glyph, sizeof (int));
744.  	mread(fd, (genericptr_t) &regions[i]->arg, sizeof (genericptr_t));
745.      }
746.      /* remove expired regions, do not trigger the expire_f callback (yet!);
747.         also update monster lists if this data is coming from a bones file */
748.      for (i = n_regions - 1; i >= 0; i--)
749.  	if (regions[i]->ttl == 0)
750.  	    remove_region(regions[i]);
751.  	else if (ghostly && regions[i]->n_monst > 0)
752.  	    reset_region_mids(regions[i]);
753.  }
754.  
755.  /* update monster IDs for region being loaded from bones; `ghostly' implied */
756.  static void
757.  reset_region_mids(reg)
758.  NhRegion *reg;
759.  {
760.      int i = 0, n = reg->n_monst;
761.      unsigned *mid_list = reg->monsters;
762.  
763.      while (i < n)
764.  	if (!lookup_id_mapping(mid_list[i], &mid_list[i])) {
765.  	    /* shrink list to remove missing monster; order doesn't matter */
766.  	    mid_list[i] = mid_list[--n];
767.  	} else {
768.  	    /* move on to next monster */
769.  	    ++i;
770.  	}
771.      reg->n_monst = n;
772.      return;
773.  }
774.  
775.  #if 0
776.  /* not yet used */
777.  
778.  /*--------------------------------------------------------------*
779.   *								*
780.   *			Create Region with just a message	*
781.   *								*
782.   *--------------------------------------------------------------*/
783.  
784.  NhRegion *
785.  create_msg_region(x, y, w, h, msg_enter, msg_leave)
786.  xchar x, y;
787.  xchar w, h;
788.  const char *msg_enter;
789.  const char *msg_leave;
790.  {
791.      NhRect tmprect;
792.      NhRegion *reg = create_region((NhRect *) 0, 0);
793.  
794.      reg->enter_msg = msg_enter;
795.      reg->leave_msg = msg_leave;
796.      tmprect.lx = x;
797.      tmprect.ly = y;
798.      tmprect.hx = x + w;
799.      tmprect.hy = y + h;
800.      add_rect_to_reg(reg, &tmprect);
801.      reg->ttl = -1;
802.      return reg;
803.  }
804.  
805.  
806.  /*--------------------------------------------------------------*
807.   *								*
808.   *			Force Field Related Code		*
809.   *			(unused yet)				*
810.   *--------------------------------------------------------------*/
811.  
812.  boolean
813.  enter_force_field(p1, p2)
814.  genericptr_t p1;
815.  genericptr_t p2;
816.  {
817.      struct monst *mtmp;
818.  
819.      if (p2 == NULL) {		/* That means the player */
820.  	if (!Blind)
821.  		You("bump into %s. Ouch!",
822.  		    Hallucination ? "an invisible tree" :
823.  			"some kind of invisible wall");
824.  	else
825.  	    pline("Ouch!");
826.      } else {
827.  	mtmp = (struct monst *) p2;
828.  	if (canseemon(mtmp))
829.  	    pline("%s bumps into %s!", Monnam(mtmp), something);
830.      }
831.      return FALSE;
832.  }
833.  
834.  NhRegion *
835.  create_force_field(x, y, radius, ttl)
836.  xchar x, y;
837.  int radius, ttl;
838.  {
839.      int i;
840.      NhRegion *ff;
841.      int nrect;
842.      NhRect tmprect;
843.  
844.      ff = create_region((NhRect *) 0, 0);
845.      nrect = radius;
846.      tmprect.lx = x;
847.      tmprect.hx = x;
848.      tmprect.ly = y - (radius - 1);
849.      tmprect.hy = y + (radius - 1);
850.      for (i = 0; i < nrect; i++) {
851.  	add_rect_to_reg(ff, &tmprect);
852.  	tmprect.lx--;
853.  	tmprect.hx++;
854.  	tmprect.ly++;
855.  	tmprect.hy--;
856.      }
857.      ff->ttl = ttl;
858.      if (!in_mklev && !flags.mon_moving)
859.  	set_heros_fault(ff);		/* assume player has created it */
860.   /* ff->can_enter_f = enter_force_field; */
861.   /* ff->can_leave_f = enter_force_field; */
862.      add_region(ff);
863.      return ff;
864.  }
865.  
866.  #endif	/*0*/
867.  
868.  /*--------------------------------------------------------------*
869.   *								*
870.   *			Gas cloud related code			*
871.   *								*
872.   *--------------------------------------------------------------*/
873.  
874.  /*
875.   * Here is an example of an expire function that may prolong
876.   * region life after some mods...
877.   */
878.  boolean
879.  expire_gas_cloud(p1, p2)
880.  genericptr_t p1;
881.  genericptr_t p2;
882.  {
883.      NhRegion *reg;
884.      int damage;
885.  
886.      reg = (NhRegion *) p1;
887.      damage = (int) reg->arg;
888.  
889.      /* If it was a thick cloud, it dissipates a little first */
890.      if (damage >= 5) {
891.  	damage /= 2;		/* It dissipates, let's do less damage */
892.  	reg->arg = (genericptr_t) damage;
893.  	reg->ttl = 2;		/* Here's the trick : reset ttl */
894.  	return FALSE;		/* THEN return FALSE, means "still there" */
895.      }
896.      return TRUE;		/* OK, it's gone, you can free it! */
897.  }
898.  
899.  boolean
900.  revive_cthulhu(p1, p2)
901.  genericptr_t p1;
902.  genericptr_t p2;
903.  {
904.      boolean ret = expire_gas_cloud(p1, p2);
905.      if (ret) {
906.  	/* Bring back Cthulhu! */
907.  	int cx, cy;
908.  	NhRegion *reg = (NhRegion *) p1;
909.  	struct monst *cthulhu = NULL;
910.  	coord cc;
911.  	
912.  	cx = (reg->bounding_box.lx + reg->bounding_box.hx) / 2;
913.  	cy = (reg->bounding_box.ly + reg->bounding_box.hy) / 2;
914.  
915.  	if (enexto(&cc, cx, cy, &mons[PM_CTHULHU])) {
916.  	    cx = cc.x;
917.  	    cy = cc.y;
918.  	} else {
919.  	    cx = cy = 0;	/* Place Cthulhu randomly */
920.  	}
921.  
922.  	/* Make sure Cthulhu doesn't get the Amulet again! :-) */
923.  	cthulhu = makemon(&mons[PM_CTHULHU], cx, cy, 
924.  				MM_NOCOUNTBIRTH | NO_MINVENT);
925.  	if (cthulhu && canseemon(cthulhu))
926.  	    pline("%s reforms!", Monnam(cthulhu));
927.      }
928.      return ret;
929.  }
930.  
931.  boolean
932.  inside_gas_cloud(p1, p2)
933.  genericptr_t p1;
934.  genericptr_t p2;
935.  {
936.      NhRegion *reg;
937.      struct monst *mtmp;
938.      int dam;
939.  
940.      reg = (NhRegion *) p1;
941.      dam = (int) reg->arg;
942.      if (p2 == NULL) {		/* This means *YOU* Bozo! */
943.  	if (nonliving(youmonst.data) || Breathless)
944.  	    return FALSE;
945.  	if (!Blind)
946.  	    make_blinded(1L, FALSE);
947.  	if (!Poison_resistance) {
948.  	    pline("%s is burning your %s!", Something, makeplural(body_part(LUNG)));
949.  	    You("cough and spit blood!");
950.  	    losehp(rnd(dam) + 5, "gas cloud", KILLED_BY_AN);
951.  	    return FALSE;
952.  	} else {
953.  	    You("cough!");
954.  	    return FALSE;
955.  	}
956.      } else {			/* A monster is inside the cloud */
957.  	mtmp = (struct monst *) p2;
958.  
959.  	/* Non living and non breathing monsters are not concerned */
960.  	if (!nonliving(mtmp->data) && !breathless(mtmp->data)) {
961.  	    if (cansee(mtmp->mx, mtmp->my))
962.  		pline("%s coughs!", Monnam(mtmp));
963.  	    if (heros_fault(reg))
964.  	    	setmangry(mtmp);
965.  	    if (haseyes(mtmp->data) && mtmp->mcansee) {
966.  		mtmp->mblinded = 1;
967.  		mtmp->mcansee = 0;
968.  	    }
969.  	    if (resists_poison(mtmp))
970.  		return FALSE;
971.  	    mtmp->mhp -= rnd(dam) + 5;
972.  	    if (mtmp->mhp <= 0) {
973.  		if (heros_fault(reg))
974.  		    killed(mtmp);
975.  		else
976.  		    monkilled(mtmp, "gas cloud", AD_DRST);
977.  		if (mtmp->mhp <= 0) {	/* not lifesaved */
978.  		    return TRUE;
979.  		}
980.  	    }
981.  	}
982.      }
983.      return FALSE;		/* Monster is still alive */
984.  }
985.  
986.  NhRegion *
987.  create_cthulhu_death_cloud(x, y, radius, damage)
988.  xchar x, y;
989.  int radius;
990.  int damage;
991.  {
992.      NhRegion *cloud;
993.  
994.      cloud = create_gas_cloud(x, y, radius, damage);
995.      if (cloud) cloud->expire_f = REVIVE_CTHULHU;
996.  
997.      return cloud;
998.  }
999.  
1000. NhRegion *
1001. create_gas_cloud(x, y, radius, damage)
1002. xchar x, y;
1003. int radius;
1004. int damage;
1005. {
1006.     NhRegion *cloud;
1007.     int i, nrect;
1008.     NhRect tmprect;
1009. 
1010.     cloud = create_region((NhRect *) 0, 0);
1011.     nrect = radius;
1012.     tmprect.lx = x;
1013.     tmprect.hx = x;
1014.     tmprect.ly = y - (radius - 1);
1015.     tmprect.hy = y + (radius - 1);
1016.     for (i = 0; i < nrect; i++) {
1017. 	add_rect_to_reg(cloud, &tmprect);
1018. 	tmprect.lx--;
1019. 	tmprect.hx++;
1020. 	tmprect.ly++;
1021. 	tmprect.hy--;
1022.     }
1023.     cloud->ttl = rn1(3,4);
1024.     if (!in_mklev && !flags.mon_moving)
1025. 	set_heros_fault(cloud);		/* assume player has created it */
1026.     cloud->inside_f = INSIDE_GAS_CLOUD;
1027.     cloud->expire_f = EXPIRE_GAS_CLOUD;
1028.     cloud->arg = (genericptr_t) damage;
1029.     cloud->visible = TRUE;
1030.     cloud->glyph = cmap_to_glyph(S_cloud);
1031.     add_region(cloud);
1032.     return cloud;
1033. }
1034. 
1035. /*region.c*/

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.