/*--------------------------------------------------------------------------*/ /* game board */ /*--------------------------------------------------------------------------*/ #include #include #include #include #include #include "board.h" #include "field.h" #include "main.h" #include "sprite.h" #include "canvas.h" #include "iface.h" #include "audio.h" /*--------------------------------------------------------------------------*/ /* defines */ /*--------------------------------------------------------------------------*/ #define BOARD_X(x) CELL_X((CANVAS_XCELLS - BOARD_XCELLS) / 2.0 + x) #define BOARD_Y(y) CELL_Y((CANVAS_YCELLS - BOARD_YCELLS) / 2.0 + y) #define FLOOR_DARK 0 /* steppings for light and dark */ #define FLOOR_LIGHT 7 /* outside luminance cycle */ #define FONT_NAME "-misc-fixed-medium-*-normal-*-15-0-*-*-*-*-iso8859-1" #define V_CELL_YSIZE 40 /* revive cell height */ /*--------------------------------------------------------------------------*/ /* selection states */ /*--------------------------------------------------------------------------*/ enum { SELECT_SOURCE = 1, /* non-spell */ SELECT_TARGET, SELECT_FIELD, /* field mode */ SELECT_GAME_OVER, /* the state to end all states! */ SELECT_SPELL, SELECT_SPELL_DONE, /* spell completed or failed */ T_SELECT_SOURCE, /* teleport */ T_SELECT_TARGET, H_SELECT_TARGET, /* heal */ X_SELECT_SOURCE, /* exchange */ X_SELECT_TARGET, L_SELECT_TARGET, /* elemental */ V_SELECT_SOURCE, /* revive */ M_SELECT_TARGET, /* imprison */ }; /*--------------------------------------------------------------------------*/ /* structures */ /*--------------------------------------------------------------------------*/ typedef struct { /* Slow Sprite Paint */ int count; int x1, y1; int both; /* double ssp -- for exchange spell */ int x2, y2; int complete; /* ssp completed */ } SSP; typedef struct { int game_status; /* 0=none, 1=active, -1=paused */ int turn; /* count of turns since game start */ int side; /* 0=light, 1=dark */ int state; /* state of the board */ int lumi, lumi_d; /* luminance value and direction */ int cx, cy; /* current cursor position */ int cstate; /* state of cursor movement */ int ax0, ay0; /* initial position of picked actor */ int fire_down; /* fire key is held */ int spell; /* spell selected */ int prev_down, next_down; /* up/down key is held */ int teleport, exchange; /* teleport/exchange taking place */ int tx0, ty0; /* teleport source / exchange 1st */ int tx1, ty1; /* teleport target / exchange 2nd */ SSP ssp; /* Slow Sprite Paint data */ CELL elem; /* cell for active elemental */ char message[64]; /* last board message displayed */ int any_output; /* if any output emitted */ } BOARD_DATA; typedef struct { void *ptr; long fg, bg; } FONT; /*--------------------------------------------------------------------------*/ /* functions */ /*--------------------------------------------------------------------------*/ static void board_paint_cell(int x, int y); static void board_paint_cursor(void); static void board_message(char *format, ...); static void board_ssp_init(int x1, int y1, int x2, int y2, int both); static void board_ssp_frame(void); static void board_init_cell(CELL *cell, int actor_num); static void board_clear_cell(CELL *cell); static void board_reset_actor(ACTOR *actor); static void board_iface_turn(void); static int board_verify_move(int state); static int board_check_win(void); static void board_end_turn(int swap_side); static void board_field(int xd, int yd, int xa, int ya); static void board_move_done(void); static void board_spell_done(void); static void board_input(void); static void board_cursor(void); static void board_spell(void); static void board_teleport(int x, int y, int side); static void board_heal(int x, int y, int side); static void board_shift_time(int x, int y, int side); static void board_exchange(int x, int y, int side); static void board_summon_elemental(int x, int y, int side); static int board_revive_frame(int *i, int *old_i, int *actors); static void board_revive(int x, int y, int side); static void board_imprison(int x, int y, int side); static void board_cease_conjuring(int x, int y, int side); static int board_get_route_2(int x1, int y1, int x2, int y2, int *route, int prev_state, int light, int ground, int distance); /*--------------------------------------------------------------------------*/ /* variables */ /*--------------------------------------------------------------------------*/ static FONT font = { NULL }; int init_board_cells[BOARD_YCELLS][BOARD_XCELLS] = { { ( CELL_DARK | ACTOR_VALKYRIE ), ( CELL_LIGHT | ACTOR_ARCHER ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LUMI | CELL_POWER ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK | ACTOR_MANTICORE ), ( CELL_LIGHT | ACTOR_BANSHEE ) }, { ( CELL_LIGHT | ACTOR_GOLEM ), ( CELL_DARK | ACTOR_KNIGHT ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_LUMI ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT | ACTOR_GOBLIN ), ( CELL_DARK | ACTOR_TROLL ) }, { ( CELL_DARK | ACTOR_UNICORN ), ( CELL_LUMI | ACTOR_KNIGHT ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI | ACTOR_GOBLIN ), ( CELL_LIGHT | ACTOR_BASILISK ) }, { ( CELL_LUMI | ACTOR_DJINNI ), ( CELL_LIGHT | ACTOR_KNIGHT ), ( CELL_DARK ), ( CELL_LIGHT ), ( CELL_LUMI ), ( CELL_DARK ), ( CELL_LIGHT ), ( CELL_DARK | ACTOR_GOBLIN ), ( CELL_LUMI | ACTOR_SHAPESHIFTER ) }, { ( CELL_LIGHT | ACTOR_WIZARD | CELL_POWER ), ( CELL_LUMI | ACTOR_KNIGHT ), ( CELL_LUMI ), ( CELL_LUMI ), ( CELL_LUMI | CELL_POWER ), ( CELL_LUMI ), ( CELL_LUMI ), ( CELL_LUMI | ACTOR_GOBLIN ), ( CELL_DARK | ACTOR_SORCERESS | CELL_POWER ) }, { ( CELL_LUMI | ACTOR_PHOENIX ), ( CELL_LIGHT | ACTOR_KNIGHT ), ( CELL_DARK ), ( CELL_LIGHT ), ( CELL_LUMI ), ( CELL_DARK ), ( CELL_LIGHT ), ( CELL_DARK | ACTOR_GOBLIN ), ( CELL_LUMI | ACTOR_DRAGON ) }, { ( CELL_DARK | ACTOR_UNICORN ), ( CELL_LUMI | ACTOR_KNIGHT ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI | ACTOR_GOBLIN ), ( CELL_LIGHT | ACTOR_BASILISK ) }, { ( CELL_LIGHT | ACTOR_GOLEM ), ( CELL_DARK | ACTOR_KNIGHT ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_LUMI ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT | ACTOR_GOBLIN ), ( CELL_DARK | ACTOR_TROLL ) }, { ( CELL_DARK | ACTOR_VALKYRIE ), ( CELL_LIGHT | ACTOR_ARCHER ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LUMI | CELL_POWER ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK | ACTOR_MANTICORE ), ( CELL_LIGHT | ACTOR_BANSHEE ) } }; /* Debugging for AI */ /* **************** */ /* int init_board_cells[BOARD_YCELLS][BOARD_XCELLS] = { { ( CELL_DARK ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LUMI | CELL_POWER ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LIGHT ) }, { ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_LUMI ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK ) }, { ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT ) }, { ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LIGHT ), ( CELL_LUMI ), ( CELL_DARK ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI ) }, { ( CELL_LIGHT | ACTOR_KNIGHT | CELL_POWER ), ( CELL_LUMI ), ( CELL_LUMI ), ( CELL_LUMI ), ( CELL_LUMI | CELL_POWER ), ( CELL_LUMI ), ( CELL_LUMI ), ( CELL_LUMI ), ( CELL_DARK | ACTOR_BANSHEE | CELL_POWER ) }, { ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LIGHT ), ( CELL_LUMI ), ( CELL_DARK ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI ) }, { ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT ) }, { ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_LUMI ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK ) }, { ( CELL_DARK ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LUMI ), ( CELL_LUMI | CELL_POWER ), ( CELL_LUMI ), ( CELL_LIGHT ), ( CELL_DARK ), ( CELL_LIGHT ) } }; */ CELL board_cells[BOARD_YCELLS][BOARD_XCELLS]; static BOARD_DATA board = { 0 }; /* game status == none */ int board_turn; static int board_frame_time = 0; /*--------------------------------------------------------------------------*/ /* spells */ /*--------------------------------------------------------------------------*/ static char *spell_names[SPELL_COUNT_2] = { NULL, "teleport", "heal", "shift time", "exchange", "summon elemental", "revive", "imprison", "cease conjuring", NULL }; static void (*spell_funcs[SPELL_COUNT_2])(int x, int y, int side) = { NULL, board_teleport, board_heal, board_shift_time, board_exchange, board_summon_elemental, board_revive, board_imprison, board_cease_conjuring, NULL }; int spell_avails[3][SPELL_COUNT_2] = { { }, /* for light */ { }, /* for dark */ { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 } /* default--used to initialize */ }; /*--------------------------------------------------------------------------*/ /* board_paint_cell */ /*--------------------------------------------------------------------------*/ void board_paint_cell(int x, int y) { int sx, sy; int height; sx = BOARD_X(x); sy = BOARD_Y(y); sprite_set_state(floor_sprite, STATE_BOARD, (board_cells[y][x].flags & CELL_LIGHT) ? FLOOR_LIGHT : (board_cells[y][x].flags & CELL_DARK) ? FLOOR_DARK : board.lumi); height = (board.ssp.count != 0) ? board.ssp.count : CELL_YSIZE; sprite_paint_clipped(floor_sprite, STATE_BOARD, sx, sy, 0, 0, CELL_XSIZE, height); if (board_cells[y][x].flags & CELL_POWER) sprite_paint(floor_sprite, STATE_POWER, sx, sy); if (board.ssp.count == 0 && board_cells[y][x].actor != NULL && (board.state != SELECT_TARGET || x != board.ax0 || y != board.ay0)) sprite_paint(board_cells[y][x].actor->sprite, SPRITE_STOP, sx, sy); board.any_output = 1; } /*--------------------------------------------------------------------------*/ /* board_paint_cursor */ /*--------------------------------------------------------------------------*/ void board_paint_cursor(void) { int sx, sy; if (board.state == SELECT_GAME_OVER) return; sx = BOARD_X(0) + board.cx; sy = BOARD_Y(0) + board.cy; if (board.state == SELECT_TARGET || board.state == L_SELECT_TARGET) { if (board.state == L_SELECT_TARGET) sprite_paint(board.elem.actor->sprite, sprite_get_state(board.elem.actor->sprite), sx, sy); else sprite_paint(board_cells[board.ay0][board.ax0].actor->sprite, ( (sx % CELL_XSIZE == 0 && sy % CELL_YSIZE == 0) ? SPRITE_STOP : board.cstate ), sx, sy); sx = BOARD_X(board.ax0); sy = BOARD_Y(board.ay0); } sprite_set_state(cursor_sprite, STATE_BOARD, board.side); sprite_paint(cursor_sprite, STATE_BOARD, sx, sy); board.any_output = 1; } /*--------------------------------------------------------------------------*/ /* board_message */ /*--------------------------------------------------------------------------*/ void board_message(char *format, ...) { va_list ap; char msg[64]; int width, height; if (format != NULL) { va_start(ap, format); vsprintf(msg, format, ap); va_end(ap); if (strcmp(msg, board.message) == 0) return; } else strcpy(msg, board.message); canvas_font_size(msg, font.ptr, &width, &height); canvas_rectangle(0, CANVAS_HEIGHT - CELL_YSIZE, CANVAS_WIDTH, CELL_YSIZE, font.bg); canvas_font_print(msg, (CANVAS_WIDTH - width) / 2, CANVAS_HEIGHT - height, font.ptr, font.fg); strcpy(board.message, msg); sprintf(msg, "(%c%c%d)", (board.lumi_d == -1 ? '-' : '+'), (board.lumi <= 3 ? 'D' : 'L'), board.lumi); canvas_font_size(msg, font.ptr, &width, &height); canvas_font_print(msg, CANVAS_WIDTH - width, CANVAS_HEIGHT - height, font.ptr, font.fg); board.any_output = 1; #ifdef AUTOPILOT printf("board: %s\n", board.message); #endif } /*--------------------------------------------------------------------------*/ /* board_ssp_init */ /*--------------------------------------------------------------------------*/ void board_ssp_init(int x1, int y1, int x2, int y2, int both) { if (x1 != x2 || y1 != y2) board_paint_cell(x2, y2); /* repaint cell to remove cursor */ board.ssp.count = 1; board.ssp.x1 = x1; board.ssp.y1 = y1; board.ssp.x2 = x2; board.ssp.y2 = y2; board.ssp.both = both; } /*--------------------------------------------------------------------------*/ /* board_ssp_frame */ /*--------------------------------------------------------------------------*/ void board_ssp_frame(void) { if (board.ssp.both) { board_paint_cell(board.ssp.x1, board.ssp.y1); board_paint_cell(board.ssp.x2, board.ssp.y2); sprite_paint_clipped(board_cells[board.ssp.y1][board.ssp.x1].actor->sprite, SPRITE_STOP, BOARD_X(board.ssp.x2), BOARD_Y(board.ssp.y2), 0, 0, CELL_XSIZE, board.ssp.count); sprite_paint_clipped(board_cells[board.ssp.y2][board.ssp.x2].actor->sprite, SPRITE_STOP, BOARD_X(board.ssp.x1), BOARD_Y(board.ssp.y1), 0, 0, CELL_XSIZE, board.ssp.count); } else { board_paint_cell(board.ssp.x1, board.ssp.y1); if ((board.ssp.x1 != board.ssp.x2 || board.ssp.y1 != board.ssp.y2) && (board_cells[board.ssp.y2][board.ssp.x2].actor != NULL)) sprite_paint_clipped(board_cells[board.ssp.y2][board.ssp.x2].actor->sprite, SPRITE_STOP, BOARD_X(board.ssp.x2), BOARD_Y(board.ssp.y2), 0, 0, CELL_XSIZE, board.ssp.count); sprite_paint_clipped(board_cells[board.ssp.y1][board.ssp.x1].actor->sprite, SPRITE_STOP, BOARD_X(board.ssp.x2), BOARD_Y(board.ssp.y2), 0, 0, CELL_XSIZE, board.ssp.count); } if (board.ssp.count == CELL_YSIZE) { /* restart the spell that requested ssp */ board.ssp.count = 0; board.ssp.complete = 1; board_spell_done(); board.ssp.complete = 0; } else board.ssp.count++; } /*--------------------------------------------------------------------------*/ /* board_init_cell */ /*--------------------------------------------------------------------------*/ void board_init_cell(CELL *cell, int actor_num) { cell->actor = malloc(sizeof(ACTOR)); memcpy(cell->actor, &actors_list[actor_num], sizeof(ACTOR)); cell->actor->sprite = sprite_copy(actors_list[actor_num].sprite, 0); sprite_set_state(cell->actor->sprite, (cell->actor->type & ACTOR_LIGHT ? STATE_MOVE_RIGHT : STATE_MOVE_LEFT), 0); } /*--------------------------------------------------------------------------*/ /* board_clear_cell */ /*--------------------------------------------------------------------------*/ void board_clear_cell(CELL *cell) { sprite_free(cell->actor->sprite); free(cell->actor); cell->actor = NULL; cell->flags &= ~CELL_IMPRISON; } /*--------------------------------------------------------------------------*/ /* board_reset_actor */ /*--------------------------------------------------------------------------*/ void board_reset_actor(ACTOR *actor) { if (!(actor->type & ACTOR_ELEMENTAL)) sprite_set_state(actor->sprite, actor->type & ACTOR_LIGHT ? STATE_MOVE_RIGHT : STATE_MOVE_LEFT, 0); } /*--------------------------------------------------------------------------*/ /* board_iface_turn */ /*--------------------------------------------------------------------------*/ void board_iface_turn(void) { board_turn = board.turn; iface_turn(board.side, IFACE_BOARD); } /*--------------------------------------------------------------------------*/ /* board_verify_move */ /*--------------------------------------------------------------------------*/ int board_verify_move(int state) { static int opposite_state[] = { 0, STATE_MOVE_DOWN, STATE_MOVE_UP, STATE_MOVE_RIGHT, STATE_MOVE_LEFT }; ACTOR *actor; int x0, y0, x1, y1; int distance; actor = board_cells[board.ay0][board.ax0].actor; x0 = board.cx / CELL_XSIZE; y0 = board.cy / CELL_YSIZE; x1 = max(0, min(BOARD_XCELLS - 1, x0 + state_move_x_step[state])); y1 = max(0, min(BOARD_YCELLS - 1, y0 + state_move_y_step[state])); /* fly actor checks: only requirement is that it is within the range */ if (actor->type & ACTOR_FLY) { distance = max(abs(x1 - board.ax0), abs(y1 - board.ay0)); if (distance > actor->distance) { sprite_set_state(board_cells[board.ay0][board.ax0].actor->sprite, state, 0); board_message("alas, master, you have moved your limit"); return 0; } return 1; } /* ground checkss: first, cannot pass over opponent actors */ if ((x0 != board.ax0 || y0 != board.ay0) && board_cells[y0][x0].actor != NULL && state != opposite_state[sprite_get_state(board_cells[board.ay0][board.ax0].actor->sprite)]) { board_message("you must attack or retreat"); return 0; } /* check if it is possible to find a route on the board between */ /* (x0,y0) and (x1,y1) for the creature standing at (x0,y0) */ if ((x1 != board.ax0 || y1 != board.ay0) && board_get_route(board.ax0, board.ay0, x1, y1) == NULL) { sprite_set_state(board_cells[board.ay0][board.ax0].actor->sprite, state, 0); /* if it isn't possible, it might be because the creature is */ /* blocked by an opponent, or because it's just too far */ if (actor->type & ACTOR_GROUND && board_cells[y1][x1].actor != NULL && (board_cells[y1][x1].actor->type & ACTOR_LIGHT) == (board_cells[board.ay0][board.ax0].actor->type & ACTOR_LIGHT)) board_message("the square ahead is occupied"); else board_message("alas, master, you have moved your limit"); return 0; } return 1; } /*--------------------------------------------------------------------------*/ /* board_check_win */ /*--------------------------------------------------------------------------*/ int board_check_win(void) { static char *msgs[] = { NULL, "the dark side wins", "the light side wins", "it is a tie!" }; int x, y; CELL *cell; int is_dark; int num_light = 0, num_dark = 0; int num_pp = 0, num_light_pp = 0, num_dark_pp = 0; int winner = 0; int old_side; for (y = 0; y < BOARD_YCELLS; y++) for (x = 0; x < BOARD_XCELLS; x++) { cell = &board_cells[y][x]; if (cell->flags & CELL_POWER) num_pp++; if (cell->actor != NULL) { is_dark = ((cell->actor->type & ACTOR_LIGHT) == 0); /* count an actor for its side only if it isn't imprisoned; */ /* or if it is imprisoned, but its side has just played. */ if ((cell->flags & CELL_IMPRISON) == 0 || board.side == is_dark) { /* count it only if it can be picked. */ old_side = board.side; board.side = (cell->actor->type & ACTOR_LIGHT) ? 0 : 1; if (board_is_pickable(x, y, 0)) { num_light += is_dark == 0; num_dark += is_dark == 1; } board.side = old_side; } /* count control of power points */ if (cell->flags & CELL_POWER) { num_light_pp += is_dark == 0; num_dark_pp += is_dark == 1; } } } if (num_light == 0 || num_dark_pp == num_pp) winner++; /* dark wins */ if (num_dark == 0 || num_light_pp == num_pp) winner += 2; /* light wins */ if (winner != 0) { board_message("the game is over. %s", msgs[winner]); board.state = SELECT_GAME_OVER; audio_end_game(!(winner - 1)); return 1; } return 0; } /*--------------------------------------------------------------------------*/ /* board_end_turn */ /*--------------------------------------------------------------------------*/ void board_end_turn(int swap_side) { int x, y; CELL *cell; ACTOR *actor; board.state = SELECT_SOURCE; board.ax0 = -1; if (swap_side) { /* otherwise just reset this turn */ board.turn++; if (board.turn % 2 == 0) { board.lumi += board.lumi_d; if (board.lumi == LUMI_DARKEST || board.lumi == LUMI_LIGHTEST) board.lumi_d = -board.lumi_d; for (y = 0; y < BOARD_YCELLS; y++) for (x = 0; x < BOARD_XCELLS; x++) if (board_cells[y][x].actor != NULL) { cell = &board_cells[y][x]; actor = cell->actor; /* un-imprison light actor when luminance cycle is lightest; */ /* un-imprison dark actor when luminance cycle is darkest. */ if (cell->flags & CELL_IMPRISON && ((board.lumi == LUMI_LIGHTEST && actor->type & ACTOR_LIGHT) || (board.lumi == LUMI_DARKEST && !(actor->type & ACTOR_LIGHT)))) cell->flags ^= CELL_IMPRISON; /* heal actors, twice as fast if on a power point */ actor->strength = min(actors_list[actor->type & ACTOR_MASK].strength, actor->strength + 2 * (1 + ((cell->flags & CELL_POWER) == CELL_POWER))); } } if (board.elem.actor != NULL) board_clear_cell(&board.elem); if (board_check_win()) { /* important that check_win() be */ board_refresh(); /* called only after un-imprison */ return; /* is done */ } board.side = !board.side; board.cx = (board.side == 0) ? CELL_X(0) : CELL_X(BOARD_XCELLS - 1); board.cy = CELL_Y(BOARD_YCELLS / 2); board.cstate = 0; audio_start_turn(board.side); } sprintf(board.message, "the %s side plays", !board.side ? "light" : "dark"); board_refresh(); board_iface_turn(); } /*--------------------------------------------------------------------------*/ /* board_field */ /*--------------------------------------------------------------------------*/ void board_field(int xd, int yd, int xa, int ya) { static CELL *defender, *attacker; static int light_attacks; ACTOR *light, *dark, *winner; if (board.state != SELECT_FIELD) { defender = &board_cells[yd][xd]; attacker = &board_cells[ya][xa]; light = attacker->actor; if (light->type & ACTOR_LIGHT) { dark = defender->actor; light_attacks = 1; } else { dark = light; light = defender->actor; light_attacks = 0; } defender->flags &= ~CELL_LUMI_MASK; if (defender->flags & CELL_LIGHT) defender->flags |= FLOOR_LIGHT; if (defender->flags & CELL_DARK) defender->flags |= FLOOR_DARK; if (defender->flags & CELL_LUMI) defender->flags |= board.lumi; board_reset_actor(defender->actor); board_reset_actor(attacker->actor); field_start_game(light, dark, defender, BOARD_X(xd), BOARD_Y(yd)); board.state = SELECT_FIELD; } else { winner = field_frame(); if (winner != NULL) { if (winner == attacker->actor) { board_clear_cell(defender); if ((attacker->actor->type & ACTOR_ELEMENTAL) != ACTOR_ELEMENTAL) { board_reset_actor(attacker->actor); defender->actor = attacker->actor; } } else if (winner == defender->actor) { board_reset_actor(defender->actor); if ((attacker->actor->type & ACTOR_ELEMENTAL) != ACTOR_ELEMENTAL) board_clear_cell(attacker); } attacker->actor = NULL; board_end_turn(1); } } } /*--------------------------------------------------------------------------*/ /* board_move_done */ /*--------------------------------------------------------------------------*/ void board_move_done(void) { int x, y; x = board.cx / CELL_XSIZE; y = board.cy / CELL_YSIZE; if (x == board.ax0 && y == board.ay0) { if ((board_cells[board.ay0][board.ax0].actor->type & ACTOR_MASTER) == ACTOR_MASTER) { board_reset_actor(board_cells[board.ay0][board.ax0].actor); board_paint_cell(board.ax0, board.ay0); board_paint_cursor(); board_message("the %s conjures a spell", board_cells[board.ay0][board.ax0].actor->name); board.state = SELECT_SPELL; board.spell = 0; } else board_message("this is where you started"); return; } if (board_cells[y][x].actor != NULL) { if ((board_cells[y][x].actor->type & ACTOR_LIGHT) == (board_cells[board.ay0][board.ax0].actor->type & ACTOR_LIGHT)) board_message("you cannot attack your own"); else board_field(x, y, board.ax0, board.ay0); return; } board_cells[y][x].actor = board_cells[board.ay0][board.ax0].actor; board_cells[board.ay0][board.ax0].actor = NULL; board_reset_actor(board_cells[y][x].actor); board_end_turn(1); } /*--------------------------------------------------------------------------*/ /* board_spell_done */ /*--------------------------------------------------------------------------*/ void board_spell_done(void) { int x, y; int side; x = board.cx / CELL_XSIZE; y = board.cy / CELL_YSIZE; if (board_cells[y][x].flags & CELL_POWER) { board_message("power points block all spells"); board.state = SELECT_SPELL_DONE; board.spell = 0; return; } if (board_cells[y][x].flags & CELL_IMPRISON && (board.state == T_SELECT_SOURCE || board.state == X_SELECT_SOURCE || board.state == X_SELECT_TARGET)) { board_message("alas, master, this %s is imprisoned", board_cells[y][x].actor->name); board.state = SELECT_SPELL_DONE; board.spell = 0; return; } /* set side: -1 if empty cell, 0 if light, 1 if dark */ if (board_cells[y][x].actor != NULL) side = (board_cells[y][x].actor->type & ACTOR_LIGHT) != ACTOR_LIGHT; else side = -1; spell_funcs[board.spell](x, y, side); } /*--------------------------------------------------------------------------*/ /* board_input */ /*--------------------------------------------------------------------------*/ void board_input(void) { int state, state_last; iface_frame(); if (board.game_status == 0) return; if (board.state == SELECT_TARGET && board_cells[board.ay0][board.ax0].actor->type & ACTOR_GROUND) state_last = STATE_MOVE_RIGHT; else state_last = STATE_MOVE_DOWN_RIGHT; for (state = state_last; state >= STATE_MOVE_FIRST; state--) if (iface_key_down(state)) if (board.state != SELECT_TARGET || (board.state == SELECT_TARGET && board_verify_move(state))) { board.cstate = state; return; } if (iface_key_down(STATE_FIRE)) board.fire_down = 1; if (board.fire_down && !iface_key_down(STATE_FIRE)) { board.fire_down = 0; if (board.state == SELECT_SOURCE) { if (board_is_pickable(board.cx / CELL_XSIZE, board.cy / CELL_YSIZE, 1)) { board.ax0 = board.cx / CELL_XSIZE; board.ay0 = board.cy / CELL_YSIZE; board.state = SELECT_TARGET; } } else if (board.state == SELECT_TARGET) board_move_done(); else /* all other states are spells */ board_spell_done(); /* (except SELECT_FIELD, but we'll */ } /* never get here in that state) */ } /*--------------------------------------------------------------------------*/ /* board_cursor */ /*--------------------------------------------------------------------------*/ void board_cursor(void) { int old_state; int old_cx, old_cy; old_state = board.state; old_cx = board.cx; old_cy = board.cy; board.cx = max(0, min((BOARD_XCELLS - 1) * CELL_XSIZE, board.cx + state_move_x_step[board.cstate] * CELL_XSIZE / 8)); board.cy = max(0, min((BOARD_YCELLS - 1) * CELL_YSIZE, board.cy + state_move_y_step[board.cstate] * CELL_YSIZE / 8)); if (board.cx != old_cx || board.cy != old_cy) { board_paint_cell(old_cx / CELL_XSIZE, old_cy / CELL_YSIZE); if (old_cx % CELL_XSIZE != 0) board_paint_cell(old_cx / CELL_XSIZE + 1, old_cy / CELL_YSIZE); if (old_cy % CELL_YSIZE != 0) board_paint_cell(old_cx / CELL_XSIZE, old_cy / CELL_YSIZE + 1); if (old_cx % CELL_XSIZE != 0 && old_cy % CELL_YSIZE != 0) board_paint_cell(old_cx / CELL_XSIZE + 1, old_cy / CELL_YSIZE + 1); board_paint_cursor(); } if (board.cx % CELL_XSIZE == 0 && board.cy % CELL_YSIZE == 0) { board.cstate = 0; board_input(); } if (board.cstate != 0 || board.state != old_state) { if (board.state == SELECT_SOURCE) board_message("the %s side plays", !board.side ? "light" : "dark"); if (board.state == SELECT_TARGET) board_message("%s %s (%s %d)", board_cells[board.ay0][board.ax0].actor->type & ACTOR_LIGHT ? "light" : "dark", board_cells[board.ay0][board.ax0].actor->name, board_cells[board.ay0][board.ax0].actor->type & ACTOR_GROUND ? "ground" : "fly", board_cells[board.ay0][board.ax0].actor->distance); } } /*--------------------------------------------------------------------------*/ /* board_spell */ /*--------------------------------------------------------------------------*/ void board_spell(void) { int fire_up = 0; int old_spell; iface_frame(); if (board.game_status == 0) return; if (iface_key_down(STATE_FIRE)) board.fire_down = 1; if (board.fire_down && !iface_key_down(STATE_FIRE)) { board.fire_down = 0; fire_up = 1; } if (board.spell == 0 || board.state == SELECT_SPELL_DONE) { if (fire_up) { if (board.state == SELECT_SPELL_DONE) { board.cx = CELL_X(board.ax0); board.cy = CELL_Y(board.ay0); board_end_turn(board.spell); } else for (board.spell = 1; !spell_avails[board.side][board.spell]; board.spell++) ; } return; } board_message("select spell: %s", spell_names[board.spell]); old_spell = board.spell; if (iface_key_down(STATE_MOVE_UP)) board.prev_down = 1; if (board.prev_down && !iface_key_down(STATE_MOVE_UP)) { board.prev_down = 0; do { board.spell--; } while (board.spell > SPELL_TELEPORT && !spell_avails[board.side][board.spell]); if (!spell_avails[board.side][board.spell]) board.spell = old_spell; } if (iface_key_down(STATE_MOVE_DOWN)) board.next_down = 1; if (board.next_down && !iface_key_down(STATE_MOVE_DOWN)) { board.next_down = 0; do { board.spell++; } while (board.spell < SPELL_CEASE_CONJURING && !spell_avails[board.side][board.spell]); if (!spell_avails[board.side][board.spell]) board.spell = old_spell; } if (fire_up) spell_funcs[board.spell](0, 0, 0); } /*--------------------------------------------------------------------------*/ /* board_teleport */ /*--------------------------------------------------------------------------*/ void board_teleport(int x, int y, int side) { static int x0, y0; switch (board.state) { case SELECT_SPELL: board_message("who would you like to teleport?"); board.state = T_SELECT_SOURCE; break; case T_SELECT_SOURCE: if (side != board.side || board_cells[y][x].flags & CELL_IMPRISON) return; x0 = x; y0 = y; board_message("where would you like to teleport it?"); board.state = T_SELECT_TARGET; break; case T_SELECT_TARGET: if (side == board.side) return; if (!board.ssp.complete) { board_ssp_init(x0, y0, x, y, 0); return; } spell_avails[board.side][SPELL_TELEPORT] = 0; if (side == -1) { board_cells[y][x].actor = board_cells[y0][x0].actor; board_cells[y0][x0].actor = NULL; board_reset_actor(board_cells[y][x].actor); board_end_turn(1); } else board_field(x, y, x0, y0); break; } } /*--------------------------------------------------------------------------*/ /* board_heal */ /*--------------------------------------------------------------------------*/ void board_heal(int x, int y, int side) { if (board.state == SELECT_SPELL) { board_message("who would you like to heal?"); board.state = H_SELECT_TARGET; } else { /* H_SELECT_TARGET */ if (side != board.side) return; spell_avails[board.side][SPELL_HEAL] = 0; board_cells[y][x].actor->strength = actors_list[board_cells[y][x].actor->type & ACTOR_MASK].strength; board_message("this %s is now healed", board_cells[y][x].actor->name); board.state = SELECT_SPELL_DONE; board.spell = 1; } } /*--------------------------------------------------------------------------*/ /* board_shift_time */ /*--------------------------------------------------------------------------*/ void board_shift_time(int x, int y, int side) { ACTOR *actor; spell_avails[board.side][SPELL_SHIFT_TIME] = 0; board.lumi = (board.lumi == LUMI_DARKEST) ? LUMI_LIGHTEST : (board.lumi == LUMI_LIGHTEST) ? LUMI_DARKEST : board.lumi; board.lumi_d = -board.lumi_d; for (y = 0; y < BOARD_YCELLS; y++) for (x = 0; x < BOARD_XCELLS; x++) if (board_cells[y][x].flags & CELL_IMPRISON) { actor = board_cells[y][x].actor; /* un-imprison light actor if luminance cycle is lightest; */ /* un-imprison dark actor if luminance cycle is darkest. */ if ((board.lumi == LUMI_LIGHTEST && actor->type & ACTOR_LIGHT) || (board.lumi == LUMI_DARKEST && !(actor->type & ACTOR_LIGHT))) board_cells[y][x].flags ^= CELL_IMPRISON; } board_message("the flow of time is reversed"); board.state = SELECT_SPELL_DONE; board.spell = 1; } /*--------------------------------------------------------------------------*/ /* board_exchange */ /*--------------------------------------------------------------------------*/ void board_exchange(int x, int y, int side) { static int x0, y0; ACTOR *actor; switch (board.state) { case SELECT_SPELL: board_message("who would you like to exchange?"); board.state = X_SELECT_SOURCE; break; case X_SELECT_SOURCE: x0 = x; y0 = y; board_message("whom to exchange with?"); board.state = X_SELECT_TARGET; break; case X_SELECT_TARGET: if (!board.ssp.complete) { board_ssp_init(x0, y0, x, y, 1); return; } spell_avails[board.side][SPELL_EXCHANGE] = 0; actor = board_cells[y0][x0].actor; board_cells[y0][x0].actor = board_cells[y][x].actor; board_cells[y][x].actor = actor; board_reset_actor(board_cells[y0][x0].actor); board_reset_actor(board_cells[y][x].actor); board_end_turn(1); break; } } /*--------------------------------------------------------------------------*/ /* board_summon_elemental */ /*--------------------------------------------------------------------------*/ void board_summon_elemental(int x, int y, int side) { static char *elem_names[] = { "an air", "an earth", "a fire", "a water" }; int y0, x0; if (board.state == SELECT_SPELL) { if (board.elem.actor == NULL) { board.elem.flags = board_frame_time % 4; board_init_cell(&board.elem, ACTOR_AIR_ELEM + board.elem.flags); } board_message("%s elemental appears", elem_names[board.elem.flags]); sprite_set_state(board.elem.actor->sprite, STATE_AIR_ELEM + board.elem.flags, 0); board.state = L_SELECT_TARGET; board_paint_cursor(); } else { /* L_SELECT_TARGET */ if (side == board.side || side == -1) return; spell_avails[board.side][SPELL_SUMMON_ELEMENTAL] = 0; for (y0 = 0; y0 < BOARD_YCELLS; y++) for (x0 = 0; x0 < BOARD_XCELLS; x0++) if (board_cells[y0][x0].actor == NULL) { board.elem.actor->type |= (!board.side) * ACTOR_LIGHT; board_cells[y0][x0].actor = board.elem.actor; board_field(x, y, x0, y0); return; /* there should be lots of empty */ } /* cells, so we will always get here */ } } /*--------------------------------------------------------------------------*/ /* board_revive_check */ /*--------------------------------------------------------------------------*/ int board_revive_check(int *actors, int *cell_x, int *cell_y) { int num_actors; int first, last, i; int y, x, dx; int init_count, real_count; int master_x, master_y; num_actors = 0; first = (board.side == 0) ? ACTOR_LIGHT_FIRST : ACTOR_DARK_FIRST; last = (board.side == 0) ? ACTOR_LIGHT_LAST : ACTOR_DARK_LAST; for (i = first; i <= last; i++) { init_count = real_count = 0; for (y = 0; y < BOARD_YCELLS; y++) for (x = 0; x < BOARD_XCELLS; x++) { if ((init_board_cells[y][x] & ACTOR_MASK) == i) init_count++; if (board_cells[y][x].actor != NULL && (board_cells[y][x].actor->type & ACTOR_MASK) == i) real_count++; } if (init_count != real_count) actors[num_actors++] = i; } if (num_actors == 0) { if (cell_x != NULL) /* only if interactive mode */ board_message("happily, master, all are alive"); return 0; } actors[num_actors] = 0; board_find_actor((board.side == 0 ? ACTOR_WIZARD : ACTOR_SORCERESS), &master_x, &master_y); dx = (board.side == 0) ? 1 : -1; for (y = master_y - 1; y <= master_y + 1; y++) for (x = master_x - dx; x != master_x + (dx * 2); x += dx) if (y >= 0 && y < BOARD_YCELLS && x >= 0 && x < BOARD_XCELLS && board_cells[y][x].actor == NULL) { if (cell_x != NULL) { /* only if interactive mode */ *cell_x = x; *cell_y = y; } return 1; } if (cell_x != NULL) /* only if interactive mode */ board_message("there is no open square near your mage"); return 0; } /*--------------------------------------------------------------------------*/ /* board_revive_frame */ /*--------------------------------------------------------------------------*/ int board_revive_frame(int *i, int *old_i, int *actors) { if (iface_key_down(STATE_FIRE)) board.fire_down = 1; if (board.fire_down && !iface_key_down(STATE_FIRE)) { board.fire_down = 0; return 1; } if (iface_key_down(STATE_MOVE_UP)) board.prev_down = 1; if (board.prev_down && !iface_key_down(STATE_MOVE_UP)) { board.prev_down = 0; if ((*i) > 0) (*i)--; } if (iface_key_down(STATE_MOVE_DOWN)) board.next_down = 1; if (board.next_down && !iface_key_down(STATE_MOVE_DOWN)) { board.next_down = 0; if (actors[(*i)] != 0) (*i)++; } if (*i != *old_i) { sprite_set_state(cursor_sprite, STATE_BOARD, 1); /* erase cursor */ sprite_paint(cursor_sprite, STATE_BOARD, (board.side == 0 ? CELL_XSIZE : CANVAS_WIDTH - CELL_XSIZE * 2), (*old_i) * 40 + 32); sprite_set_state(cursor_sprite, STATE_BOARD, 2); /* draw cursor */ sprite_paint(cursor_sprite, STATE_BOARD, (board.side == 0 ? CELL_XSIZE : CANVAS_WIDTH - CELL_XSIZE * 2), (*i) * 40 + 32); board.any_output = 1; } return 0; } /*--------------------------------------------------------------------------*/ /* board_revive */ /*--------------------------------------------------------------------------*/ void board_revive(int x, int y, int side) { static int actors[10], i; static int cell_x, cell_y; int old_i; if (board.ssp.complete) { board.cx = CELL_X(cell_x); /* once ssp is complete, place */ board.cy = CELL_Y(cell_y); /* cursor on revived cell */ board_end_turn(1); return; } if (x >= 0) { if (!board_revive_check(actors, &cell_x, &cell_y)) { board.state = SELECT_SPELL_DONE; board.spell = 0; return; } board_message("select who to revive"); for (i = 0; actors[i] != 0; i++) sprite_paint(actors_list[actors[i]].sprite, (board.side == 0 ? STATE_MOVE_RIGHT : STATE_MOVE_LEFT), (board.side == 0 ? CELL_XSIZE : CANVAS_WIDTH - CELL_XSIZE * 2), i * 40 + 32); old_i = 0; /* force i != old_i, thus redraw */ board.state = V_SELECT_SOURCE; } else old_i = i; if (board_revive_frame(&i, &old_i, actors)) { if (actors[i] != 0) { spell_avails[board.side][SPELL_REVIVE] = 0; board_init_cell(&board_cells[cell_y][cell_x], actors[i]); board_ssp_init(cell_x, cell_y, cell_x, cell_y, 0); board.cx = CELL_X(1); /* make sure cursor is not on a */ board.cy = CELL_Y(1); /* power cell (temporarily) */ } else { board.cx = CELL_X(board.ax0); /* put the cursor on the master */ board.cy = CELL_Y(board.ay0); board_end_turn(0); } } else board.cy = i; /* for board_absolute_control_delta() */ } /*--------------------------------------------------------------------------*/ /* board_imprison */ /*--------------------------------------------------------------------------*/ void board_imprison(int x, int y, int side) { if (board.state == SELECT_SPELL) { if (!board_is_imprison_ok()) { board_message("the %s side cannot be imprisoned at this time", board.side == 0 ? "dark" : "light"); board.state = SELECT_SPELL_DONE; board.spell = 0; } else { board_message("who would you like to imprison?"); board.state = M_SELECT_TARGET; } } else if (side != board.side) { spell_avails[board.side][SPELL_IMPRISON] = 0; board_cells[y][x].flags |= CELL_IMPRISON; board_message("this %s is now imprisoned", board_cells[y][x].actor->name); board.state = SELECT_SPELL_DONE; board.spell = 1; } } /*--------------------------------------------------------------------------*/ /* board_cease_conjuring */ /*--------------------------------------------------------------------------*/ void board_cease_conjuring(int x, int y, int side) { board_end_turn(0); /* reset this turn */ } /*--------------------------------------------------------------------------*/ /* board_start_game */ /*--------------------------------------------------------------------------*/ void board_start_game(int light_first) { int x, y; CELL *cell; /* setup font stuff */ if (font.ptr == NULL) { font.ptr = canvas_font_load(FONT_NAME); font.fg = canvas_alloc_color(255, 255, 0); font.bg = canvas_alloc_color(255, 0, 0); } /* setup initial board[] data */ memset(&board, 0, sizeof(board)); board.game_status = 1; /* game on! */ board.side = !light_first; board.state = SELECT_SOURCE; board.lumi = light_first ? LUMI_LIGHTEST : LUMI_DARKEST; board.lumi_d = light_first ? -1 : 1; board.cx = light_first ? CELL_X(0) : CELL_X(BOARD_XCELLS - 1); board.cy = CELL_Y(BOARD_YCELLS / 2); board.ax0 = -1; board.elem.actor = NULL; sprintf(board.message, "the %s side goes first", !board.side ? "light" : "dark"); board.any_output = 0; /* setup actors on the board */ for (y = 0; y < BOARD_YCELLS; y++) for (x = 0; x < BOARD_XCELLS; x++) { cell = &board_cells[y][x]; cell->flags = init_board_cells[y][x]; if ((cell->flags & ACTOR_MASK) != 0) board_init_cell(cell, cell->flags & ACTOR_MASK); else cell->actor = NULL; } field_setup_rocks(); /* setup global variables */ memcpy(spell_avails[0], spell_avails[2], sizeof(spell_avails[2])); memcpy(spell_avails[1], spell_avails[2], sizeof(spell_avails[2])); board_frame_time = 0; board_refresh(); board_iface_turn(); audio_start_game(); /* sleep(2); audio_start_turn(board.side); */ } /*--------------------------------------------------------------------------*/ /* board_end_game */ /*--------------------------------------------------------------------------*/ int board_end_game(void) { int x, y; if (board.game_status == 0) return 0; if (board.state == SELECT_FIELD) field_end_game(); for (y = 0; y < BOARD_YCELLS; y++) for (x = 0; x < BOARD_XCELLS; x++) if (board_cells[y][x].actor != NULL) { if (board_cells[y][x].actor == board.elem.actor) board.elem.actor = NULL; board_clear_cell(&board_cells[y][x]); } if (board.elem.actor != NULL) board_clear_cell(&board.elem); board.game_status = 0; /* game ends */ board.state = SELECT_GAME_OVER; audio_terminate(); return 1; } /*--------------------------------------------------------------------------*/ /* board_pause_game */ /*--------------------------------------------------------------------------*/ int board_pause_game(int pause) { if (board.game_status == 0) return 0; if (pause != -1) board.game_status = pause ? -1 : 1; return 1; } /*--------------------------------------------------------------------------*/ /* board_refresh */ /*--------------------------------------------------------------------------*/ void board_refresh(void) { int x, y; if (board.state == SELECT_FIELD) { field_refresh(); return; } canvas_clear(); for (y = 0; y < BOARD_YCELLS; y++) for (x = 0; x < BOARD_XCELLS; x++) board_paint_cell(x, y); board_message(NULL); board_paint_cursor(); canvas_refresh(); } /*--------------------------------------------------------------------------*/ /* board_frame */ /*--------------------------------------------------------------------------*/ int board_frame(void) { #ifdef AUTOPILOT if (board.turn == 1000) { printf("board: game is taking too long, ending it.\n"); board_end_game(); } #endif if (board.game_status != 1) return (board.state != SELECT_GAME_OVER); if (board.ssp.count != 0) board_ssp_frame(); else { switch (board.state) { case SELECT_SPELL: case SELECT_SPELL_DONE: board_spell(); break; case SELECT_FIELD: board_field(0, 0, 0, 0); break; case V_SELECT_SOURCE: iface_frame(); if (board.game_status != 0) board_revive(-99, 0, 0); break; default: board_cursor(); break; } if (board.state == SELECT_GAME_OVER) board_end_game(); } if (board.any_output) { canvas_refresh(); board.any_output = 0; } board_frame_time++; return (board.state != SELECT_GAME_OVER); } /*--------------------------------------------------------------------------*/ /* board_cell_lumi */ /*--------------------------------------------------------------------------*/ int board_cell_lumi(CELL *cell) { if (cell->flags & CELL_DARK) return CELL_DARK | (LUMI_COUNT / 2); if (cell->flags & CELL_LIGHT) return CELL_LIGHT | (LUMI_COUNT / 2); if (board.lumi < LUMI_COUNT / 2) return CELL_DARK | ((LUMI_COUNT / 2) - board.lumi); else return CELL_LIGHT | (board.lumi - (LUMI_COUNT / 2) + 1); } /*--------------------------------------------------------------------------*/ /* board_is_pickable */ /*--------------------------------------------------------------------------*/ int board_is_pickable(int cx, int cy, int msg) { int x0, y0; int x, y; int distance; x0 = cx; y0 = cy; if (board_cells[y0][x0].actor == NULL) return 0; if (!actor_is_side(board_cells[y0][x0].actor, board.side)) return 0; if (board_cells[y0][x0].flags & CELL_IMPRISON) { if (msg) board_message("alas, master, this %s is imprisoned", board_cells[y0][x0].actor->name); return 0; } if ((board_cells[y0][x0].actor->type & ACTOR_MASTER) == ACTOR_MASTER) return 1; distance = (board_cells[y0][x0].actor->type & ACTOR_GROUND) ? 1 : (board_cells[y0][x0].actor->distance); for (y = y0 - distance; y <= y0 + distance; y++) if (y >= 0 && y <= BOARD_YCELLS - 1) for (x = x0 - distance; x <= x0 + distance; x++) { if (x < 0 || x > BOARD_XCELLS - 1) continue; if (board_cells[y0][x0].actor->type & ACTOR_GROUND && abs(x - x0) == 1 && abs(y - y0) == 1) continue; if (board_cells[y][x].actor == NULL) return 1; if (actor_is_side(board_cells[y][x].actor, !board.side)) return 1; } if (msg) board_message("alas, master, this %s cannot move", board_cells[y0][x0].actor->name); return 0; } /*--------------------------------------------------------------------------*/ /* board_get_route_2 */ /*--------------------------------------------------------------------------*/ int board_get_route_2(int x1, int y1, int x2, int y2, int *route, int prev_state, int light, int ground, int distance) { int state, state_last; int x, y; int count; if (distance == 0) return 0; state_last = ground ? STATE_MOVE_RIGHT : STATE_MOVE_DOWN_RIGHT; for (state = STATE_MOVE_FIRST; state <= state_last; state++) { if (state == state_opposite[prev_state]) continue; x = max(0, min(BOARD_XCELLS - 1, x1 + state_move_x_step[state])); y = max(0, min(BOARD_YCELLS - 1, y1 + state_move_y_step[state])); if (x == x1 && y == y1) continue; if (ground && board_cells[y][x].actor != NULL && (board_cells[y][x].actor->type & ACTOR_LIGHT) == light) continue; *route = state; if (x == x2 && y == y2) return 1; if (ground && board_cells[y][x].actor != NULL) continue; count = board_get_route_2(x, y, x2, y2, route + 1, state, light, ground, distance - 1); if (count != 0) return (count + 1); } return 0; } /*--------------------------------------------------------------------------*/ /* board_get_route */ /*--------------------------------------------------------------------------*/ int *board_get_route(int x1, int y1, int x2, int y2) { static int route[16]; ACTOR *actor; int count; route[0] = 0; if (x1 == x2 && y1 == y2) return NULL; actor = board_cells[y1][x1].actor; if (board_cells[y2][x2].actor != NULL && (board_cells[y2][x2].actor->type & ACTOR_LIGHT) == (actor->type & ACTOR_LIGHT)) return NULL; count = board_get_route_2(x1, y1, x2, y2, route, 0, (actor->type & ACTOR_LIGHT), (actor->type & ACTOR_GROUND), actor->distance); route[count] = 0; return (count == 0) ? NULL : route; } /*--------------------------------------------------------------------------*/ /* board_find_actor */ /*--------------------------------------------------------------------------*/ int board_find_actor(int type, int *ax, int *ay) { int x, y; for (y = 0; y < BOARD_YCELLS; y++) for (x = 0; x < BOARD_XCELLS; x++) if (board_cells[y][x].actor != NULL && (board_cells[y][x].actor->type & ACTOR_MASK) == type) { *ax = x; *ay = y; return 1; } *ax = -1; *ay = -1; return 0; } /*--------------------------------------------------------------------------*/ /* board_is_imprison_ok */ /*--------------------------------------------------------------------------*/ int board_is_imprison_ok(void) { int next_lumi; /* don't allow if luminance on next turn is max of enemy's side */ next_lumi = board.lumi + board.lumi_d * ((board.turn + 1) % 2 == 0); if ((board.side == 0 && next_lumi == LUMI_DARKEST) || (board.side == 1 && next_lumi == LUMI_LIGHTEST)) return 0; return 1; } /*--------------------------------------------------------------------------*/ /* board_get_data */ /*--------------------------------------------------------------------------*/ void board_get_data(int *_side, int *_turn, int *_lumi, int *_lumi_d) { *_side = board.side; *_turn = board.turn; *_lumi = board.lumi; *_lumi_d = board.lumi_d; } /*--------------------------------------------------------------------------*/ /* board_absolute_control_delta */ /*--------------------------------------------------------------------------*/ void board_absolute_control_delta(int *dx, int *dy) { int spell; int curr_x, curr_y; int target_x, target_y; switch (board.state) { case SELECT_SPELL: *dx = 0; /* don't just hold the direction down, or the selection will get * stuck on the first option */ if (board.prev_down || board.next_down) *dy = 0; else { *dy = (*dy / CELL_YSIZE) - 2; for (spell = 0; spell < board.spell; spell++) if (spell_avails[board.side][spell]) (*dy)--; } break; case V_SELECT_SOURCE: *dx = 0; /* don't just hold the direction down, or the selection will get * stuck on the first option */ if (board.prev_down || board.next_down) *dy = 0; else *dy = ((*dy - CELL_YSIZE) / V_CELL_YSIZE) - board.cy; break; default: *dx = (*dx / CELL_XSIZE) * CELL_XSIZE - BOARD_X(0) - board.cx; *dy = (*dy / CELL_YSIZE) * CELL_YSIZE - BOARD_Y(0) - board.cy; /* elimiate diagonals when moving ground units */ if (*dx && *dy && board_cells[board.ay0][board.ax0].actor && (board_cells[board.ay0][board.ax0].actor->type & ACTOR_GROUND)) { curr_x = board.cx / CELL_XSIZE; curr_y = board.cy / CELL_YSIZE; target_x = curr_x + ((*dx > 0) ? 1 : -1); target_y = curr_y + ((*dy > 0) ? 1 : -1); if (target_x >= 0 && target_x < BOARD_XCELLS && target_y >= 0 && target_y < BOARD_YCELLS) { if (board_cells[target_y][curr_x].actor || (!board_cells[curr_y][target_x].actor && (curr_x - board.ax0 > 0) != (*dx > 0))) *dy = 0; else *dx = 0; } } break; } }