
#include <stdio.h>
#include <errno.h>
extern int errno; /* sigh... */
#include <fcntl.h>
#include <signal.h>

#include "game.h"
#include "main.h"
#include "data_sprite.h"
#include "data_neighb.h"
#include "data_monsters.h"
#include "data_flags.h"
#include "score.h"
#include "bleep.c"

void draw_monsters ();

#define SAVEDPOS 50



typedef struct {
    int x;
    int y;
    int lastdir;
    int room;
} Pos;
Pos saved_pos[SAVEDPOS];

int discovery_mode;
int has_won; /* went into the last room */

int global_state;
int time_cnt;
int room_no = 0x1f;
int x_pos;
int y_pos;
int lastdir; /* 1 = right, -1 = left */
int x_delta;
int y_delta;
int y_correction;
int stairtype;
int jumping;
int height_fallen;
#define ON_WALL		(1<<0)
#define ON_STAIR	(1<<1)
#define ON_MOVELEFT	(1<<2)
#define ON_MOVERIGHT	(1<<3)
int onwhat;
int winning; /* went on the bedroom's bed */
int trip_switch;
int trip_flag; /* 1 if already changed for this room&life */
int trip_switch_shown;
int nb_lives;
int nb_deaths;
int nb_items_taken;
int liane_pos;
int old_liane_pos;
int liane_dir; /* at right or left of vertical */
int liane_speed;
int liane_catch_counter;
int liane_catched;
int liane_catched_pos;
int liane_dont_catch;
unsigned long items_taken[NROOM];
unsigned char room_visited[NROOM];


/* misc */


int exit_room;

int toleft;
int toright;
int tojump;

int goright = 0;
int goleft = 0;
int dojump = 0;


/* set by change_room/get_room : */

int player_sprite_base;
int player_sprite;
int prev_x_pos;
int prev_y_pos;
int prev_player_sprite;
int teleport_sprite;

int dead;
int dead_cnt;
int nb_automoves;
int x_automove;
int y_automove;
int dir_automove;
int automove_offset = 0;
/*#define ROOM_LIANE		(1<<0)*/
/*#define ROOM_NO_AUTOMOVE	(1<<1)*/
/*#define ROOM_DBL_AUTOMOVE	(1<<2)*/
/*#define ROOM_SPECIAL		(1<<3)*/
int r_flags;
unsigned char room_data[YROOM][XROOM];
struct {
    unsigned long mask;
    int xx;
    int yy;
    unsigned int flashstate;
#define FLASHTIME (1<<1) /* power of 2 */
} room_items[32];
int items_in_room;
int items_remaining; /* remaining in room */

Monster monsters[MONSTERS_PER_ROOM];
struct {
    int new_sprite;
    int new_x;
    int new_y;
    int prev_sprite;
    int prev_x;
    int prev_y;
} monsters_spr[MONSTERS_PER_ROOM];
int nb_monsters;

int just_entered;

int special_room;

int lift[2];
int lift_num;
int close_to_lift;

unsigned char holes_pos[4] = {0x00, 0x1b, 0x60, 0x7b};
int oldholes[0x100];
int newholes[0x100];


/* special counters */

int rocket_cnt;
int boat_cnt;
int foot_cnt;
int rescue_cnt;
int island_cnt;


int teleport_cnt;
int tel_x_pos;
int tel_y_pos;
int tel_room_no;


int roompos_list[] =
{
											  0x73, 0x74, 0x75, 0x76,
				    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,	  0x72,
						      0x68, 0x69,			  0x71,
						      0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
									0x77,
			     0x5e,			                0x30,       0x44,             0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
     0x59, 0x5a, 0x5b, 0x5c, 0x5d,		      0x2d, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x2a,				0x80, /* no 0x81 */
			     0x5f,  0x29, 0x28, 0x27, 0x3c, 0x26, 0x3d, 0x25, 0x24,
				    0x36, 0x35, 0x23, 0x22, 0x21, 0x20, 0x3e, 0x3f, 0x1f, 0x1e,
				    0x34, 0x33, 0x46, 0x1d, 0x1c, 0x1a, 0x40, 0x41, 0x19, 0x18,	/* no 82 */ 0x0d, 0x0c,
				    0x32, 0x31, 0x17, 0x16, 0x15, 0x14, 0x42, 0x43, 0x13, 0x3a, 0x0b, 0x0a, 0x09, 0x08, 0x07,
      0x50, 0x4f, 0x37, 0x38, 0x1b, 0x2f, 0x2e, 0x39, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x05, 0x04, 0x03, 0x02, 0x01, 0x45, 0x00,
							    0x51, 0x52, 0x53, 0x54, 0x55,	      0x3b, 0x2b, 0x2c,
										    0x56, 0x57,	      0x06,
											  0x58,	/* no 83 84 85 */
};

static void make_map ()
{
    int i, j;
    int *p;

    p = roompos_list;
    for (j=0; j<YROOM; j++)
	for (i=0; i<XROOM; i++)
	    if (room_data[j][i] == 1) {
		if (!room_visited[*p++])
		    room_data[j][i] = 0;
	    }
}


static void get_room ()
{
    int i, j;
    unsigned long mask = 1;
    static unsigned int flashstate = 0;

    items_in_room = 0;
    nb_automoves = 0;
    special_room = 0;
    lift_num = 0;
    for (j=0; j<YROOM; j++)
	for (i=0; i<XROOM; i++) {
	    unsigned char c;
	    c = rooms[room_no].data[j][i];
	    switch (c) {
	    case I_ITEM:
		if (items_taken[room_no] & mask)
		    c = 0;
		else {
		    flashstate += FLASHTIME+1;
		    room_items[items_in_room].mask = mask;
		    room_items[items_in_room].xx = i;
		    room_items[items_in_room].yy = j;
		    room_items[items_in_room].flashstate = flashstate;
		    items_in_room++;
		}
		mask <<= 1;
		break;
	    case I_MOVELEFT:
	    case I_MOVERIGHT:
		if (!nb_automoves) {
		    x_automove = i*16;
		    y_automove = j*16;
		    dir_automove = (c == I_MOVELEFT) ? -1 : 1;
		}
		nb_automoves++;
		break;
	    }
	    room_data[j][i] = c;
	}
    room_visited[room_no] = 1;
    if (room_no == 0x6c) /* Cartography Room */
	make_map ();
    items_remaining = items_in_room;

    nb_monsters = 0;
    for (i=0; i<MONSTERS_PER_ROOM; i++) {
	monsters[i] = room_monsters[room_no][i];
	monsters_spr[i].prev_sprite = -1;
	if (monsters[i].sprite != -1) {
	    if (monsters[i].flags & MO_LIFT)
		lift[lift_num++] = i;
	    nb_monsters++;
	}
    }

    r_flags = room_flags[room_no];
    if (r_flags & ROOM_SPECIAL)
	special_room = 1;
}



static void draw_items (int rotate)
{
    int k;

    if (items_remaining)
	for (k=0; k<items_in_room; k++)
	    if (room_items[k].mask) {
		if (0 /*color_display*/) {
		    static int a = 0;
		    if (!a) {
			a = 1;
			printf ("flash color\n");
		    }
		} else {
		    int i;
		    int state;

		    state = room_items[k].flashstate;
		    if (rotate)
			room_items[k].flashstate++;
		    if (!rotate || (state & (FLASHTIME-1)) == (FLASHTIME-1)) {
			for (i=rotate?2:1; i; i--) {
			    xor_item (I_ITEM,
				      room_items[k].xx << 3,
				      room_items[k].yy << 3,
				      state/FLASHTIME,
				      0);
			    state = room_items[k].flashstate;
			}
		    }
		}
	    }
}


#define NB_LIANE_PIX 86

int liane_x_ofs[NB_LIANE_PIX] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2
};

int liane_y_ofs[NB_LIANE_PIX] = {
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
    2, 3, 3, 2, 3, 2, 3, 2, 3, 2, 2, 2, 3, 2, 2, 2,
    2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, 3, 2, 3, 2,
    3, 3, 3, 3, 3, 3
};



static int liane_undrawing; /* local */


static void draw_liane_at (int pos)
{
#define NBP 0x1f
    XPoint points[NBP*4];
    int x = 0x1f*4+3;
    int y = 0;
    int *dx = &(liane_x_ofs[2*pos]);
    int *dy = &(liane_y_ofs[2*pos]);
    int i;
    int f = (!liane_undrawing && !liane_dont_catch
	     && (liane_catch_counter == 0));

    for (i=0; i<NBP; i++) {
	if (f && !liane_catched) {
	    if (pixel_collide (prev_player_sprite, prev_x_pos, prev_y_pos,
			       2*x, 2*y)) {
		liane_catched_pos = i;
		liane_catched = 1;
	    }
	}
	points[4*i].x = 2*x;
	points[4*i].y = 2*y;
	points[4*i+1].x = 2*x+1;
	points[4*i+1].y = 2*y;
	points[4*i+2].x = 2*x;
	points[4*i+2].y = 2*y+1;
	points[4*i+3].x = 2*x+1;
	points[4*i+3].y = 2*y+1;
	if (liane_dir == 1)
	    x += *dx++;
	else
	    x -= *dx++;
	y += *dy++;
	if (f && liane_catched && i == liane_catched_pos) {
	    if (room_no == 0x1b || room_no == 0x12 || room_no == 0x6f)
		if (liane_catched_pos <= 0x0e)
		    liane_catched_pos = 0x0e;
	    jumping = 0;
	    height_fallen = 0;
	    y_delta = 9;
	    onwhat = ON_WALL;
	    y_pos = y-8;
	    if (y_pos < 0) {
		exit_room = 1 + DIR_UP;	/* XXX exit */
	    }
	    x_pos = x/2-2;
	}
    }
    draw_liane_pixels (points, NBP*4);
}


static int draw_next_liane ()
{
    int dpos;

    liane_undrawing = 0;
    draw_liane_at (liane_pos);
    old_liane_pos = liane_pos;
    liane_pos += (liane_pos < 0x0c) ? 2*liane_speed : liane_speed;
    if (liane_pos < 0) {
	liane_pos = 4;
	liane_dir = -liane_dir;
	liane_speed = -liane_speed;
    } else if (liane_pos >= 0x1a) {
	liane_speed = -liane_speed;
    }


    if (liane_dont_catch || liane_catch_counter || !liane_catched)
	return 0;
    dpos = (toright != 0) - (toleft != 0);
    if (dpos != 0)
	x_delta = dpos;
    if (liane_dir == liane_speed)
	dpos = -dpos;
    liane_catched_pos -= dpos;
    if (liane_catched_pos != NBP) {
	if (!tojump)
	    return 1;
	jumping = 1;
	y_delta = -8;
    }
    y_pos &= ~7;
    liane_dont_catch = 1;
    liane_catch_counter = 7;
    liane_catched = 0;
    return 0;
}

static int redraw_liane ()
{
    if (!(r_flags & ROOM_LIANE))
	return 0;
    if (liane_catch_counter)
	liane_catch_counter--;
    liane_undrawing = 1;
    draw_liane_at (old_liane_pos);
    return draw_next_liane ();
}

static void liane_init ()
{
    if (!(r_flags & ROOM_LIANE))
	return;
    liane_dont_catch = 0;
    liane_undrawing = 0;
    liane_catched = 0;
    liane_catch_counter = 0;
    liane_dir = 1;
    liane_speed = -1;
    liane_pos = 0x1a;
    draw_next_liane ();
}


static void special_init ()
{
    switch (room_no) {
    case 0x3b: /* Highway to Hell */
    case 0x71: { /* The Trubble with Tribbles is.... */
	int i;
	for (i=0; i<0x100; i++)
	    oldholes[i] = newholes[i] = 0;
	break;
    }
    case 0x67: /* Foot Room */
	put_sprite_noxor (0x000, 2*128, 16, 3);
	foot_cnt = 0xbc;
	break;
    case 0x44: /* Belfry */
    case 0x79: /* Galactic Invasion */
	{
	    int i;
	    for (i=0; i<5; i++) {
		int cnt = monsters[i].y;
		/*if (monsters[i].dy < 0)
		    cnt -= monsters[i].dy;*/
		draw_thread (monsters[i].x, 0, cnt);
	    }
	}
	break;
    }
}



static void set_room ()
{
#if 0
    extern int slider_pos;
    extern Widget slider;
    extern int debugging;
#endif

    player_sprite_base = room_sprite[room_no];
    prev_player_sprite = -1;
    teleport_sprite = -1;
    get_room ();
    draw_room ();
    draw_items (0);

#if 0
    if (debugging) {
	slider_pos = room_no;
	set_slider (slider);
    }
#endif

    exit_room = 0;
    dead = 0;
    dead_cnt = (color_display ? NB_FLASHES_COLOR : NB_FLASHES_MONO) + 1;
}


static void init_room ()
{
    if (special_room)
	special_init ();
    liane_init ();
    trip_flag = 0;
    close_to_lift = 0;
}


static void change_room ()
{
    set_room ();
    init_room ();
    just_entered = 2;
}


static void new_live ()
{
    x_delta = 0;
    y_delta = 9;
    y_correction = 0;
    stairtype = 0;
    jumping = 0;
    height_fallen = 0;
    onwhat = 0;
    x_pos = saved_pos[1].x;
    y_pos = saved_pos[1].y;
    lastdir = saved_pos[1].lastdir;
    room_no = saved_pos[1].room;
    bcopy (saved_pos+3, saved_pos, (SAVEDPOS-3)*sizeof (Pos));
    show_nb_lives ();
    change_room ();
    just_entered = 0;
}

void new_game ()
{
    int i;

    enable_colormap (1);
    global_state = STATE_PLAYING;
    set_play_state ();
    discovery_mode = 0;
    set_discovery_state ();
    time_cnt = -60;
    winning = 0;
    has_won = 0;
    rescue_cnt = 1000;
    saved_pos[0].x = 0x50;
    saved_pos[0].y = 0x68;
    saved_pos[0].room = 0x1f;
    saved_pos[0].lastdir = 1;
    for (i=1; i<SAVEDPOS; i++)
	saved_pos[i] = saved_pos[0];
    for (i=0; i<NROOM; i++) {
	items_taken[i] = 0;
	room_visited[i] = 0;
    }
    nb_items_taken = 0;
    teleport_cnt = 0;
    show_nb_items_taken ();
    trip_switch = 0;
    trip_switch_shown = 0;
    show_tripswitch (0); /* empty */
    nb_lives = 500;
    nb_deaths = 0;
    new_live ();
}


static unsigned char what_at (int x, int y)
{
    if (y>=0 && y<8*YROOM && x>=0 && x<4*XROOM)
	return room_data[y >> 3][x >> 2];
    else
	return 0;
}


static void take_item (int x, int y)
{
    int k;

    x >>= 2;
    y >>= 3;
    room_data[y][x] = 0;
    for (k=0; k<items_in_room; k++) {
	if (room_items[k].xx == x && room_items[k].yy == y) {
	    items_taken[room_no] |= room_items[k].mask;
	    room_items[k].mask = 0; /* invalidate item */
	    xor_item (I_ITEM, x<<3, y<<3,
		      room_items[k].flashstate/FLASHTIME,
		      0);
	    break;
	}
    }
    nb_items_taken++;
    putc(07,stderr);
    items_remaining--;
    show_nb_items_taken ();
}


static int do_lift ()
{
    int i;
    int y_on_lift;

    if (!lift_num)
	return 0;
    close_to_lift = 0;
    if (y_delta >= 0) {
	for (i=0; i<lift_num; i++) {
	    int li = lift[i];
	    int dx, dy, d;
	    int liy;

	    dx = x_pos - monsters[li].x + 4;
	    if (dx < 0 || dx >= 0x0c)
		continue;
	    liy = monsters[li].y;
	    d = (monsters[li].dy == 1) ? 1 : -1;
	    if (monsters[li].counter == 1)
		d = -d;
	    liy += d;
	    dy = y_pos + y_correction - liy + 0x15;
	    if (dy < 0 || dy >= 0x07)
		continue;
	    close_to_lift = 1;
	    y_on_lift = liy - 0x10;
	}
    }
    if (!close_to_lift)
	return 0;
    if (height_fallen >= 0x30) {
	dead = 1;
	return 0;
    }
    close_to_lift = 0;
    height_fallen = 0;
    if (tojump)
	return 1; /* 83a9 */
    y_pos = y_on_lift & ~7;
    y_correction = y_on_lift & 7;
    jumping = 0;
    y_delta = 9;
    onwhat = ON_WALL;
    close_to_lift = 1;
    return 2; /* 84b0 */
}



static int do_special ()
{
    if (!special_room)
	return 0;
    switch (room_no) {
    case 0x77:						      /* Rocket Room */
	if (items_taken[room_no] == 0x03 && y_pos == 0x30
	    && global_state != STATE_ROCKET) {
	    global_state = STATE_ROCKET;
	    rocket_cnt = 0x80;
	}
	return 0;
    case 0x4b:						     /* Rigor Mortis */
	if (items_taken[room_no] == 0x03 && monsters[0].dx == 0) {
	    monsters[0].dx = -1;
	    monsters[0].counter = 0x1c;
	    monsters[1].dx = 1;
	    monsters[1].counter = 0x1c;
	}
	return 0;
    case 0x4c:							    /* Crypt */
	if ((   what_at (x_pos  , y_pos) == I_MOVELEFT
	     || what_at (x_pos+4, y_pos) == I_MOVELEFT) /* (5) switch ? */
	    && monsters[0].reload != 0x1f) {
	    xor_item (I_MOVELEFT, 128, 24, 0, 1);
	    xor_item (I_MOVERIGHT, 128, 24, 0, 1);
	    monsters[0].reload += 0x10;
	    if (monsters[0].dx < 0)
		monsters[0].counter += 0x10;
	}
	return 0;
    case 0x3b: /* Highway to Hell */
    case 0x71: /* The Trubble with Tribbles is.... */
	{
	    int i;
	    for (i=0; i<4; i++) {
		int j;
		for (j=0; j<0x0a; j++)
		    newholes[(holes_pos[i]+j)&0xff] = 0;
	    }
	    for (i=0; i<0x100; i++) {
		if (oldholes[i] != newholes[i]) {
		    int x = i & 0x3f;
		    int y = (i >> 6)*3 + 4;
		    xor_floor (4*x, 8*y);
		    room_data[y][x>>1] = newholes[i];
		}
		oldholes[i] = newholes[i];
		newholes[i] = 1;
	    }
	    holes_pos[0]++;
	    holes_pos[1]--;
	    holes_pos[2]++;
	    holes_pos[3]--;
	}
	return 0;
    case 0x7e: /* Eggoids */
	{
	    int i;
	    for (i=0; i<nb_monsters; i++) {
		if (((monsters[i].y - 4) & 0xff) >= 0x60)
		    monsters[i].dy = - monsters[i].dy;
		if (((monsters[i].x - 2) & 0xff) >= 0x77)
		    monsters[i].dx = - monsters[i].dx;
		monsters[i].counter = 0;
	    }
	}
	return 0;
    case 0x67: /* Foot Room */
	if (items_taken[room_no] == 0x03
	    && foot_cnt != 0) {
	    int y, yy;

	    foot_cnt -= 2;
	    y = 0xd0 - foot_cnt;
	    put_sprite_noxor (0x000, 2*128, y, 3);
	    yy = 2+((y>>4)&0x0f);
	    room_data[yy][16] = 3;
	    if (y >= 0xc0)
		room_data[yy-1][16] = 3;
	}
	return 0;
    case 0x60: /* Beam me down Spotty */
	if (   ((x_pos & 0xfc) == 0x14 && y_pos == 0x18)
	    || ((x_pos & 0xfc) == 0x3c && y_pos == 0x18)) {
	    teleport_cnt = 0x64;
	    global_state = STATE_TELEPORT;
	    if ((x_pos & 0xfc) == 0x14) {
		tel_x_pos = 0x0c;
		tel_y_pos = 0x08;
		tel_room_no = 0x78;
	    } else {
		tel_x_pos = 0x48;
		tel_y_pos = 0x68;
		tel_room_no = 0x1f;
	    }
	    return 3; /* teleport */
	}
	return 0;
    case 0x7f: /* Beam me up Spotty */
	if ((x_pos & 0xfc) == 0x70 && y_pos == 0x10) {
	    teleport_cnt = 0x64;
	    global_state = STATE_TELEPORT;
	    tel_x_pos = 0x0c;
	    tel_y_pos = 0x58;
	    tel_room_no = 0x60;
	    return 3; /* teleport */
	}
	return 0;
    case 0x50: /* Deserted Isle */
	if (items_taken[room_no] == 1) {
	    if (rescue_cnt != 0) {
		--rescue_cnt;
		draw_rescue (rescue_cnt);
		island_cnt = 0;
		return 0;
	    } else {
		island_cnt++;
		if (island_cnt < 0x28) {
		    toleft = 1;
		    toright = 0;
		    tojump = 0;
		    return 0;
		}
		if (island_cnt < 0x7d) {
		    toleft = 1;
		    toright = 0;
		    tojump = 0;
		    move_tree ();
		    return 0;
		}
		if (island_cnt == 0x7d)
		    toleft = 0;
		island_cnt = 0x80;
		{
		    int i;
		    for (i=0; i<5; i++)
			room_data[7+i][14] = 0;
		}
		if ((x_pos & 0xfc) == 0x40 && y_pos == 0x50) {
		    teleport_cnt = 0x64;
		    global_state = STATE_TELEPORT;
		    tel_x_pos = 0x44;
		    tel_y_pos = 0x58;
		    tel_room_no = 0x60;
		    return 3; /* teleport */
		}
	    }
	}
	return 0;
    case 0x44: /* Belfry */
    case 0x79: /* Galactic Invasion */
	{
	    int i;
	    for (i=0; i<5; i++) {
		int y = monsters[i].y;
		int cnt = monsters[i].dy;
		if (monsters[i].counter == 1)
		    cnt = - cnt;
		if (cnt < 0) {
		    cnt = - cnt;
		    y -= cnt;
		}
		draw_thread (monsters[i].x, y, cnt);
	    }
	}
	return 0;
    case 0x47: /* Trip Switch */
	if ((   what_at (x_pos  , y_pos) == I_MOVELEFT
	     || what_at (x_pos+4, y_pos) == I_MOVELEFT) /* (5) switch ? */
	    && !trip_flag) {
	    xor_item (I_MOVELEFT, 24, 8, 0, 1);
	    xor_item (I_MOVERIGHT, 24, 8, 0, 1);
	    trip_switch = 1-trip_switch;
	    trip_switch_shown = 1;
	    trip_flag = 1;
	    show_tripswitch (trip_switch?1:2);
	}
	return 0;
    case 0x38: /* The Yacht */
	if (trip_switch
	    && room_visited[0x37]
	    && items_taken[0x38] == 1
	    && items_taken[0x37] == 1
	    && y_pos == 0x60 && x_pos == 0x20) {
	    global_state = STATE_BOAT;
	    boat_cnt = 0x2a;
	    monsters[0].sprite = -1;
	    monsters[1].sprite = -1;
	    draw_monsters ();
	}
	return 0;
    case 0x21: /* Master Bedroom */
	if (nb_items_taken < WIN_ITEMS || discovery_mode) {
	    monsters[0].x = (monsters[0].x ^ 1) & 0xfd;
	    if (y_pos != 0x68) {
		monsters[0].x |= (~(y_pos/8+1)) & 3;
	    }
	} else {
	    monsters[0].sprite = -1;
	    if (!winning) {
		if (what_at (x_pos, y_pos+16) != I_MOVERIGHT)
		    return 0;
		winning = 1;
	    }
	    toright = 1;
	    toleft = 0;
	    tojump = 0;
	}
	return 0;
    case 0x1a: /* First landing */
    case 0x20: /* Top Landing */
    case 0x3e: /* Macaroni Ted */
    case 0x3f: /* Dumb Waiter */
	if (winning) {
	    toright = 1;
	    toleft = 0;
	    tojump = 0;
	}
	return 0;
    case 0x1f: /* Bathroom */
	if (winning) {
	    toright = 1;
	    toleft = 0;
	    tojump = 0;
	    if (x_pos == 0x6e) {
		x_pos = 0x0f;
		room_no = 0x85;
		x_delta = 0;
		y_delta = 9;
		jumping = 0;
		y_correction = 0;
		change_room ();
	    }
	}
	return 0;
    case 0x85:
	toright = 0;
	toleft = 0;
	tojump = 1;
	if (!has_won) {
	    has_won = 1;
	    set_discovery_state ();
	}
	return 0;
    }
    return 0;
}



static void move_player ()
{
    int old_x_pos;
    int old_y_pos;
    int nb;
    int i, j;
    int shunt;
    int maybe_save_pos = 0;
    int maybe_save_x;
    int maybe_save_y;
    int maybe_save_lastdir;
    int maybe_save_room;

    toleft = goleft;
    toright = goright;
    tojump = dojump;
    
    if (special_room) {
	switch (do_special ()) {
	case 0:
	    break;
	case 3:	/* teleport */
	    return;
	default:
	    printf ("bug\n");
	    exit (2);
	}
    }

    if (lift_num) {
	switch (do_lift ()) {
	case 0:
	    break;
	case 1:	/* 0x83a9 */
	    goto aftertestjump;
	case 2:	/* 84b0 */
	    goto changedelta;
	default:
	    printf ("bug\n");
	    exit (2);
	}
    }
    

    close_to_lift = 0;

    /* Inside "move_player" because has to override some movements */
    shunt = redraw_liane ();
    if (exit_room)
	return;
    if (shunt)
	goto aftershunt;

    if (tojump && !jumping && onwhat) {
	unsigned char c1, c2;
	c1 = what_at (x_pos, y_pos+16);
	c2 = what_at (x_pos+4, y_pos+16);
	if (c1 != 0 || c2 != 0) {
	    if (   c1 != I_MOVELEFT && c1 != I_MOVERIGHT
		&& c2 != I_MOVELEFT && c2 != I_MOVERIGHT) {
		x_delta = 0;
		if (toleft)
		    x_delta--;
		if (toright)
		    x_delta++;
	    }
	aftertestjump:
	    y_delta = -8;
	    jumping = 1;
	    y_correction = 0;
	    stairtype = 0;
	}
    }

    old_y_pos = y_pos;
    y_pos += (y_delta >> 1);

    if (y_pos < 0) {
	exit_room = 1 + DIR_UP;
	return;
    }

    if (y_delta >= 0 && (old_y_pos & 7) == 0) {
	unsigned char c;
	int i;

	stairtype = 0;
	y_correction = 0;
	onwhat = 0;
	for (i=0; i<=4; i+=4) {
	    c = what_at (x_pos+i, y_pos+16);
	    switch (c) {
	    case I_WALLSOFT:
	    case I_WALLHARD:
		onwhat |= ON_WALL;
		maybe_save_pos = 1;
		maybe_save_x = x_pos;
		maybe_save_y = y_pos & ~7;
		maybe_save_lastdir = lastdir;
		maybe_save_room = room_no;
#if 0
		if (just_entered && flag == 0) {
		    flag = 1;
		    if (!--just_entered) {
			savepos ();
			pos_safe2 = pos_safe1;
			pos_safe1 = pos1;
		    }
		}
		if (   pos1.x != x_pos
		    || pos1.y != y_pos
		    || pos1.room != room_no) {
		    pos3 = pos2;
		    pos2 = pos1;
		    savepos ();
		}
#endif
		break;
	    case I_DIE:
		dead = 1;
		return;
	    case I_STAIRRIGHT:
	    case I_STAIRLEFT:
		onwhat |= ON_STAIR;
		stairtype = c;
		break;
	    case I_MOVELEFT:
		onwhat |= ON_MOVELEFT;
		break;
	    case I_MOVERIGHT:
		onwhat |= ON_MOVERIGHT;
		break;
	    case I_ITEM:
		break;
	    }
	}
	if (onwhat & (ON_MOVELEFT | ON_MOVERIGHT)) {
	    int dir = (onwhat & ON_MOVELEFT) ? -1 : 1;
	    if (x_delta == 0) {
		if (dir == -1)
		    toleft = 1;
		else
		    toright = 1;
	    } else {
		if (   dir == lastdir
		    || (! (toleft|toright))
		    || ((dir == -1) ? toleft : toright)) {

		    if (dir == -1) {
			toleft = 1;
			toright = 0;
		    } else {
			toleft = 0;
			toright = 1;
		    }
		}
	    }
	}

	if (onwhat == 0) {
	    if (y_delta == 9) {
		liane_dont_catch = 0;
		x_delta = 0;
		height_fallen += 8;
		if (height_fallen >= 0x96)
		    height_fallen = 0x82;			  /* XXX ??? */
	    }
	} else {
	    if (height_fallen + (jumping?0x14:0) >= 0x28) {
		dead = 1;
		return;
	    }
	    liane_dont_catch = 0;
	    y_pos = old_y_pos;
	    jumping = 0;
	    height_fallen = 0;
	    y_delta = 9;
	}
    }

    if (!jumping && onwhat) {
    changedelta:
	x_delta = 0;
	if (toleft)
	    x_delta--;
	if (toright)
	    x_delta++;
    }


    old_x_pos = x_pos;
    x_pos += x_delta;


    if (!close_to_lift) {
	if (!jumping) {
	    unsigned char c;

	    c = what_at (x_pos, y_pos+8);
	    if (c == I_STAIRLEFT && (x_pos & 3) == 3 && x_delta == -1) {
		y_pos -= 8;
		stairtype = c;
		onwhat = ON_WALL;
	    }
	    c = what_at (x_pos+4, y_pos+8);
	    if (c == I_STAIRRIGHT && (x_pos & 3) == 0 && x_delta == 1) {
		y_pos -= 8;
		stairtype = c;
		onwhat = ON_WALL;
	    }
	    c = what_at (x_pos-4, y_pos+16);
	    if (c == I_STAIRLEFT && (x_pos & 3) == 0 && x_delta == 1) {
		y_pos += 8;
		stairtype = c;
		onwhat = ON_WALL;
	    }
	    c = what_at (x_pos+8, y_pos+16);
	    if (c == I_STAIRRIGHT && (x_pos & 3) == 3 && x_delta == -1) {
		y_pos += 8;
		stairtype = c;
		onwhat = ON_WALL;
	    }

	    /* test if at top of stairs */
	    if (   stairtype == I_STAIRRIGHT
		&& what_at (x_pos+4, y_pos+16) != I_STAIRRIGHT)
		stairtype = 0;
	    else if (   stairtype == I_STAIRLEFT
		     && what_at (x_pos, y_pos+16) != I_STAIRLEFT)
		stairtype = 0;
	}
	switch (stairtype) {
	case I_STAIRLEFT:
	    y_correction = 2*(x_pos & 3);
	    break;
	case I_STAIRRIGHT:
	    y_correction = 2*(3 - (x_pos & 3));
	    break;
	default:
	    y_correction = 0;
	    break;
	}
    }

 aftershunt:

    nb = (y_pos & 7) ? 3 : 2;
    for (j=0; j<nb; j++)
	for (i=0; i<=4; i+=4) {
	    unsigned char c;

	    c = what_at (x_pos+i, y_pos+8*j);
	    if (c == I_DIE) {
		dead = 1;
		return;
	    } else if (c == I_ITEM)
		take_item (x_pos+i, y_pos+8*j);
	    else if (c == I_WALLHARD) {
		x_pos = old_x_pos;
		j = nb;
		break;
	    }
	}

    if (jumping && y_delta < 0 && (old_y_pos & 7) == 0) {
	for (i=0; i<=4; i+=4) {
	    unsigned char c;
	    c = what_at (x_pos+i, y_pos);
	    if (c == I_DIE) {
		dead = 1;
		return;
	    } else if (c == I_ITEM)
		take_item (x_pos+i, y_pos);
	    else if (c == I_WALLHARD) {
		y_pos = old_y_pos;
		y_delta = 7;
		break;
	    }
	}
    }

    if (maybe_save_pos) {
	int i;
	Pos *p = saved_pos;
	for (i=0; i<SAVEDPOS-1; i++, p++) {
	    if (   p->x == maybe_save_x
		&& p->y == maybe_save_y
		&& p->lastdir == maybe_save_lastdir
		&& p->room == maybe_save_room) {
		if (i > 0) {
		    Pos po = *p;
		    bcopy (saved_pos, saved_pos+1, i * sizeof (Pos));
		    saved_pos[0] = po;
		}
		break;
	    }
	}
	if (i == SAVEDPOS-1) {
	    bcopy (saved_pos, saved_pos+1, (SAVEDPOS-1) * sizeof (Pos));
	    saved_pos[0].x = maybe_save_x;
	    saved_pos[0].y = maybe_save_y;
	    saved_pos[0].lastdir = maybe_save_lastdir;
	    saved_pos[0].room = maybe_save_room;
	}
    }




    if (++y_delta == 10)
	y_delta = 9;
    

    if (y_pos + y_correction < 0) {
	exit_room = 1 + DIR_UP;
	return;
    } else if (y_pos + y_correction >= 0x6d) {
	exit_room = 1 + DIR_DOWN;
	return;
    }


    /* if (!onwhat || jumping) { dosound; } */


    if (x_delta != 0)
	lastdir = x_delta;

    if (x_pos == 0) {
	exit_room = 1 + DIR_LEFT;
	return;
    }
    if (x_pos == 0x7b) {
	exit_room = 1 + DIR_RIGHT;
	return;
    }
}


static void move_monsters ()
{
    int i;

    for (i=0; i<nb_monsters; i++) {
	int x, y, sprite;
	int offspr;
	int flags = monsters[i].flags;

	if (flags & MO_ARROW) {
	    int visible;

	    monsters[i].x = (monsters[i].x + monsters[i].dx) & 0xff;
	    visible = (monsters[i].x < 0x20);
	    sprite = visible ? monsters[i].sprite : -1;
	    x = monsters[i].x * 4;
	    y = monsters[i].y;
	} else {
	    if (!--monsters[i].counter) {
		monsters[i].counter = monsters[i].reload;
		monsters[i].dx = - monsters[i].dx;
		monsters[i].dy = - monsters[i].dy;
	    }
	    monsters[i].x += monsters[i].dx;
	    monsters[i].y += monsters[i].dy;
	    sprite = monsters[i].sprite;
	    x = monsters[i].x;
	    y = monsters[i].y;
	}
	offspr = (flags & MO_OFF_IS_X) ? x : monsters[i].counter;
	offspr &= monsters[i].offsetmask;	/* <=3 */
	if (!(flags & MO_FIXED_DIR)) {
	    if (flags & MO_OFF_IS_X) {
		if (monsters[i].dx >= 0)
		    offspr += 4;
	    } else {
		if (monsters[i].dy < 0)
		    offspr += 4;
	    }
	}
	if (flags & MO_ONE_WAY)
	    if (offspr >= 4)
		sprite = -1;
	if (sprite != -1)
	    sprite += offspr;
	monsters_spr[i].new_sprite = sprite;
	monsters_spr[i].new_x = x;
	monsters_spr[i].new_y = y;
    }
}


static void draw_player ()
{
    player_sprite = player_sprite_base + (x_pos & 3) + 4*(lastdir == -1);
    if (room_no == 0x1c)				   /* nightmare room */
	player_sprite = player_sprite_base + (x_pos & 3)
	    + 4*(lastdir == 1);
    else
	player_sprite = player_sprite_base + (x_pos & 3)
	    + 4*(lastdir == -1);
    
    /* Erase player sprite and draw new one */
    
    if (teleport_sprite != -1) {
	put_sprite (teleport_sprite,
		    prev_x_pos,
		    prev_y_pos,
		    3);
    } else {
	if (prev_player_sprite != -1) {
	    put_sprite (prev_player_sprite,
			prev_x_pos,
			prev_y_pos,
			3);
	}
    }
    prev_x_pos = 2*((x_pos & ~3)<<1);
    prev_y_pos = 2*(y_pos+y_correction);
    prev_player_sprite = player_sprite;

    if (global_state == STATE_TELEPORT) {
	teleport_sprite = make_teleport_sprite (player_sprite);
	put_sprite (teleport_sprite,
		    prev_x_pos,
		    prev_y_pos,
		    3);
    } else {
	teleport_sprite = -1;
	put_sprite (prev_player_sprite,
		    prev_x_pos,
		    prev_y_pos,
		    3);
    }
}

void draw_monsters ()
{	
    int i;

    for (i=0; i<nb_monsters; i++) {
	if (monsters_spr[i].prev_sprite != -1) {
	    put_sprite (monsters_spr[i].prev_sprite,
			monsters_spr[i].prev_x,
			monsters_spr[i].prev_y,
			monsters[i].color);
	}
	monsters_spr[i].prev_sprite = monsters_spr[i].new_sprite;
	monsters_spr[i].prev_x = 2*((monsters_spr[i].new_x & ~3)<<1);
	monsters_spr[i].prev_y = 2*monsters_spr[i].new_y;
	if (monsters_spr[i].prev_sprite != -1) {
	    put_sprite (monsters_spr[i].prev_sprite,
			monsters_spr[i].prev_x,
			monsters_spr[i].prev_y,
			monsters[i].color);
	}
    }
}



static void test_collided ()		     /* must be called AFTER drawing */
{
    int i;

    if (dead)
	return;
    for (i=0; i<nb_monsters; i++) {
	if (!(monsters[i].flags & (MO_LIFT | MO_FRIENDLY))) {
	    if (sprites_collide (prev_player_sprite,
				 prev_x_pos,
				 prev_y_pos,
				 monsters_spr[i].prev_sprite,
				 monsters_spr[i].prev_x,
				 monsters_spr[i].prev_y)) {
				    dead = 1;
				    bleeep();
				    return;
				 }
	}
    }
}


static void draw_automoves ()
{
    if (!nb_automoves)
	return;
    if (r_flags & ROOM_NO_AUTOMOVE)
	return;
    draw_automove (x_automove, y_automove, 16*nb_automoves,
		   dir_automove, automove_offset&3);
    if (r_flags & ROOM_DBL_AUTOMOVE)
	draw_automove (x_automove, y_automove+4, 16*nb_automoves,
		       -dir_automove, automove_offset&3);
    automove_offset++;
}



void die ()
{
   if (!discovery_mode)
	save_score (nb_items_taken, nb_lives, time_cnt/1000, SCORE_DEAD);
    global_state = STATE_PRESENT;
    set_play_state ();
    nb_items_taken = 0;
    discovery_mode = 0;
    set_discovery_state ();
    present ();
}



void move ()
{
    if (global_state == STATE_PRESENT) {
	do_scroll ();
	return;
    }

    time_cnt += 60;
    if ((time_cnt % 1000) < 60)
	show_time (time_cnt/1000);


    switch (global_state) {
    case STATE_DYING:
	if (--dead_cnt) {
	    flash_dead (x_pos*4, y_pos*2, dead_cnt);
	    return;
	} else {
	    if (nb_lives) {
		new_live ();
		global_state = STATE_PLAYING;
	    } else {
		die ();
		return;
	    }
	}
	break;
    case STATE_ROCKET:
	if (--rocket_cnt) {
	    move_rocket ();
	    return;
	} else {
	    global_state = STATE_PLAYING;
	    exit_room = 1 + DIR_UP;
	    goto gotoexit;
	}
    case STATE_BOAT:
	if (--boat_cnt) {
	    move_boat ();
	} else {
	    global_state = STATE_PLAYING;
	    x_pos = 0x28;
	    y_pos = 0x50;
	    room_no = 0x50;
	    x_delta = 0;
	    y_delta = 9;
	    jumping = 0;
	    y_correction = 0;
	    change_room ();
	}
	return;
    case STATE_TELEPORT:
	teleport_cnt--;
	if (teleport_cnt == 0) {
	    global_state = STATE_PLAYING;
	} else if (teleport_cnt == 0x32) {
	    x_pos = tel_x_pos;
	    y_pos = tel_y_pos;
	    room_no = tel_room_no;
	    x_delta = 0;
	    y_delta = 9;
	    jumping = 0;
	    y_correction = 0;
	    change_room ();
	}
	draw_player ();	/* XXX */
	goto gotoafterplayer;
    }


    move_player ();
    if (!dead)
	draw_player ();

 gotoafterplayer:

    draw_items (1);

    move_monsters ();
    draw_monsters ();

    draw_automoves ();

    flush_rects ();
    XFlush (display);

    test_collided ();

    if (dead) {
	nb_deaths++;
	if (!discovery_mode)
	    nb_lives--;
       bleeep();
	show_nb_lives ();
	global_state = STATE_DYING;
	return;
    }

 gotoexit:
    if (exit_room) {
	switch (exit_room-1) {
	case DIR_UP:
	    y_pos = 0x68;
	    if (close_to_lift || jumping)
		x_delta = 0;
	    goto endupdown;
	    break;
	case DIR_DOWN:
	    y_pos = 0;
	    if ((height_fallen -= 8) < 0)
		height_fallen = 0;
	endupdown:
	    x_pos += x_delta;
	    x_delta = 0;
	    jumping = 0;
	    y_delta = 9;
	    break;
	case DIR_LEFT:
	    x_pos = 0x78;
	    break;
	case DIR_RIGHT:
	    x_pos = 3;
	    break;
	}
	room_no = room_neighb[room_no][exit_room - 1];
	y_correction = 0;
	change_room ();
    }
}









static char *savename = NULL;
static char *bakname = NULL;
static char *lockname = NULL;

static void create_savename ()
{
    char *savedir = SAVEDIR;

    if (savename == NULL) {
	savename = (char *) malloc (strlen (savedir) + 20);
	sprintf (savename, "%s/%d", savedir, getuid ());
	bakname = (char *) malloc (strlen (savename) + 10);
	sprintf (bakname, "%s.bak", savename);
	lockname = (char *) malloc (strlen (savename) + 10);
	sprintf (lockname, "%s.lock", savename);
    }
}

static void write_long (int fd, unsigned long n)
{
    static unsigned char buf[4];

    buf[0] = (n>>24) & 0xff;
    buf[1] = (n>>16) & 0xff;
    buf[2] = (n>>8)  & 0xff;
    buf[3] =  n      & 0xff;
    write (fd, buf, 4);
}

static unsigned long read_long (int fd)
{
    static unsigned char buf[4];

    read (fd, buf, 4);
    return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
}

static int lock_save ()
{
    int i;
    int res;

#define TRIES 2
    create_savename ();
    for (i=0; i<TRIES; i++) {
	if (i>0)
	    sleep (1);
	res = mkdir (lockname, 0400);
	if (res == 0)
	    break;
    }
    if (i == TRIES) {
	perror ("lock");			     /* couldn't create lock */
	return 0;
    }
    return 1;
}

static void unlock_save ()
{
    rmdir (lockname);
}


static void restore_game (void);

static Monster load_monsters[MONSTERS_PER_ROOM];

int load_game ()			     /* return 1 if loaded correctly */
{
    int fd;
    int i;

    if (!lock_save ())
	return 0;
    fd = open (savename, O_RDONLY);
    if (fd < 0) {
	if (errno  != ENOENT)
	    perror (savename);
	unlock_save ();
	return 0;
    }

    global_state	= read_long (fd);
    time_cnt		= read_long (fd);
    room_no		= read_long (fd);
    x_pos		= read_long (fd);
    y_pos		= read_long (fd);
    lastdir		= read_long (fd);
    x_delta		= read_long (fd);
    y_delta		= read_long (fd);
    y_correction	= read_long (fd);
    stairtype		= read_long (fd);
    jumping		= read_long (fd);
    height_fallen	= read_long (fd);
    onwhat		= read_long (fd);
    winning		= read_long (fd);
    trip_switch		= read_long (fd);
    trip_flag		= read_long (fd);
    trip_switch_shown	= read_long (fd);
    discovery_mode	= read_long (fd);
    nb_lives		= read_long (fd);
    nb_deaths		= read_long (fd);
    nb_items_taken	= read_long (fd);
    liane_pos		= read_long (fd);
    old_liane_pos	= read_long (fd);
    liane_dir		= read_long (fd);
    liane_speed		= read_long (fd);
    liane_catch_counter	= read_long (fd);
    liane_catched	= read_long (fd);
    liane_catched_pos	= read_long (fd);
    liane_dont_catch	= read_long (fd);
    rescue_cnt		= read_long (fd);
    island_cnt		= read_long (fd);
    foot_cnt		= read_long (fd);

    for (i=0; i<NROOM; i++)
	items_taken[i] = read_long (fd);
    for (i=0; i<NROOM; i++)
	room_visited[i] = read_long (fd);
    for (i=0; i<MONSTERS_PER_ROOM; i++) {
	load_monsters[i].sprite		= read_long (fd);
	load_monsters[i].counter	= read_long (fd);
	load_monsters[i].reload		= read_long (fd);
	load_monsters[i].x		= read_long (fd);
	load_monsters[i].y		= read_long (fd);
	load_monsters[i].dx		= read_long (fd);
	load_monsters[i].dy		= read_long (fd);
    }
    for (i=0; i<SAVEDPOS; i++) {
	saved_pos[i].x		= read_long (fd);
	saved_pos[i].y		= read_long (fd);
	saved_pos[i].lastdir	= read_long (fd);
	saved_pos[i].room	= read_long (fd);
    }


    close (fd);
    rename (savename, bakname);
    unlink (savename);
    unlock_save ();

    restore_game ();

    return 1;
}



int save_game (int emergency)			 /* return 1 if really saved */
{
    int fd;
    int i;

    if (!emergency)
	if (!lock_save ())
	    return 0;
    unlink (savename);					/* you never know... */
    fd = open (savename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd < 0) {
	if (!emergency) {
	    perror (savename);
	    unlock_save ();
	}
	return 0;
    }

    write_long (fd, global_state);
    write_long (fd, time_cnt);
    write_long (fd, room_no);
    write_long (fd, x_pos);
    write_long (fd, y_pos);
    write_long (fd, lastdir);
    write_long (fd, x_delta);
    write_long (fd, y_delta);
    write_long (fd, y_correction);
    write_long (fd, stairtype);
    write_long (fd, jumping);
    write_long (fd, height_fallen);
    write_long (fd, onwhat);
    write_long (fd, winning);
    write_long (fd, trip_switch);
    write_long (fd, trip_flag);
    write_long (fd, trip_switch_shown);
    write_long (fd, discovery_mode);
    write_long (fd, nb_lives);
    write_long (fd, nb_deaths);
    write_long (fd, nb_items_taken);
    write_long (fd, liane_pos);
    write_long (fd, old_liane_pos);
    write_long (fd, liane_dir);
    write_long (fd, liane_speed);
    write_long (fd, liane_catch_counter);
    write_long (fd, liane_catched);
    write_long (fd, liane_catched_pos);
    write_long (fd, liane_dont_catch);
    write_long (fd, rescue_cnt);
    write_long (fd, island_cnt);
    write_long (fd, foot_cnt);

    for (i=0; i<NROOM; i++)
	write_long (fd, items_taken[i]);
    for (i=0; i<NROOM; i++)
	write_long (fd, room_visited[i]);
    for (i=0; i<MONSTERS_PER_ROOM; i++) {
	write_long (fd, monsters[i].sprite);
	write_long (fd, monsters[i].counter);
	write_long (fd, monsters[i].reload);
	write_long (fd, monsters[i].x);
	write_long (fd, monsters[i].y);
	write_long (fd, monsters[i].dx);
	write_long (fd, monsters[i].dy);
    }
    for (i=0; i<SAVEDPOS; i++) {
	write_long (fd, saved_pos[i].x);
	write_long (fd, saved_pos[i].y);
	write_long (fd, saved_pos[i].lastdir);
	write_long (fd, saved_pos[i].room);
    }

    close (fd);
    if (!emergency)
	unlock_save ();
    return 1;
}



static void restore_game ()
{
    int i;

    switch (global_state) {
    case STATE_ROCKET:
    case STATE_TELEPORT:
	global_state = STATE_PLAYING;
	break;
    }
    boat_cnt = 0x2a;
    teleport_cnt = 0; /* restart teleportation */

    set_play_state ();
    show_time (time_cnt/1000);
    show_nb_lives ();
    show_nb_items_taken ();
    set_discovery_state ();
    if (trip_switch_shown)
	show_tripswitch (trip_switch?1:2);

    set_room ();
    enable_colormap (1);
    for (i=0; i<nb_monsters; i++) {
	monsters[i].sprite = load_monsters[i].sprite;
	monsters[i].counter = load_monsters[i].counter;
	monsters[i].reload = load_monsters[i].reload;
	monsters[i].x = load_monsters[i].x;
	monsters[i].y = load_monsters[i].y;
	monsters[i].dx = load_monsters[i].dx;
	monsters[i].dy = load_monsters[i].dy;
    }

    just_entered = 0; /* XXX ? */
    if (special_room) {
	int f = foot_cnt;
	special_init ();
	foot_cnt = f;
    }
    if (room_no == 0x50) { /* Deserted Isle */
	if (rescue_cnt == 0) {
	    int i;
	    island_cnt = 0x80; /* tree fallen */
	    clear_tree ();
	    for (i=0; i<5; i++)
		room_data[7+i][14] = 0;
	}
    }
    if (room_no == 0x67) { /* Foot Room */
	if (items_taken[room_no] == 0x03) {
	    int f = foot_cnt;
	    foot_cnt = 0xbc;
	    while (foot_cnt != f) {
		do_special ();
	    }
	}
    }
}


void emergency (int sig)
{
    int i;

    for (i=1; i<32; i++)
	signal (i, SIG_DFL);

    if (global_state != STATE_PRESENT && !has_won) {
	write (2, "Emergency save !\n", 17);
	if (!save_game (1))
	    write (2, "Couldn't save the game\n", 23);
    }

    if (sig == SIGQUIT || sig == SIGSEGV || sig == SIGBUS)
	abort ();
    else
	exit (255);
}
