Beispiel #1
0
static automap_path *automap_find_path(loc_node *location, loc_node *dest,
				       BOOL by_walking)
{
  automap_path *path = NULL;
  automap_path *rev;
  automap_path newnode;
  loc_node *p;

  /* Find the distances of all nodes from dest */
  n_hash_enumerate(&rooms, make_distant);
  automap_calc_distances(dest, 0, by_walking);

  /* If dest isn't reachable, location's distance will still be infinite */
  if(location->dist == INFINITY)
    return NULL;

  /* At each step, go toward a nearer node 'till we're there */
  p = location;
  while(p != dest) {
    unsigned i;
    unsigned best_dir;
    glui32 best_dist = INFINITY;
    loc_node *best_node = NULL;
    unsigned maxdir = by_walking ? NUM_EXITS : NUM_DIRS;
    for(i = 0; i < maxdir; i++) {
      loc_node *thisdest;
      if(by_walking)
	thisdest = p->exits[i];
      else
	thisdest = automap_edge_follow(p, i);
      
      if(thisdest && thisdest->dist < best_dist) {
	best_dir = i;
	best_dist = thisdest->dist;
	best_node = thisdest;
      }
    }
    if(!best_node) {
      n_show_error(E_SYSTEM, "couldn't find path there", 0);
      return NULL;
    }
    newnode.loc = p;
    newnode.dir = best_dir;
    LEadd(path, newnode);
    p = best_node;
  }

  rev = NULL;
  while(path) {
    LEadd(rev, *path);
    LEremove(path);
  }

  return rev;
}
Beispiel #2
0
static void automap_find_cycles(loc_node *location, automap_path *curpath)
{
  unsigned i;
  location->touched = TRUE;
  for(i = 0; i < NUM_DIRS; i++) {
    loc_node *thisdest = automap_edge_follow(location, i);
    if(thisdest && thisdest->found) {
      automap_path newnode;
      newnode.dir = i;
      newnode.loc = location;
      LEadd(curpath, newnode);

      if(thisdest->touched) {           /* Found a cycle! */
	int cyclelength = 0;
	automap_path *p;
	cycleequation *cycle = NULL;
	cycleequation newcycle;
	for(p = curpath; p; p=p->next) {
	  int dir = p->dir;
	  newcycle.var = &(p->loc->outgoing[dir]->guess_length);
	  newcycle.min = &(p->loc->outgoing[dir]->min_length);
	  newcycle.xcoefficient = dirways[dir].deltax;
	  newcycle.ycoefficient = dirways[dir].deltay;
	  LEadd(cycle, newcycle);
	  
	  cyclelength++;
	  if(p->loc == thisdest) {      /* Found the relevant endpoint */
	    if(cyclelength <= 2)     /* Ignore two nodes going to each other */
	      LEdestroy(cycle);
	    else
	      automap_add_cycle(cycle); /* automap_add_cycle gets ownership */
	    break;
	  }
	}
	if(!p) {                        /* The cycle had already been found */
	  LEdestroy(cycle);
	}
      } else {
	automap_find_cycles(thisdest, curpath);
      }
      LEremove(curpath);
    }
  }
}
Beispiel #3
0
void kill_undo(void)
{
  n_free(prevstate);
  prevstate = 0;

  while(movelist) {
    n_free(movelist->delta);
    n_free(movelist->stackchunk);
    LEremove(movelist);
  }
  move_index = 0;

#ifdef DEBUGGING
  n_free(automap_undoslot.z_mem);
  n_free(automap_undoslot.stackchunk);
  automap_undoslot.z_mem = NULL;
  automap_undoslot.z_memsize = 0;
  automap_undoslot.PC = 0;
  automap_undoslot.stackchunk = NULL;
  automap_undoslot.stackchunksize = 0;
  automap_undoslot.stacklength = 0;
#endif
}
Beispiel #4
0
BOOL saveundo(BOOL in_instruction)
{
  move_difference newdiff;
  strid_t stack;
  stream_result_t poo;

  if(!allow_saveundo)
    return TRUE;

  /* In games which provide @save_undo, we will have already issued a faked
     saveundo before the first @save_undo hits, since there hadn't been any
     @save_undo before the first read line.  So when this happens, wipe the
     fake saveundo in favor of the real one */
  if(in_instruction && movelist && !movelist->next
     && !movelist->PC_in_instruction)
    init_undo();

    
  if(!quetzal_diff(z_memory, prevstate, dynamic_size, &newdiff.delta,
		   &newdiff.deltalength, TRUE))
    return FALSE;

#ifdef PARANOID
  {
    char *newmem = (char *) n_malloc(dynamic_size);
    n_memcpy(newmem, prevstate, dynamic_size);
    quetzal_undiff(newmem, dynamic_size, newdiff.delta,
		   newdiff.deltalength, TRUE);
    if(n_memcmp(z_memory, newmem, dynamic_size)) {
      n_show_error(E_SAVE, "save doesn't match itself", 0);
    }
    n_free(newmem);
  }
#endif
  
  newdiff.PC = PC;
  newdiff.oldPC = oldPC;
  
  newdiff.PC_in_instruction = in_instruction;
  newdiff.stacklength = get_quetzal_stack_size();
  newdiff.stackchunk = (zbyte *) n_malloc(newdiff.stacklength);
  stack = glk_stream_open_memory((char *) newdiff.stackchunk,
				 newdiff.stacklength, filemode_Write, 0);
  if(!stack) {
    n_free(newdiff.delta);
    n_free(newdiff.stackchunk);
    return FALSE;
  }
  if(!quetzal_stack_save(stack)) {
    glk_stream_close(stack, NULL);
    n_free(newdiff.delta);
    n_free(newdiff.stackchunk);
    return FALSE;
  }
  glk_stream_close(stack, &poo);
  if(poo.writecount != newdiff.stacklength) {
    n_show_error(E_SAVE, "incorrect stack size assessment", poo.writecount);
    n_free(newdiff.delta);
    n_free(newdiff.stackchunk);
    return FALSE;
  }

  while(move_index-- > 0) {
    n_free(movelist->delta);
    n_free(movelist->stackchunk);
    LEremove(movelist);
  }
  LEadd(movelist, newdiff);
  move_index++;
  n_memcpy(prevstate, z_memory, dynamic_size);

  has_done_save_undo = TRUE;
  return TRUE;
}