Wikia

Wikihack

Source:Light.c

2,032pages on
this wiki
Talk0

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

Top of file Edit

1.    /*	SCCS Id: @(#)light.c	3.4	1997/04/10	*/
2.    /* Copyright (c) Dean Luick, 1994					*/
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"	/* for checking save modes */
7.    
8.    /*
9.     * Mobile light sources.
10.    *
11.    * This implementation minimizes memory at the expense of extra
12.    * recalculations.
13.    *
14.    * Light sources are "things" that have a physical position and range.
15.    * They have a type, which gives us information about them.  Currently
16.    * they are only attached to objects and monsters.  Note well:  the
17.    * polymorphed-player handling assumes that both youmonst.m_id and
18.    * youmonst.mx will always remain 0.
19.    *
20.    * Light sources, like timers, either follow game play (RANGE_GLOBAL) or
21.    * stay on a level (RANGE_LEVEL).  Light sources are unique by their
22.    * (type, id) pair.  For light sources attached to objects, this id
23.    * is a pointer to the object.
24.    *
25.    * The major working function is do_light_sources(). It is called
26.    * when the vision system is recreating its "could see" array.  Here
27.    * we add a flag (TEMP_LIT) to the array for all locations that are lit
28.    * via a light source.  The bad part of this is that we have to
29.    * re-calculate the LOS of each light source every time the vision
30.    * system runs.  Even if the light sources and any topology (vision blocking
31.    * positions) have not changed.  The good part is that no extra memory
32.    * is used, plus we don't have to figure out how far the sources have moved,
33.    * or if the topology has changed.
34.    *
35.    * The structure of the save/restore mechanism is amazingly similar to
36.    * the timer save/restore.  This is because they both have the same
37.    * principals of having pointers into objects that must be recalculated
38.    * across saves and restores.
39.    */
40.   
41.   #ifdef OVL3
42.   
43.   /* flags */
44.   #define LSF_SHOW	0x1		/* display the light source */
45.   #define LSF_NEEDS_FIXUP	0x2		/* need oid fixup */
46.   
47.   static light_source *light_base = 0;
48.   
49.   STATIC_DCL void FDECL(write_ls, (int, light_source *));
50.   STATIC_DCL int FDECL(maybe_write_ls, (int, int, BOOLEAN_P));
51.   
52.   /* imported from vision.c, for small circles */
53.   extern char circle_data[];
54.   extern char circle_start[];
55.   
56.   

new_light_source Edit

57.   /* Create a new light source.  */
58.   void
59.   new_light_source(x, y, range, type, id)
60.       xchar x, y;
61.       int range, type;
62.       genericptr_t id;
63.   {
64.       light_source *ls;
65.   
66.       if (range > MAX_RADIUS || range < 1) {
67.   	impossible("new_light_source:  illegal range %d", range);
68.   	return;
69.       }
70.   
71.       ls = (light_source *) alloc(sizeof(light_source));
72.   
73.       ls->next = light_base;
74.       ls->x = x;
75.       ls->y = y;
76.       ls->range = range;
77.       ls->type = type;
78.       ls->id = id;
79.       ls->flags = 0;
80.       light_base = ls;
81.   
82.       vision_full_recalc = 1;	/* make the source show up */
83.   }
84.   

del_light_source Edit

85.   /*
86.    * Delete a light source. This assumes only one light source is attached
87.    * to an object at a time.
88.    */
89.   void
90.   del_light_source(type, id)
91.       int type;
92.       genericptr_t id;
93.   {
94.       light_source *curr, *prev;
95.       genericptr_t tmp_id;
96.   
97.       /* need to be prepared for dealing a with light source which
98.          has only been partially restored during a level change
99.          (in particular: chameleon vs prot. from shape changers) */
100.      switch (type) {
101.      case LS_OBJECT:	tmp_id = (genericptr_t)(((struct obj *)id)->o_id);
102.  			break;
103.      case LS_MONSTER:	tmp_id = (genericptr_t)(((struct monst *)id)->m_id);
104.  			break;
105.      default:		tmp_id = 0;
106.  			break;
107.      }
108.  
109.      for (prev = 0, curr = light_base; curr; prev = curr, curr = curr->next) {
110.  	if (curr->type != type) continue;
111.  	if (curr->id == ((curr->flags & LSF_NEEDS_FIXUP) ? tmp_id : id)) {
112.  	    if (prev)
113.  		prev->next = curr->next;
114.  	    else
115.  		light_base = curr->next;
116.  
117.  	    free((genericptr_t)curr);
118.  	    vision_full_recalc = 1;
119.  	    return;
120.  	}
121.      }
122.      impossible("del_light_source: not found type=%d, id=0x%lx", type, (long)id);
123.  }
124.  

do_light_sources Edit

125.  /* Mark locations that are temporarily lit via mobile light sources. */
126.  void
127.  do_light_sources(cs_rows)
128.      char **cs_rows;
129.  {
130.      int x, y, min_x, max_x, max_y, offset;
131.      char *limits;
132.      short at_hero_range = 0;
133.      light_source *ls;
134.      char *row;
135.  
136.      for (ls = light_base; ls; ls = ls->next) {
137.  	ls->flags &= ~LSF_SHOW;
138.  
139.  	/*
140.  	 * Check for moved light sources.  It may be possible to
141.  	 * save some effort if an object has not moved, but not in
142.  	 * the current setup -- we need to recalculate for every
143.  	 * vision recalc.
144.  	 */
145.  	if (ls->type == LS_OBJECT) {
146.  	    if (get_obj_location((struct obj *) ls->id, &ls->x, &ls->y, 0))
147.  		ls->flags |= LSF_SHOW;
148.  	} else if (ls->type == LS_MONSTER) {
149.  	    if (get_mon_location((struct monst *) ls->id, &ls->x, &ls->y, 0))
150.  		ls->flags |= LSF_SHOW;
151.  	}
152.  
153.  	/* minor optimization: don't bother with duplicate light sources */
154.  	/* at hero */
155.  	if (ls->x == u.ux && ls->y == u.uy) {
156.  	    if (at_hero_range >= ls->range)
157.  		ls->flags &= ~LSF_SHOW;
158.  	    else
159.  		at_hero_range = ls->range;
160.  	}
161.  
162.  	if (ls->flags & LSF_SHOW) {
163.  	    /*
164.  	     * Walk the points in the circle and see if they are
165.  	     * visible from the center.  If so, mark'em.
166.  	     *
167.  	     * Kevin's tests indicated that doing this brute-force
168.  	     * method is faster for radius <= 3 (or so).
169.  	     */
170.  	    limits = circle_ptr(ls->range);
171.  	    if ((max_y = (ls->y + ls->range)) >= ROWNO) max_y = ROWNO-1;
172.  	    if ((y = (ls->y - ls->range)) < 0) y = 0;
173.  	    for (; y <= max_y; y++) {
174.  		row = cs_rows[y];
175.  		offset = limits[abs(y - ls->y)];
176.  		if ((min_x = (ls->x - offset)) < 0) min_x = 0;
177.  		if ((max_x = (ls->x + offset)) >= COLNO) max_x = COLNO-1;
178.  
179.  		if (ls->x == u.ux && ls->y == u.uy) {
180.  		    /*
181.  		     * If the light source is located at the hero, then
182.  		     * we can use the COULD_SEE bits already calcualted
183.  		     * by the vision system.  More importantly than
184.  		     * this optimization, is that it allows the vision
185.  		     * system to correct problems with clear_path().
186.  		     * The function clear_path() is a simple LOS
187.  		     * path checker that doesn't go out of its way
188.  		     * make things look "correct".  The vision system
189.  		     * does this.
190.  		     */
191.  		    for (x = min_x; x <= max_x; x++)
192.  			if (row[x] & COULD_SEE)
193.  			    row[x] |= TEMP_LIT;
194.  		} else {
195.  		    for (x = min_x; x <= max_x; x++)
196.  			if ((ls->x == x && ls->y == y)
197.  				|| clear_path((int)ls->x, (int) ls->y, x, y))
198.  			    row[x] |= TEMP_LIT;
199.  		}
200.  	    }
201.  	}
202.      }
203.  }
204.  

find_mid Edit

205.  /* (mon->mx == 0) implies migrating */
206.  #define mon_is_local(mon)	((mon)->mx > 0)
207.  
208.  struct monst *
209.  find_mid(nid, fmflags)
210.  unsigned nid;
211.  unsigned fmflags;
212.  {
213.  	struct monst *mtmp;
214.  
215.  	if (!nid)
216.  	    return &youmonst;
217.  	if (fmflags & FM_FMON)
218.  		for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
219.  		    if (!DEADMONSTER(mtmp) && mtmp->m_id == nid) return mtmp;
220.  	if (fmflags & FM_MIGRATE)
221.  		for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
222.  	    	    if (mtmp->m_id == nid) return mtmp;
223.  	if (fmflags & FM_MYDOGS)
224.  		for (mtmp = mydogs; mtmp; mtmp = mtmp->nmon)
225.  	    	    if (mtmp->m_id == nid) return mtmp;
226.  	return (struct monst *) 0;
227.  }
228.  

save_light_sources Edit

229.  /* Save all light sources of the given range. */
230.  void
231.  save_light_sources(fd, mode, range)
232.      int fd, mode, range;
233.  {
234.      int count, actual, is_global;
235.      light_source **prev, *curr;
236.  
237.      if (perform_bwrite(mode)) {
238.  	count = maybe_write_ls(fd, range, FALSE);
239.  	bwrite(fd, (genericptr_t) &count, sizeof count);
240.  	actual = maybe_write_ls(fd, range, TRUE);
241.  	if (actual != count)
242.  	    panic("counted %d light sources, wrote %d! [range=%d]",
243.  		  count, actual, range);
244.      }
245.  
246.      if (release_data(mode)) {
247.  	for (prev = &light_base; (curr = *prev) != 0; ) {
248.  	    if (!curr->id) {
249.  		impossible("save_light_sources: no id! [range=%d]", range);
250.  		is_global = 0;
251.  	    } else
252.  	    switch (curr->type) {
253.  	    case LS_OBJECT:
254.  		is_global = !obj_is_local((struct obj *)curr->id);
255.  		break;
256.  	    case LS_MONSTER:
257.  		is_global = !mon_is_local((struct monst *)curr->id);
258.  		break;
259.  	    default:
260.  		is_global = 0;
261.  		impossible("save_light_sources: bad type (%d) [range=%d]",
262.  			   curr->type, range);
263.  		break;
264.  	    }
265.  	    /* if global and not doing local, or vice versa, remove it */
266.  	    if (is_global ^ (range == RANGE_LEVEL)) {
267.  		*prev = curr->next;
268.  		free((genericptr_t)curr);
269.  	    } else {
270.  		prev = &(*prev)->next;
271.  	    }
272.  	}
273.      }
274.  }
275.  

restore_light_sources Edit

276.  /*
277.   * Pull in the structures from disk, but don't recalculate the object
278.   * pointers.
279.   */
280.  void
281.  restore_light_sources(fd)
282.      int fd;
283.  {
284.      int count;
285.      light_source *ls;
286.  
287.      /* restore elements */
288.      mread(fd, (genericptr_t) &count, sizeof count);
289.  
290.      while (count-- > 0) {
291.  	ls = (light_source *) alloc(sizeof(light_source));
292.  	mread(fd, (genericptr_t) ls, sizeof(light_source));
293.  	ls->next = light_base;
294.  	light_base = ls;
295.      }
296.  }
297.  

relink_light_sources Edit

298.  /* Relink all lights that are so marked. */
299.  void
300.  relink_light_sources(ghostly)
301.      boolean ghostly;
302.  {
303.      char which;
304.      unsigned nid;
305.      light_source *ls;
306.  
307.      for (ls = light_base; ls; ls = ls->next) {
308.  	if (ls->flags & LSF_NEEDS_FIXUP) {
309.  	    if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) {
310.  		if (ghostly) {
311.  		    if (!lookup_id_mapping((unsigned)ls->id, &nid))
312.  			impossible("relink_light_sources: no id mapping");
313.  		} else
314.  		    nid = (unsigned) ls->id;
315.  		if (ls->type == LS_OBJECT) {
316.  		    which = 'o';
317.  		    ls->id = (genericptr_t) find_oid(nid);
318.  		} else {
319.  		    which = 'm';
320.  		    ls->id = (genericptr_t) find_mid(nid, FM_EVERYWHERE);
321.  		}
322.  		if (!ls->id)
323.  		    impossible("relink_light_sources: cant find %c_id %d",
324.  			       which, nid);
325.  	    } else
326.  		impossible("relink_light_sources: bad type (%d)", ls->type);
327.  
328.  	    ls->flags &= ~LSF_NEEDS_FIXUP;
329.  	}
330.      }
331.  }
332.  

maybe_write_ls Edit

333.  /*
334.   * Part of the light source save routine.  Count up the number of light
335.   * sources that would be written.  If write_it is true, actually write
336.   * the light source out.
337.   */
338.  STATIC_OVL int
339.  maybe_write_ls(fd, range, write_it)
340.      int fd, range;
341.      boolean write_it;
342.  {
343.      int count = 0, is_global;
344.      light_source *ls;
345.  
346.      for (ls = light_base; ls; ls = ls->next) {
347.  	if (!ls->id) {
348.  	    impossible("maybe_write_ls: no id! [range=%d]", range);
349.  	    continue;
350.  	}
351.  	switch (ls->type) {
352.  	case LS_OBJECT:
353.  	    is_global = !obj_is_local((struct obj *)ls->id);
354.  	    break;
355.  	case LS_MONSTER:
356.  	    is_global = !mon_is_local((struct monst *)ls->id);
357.  	    break;
358.  	default:
359.  	    is_global = 0;
360.  	    impossible("maybe_write_ls: bad type (%d) [range=%d]",
361.  		       ls->type, range);
362.  	    break;
363.  	}
364.  	/* if global and not doing local, or vice versa, count it */
365.  	if (is_global ^ (range == RANGE_LEVEL)) {
366.  	    count++;
367.  	    if (write_it) write_ls(fd, ls);
368.  	}
369.      }
370.  
371.      return count;
372.  }
373.  

write_ls Edit

374.  /* Write a light source structure to disk. */
375.  STATIC_OVL void
376.  write_ls(fd, ls)
377.      int fd;
378.      light_source *ls;
379.  {
380.      genericptr_t arg_save;
381.      struct obj *otmp;
382.      struct monst *mtmp;
383.  
384.      if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) {
385.  	if (ls->flags & LSF_NEEDS_FIXUP)
386.  	    bwrite(fd, (genericptr_t)ls, sizeof(light_source));
387.  	else {
388.  	    /* replace object pointer with id for write, then put back */
389.  	    arg_save = ls->id;
390.  	    if (ls->type == LS_OBJECT) {
391.  		otmp = (struct obj *)ls->id;
392.  		ls->id = (genericptr_t)otmp->o_id;
393.  #ifdef DEBUG
394.  		if (find_oid((unsigned)ls->id) != otmp)
395.  		    panic("write_ls: can't find obj #%u!", (unsigned)ls->id);
396.  #endif
397.  	    } else { /* ls->type == LS_MONSTER */
398.  		mtmp = (struct monst *)ls->id;
399.  		ls->id = (genericptr_t)mtmp->m_id;
400.  #ifdef DEBUG
401.  		if (find_mid((unsigned)ls->id, FM_EVERYWHERE) != mtmp)
402.  		    panic("write_ls: can't find mon #%u!", (unsigned)ls->id);
403.  #endif
404.  	    }
405.  	    ls->flags |= LSF_NEEDS_FIXUP;
406.  	    bwrite(fd, (genericptr_t)ls, sizeof(light_source));
407.  	    ls->id = arg_save;
408.  	    ls->flags &= ~LSF_NEEDS_FIXUP;
409.  	}
410.      } else {
411.  	impossible("write_ls: bad type (%d)", ls->type);
412.      }
413.  }
414.  

obj_move_light_source Edit

415.  /* Change light source's ID from src to dest. */
416.  void
417.  obj_move_light_source(src, dest)
418.      struct obj *src, *dest;
419.  {
420.      light_source *ls;
421.  
422.      for (ls = light_base; ls; ls = ls->next)
423.  	if (ls->type == LS_OBJECT && ls->id == (genericptr_t) src)
424.  	    ls->id = (genericptr_t) dest;
425.      src->lamplit = 0;
426.      dest->lamplit = 1;
427.  }
428.  

any_light_source Edit

429.  /* return true if there exist any light sources */
430.  boolean
431.  any_light_source()
432.  {
433.      return light_base != (light_source *) 0;
434.  }
435.  

snuff_light_source Edit

436.  /*
437.   * Snuff an object light source if at (x,y).  This currently works
438.   * only for burning light sources.
439.   */
440.  void
441.  snuff_light_source(x, y)
442.      int x, y;
443.  {
444.      light_source *ls;
445.      struct obj *obj;
446.  
447.      for (ls = light_base; ls; ls = ls->next)
448.  	/*
449.  	Is this position check valid??? Can I assume that the positions
450.  	will always be correct because the objects would have been
451.  	updated with the last vision update?  [Is that recent enough???]
452.  	*/
453.  	if (ls->type == LS_OBJECT && ls->x == x && ls->y == y) {
454.  	    obj = (struct obj *) ls->id;
455.  	    if (obj_is_burning(obj)) {
456.  		/* The only way to snuff Sunsword is to unwield it.  Darkness
457.  		 * scrolls won't affect it.  (If we got here because it was
458.  		 * dropped or thrown inside a monster, this won't matter anyway
459.  		 * because it will go out when dropped.)
460.  		 */
461.  		if (artifact_light(obj)) continue;
462.  		end_burn(obj, obj->otyp != MAGIC_LAMP);
463.  		/*
464.  		 * The current ls element has just been removed (and
465.  		 * ls->next is now invalid).  Return assuming that there
466.  		 * is only one light source attached to each object.
467.  		 */
468.  		return;
469.  	    }
470.  	}
471.  }
472.  

obj_sheds_light Edit

473.  /* Return TRUE if object sheds any light at all. */
474.  boolean
475.  obj_sheds_light(obj)
476.      struct obj *obj;
477.  {
478.      /* so far, only burning objects shed light */
479.      return obj_is_burning(obj);
480.  }
481.  

obj_is_burning Edit

482.  /* Return TRUE if sheds light AND will be snuffed by end_burn(). */
483.  boolean
484.  obj_is_burning(obj)
485.      struct obj *obj;
486.  {
487.      return (obj->lamplit &&
488.  		(obj->otyp == MAGIC_LAMP || ignitable(obj) || artifact_light(obj)));
489.  }
490.  

obj_split_light_source Edit

491.  /* copy the light source(s) attachted to src, and attach it/them to dest */
492.  void
493.  obj_split_light_source(src, dest)
494.      struct obj *src, *dest;
495.  {
496.      light_source *ls, *new_ls;
497.  
498.      for (ls = light_base; ls; ls = ls->next)
499.  	if (ls->type == LS_OBJECT && ls->id == (genericptr_t) src) {
500.  	    /*
501.  	     * Insert the new source at beginning of list.  This will
502.  	     * never interfere us walking down the list - we are already
503.  	     * past the insertion point.
504.  	     */
505.  	    new_ls = (light_source *) alloc(sizeof(light_source));
506.  	    *new_ls = *ls;
507.  	    if (Is_candle(src)) {
508.  		/* split candles may emit less light than original group */
509.  		ls->range = candle_light_range(src);
510.  		new_ls->range = candle_light_range(dest);
511.  		vision_full_recalc = 1;	/* in case range changed */
512.  	    }
513.  	    new_ls->id = (genericptr_t) dest;
514.  	    new_ls->next = light_base;
515.  	    light_base = new_ls;
516.  	    dest->lamplit = 1;		/* now an active light source */
517.  	}
518.  }
519.  

obj_merge_light_sources Edit

520.  /* light source `src' has been folded into light source `dest';
521.     used for merging lit candles and adding candle(s) to lit candelabrum */
522.  void
523.  obj_merge_light_sources(src, dest)
524.  struct obj *src, *dest;
525.  {
526.      light_source *ls;
527.  
528.      /* src == dest implies adding to candelabrum */
529.      if (src != dest) end_burn(src, TRUE);		/* extinguish candles */
530.  
531.      for (ls = light_base; ls; ls = ls->next)
532.  	if (ls->type == LS_OBJECT && ls->id == (genericptr_t) dest) {
533.  	    ls->range = candle_light_range(dest);
534.  	    vision_full_recalc = 1;	/* in case range changed */
535.  	    break;
536.  	}
537.  }
538.  

candle_light_range Edit

539.  /* Candlelight is proportional to the number of candles;
540.     minimum range is 2 rather than 1 for playability. */
541.  int
542.  candle_light_range(obj)
543.  struct obj *obj;
544.  {
545.      int radius;
546.  
547.      if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
548.  	/*
549.  	 *	The special candelabrum emits more light than the
550.  	 *	corresponding number of candles would.
551.  	 *	 1..3 candles, range 2 (minimum range);
552.  	 *	 4..6 candles, range 3 (normal lamp range);
553.  	 *	    7 candles, range 4 (bright).
554.  	 */
555.  	radius = (obj->spe < 4) ? 2 : (obj->spe < 7) ? 3 : 4;
556.      } else if (Is_candle(obj)) {
557.  	/*
558.  	 *	Range is incremented by powers of 7 so that it will take
559.  	 *	wizard mode quantities of candles to get more light than
560.  	 *	from a lamp, without imposing an arbitrary limit.
561.  	 *	 1..6   candles, range 2;
562.  	 *	 7..48  candles, range 3;
563.  	 *	49..342 candles, range 4; &c.
564.  	 */
565.  	long n = obj->quan;
566.  
567.  	radius = 1;	/* always incremented at least once */
568.  	do {
569.  	    radius++;
570.  	    n /= 7L;
571.  	} while (n > 0L);
572.      } else {
573.  	/* we're only called for lit candelabrum or candles */
574.       /* impossible("candlelight for %d?", obj->otyp); */
575.  	radius = 3;		/* lamp's value */
576.      }
577.      return radius;
578.  }
579.  

wiz_light_sources Edit

580.  #ifdef WIZARD
581.  extern char *FDECL(fmt_ptr, (const genericptr, char *));  /* from alloc.c */
582.  
583.  int
584.  wiz_light_sources()
585.  {
586.      winid win;
587.      char buf[BUFSZ], arg_address[20];
588.      light_source *ls;
589.  
590.      win = create_nhwindow(NHW_MENU);	/* corner text window */
591.      if (win == WIN_ERR) return 0;
592.  
593.      Sprintf(buf, "Mobile light sources: hero @ (%2d,%2d)", u.ux, u.uy);
594.      putstr(win, 0, buf);
595.      putstr(win, 0, "");
596.  
597.      if (light_base) {
598.  	putstr(win, 0, "location range flags  type    id");
599.  	putstr(win, 0, "-------- ----- ------ ----  -------");
600.  	for (ls = light_base; ls; ls = ls->next) {
601.  	    Sprintf(buf, "  %2d,%2d   %2d   0x%04x  %s  %s",
602.  		ls->x, ls->y, ls->range, ls->flags,
603.  		(ls->type == LS_OBJECT ? "obj" :
604.  		 ls->type == LS_MONSTER ?
605.  		    (mon_is_local((struct monst *)ls->id) ? "mon" :
606.  		     ((struct monst *)ls->id == &youmonst) ? "you" :
607.  		     "<m>") :		/* migrating monster */
608.  		 "???"),
609.  		fmt_ptr(ls->id, arg_address));
610.  	    putstr(win, 0, buf);
611.  	}
612.      } else
613.  	putstr(win, 0, "<none>");
614.  
615.  
616.      display_nhwindow(win, FALSE);
617.      destroy_nhwindow(win);
618.  
619.      return 0;
620.  }
621.  
622.  #endif /* WIZARD */
623.  
624.  #endif /* OVL3 */
625.  
626.  /*light.c*/

Around Wikia's network

Random Wiki