Wikihack
Advertisement

Below is the full text to src/region.c from NetHack 3.4.3. To link to a particular line, write [[region.c#line123]], for example.

Top of file[]

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.    
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
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(inside_rect, (NhRect *,int,int));
23.   boolean FDECL(inside_region, (NhRegion *,int,int));
24.   NhRegion *FDECL(create_region, (NhRect *,int));
25.   void FDECL(add_rect_to_reg, (NhRegion *,NhRect *));
26.   void FDECL(add_mon_to_reg, (NhRegion *,struct monst *));
27.   void FDECL(remove_mon_from_reg, (NhRegion *,struct monst *));
28.   boolean FDECL(mon_in_region, (NhRegion *,struct monst *));
29.   
30.   #if 0
31.   NhRegion *FDECL(clone_region, (NhRegion *));
32.   #endif
33.   void FDECL(free_region, (NhRegion *));
34.   void FDECL(add_region, (NhRegion *));
35.   void FDECL(remove_region, (NhRegion *));
36.   
37.   #if 0
38.   void FDECL(replace_mon_regions, (struct monst *,struct monst *));
39.   void FDECL(remove_mon_from_regions, (struct monst *));
40.   NhRegion *FDECL(create_msg_region, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,
41.   				    const char *,const char *));
42.   boolean FDECL(enter_force_field, (genericptr,genericptr));
43.   NhRegion *FDECL(create_force_field, (XCHAR_P,XCHAR_P,int,int));
44.   #endif
45.   
46.   static void FDECL(reset_region_mids, (NhRegion *));
47.   
48.   static callback_proc callbacks[] = {
49.   #define INSIDE_GAS_CLOUD 0
50.       inside_gas_cloud,
51.   #define EXPIRE_GAS_CLOUD 1
52.       expire_gas_cloud
53.   };
54.   

inside_rect[]

55.   /* Should be inlined. */
56.   boolean
57.   inside_rect(r, x, y)
58.   NhRect *r;
59.   int x, y;
60.   {
61.       return (x >= r->lx && x <= r->hx && y >= r->ly && y <= r->hy);
62.   }
63.   

inside_region[]

64.   /*
65.    * Check if a point is inside a region.
66.    */
67.   boolean
68.   inside_region(reg, x, y)
69.   NhRegion *reg;
70.   int x, y;
71.   {
72.       int i;
73.   
74.       if (reg == NULL || !inside_rect(&(reg->bounding_box), x, y))
75.   	return FALSE;
76.       for (i = 0; i < reg->nrects; i++)
77.   	if (inside_rect(&(reg->rects[i]), x, y))
78.   	    return TRUE;
79.       return FALSE;
80.   }
81.   

create_region[]

82.   /*
83.    * Create a region. It does not activate it.
84.    */
85.   NhRegion *
86.   create_region(rects, nrect)
87.   NhRect *rects;
88.   int nrect;
89.   {
90.       int i;
91.       NhRegion *reg;
92.   
93.       reg = (NhRegion *) alloc(sizeof (NhRegion));
94.       /* Determines bounding box */
95.       if (nrect > 0) {
96.   	reg->bounding_box = rects[0];
97.       } else {
98.   	reg->bounding_box.lx = 99;
99.   	reg->bounding_box.ly = 99;
100.  	reg->bounding_box.hx = 0;
101.  	reg->bounding_box.hy = 0;
102.      }
103.      reg->nrects = nrect;
104.      reg->rects = nrect > 0 ? (NhRect *)alloc((sizeof (NhRect)) * nrect) : NULL;
105.      for (i = 0; i < nrect; i++) {
106.  	if (rects[i].lx < reg->bounding_box.lx)
107.  	    reg->bounding_box.lx = rects[i].lx;
108.  	if (rects[i].ly < reg->bounding_box.ly)
109.  	    reg->bounding_box.ly = rects[i].ly;
110.  	if (rects[i].hx > reg->bounding_box.hx)
111.  	    reg->bounding_box.hx = rects[i].hx;
112.  	if (rects[i].hy > reg->bounding_box.hy)
113.  	    reg->bounding_box.hy = rects[i].hy;
114.  	reg->rects[i] = rects[i];
115.      }
116.      reg->ttl = -1;		/* Defaults */
117.      reg->attach_2_u = FALSE;
118.      reg->attach_2_m = 0;
119.      /* reg->attach_2_o = NULL; */
120.      reg->enter_msg = NULL;
121.      reg->leave_msg = NULL;
122.      reg->expire_f = NO_CALLBACK;
123.      reg->enter_f = NO_CALLBACK;
124.      reg->can_enter_f = NO_CALLBACK;
125.      reg->leave_f = NO_CALLBACK;
126.      reg->can_leave_f = NO_CALLBACK;
127.      reg->inside_f = NO_CALLBACK;
128.      clear_hero_inside(reg);
129.      clear_heros_fault(reg);
130.      reg->n_monst = 0;
131.      reg->max_monst = 0;
132.      reg->monsters = NULL;
133.      reg->arg = NULL;
134.      return reg;
135.  }
136.  

add_rect_to_reg[]

137.  /*
138.   * Add rectangle to region.
139.   */
140.  void
141.  add_rect_to_reg(reg, rect)
142.  NhRegion *reg;
143.  NhRect *rect;
144.  {
145.      NhRect *tmp_rect;
146.  
147.      tmp_rect = (NhRect *) alloc(sizeof (NhRect) * (reg->nrects + 1));
148.      if (reg->nrects > 0) {
149.  	(void) memcpy((genericptr_t) tmp_rect, (genericptr_t) reg->rects,
150.  		      (sizeof (NhRect) * reg->nrects));
151.  	free((genericptr_t) reg->rects);
152.      }
153.      tmp_rect[reg->nrects] = *rect;
154.      reg->nrects++;
155.      reg->rects = tmp_rect;
156.      /* Update bounding box if needed */
157.      if (reg->bounding_box.lx > rect->lx)
158.  	reg->bounding_box.lx = rect->lx;
159.      if (reg->bounding_box.ly > rect->ly)
160.  	reg->bounding_box.ly = rect->ly;
161.      if (reg->bounding_box.hx < rect->hx)
162.  	reg->bounding_box.hx = rect->hx;
163.      if (reg->bounding_box.hy < rect->hy)
164.  	reg->bounding_box.hy = rect->hy;
165.  }
166.  

add_mon_to_reg[]

167.  /*
168.   * Add a monster to the region
169.   */
170.  void
171.  add_mon_to_reg(reg, mon)
172.  NhRegion *reg;
173.  struct monst *mon;
174.  {
175.      int i;
176.      unsigned *tmp_m;
177.  
178.      if (reg->max_monst <= reg->n_monst) {
179.  	tmp_m = (unsigned *)
180.  		    alloc(sizeof (unsigned) * (reg->max_monst + MONST_INC));
181.  	if (reg->max_monst > 0) {
182.  	    for (i = 0; i < reg->max_monst; i++)
183.  		tmp_m[i] = reg->monsters[i];
184.  	    free((genericptr_t) reg->monsters);
185.  	}
186.  	reg->monsters = tmp_m;
187.  	reg->max_monst += MONST_INC;
188.      }
189.      reg->monsters[reg->n_monst++] = mon->m_id;
190.  }
191.  

remove_mon_from_reg[]

192.  /*
193.   * Remove a monster from the region list (it left or died...)
194.   */
195.  void
196.  remove_mon_from_reg(reg, mon)
197.  NhRegion *reg;
198.  struct monst *mon;
199.  {
200.      register int i;
201.  
202.      for (i = 0; i < reg->n_monst; i++)
203.  	if (reg->monsters[i] == mon->m_id) {
204.  	    reg->n_monst--;
205.  	    reg->monsters[i] = reg->monsters[reg->n_monst];
206.  	    return;
207.  	}
208.  }
209.  

mon_in_region[]

210.  /*
211.   * Check if a monster is inside the region.
212.   * It's probably quicker to check with the region internal list
213.   * than to check for coordinates.
214.   */
215.  boolean
216.  mon_in_region(reg, mon)
217.  NhRegion *reg;
218.  struct monst *mon;
219.  {
220.      int i;
221.  
222.      for (i = 0; i < reg->n_monst; i++)
223.  	if (reg->monsters[i] == mon->m_id)
224.  	    return TRUE;
225.      return FALSE;
226.  }
227.  
228.  #if 0
229.  /* not yet used */
230.  

clone_region[]

231.  /*
232.   * Clone (make a standalone copy) the region.
233.   */
234.  NhRegion *
235.  clone_region(reg)
236.  NhRegion *reg;
237.  {
238.      NhRegion *ret_reg;
239.  
240.      ret_reg = create_region(reg->rects, reg->nrects);
241.      ret_reg->ttl = reg->ttl;
242.      ret_reg->attach_2_u = reg->attach_2_u;
243.      ret_reg->attach_2_m = reg->attach_2_m;
244.   /* ret_reg->attach_2_o = reg->attach_2_o; */
245.      ret_reg->expire_f = reg->expire_f;
246.      ret_reg->enter_f = reg->enter_f;
247.      ret_reg->can_enter_f = reg->can_enter_f;
248.      ret_reg->leave_f = reg->leave_f;
249.      ret_reg->can_leave_f = reg->can_leave_f;
250.      ret_reg->player_flags = reg->player_flags;	/* set/clear_hero_inside,&c*/
251.      ret_reg->n_monst = reg->n_monst;
252.      if (reg->n_monst > 0) {
253.  	ret_reg->monsters = (unsigned *)
254.  				alloc((sizeof (unsigned)) * reg->n_monst);
255.  	(void) memcpy((genericptr_t) ret_reg->monsters, (genericptr_t) reg->monsters,
256.  		      sizeof (unsigned) * reg->n_monst);
257.      } else
258.  	ret_reg->monsters = NULL;
259.      return ret_reg;
260.  }
261.  
262.  #endif	/*0*/
263.  

free_region[]

264.  /*
265.   * Free mem from region.
266.   */
267.  void
268.  free_region(reg)
269.  NhRegion *reg;
270.  {
271.      if (reg) {
272.  	if (reg->rects)
273.  	    free((genericptr_t) reg->rects);
274.  	if (reg->monsters)
275.  	    free((genericptr_t) reg->monsters);
276.  	free((genericptr_t) reg);
277.      }
278.  }
279.  

add_region[]

280.  /*
281.   * Add a region to the list.
282.   * This actually activates the region.
283.   */
284.  void
285.  add_region(reg)
286.  NhRegion *reg;
287.  {
288.      NhRegion **tmp_reg;
289.      int i, j;
290.  
291.      if (max_regions <= n_regions) {
292.  	tmp_reg = regions;
293.  	regions = (NhRegion **)alloc(sizeof (NhRegion *) * (max_regions + 10));
294.  	if (max_regions > 0) {
295.  	    (void) memcpy((genericptr_t) regions, (genericptr_t) tmp_reg,
296.  			  max_regions * sizeof (NhRegion *));
297.  	    free((genericptr_t) tmp_reg);
298.  	}
299.  	max_regions += 10;
300.      }
301.      regions[n_regions] = reg;
302.      n_regions++;
303.      /* Check for monsters inside the region */
304.      for (i = reg->bounding_box.lx; i <= reg->bounding_box.hx; i++)
305.  	for (j = reg->bounding_box.ly; j <= reg->bounding_box.hy; j++) {
306.  	    /* Some regions can cross the level boundaries */
307.  	    if (!isok(i,j))
308.  		continue;
309.  	    if (MON_AT(i, j) && inside_region(reg, i, j))
310.  		add_mon_to_reg(reg, level.monsters[i][j]);
311.  	    if (reg->visible && cansee(i, j))
312.  		newsym(i, j);
313.  	}
314.      /* Check for player now... */
315.      if (inside_region(reg, u.ux, u.uy)) 
316.  	set_hero_inside(reg);
317.      else
318.  	clear_hero_inside(reg);
319.  }
320.  

remove_region[]

321.  /*
322.   * Remove a region from the list & free it.
323.   */
324.  void
325.  remove_region(reg)
326.  NhRegion *reg;
327.  {
328.      register int i, x, y;
329.  
330.      for (i = 0; i < n_regions; i++)
331.  	if (regions[i] == reg)
332.  	    break;
333.      if (i == n_regions)
334.  	return;
335.  
336.      /* Update screen if necessary */
337.      if (reg->visible)
338.  	for (x = reg->bounding_box.lx; x <= reg->bounding_box.hx; x++)
339.  	    for (y = reg->bounding_box.ly; y <= reg->bounding_box.hy; y++)
340.  		if (isok(x,y) && inside_region(reg, x, y) && cansee(x, y))
341.  		    newsym(x, y);
342.  
343.      free_region(reg);
344.      regions[i] = regions[n_regions - 1];
345.      regions[n_regions - 1] = (NhRegion *) 0;
346.      n_regions--;
347.  }
348.  

clear_regions[]

349.  /*
350.   * Remove all regions and clear all related data (This must be down
351.   * when changing level, for instance).
352.   */
353.  void
354.  clear_regions()
355.  {
356.      register int i;
357.  
358.      for (i = 0; i < n_regions; i++)
359.  	free_region(regions[i]);
360.      n_regions = 0;
361.      if (max_regions > 0)
362.  	free((genericptr_t) regions);
363.      max_regions = 0;
364.      regions = NULL;
365.  }
366.  

run_regions[]

367.  /*
368.   * This function is called every turn.
369.   * It makes the regions age, if necessary and calls the appropriate
370.   * callbacks when needed.
371.   */
372.  void
373.  run_regions()
374.  {
375.      register int i, j, k;
376.      int f_indx;
377.  
378.      /* End of life ? */
379.      /* Do it backward because the array will be modified */
380.      for (i = n_regions - 1; i >= 0; i--) {
381.  	if (regions[i]->ttl == 0) {
382.  	    if ((f_indx = regions[i]->expire_f) == NO_CALLBACK ||
383.  		(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
384.  		remove_region(regions[i]);
385.  	}
386.      }
387.  
388.      /* Process remaining regions */
389.      for (i = 0; i < n_regions; i++) {
390.  	/* Make the region age */
391.  	if (regions[i]->ttl > 0)
392.  	    regions[i]->ttl--;
393.  	/* Check if player is inside region */
394.  	f_indx = regions[i]->inside_f;
395.  	if (f_indx != NO_CALLBACK && hero_inside(regions[i]))
396.  	    (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
397.  	/* Check if any monster is inside region */
398.  	if (f_indx != NO_CALLBACK) {
399.  	    for (j = 0; j < regions[i]->n_monst; j++) {
400.  		struct monst *mtmp = find_mid(regions[i]->monsters[j], FM_FMON);
401.  
402.  		if (!mtmp || mtmp->mhp <= 0 ||
403.  				(*callbacks[f_indx])(regions[i], mtmp)) {
404.  		    /* The monster died, remove it from list */
405.  		    k = (regions[i]->n_monst -= 1);
406.  		    regions[i]->monsters[j] = regions[i]->monsters[k];
407.  		    regions[i]->monsters[k] = 0;
408.  		    --j;    /* current slot has been reused; recheck it next */
409.  		}
410.  	    }
411.  	}
412.      }
413.  }
414.  

in_out_region[]

415.  /*
416.   * check whether player enters/leaves one or more regions.
417.   */
418.  boolean
419.  in_out_region(x, y)
420.  xchar
421.      x, y;
422.  {
423.      int i, f_indx;
424.  
425.      /* First check if we can do the move */
426.      for (i = 0; i < n_regions; i++) {
427.  	if (inside_region(regions[i], x, y)
428.  	    && !hero_inside(regions[i]) && !regions[i]->attach_2_u) {
429.  	    if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK)
430.  		if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
431.  		    return FALSE;
432.  	} else
433.  	    if (hero_inside(regions[i])
434.  		&& !inside_region(regions[i], x, y)
435.  		&& !regions[i]->attach_2_u) {
436.  	    if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK)
437.  		if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
438.  		    return FALSE;
439.  	}
440.      }
441.  
442.      /* Callbacks for the regions we do leave */
443.      for (i = 0; i < n_regions; i++)
444.  	if (hero_inside(regions[i]) &&
445.  		!regions[i]->attach_2_u && !inside_region(regions[i], x, y)) {
446.  	    clear_hero_inside(regions[i]);
447.  	    if (regions[i]->leave_msg != NULL)
448.  		pline(regions[i]->leave_msg);
449.  	    if ((f_indx = regions[i]->leave_f) != NO_CALLBACK)
450.  		(void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
451.  	}
452.  
453.      /* Callbacks for the regions we do enter */
454.      for (i = 0; i < n_regions; i++)
455.  	if (!hero_inside(regions[i]) &&
456.  		!regions[i]->attach_2_u && inside_region(regions[i], x, y)) {
457.  	    set_hero_inside(regions[i]);
458.  	    if (regions[i]->enter_msg != NULL)
459.  		pline(regions[i]->enter_msg);
460.  	    if ((f_indx = regions[i]->enter_f) != NO_CALLBACK)
461.  		(void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
462.  	}
463.      return TRUE;
464.  }
465.  

m_in_out_region[]

466.  /*
467.   * check wether a monster enters/leaves one or more region.
468.  */
469.  boolean
470.  m_in_out_region(mon, x, y)
471.  struct monst *mon;
472.  xchar x, y;
473.  {
474.      int i, f_indx;
475.  
476.      /* First check if we can do the move */
477.      for (i = 0; i < n_regions; i++) {
478.  	if (inside_region(regions[i], x, y) &&
479.  		!mon_in_region(regions[i], mon) &&
480.  		regions[i]->attach_2_m != mon->m_id) {
481.  	    if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK)
482.  		if (!(*callbacks[f_indx])(regions[i], mon))
483.  		    return FALSE;
484.  	} else if (mon_in_region(regions[i], mon) &&
485.  		!inside_region(regions[i], x, y) &&
486.  		regions[i]->attach_2_m != mon->m_id) {
487.  	    if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK)
488.  		if (!(*callbacks[f_indx])(regions[i], mon))
489.  		    return FALSE;
490.  	}
491.      }
492.  
493.      /* Callbacks for the regions we do leave */
494.      for (i = 0; i < n_regions; i++)
495.  	if (mon_in_region(regions[i], mon) &&
496.  		regions[i]->attach_2_m != mon->m_id &&
497.  		!inside_region(regions[i], x, y)) {
498.  	    remove_mon_from_reg(regions[i], mon);
499.  	    if ((f_indx = regions[i]->leave_f) != NO_CALLBACK)
500.  		(void) (*callbacks[f_indx])(regions[i], mon);
501.  	}
502.  
503.      /* Callbacks for the regions we do enter */
504.      for (i = 0; i < n_regions; i++)
505.  	if (!hero_inside(regions[i]) &&
506.  		!regions[i]->attach_2_u && inside_region(regions[i], x, y)) {
507.  	    add_mon_to_reg(regions[i], mon);
508.  	    if ((f_indx = regions[i]->enter_f) != NO_CALLBACK)
509.  		(void) (*callbacks[f_indx])(regions[i], mon);
510.  	}
511.      return TRUE;
512.  }
513.  

update_player_regions[]

514.  /*
515.   * Checks player's regions after a teleport for instance.
516.   */
517.  void
518.  update_player_regions()
519.  {
520.      register int i;
521.  
522.      for (i = 0; i < n_regions; i++)
523.  	if (!regions[i]->attach_2_u && inside_region(regions[i], u.ux, u.uy))
524.  	    set_hero_inside(regions[i]);
525.  	else
526.  	    clear_hero_inside(regions[i]);
527.  }
528.  

update_monster_region[]

529.  /*
530.   * Ditto for a specified monster.
531.   */
532.  void
533.  update_monster_region(mon)
534.  struct monst *mon;
535.  {
536.      register int i;
537.  
538.      for (i = 0; i < n_regions; i++) {
539.  	if (inside_region(regions[i], mon->mx, mon->my)) {
540.  	    if (!mon_in_region(regions[i], mon))
541.  		add_mon_to_reg(regions[i], mon);
542.  	} else {
543.  	    if (mon_in_region(regions[i], mon))
544.  		remove_mon_from_reg(regions[i], mon);
545.  	}
546.      }
547.  }
548.  
549.  #if 0

replace_mon_regions[]

550.  /* not yet used */
551.  
552.  /*
553.   * Change monster pointer in regions
554.   * This happens, for instance, when a monster grows and
555.   * need a new structure (internally that is).
556.   */
557.  void
558.  replace_mon_regions(monold, monnew)
559.  struct monst *monold, *monnew;
560.  {
561.      register int i;
562.  
563.      for (i = 0; i < n_regions; i++)
564.  	if (mon_in_region(regions[i], monold)) {
565.  	    remove_mon_from_reg(regions[i], monold);
566.  	    add_mon_to_reg(regions[i], monnew);
567.  	}
568.  }
569.  

remove_mon_from_regions[]

570.  /*
571.   * Remove monster from all regions it was in (ie monster just died)
572.   */
573.  void
574.  remove_mon_from_regions(mon)
575.  struct monst *mon;
576.  {
577.      register int i;
578.  
579.      for (i = 0; i < n_regions; i++)
580.  	if (mon_in_region(regions[i], mon))
581.  	    remove_mon_from_reg(regions[i], mon);
582.  }
583.  
584.  #endif	/*0*/
585.  

visible_region_at[]

586.  /*
587.   * Check if a spot is under a visible region (eg: gas cloud).
588.   * Returns NULL if not, otherwise returns region.
589.   */
590.  NhRegion *
591.  visible_region_at(x, y)
592.  xchar x, y;
593.  {
594.      register int i;
595.  
596.      for (i = 0; i < n_regions; i++)
597.  	if (inside_region(regions[i], x, y) && regions[i]->visible &&
598.  		regions[i]->ttl != 0)
599.  	    return regions[i];
600.      return (NhRegion *) 0;
601.  }
602.  

show_region[]

603.  void
604.  show_region(reg, x, y)
605.  NhRegion *reg;
606.  xchar x, y;
607.  {
608.      show_glyph(x, y, reg->glyph);
609.  }
610.  

save_regions[]

611.  /**
612.   * save_regions :
613.   */
614.  void
615.  save_regions(fd, mode)
616.  int fd;
617.  int mode;
618.  {
619.      int i, j;
620.      unsigned n;
621.  
622.      if (!perform_bwrite(mode)) goto skip_lots;
623.  
624.      bwrite(fd, (genericptr_t) &moves, sizeof (moves));	/* timestamp */
625.      bwrite(fd, (genericptr_t) &n_regions, sizeof (n_regions));
626.      for (i = 0; i < n_regions; i++) {
627.  	bwrite(fd, (genericptr_t) &regions[i]->bounding_box, sizeof (NhRect));
628.  	bwrite(fd, (genericptr_t) &regions[i]->nrects, sizeof (short));
629.  	for (j = 0; j < regions[i]->nrects; j++)
630.  	    bwrite(fd, (genericptr_t) &regions[i]->rects[j], sizeof (NhRect));
631.  	bwrite(fd, (genericptr_t) &regions[i]->attach_2_u, sizeof (boolean));
632.  	n = 0;
633.  	bwrite(fd, (genericptr_t) &regions[i]->attach_2_m, sizeof (unsigned));
634.  	n = regions[i]->enter_msg != NULL ? strlen(regions[i]->enter_msg) : 0;
635.  	bwrite(fd, (genericptr_t) &n, sizeof n);
636.  	if (n > 0)
637.  	    bwrite(fd, (genericptr_t) regions[i]->enter_msg, n);
638.  	n = regions[i]->leave_msg != NULL ? strlen(regions[i]->leave_msg) : 0;
639.  	bwrite(fd, (genericptr_t) &n, sizeof n);
640.  	if (n > 0)
641.  	    bwrite(fd, (genericptr_t) regions[i]->leave_msg, n);
642.  	bwrite(fd, (genericptr_t) &regions[i]->ttl, sizeof (short));
643.  	bwrite(fd, (genericptr_t) &regions[i]->expire_f, sizeof (short));
644.  	bwrite(fd, (genericptr_t) &regions[i]->can_enter_f, sizeof (short));
645.  	bwrite(fd, (genericptr_t) &regions[i]->enter_f, sizeof (short));
646.  	bwrite(fd, (genericptr_t) &regions[i]->can_leave_f, sizeof (short));
647.  	bwrite(fd, (genericptr_t) &regions[i]->leave_f, sizeof (short));
648.  	bwrite(fd, (genericptr_t) &regions[i]->inside_f, sizeof (short));
649.  	bwrite(fd, (genericptr_t) &regions[i]->player_flags, sizeof (boolean));
650.  	bwrite(fd, (genericptr_t) &regions[i]->n_monst, sizeof (short));
651.  	for (j = 0; j < regions[i]->n_monst; j++)
652.  	    bwrite(fd, (genericptr_t) &regions[i]->monsters[j],
653.  	     sizeof (unsigned));
654.  	bwrite(fd, (genericptr_t) &regions[i]->visible, sizeof (boolean));
655.  	bwrite(fd, (genericptr_t) &regions[i]->glyph, sizeof (int));
656.  	bwrite(fd, (genericptr_t) &regions[i]->arg, sizeof (genericptr_t));
657.      }
658.  
659.  skip_lots:
660.      if (release_data(mode))
661.  	clear_regions();
662.  }
663.  

rest_regions[]

664.  void
665.  rest_regions(fd, ghostly)
666.  int fd;
667.  boolean ghostly; /* If a bones file restore */
668.  {
669.      int i, j;
670.      unsigned n;
671.      long tmstamp;
672.      char *msg_buf;
673.  
674.      clear_regions();		/* Just for security */
675.      mread(fd, (genericptr_t) &tmstamp, sizeof (tmstamp));
676.      if (ghostly) tmstamp = 0;
677.      else tmstamp = (moves - tmstamp);
678.      mread(fd, (genericptr_t) &n_regions, sizeof (n_regions));
679.      max_regions = n_regions;
680.      if (n_regions > 0)
681.  	regions = (NhRegion **) alloc(sizeof (NhRegion *) * n_regions);
682.      for (i = 0; i < n_regions; i++) {
683.  	regions[i] = (NhRegion *) alloc(sizeof (NhRegion));
684.  	mread(fd, (genericptr_t) &regions[i]->bounding_box, sizeof (NhRect));
685.  	mread(fd, (genericptr_t) &regions[i]->nrects, sizeof (short));
686.  
687.  	if (regions[i]->nrects > 0)
688.  	    regions[i]->rects = (NhRect *)
689.  				  alloc(sizeof (NhRect) * regions[i]->nrects);
690.  	for (j = 0; j < regions[i]->nrects; j++)
691.  	    mread(fd, (genericptr_t) &regions[i]->rects[j], sizeof (NhRect));
692.  	mread(fd, (genericptr_t) &regions[i]->attach_2_u, sizeof (boolean));
693.  	mread(fd, (genericptr_t) &regions[i]->attach_2_m, sizeof (unsigned));
694.  
695.  	mread(fd, (genericptr_t) &n, sizeof n);
696.  	if (n > 0) {
697.  	    msg_buf = (char *) alloc(n + 1);
698.  	    mread(fd, (genericptr_t) msg_buf, n);
699.  	    msg_buf[n] = '\0';
700.  	    regions[i]->enter_msg = (const char *) msg_buf;
701.  	} else
702.  	    regions[i]->enter_msg = NULL;
703.  
704.  	mread(fd, (genericptr_t) &n, sizeof n);
705.  	if (n > 0) {
706.  	    msg_buf = (char *) alloc(n + 1);
707.  	    mread(fd, (genericptr_t) msg_buf, n);
708.  	    msg_buf[n] = '\0';
709.  	    regions[i]->leave_msg = (const char *) msg_buf;
710.  	} else
711.  	    regions[i]->leave_msg = NULL;
712.  
713.  	mread(fd, (genericptr_t) &regions[i]->ttl, sizeof (short));
714.  	/* check for expired region */
715.  	if (regions[i]->ttl >= 0)
716.  	    regions[i]->ttl =
717.  		(regions[i]->ttl > tmstamp) ? regions[i]->ttl - tmstamp : 0;
718.  	mread(fd, (genericptr_t) &regions[i]->expire_f, sizeof (short));
719.  	mread(fd, (genericptr_t) &regions[i]->can_enter_f, sizeof (short));
720.  	mread(fd, (genericptr_t) &regions[i]->enter_f, sizeof (short));
721.  	mread(fd, (genericptr_t) &regions[i]->can_leave_f, sizeof (short));
722.  	mread(fd, (genericptr_t) &regions[i]->leave_f, sizeof (short));
723.  	mread(fd, (genericptr_t) &regions[i]->inside_f, sizeof (short));
724.  	mread(fd, (genericptr_t) &regions[i]->player_flags, sizeof (boolean));
725.  	if (ghostly) {	/* settings pertained to old player */
726.  	    clear_hero_inside(regions[i]);
727.  	    clear_heros_fault(regions[i]);
728.  	}
729.  	mread(fd, (genericptr_t) &regions[i]->n_monst, sizeof (short));
730.  	if (regions[i]->n_monst > 0)
731.  	    regions[i]->monsters =
732.  		(unsigned *) alloc(sizeof (unsigned) * regions[i]->n_monst);
733.  	else
734.  	    regions[i]->monsters = NULL;
735.  	regions[i]->max_monst = regions[i]->n_monst;
736.  	for (j = 0; j < regions[i]->n_monst; j++)
737.  	    mread(fd, (genericptr_t) &regions[i]->monsters[j],
738.  		  sizeof (unsigned));
739.  	mread(fd, (genericptr_t) &regions[i]->visible, sizeof (boolean));
740.  	mread(fd, (genericptr_t) &regions[i]->glyph, sizeof (int));
741.  	mread(fd, (genericptr_t) &regions[i]->arg, sizeof (genericptr_t));
742.      }
743.      /* remove expired regions, do not trigger the expire_f callback (yet!);
744.         also update monster lists if this data is coming from a bones file */
745.      for (i = n_regions - 1; i >= 0; i--)
746.  	if (regions[i]->ttl == 0)
747.  	    remove_region(regions[i]);
748.  	else if (ghostly && regions[i]->n_monst > 0)
749.  	    reset_region_mids(regions[i]);
750.  }
751.  

reset_region_mids[]

752.  /* update monster IDs for region being loaded from bones; `ghostly' implied */
753.  static void
754.  reset_region_mids(reg)
755.  NhRegion *reg;
756.  {
757.      int i = 0, n = reg->n_monst;
758.      unsigned *mid_list = reg->monsters;
759.  
760.      while (i < n)
761.  	if (!lookup_id_mapping(mid_list[i], &mid_list[i])) {
762.  	    /* shrink list to remove missing monster; order doesn't matter */
763.  	    mid_list[i] = mid_list[--n];
764.  	} else {
765.  	    /* move on to next monster */
766.  	    ++i;
767.  	}
768.      reg->n_monst = n;
769.      return;
770.  }
771.  
772.  #if 0

create_msg_region[]

773.  /* not yet used */
774.  
775.  /*--------------------------------------------------------------*
776.   *								*
777.   *			Create Region with just a message	*
778.   *								*
779.   *--------------------------------------------------------------*/
780.  
781.  NhRegion *
782.  create_msg_region(x, y, w, h, msg_enter, msg_leave)
783.  xchar x, y;
784.  xchar w, h;
785.  const char *msg_enter;
786.  const char *msg_leave;
787.  {
788.      NhRect tmprect;
789.      NhRegion *reg = create_region((NhRect *) 0, 0);
790.  
791.      reg->enter_msg = msg_enter;
792.      reg->leave_msg = msg_leave;
793.      tmprect.lx = x;
794.      tmprect.ly = y;
795.      tmprect.hx = x + w;
796.      tmprect.hy = y + h;
797.      add_rect_to_reg(reg, &tmprect);
798.      reg->ttl = -1;
799.      return reg;
800.  }
801.  
802.  

enter_force_field[]

803.  /*--------------------------------------------------------------*
804.   *								*
805.   *			Force Field Related Code		*
806.   *			(unused yet)				*
807.   *--------------------------------------------------------------*/
808.  
809.  boolean
810.  enter_force_field(p1, p2)
811.  genericptr_t p1;
812.  genericptr_t p2;
813.  {
814.      struct monst *mtmp;
815.  
816.      if (p2 == NULL) {		/* That means the player */
817.  	if (!Blind)
818.  		You("bump into %s. Ouch!",
819.  		    Hallucination ? "an invisible tree" :
820.  			"some kind of invisible wall");
821.  	else
822.  	    pline("Ouch!");
823.      } else {
824.  	mtmp = (struct monst *) p2;
825.  	if (canseemon(mtmp))
826.  	    pline("%s bumps into %s!", Monnam(mtmp), something);
827.      }
828.      return FALSE;
829.  }
830.  

create_force_field[]

831.  NhRegion *
832.  create_force_field(x, y, radius, ttl)
833.  xchar x, y;
834.  int radius, ttl;
835.  {
836.      int i;
837.      NhRegion *ff;
838.      int nrect;
839.      NhRect tmprect;
840.  
841.      ff = create_region((NhRect *) 0, 0);
842.      nrect = radius;
843.      tmprect.lx = x;
844.      tmprect.hx = x;
845.      tmprect.ly = y - (radius - 1);
846.      tmprect.hy = y + (radius - 1);
847.      for (i = 0; i < nrect; i++) {
848.  	add_rect_to_reg(ff, &tmprect);
849.  	tmprect.lx--;
850.  	tmprect.hx++;
851.  	tmprect.ly++;
852.  	tmprect.hy--;
853.      }
854.      ff->ttl = ttl;
855.      if (!in_mklev && !flags.mon_moving)
856.  	set_heros_fault(ff);		/* assume player has created it */
857.   /* ff->can_enter_f = enter_force_field; */
858.   /* ff->can_leave_f = enter_force_field; */
859.      add_region(ff);
860.      return ff;
861.  }
862.  
863.  #endif	/*0*/
864.  

expire_gas_cloud[]

865.  /*--------------------------------------------------------------*
866.   *								*
867.   *			Gas cloud related code			*
868.   *								*
869.   *--------------------------------------------------------------*/
870.  
871.  /*
872.   * Here is an example of an expire function that may prolong
873.   * region life after some mods...
874.   */
875.  boolean
876.  expire_gas_cloud(p1, p2)
877.  genericptr_t p1;
878.  genericptr_t p2;
879.  {
880.      NhRegion *reg;
881.      int damage;
882.  
883.      reg = (NhRegion *) p1;
884.      damage = (int) reg->arg;
885.  
886.      /* If it was a thick cloud, it dissipates a little first */
887.      if (damage >= 5) {
888.  	damage /= 2;		/* It dissipates, let's do less damage */
889.  	reg->arg = (genericptr_t) damage;
890.  	reg->ttl = 2;		/* Here's the trick : reset ttl */
891.  	return FALSE;		/* THEN return FALSE, means "still there" */
892.      }
893.      return TRUE;		/* OK, it's gone, you can free it! */
894.  }
895.  

inside_gas_cloud[]

896.  boolean
897.  inside_gas_cloud(p1, p2)
898.  genericptr_t p1;
899.  genericptr_t p2;
900.  {
901.      NhRegion *reg;
902.      struct monst *mtmp;
903.      int dam;
904.  
905.      reg = (NhRegion *) p1;
906.      dam = (int) reg->arg;
907.      if (p2 == NULL) {		/* This means *YOU* Bozo! */
908.  	if (nonliving(youmonst.data) || Breathless)
909.  	    return FALSE;
910.  	if (!Blind)
911.  	    make_blinded(1L, FALSE);
912.  	if (!Poison_resistance) {
913.  	    pline("%s is burning your %s!", Something, makeplural(body_part(LUNG)));
914.  	    You("cough and spit blood!");
915.  	    losehp(rnd(dam) + 5, "gas cloud", KILLED_BY_AN);
916.  	    return FALSE;
917.  	} else {
918.  	    You("cough!");
919.  	    return FALSE;
920.  	}
921.      } else {			/* A monster is inside the cloud */
922.  	mtmp = (struct monst *) p2;
923.  
924.  	/* Non living and non breathing monsters are not concerned */
925.  	if (!nonliving(mtmp->data) && !breathless(mtmp->data)) {
926.  	    if (cansee(mtmp->mx, mtmp->my))
927.  		pline("%s coughs!", Monnam(mtmp));
928.  	    setmangry(mtmp);
929.  	    if (haseyes(mtmp->data) && mtmp->mcansee) {
930.  		mtmp->mblinded = 1;
931.  		mtmp->mcansee = 0;
932.  	    }
933.  	    if (resists_poison(mtmp))
934.  		return FALSE;
935.  	    mtmp->mhp -= rnd(dam) + 5;
936.  	    if (mtmp->mhp <= 0) {
937.  		if (heros_fault(reg))
938.  		    killed(mtmp);
939.  		else
940.  		    monkilled(mtmp, "gas cloud", AD_DRST);
941.  		if (mtmp->mhp <= 0) {	/* not lifesaved */
942.  		    return TRUE;
943.  		}
944.  	    }
945.  	}
946.      }
947.      return FALSE;		/* Monster is still alive */
948.  }
949.  

create_gas_cloud[]

950.  NhRegion *
951.  create_gas_cloud(x, y, radius, damage)
952.  xchar x, y;
953.  int radius;
954.  int damage;
955.  {
956.      NhRegion *cloud;
957.      int i, nrect;
958.      NhRect tmprect;
959.  
960.      cloud = create_region((NhRect *) 0, 0);
961.      nrect = radius;
962.      tmprect.lx = x;
963.      tmprect.hx = x;
964.      tmprect.ly = y - (radius - 1);
965.      tmprect.hy = y + (radius - 1);
966.      for (i = 0; i < nrect; i++) {
967.  	add_rect_to_reg(cloud, &tmprect);
968.  	tmprect.lx--;
969.  	tmprect.hx++;
970.  	tmprect.ly++;
971.  	tmprect.hy--;
972.      }
973.      cloud->ttl = rn1(3,4);
974.      if (!in_mklev && !flags.mon_moving)
975.  	set_heros_fault(cloud);		/* assume player has created it */
976.      cloud->inside_f = INSIDE_GAS_CLOUD;
977.      cloud->expire_f = EXPIRE_GAS_CLOUD;
978.      cloud->arg = (genericptr_t) damage;
979.      cloud->visible = TRUE;
980.      cloud->glyph = cmap_to_glyph(S_cloud);
981.      add_region(cloud);
982.      return cloud;
983.  }
984.  
985.  /*region.c*/
Advertisement