Fandom

Wikihack

Source:NetHack 3.4.0/light.c

2,034pages on
this wiki
Add New Page
Talk0

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.

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

Warning! This is the source code from an old release. For the latest release, see Source code

The NetHack General Public License applies to screenshots, source code and other content from NetHack.
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.    
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.   
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.   
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.  
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.  
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.  
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.  
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.  
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.  
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.  
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.  
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.  
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.  
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.  
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.  
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
489.  		|| obj->otyp == BRASS_LANTERN
490.  		|| obj->otyp == OIL_LAMP
491.  		|| obj->otyp == CANDELABRUM_OF_INVOCATION
492.  		|| obj->otyp == TALLOW_CANDLE
493.  		|| obj->otyp == WAX_CANDLE
494.  		|| obj->otyp == POT_OIL
495.  		|| artifact_light(obj)));
496.  }
497.  
498.  /* copy the light source(s) attachted to src, and attach it/them to dest */
499.  void
500.  obj_split_light_source(src, dest)
501.      struct obj *src, *dest;
502.  {
503.      light_source *ls, *new_ls;
504.  
505.      for (ls = light_base; ls; ls = ls->next)
506.  	if (ls->type == LS_OBJECT && ls->id == (genericptr_t) src) {
507.  	    /*
508.  	     * Insert the new source at beginning of list.  This will
509.  	     * never interfere us walking down the list - we are already
510.  	     * past the insertion point.
511.  	     */
512.  	    new_ls = (light_source *) alloc(sizeof(light_source));
513.  	    *new_ls = *ls;
514.  	    if (Is_candle(src)) {
515.  		/* split candles may emit less light than original group */
516.  		ls->range = candle_light_range(src);
517.  		new_ls->range = candle_light_range(dest);
518.  		vision_full_recalc = 1;	/* in case range changed */
519.  	    }
520.  	    new_ls->id = (genericptr_t) dest;
521.  	    new_ls->next = light_base;
522.  	    light_base = new_ls;
523.  	    dest->lamplit = 1;		/* now an active light source */
524.  	}
525.  }
526.  
527.  /* light source `src' has been folded into light source `dest';
528.     used for merging lit candles and adding candle(s) to lit candelabrum */
529.  void
530.  obj_merge_light_sources(src, dest)
531.  struct obj *src, *dest;
532.  {
533.      light_source *ls;
534.  
535.      /* src == dest implies adding to candelabrum */
536.      if (src != dest) end_burn(src, TRUE);		/* extinguish candles */
537.  
538.      for (ls = light_base; ls; ls = ls->next)
539.  	if (ls->type == LS_OBJECT && ls->id == (genericptr_t) dest) {
540.  	    ls->range = candle_light_range(dest);
541.  	    vision_full_recalc = 1;	/* in case range changed */
542.  	    break;
543.  	}
544.  }
545.  
546.  /* Candlelight is proportional to the number of candles;
547.     minimum range is 2 rather than 1 for playability. */
548.  int
549.  candle_light_range(obj)
550.  struct obj *obj;
551.  {
552.      int radius;
553.  
554.      if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
555.  	/*
556.  	 *	The special candelabrum emits more light than the
557.  	 *	corresponding number of candles would.
558.  	 *	 1..3 candles, range 2 (minimum range);
559.  	 *	 4..6 candles, range 3 (normal lamp range);
560.  	 *	    7 candles, range 4 (bright).
561.  	 */
562.  	radius = (obj->spe < 4) ? 2 : (obj->spe < 7) ? 3 : 4;
563.      } else if (Is_candle(obj)) {
564.  	/*
565.  	 *	Range is incremented by powers of 7 so that it will take
566.  	 *	wizard mode quantities of candles to get more light than
567.  	 *	from a lamp, without imposing an arbitrary limit.
568.  	 *	 1..6   candles, range 2;
569.  	 *	 7..48  candles, range 3;
570.  	 *	49..342 candles, range 4; &c.
571.  	 */
572.  	long n = obj->quan;
573.  
574.  	radius = 1;	/* always incremented at least once */
575.  	do {
576.  	    radius++;
577.  	    n /= 7L;
578.  	} while (n > 0L);
579.      } else {
580.  	/* we're only called for lit candelabrum or candles */
581.       /* impossible("candlelight for %d?", obj->otyp); */
582.  	radius = 3;		/* lamp's value */
583.      }
584.      return radius;
585.  }
586.  
587.  #ifdef WIZARD
588.  extern char *FDECL(fmt_ptr, (const genericptr, char *));  /* from alloc.c */
589.  
590.  int
591.  wiz_light_sources()
592.  {
593.      winid win;
594.      char buf[BUFSZ], arg_address[20];
595.      light_source *ls;
596.  
597.      win = create_nhwindow(NHW_MENU);	/* corner text window */
598.      if (win == WIN_ERR) return 0;
599.  
600.      Sprintf(buf, "Mobile light sources: hero @ (%2d,%2d)", u.ux, u.uy);
601.      putstr(win, 0, buf);
602.      putstr(win, 0, "");
603.  
604.      if (light_base) {
605.  	putstr(win, 0, "location range flags  type    id");
606.  	putstr(win, 0, "-------- ----- ------ ----  -------");
607.  	for (ls = light_base; ls; ls = ls->next) {
608.  	    Sprintf(buf, "  %2d,%2d   %2d   0x%04x  %s  %s",
609.  		ls->x, ls->y, ls->range, ls->flags,
610.  		(ls->type == LS_OBJECT ? "obj" :
611.  		 ls->type == LS_MONSTER ?
612.  		    (mon_is_local((struct monst *)ls->id) ? "mon" :
613.  		     ((struct monst *)ls->id == &youmonst) ? "you" :
614.  		     "<m>") :		/* migrating monster */
615.  		 "???"),
616.  		fmt_ptr(ls->id, arg_address));
617.  	    putstr(win, 0, buf);
618.  	}
619.      } else
620.  	putstr(win, 0, "<none>");
621.  
622.  
623.      display_nhwindow(win, FALSE);
624.      destroy_nhwindow(win);
625.  
626.      return 0;
627.  }
628.  
629.  #endif /* WIZARD */
630.  
631.  #endif /* OVL3 */
632.  
633.  /*light.c*/

Also on Fandom

Random Wiki