Hi,<br><br>I have been working on a roguelike game in scheme. Due to being unable to find an implementation of scheme with support for ncurses, and after a somewhat disappointing (but informative) attempt using chicken scheme, I eventually decided that extending mzscheme was the way forward.
<br><br>The extension has gone fairly well and provides most of the functionality I desire (including much of the number crunching for line of sight). However the following problems are unresolved.<br><br>I am using mzscheme v370, and emacs.
<br><br>1. the scheme_malloc_* family of functions segfault if the requested memory is unavailable.<br><br>2. Is it possible to register a function which is called when a object is garbage collected?<br><br>3. I have found it desirable to create scheme objects which act as a wrapper for the actual game data. It is undesirable to have to use (map-width * map-height * sizeof(Scheme_Object)) bytes when only a few map elements are accessed at any one time. Secondly when handling map elements it is often desirable to know its coordinates, which can be stored in the wrapper.
<br>This would be simple, except that i would prefer for there to never be two objects which are a wrapper for the same map element. Not only is this unintuitive, but it prevents the possibility of testing for equality using the eqv?.
<br>The best idea I have had is to use a hash map to keep a record of currently available wrapper objects and return the appropriate wrapper. However, question 2 would have to be possible in order to keep the table updated. Also there is the issue of how long to keep unreferenced wrappers around (a round robbin system similar to that used in the caching of some operating systems could be profitable).
<br><br><br><br>As the source is around 2000 lines, I will not post it all here. However the functions involving memory allocation follow. Please note that I have not yet started altering the code to use a wrapper for the scheme type map-element.
<br><br>/* A structure representing indevidual tiles (map elements) of a dungeon.<br> Notice the data field. This allows game specific data to be stored on the tile<br> while keeping all the engine relevent data visible to the engine.*/
<br>typedef struct {<br> Scheme_Object so ; <br> unsigned char seen : 1 ; /* has this map element ever been seen? */<br> unsigned char visible : 1 ; /* can this map element be seen right now? */<br>
unsigned char opaque_to_visible : 1 ; /* is this map element opaque to normal light? */<br> unsigned char opaque_to_uv : 1 ; /* is this map element opaque to uv light? */<br> unsigned char opaque_to_ir : 1 ; /* is this map element opaque to ir light? */
<br> unsigned char solid : 1 ;<br> unsigned char changed : 1 ; /* Not really shure about the advisibility of this, however it avoids<br> repeatedly inserting the same coordinates into the changed list. */
<br> unsigned char residual_heat ;<br> unsigned char lit_visible ; /* is this map element lit by normal light?*/<br> unsigned char lit_uv ; /* is this map element lit by uv light? */<br> char print_char ;
<br> char display_print_char ;<br> Scheme_Object *data ;<br>} Map_element ;<br><br>/* The structure representing the actual dungeon. */<br>typedef struct {<br> Scheme_Object so ; <br> unsigned int w ;<br> unsigned int h ;
<br> unsigned int l ;<br> unsigned char ambient_visible_light ;<br> unsigned char ambient_uv_light ;<br> unsigned char ambient_heat ;<br> Map_element *map;<br> struct changed *changed_list ;<br>} Dungeon ;<br><br><br>
Scheme_Object *make_dungeon(int argc, Scheme_Object **argv) {<br> unsigned long w, h, l, i ;<br> Map_element *map ;<br> Dungeon *dn ;<br><br> if (!SCHEME_INTP(argv[0]) || negative(argv[0]))<br> scheme_wrong_type("make-dungeon", "positive integer", 0, argc, argv);
<br> if (!SCHEME_INTP(argv[1]) || (negative(argv[1])))<br> scheme_wrong_type("make-dungeon", "positive integer", 1, argc, argv);<br><br> w = SCHEME_INT_VAL(argv[0]);<br> h = SCHEME_INT_VAL(argv[1]);
<br> l = w * h ;<br><br> /* Malloc the dungeon */<br> dn = (Dungeon *)scheme_malloc_tagged(sizeof(Dungeon)) ;<br> dn->so.type = dungeon_type;<br><br> /*map = (Map_element *)scheme_malloc_fail_ok(scheme_malloc, sizeof(Map_element) * l);*/
<br> map = (Map_element *)scheme_malloc_tagged(sizeof(Map_element) * l) ;<br> if (!map) {<br> scheme_raise_exn(MZEXN_FAIL, "make-dungeon: out of memory") ;<br> }<br><br> dn->w = w ;<br> dn->h = h ;
<br> dn->l = l ;<br> dn->map = map ;<br> dn->changed_list = NULL ;<br><br> /* Init dungeon to safe vals : */<br> for (i = 0 ; i < l ; i++) {<br> dn->map[i].so.type = map_element_type ;
<br> dn->map[i].seen = 0 ;<br> dn->map[i].visible = 0 ;<br> dn->map[i].changed = 0 ;<br> dn->map[i].residual_heat = 0 ;<br> dn->map[i].lit_visible = 0 ;<br> dn->map[i].lit_uv = 0 ;<br> dn->map[i].opaque_to_visible = 0 ;
<br> dn->map[i].opaque_to_uv = 0 ;<br> dn->map[i].opaque_to_ir = 0 ;<br> dn->map[i].print_char = ' ' ;<br> dn->map[i].display_print_char = ' ' ;<br> dn->map[i].data = scheme_false ;
<br> }<br><br> return (Scheme_Object *)dn ;<br>}<br><br><br><br><br>Thanks<br><br><br>Dragal<br>