#include #include "constant.h" /**** x include files ****/ #include #include #include #include #include #if USE_LONGJMP #include #endif #include "extern.h" /****************************************************************************** draw_board (current_player, justboard) Draw the entire blank board and all message strings for . ******************************************************************************/ draw_board (current_player, justboard) int current_player, justboard; { int i, j, player, side, current_side; char line[MAX_TEXT]; cell_type *cell; xwindow_type *xwindow; shape_type *shape; current_side = Config->player_to_side[current_player]; xwindow = XWindow[current_player]; shape = Board->shapes[current_side][0]; /** If the window is open **/ if (xwindow->open) { /** Fill entire gameboard with hue_mark[1] **/ XFillRectangle (xwindow->display, xwindow->window, xwindow->hue_mark[1], xwindow->offset_play.x, xwindow->offset_play.y, xwindow->size_play.x, xwindow->size_play.y); XFillRectangle (xwindow->display, xwindow->window, xwindow->hue_terrain[0], xwindow->offset_text.x, xwindow->offset_text.y, xwindow->size_text.x, xwindow->size_text.y); /** If using backing store, must draw blank cells then copy them **/ /** to the backing store, else we just set redraw_status to use **/ /** a REDRAW_FULL, which ensures that the whole cell (and grid) **/ /** will be rendered appropriately. **/ if (shape->copy_method == COPY_BACK || shape->copy_method == COPY_WINDOW) { for (i=0; icell_count; i++) { cell = CELL(i); shape = Board->shapes[current_side][cell->shape_index]; cell->redraw_status = REDRAW_BLANK; draw_cell (cell, current_player, TRUE); if (Config->enable_all[OPTION_STORE] && current_player == 0) store_draw_cell (cell); if (shape->copy_method == COPY_BACK) { /** Copy the blank cell to the backing store **/ XCopyArea (xwindow->display, xwindow->window, xwindow->backing_space, xwindow->hue_mark[0], cell->x_center[current_side] - shape->center_bound.x, cell->y_center[current_side] - shape->center_bound.y, shape->size_bound.x, shape->size_bound.y, cell->x_center[current_side] - shape->center_bound.x, cell->y_center[current_side] - shape->center_bound.y); } cell->redraw_status = REDRAW_NORMAL; } } /** Paint the individual cells (and troops) **/ for (i=0; icell_count; i++) { cell = CELL(i); /** Draw whole cell, unless we just did that above **/ if (shape->copy_method != COPY_BACK && shape->copy_method != COPY_WINDOW) cell->redraw_status = REDRAW_FULL; if (is_visible (cell, current_side)) draw_cell (cell, current_player, TRUE); else draw_cell (cell, current_player, FALSE); if (Config->enable_all[OPTION_STORE] && current_player == 0) store_draw_cell (cell); cell->redraw_status = REDRAW_NORMAL; } } /** Display the messages **/ if (!justboard) { for (player=0; playerplayer_count; player++) { if (XWindow[player]->open) { side = Config->player_to_side[player]; XDrawImageString (xwindow->display, xwindow->window, xwindow->hue[side], Config->text_offset, xwindow->text_y_pos[player], Blank, strlen(Blank)); sprintf (line, "%s > %s", XWindow[player]->display_name, Config->message_single[player]); XDrawImageString (xwindow->display, xwindow->window, xwindow->hue[side], Config->text_offset, xwindow->text_y_pos[player], line, strlen(line)); } } } } /****************************************************************************** draw_multiple_cell (cell) Draw on every display (for which it should be visible). ******************************************************************************/ draw_multiple_cell (cell) cell_type *cell; { int player, side; /** For each player **/ for (player=0; playerplayer_count; player++) { if (!XWindow[player]->open) continue; /** Draw if visible to **/ side = Config->player_to_side[player]; if (is_visible (cell, side)) { if (!Config->enable[OPTION_HIDDEN][side] || cell->side == side) draw_cell (cell, player, TRUE); } } /** Store-draw if store enabled **/ if (Config->enable_all[OPTION_STORE]) store_draw_cell (cell); } /****************************************************************************** draw_cell (cell, player, use_full) Draw individual on window of . If then cell terrain is visible. ******************************************************************************/ draw_cell (cell, player, use_full) cell_type *cell; int player, use_full; { int k, x_center, y_center, x_corner, y_corner, x_draw_center, y_draw_center, x_draw_corner, y_draw_corner, x_size, y_size, token_size, half_token_size, token2_size, half_token2_size, value, level, shape_index, erase_shape, copy_method, erase_method, side, side_first, side_second, value_first, value_second; Window drawable; static GC hue_on, hue_off, hue_mark; shape_type *shape; xwindow_type *xwindow; side = Config->player_to_side[player]; /** If status is REDRAW_BLANK, just draw a blank cell and get out **/ if (cell->redraw_status == REDRAW_BLANK) { if (Config->enable[OPTION_MAP][side] && !is_visible (cell, side)) draw_blank_cell (cell, player, FALSE); else draw_blank_cell (cell, player, TRUE); return; } /** Set xwindow **/ xwindow = XWindow[player]; /** Set shape of cell **/ shape_index = cell->shape_index; shape = Board->shapes[side][shape_index]; /** Set temporary drawing and erasing methods **/ if (cell->redraw_status == REDRAW_FULL) { /** Need to redraw whole polygon, not just erase center **/ if (Config->enable[OPTION_SEA_BLOCK][side] && cell->level < 0 && cell->level > Config->level_min) { /** Need to copy over masked pixmap to handle block seas **/ erase_shape = SHAPE_POLYGON; copy_method = COPY_WINDOW; erase_method = ERASE_MASK; } else { erase_shape = SHAPE_POLYGON; copy_method = shape->copy_method; erase_method = shape->erase_method; } } else { erase_shape = shape->erase_shape; copy_method = shape->copy_method; erase_method = shape->erase_method; } /** Set temporary level **/ if (use_full) level = cell->level; else if (cell->seen[side] && !Config->enable[OPTION_LOCALMAP][side]) level = cell->level; else { level = Config->level_max+1; erase_shape = SHAPE_POLYGON; } /** If cell "level" has changed since last draw, must redraw entire **/ /** polygon. This is primarily used for -localmap, when cell flips **/ /** between seen and unseen. **/ if (level != cell->draw_level[side]) { erase_shape = SHAPE_POLYGON; cell->draw_level[side] = level; } /** Set cell coordinates (center of cell) **/ x_center = cell->x_center[side]; y_center = cell->y_center[side]; /** Set cell coordinates (left corner of cell) **/ x_corner = x_center - shape->center_bound.x; y_corner = y_center - shape->center_bound.y; /** Set cell size **/ x_size = shape->size_bound.x; y_size = shape->size_bound.y; /** Determine how to do erase/draw **/ if (copy_method == COPY_NONE || copy_method == COPY_BACK) { if (copy_method == COPY_BACK) drawable = xwindow->backing_space; else drawable = xwindow->window; x_draw_corner = x_corner; y_draw_corner = y_corner; x_draw_center = x_center; y_draw_center = y_center; } else { drawable = xwindow->work_space; x_draw_corner = 0; y_draw_corner = 0; x_draw_center = shape->center_bound.x; y_draw_center = shape->center_bound.y; } xwindow->drawable = drawable; /** Either copy cell (and surroundings) to the work space pixmap, or **/ /** copy a blank cell from the terrain pixmap to the work space, or **/ /** don't do any copies (just do drawing right on the screen or use **/ /** the backing store). **/ if (copy_method == COPY_WINDOW) XCopyArea (xwindow->display, xwindow->window, drawable, xwindow->hue_terrain[0], x_corner, y_corner, x_size, y_size, 0, 0); else if (copy_method == COPY_PIXMAP) XCopyArea (xwindow->display, xwindow->terrain[shape_index][level], drawable, xwindow->hue_terrain[0], 0, 0, x_size, y_size, 0, 0); /** Erase old cell body **/ if (erase_method == ERASE_DRAW) { if (erase_shape == SHAPE_CIRCLE) XFillArc (xwindow->display, drawable, xwindow->hue_terrain[level], x_draw_center - shape->center_erase.x, y_draw_center - shape->center_erase.y, shape->size_erase.x, shape->size_erase.y, 0, ANGLE_FULL); else if (erase_shape == SHAPE_SQUARE) XFillRectangle (xwindow->display, drawable, xwindow->hue_terrain[level], x_draw_center - shape->center_erase.x, y_draw_center - shape->center_erase.y, shape->size_erase.x, shape->size_erase.y); else if (erase_shape == SHAPE_POLYGON) { shape->points[0].x = x_draw_corner + shape->corner_vertex.x; shape->points[0].y = y_draw_corner + shape->corner_vertex.y; /** ALTER: possible error here (northrup@onyx.slu.edu) **/ /** ALTER: level=253 point_count='^G' copy_method=0 **/ XFillPolygon (xwindow->display, drawable, xwindow->hue_terrain[level], shape->points, shape->point_count-1, Convex, CoordModePrevious); if (Config->enable[OPTION_GRID][side]) XDrawLines (xwindow->display, drawable, xwindow->hue_mark[0], shape->points, shape->point_count, CoordModePrevious); else XDrawLines (xwindow->display, drawable, xwindow->hue_terrain[level], shape->points, shape->point_count, CoordModePrevious); } } else if (erase_method == ERASE_MASK) { /** Clear inside of polygon, keep outside the same **/ XCopyArea (xwindow->display, xwindow->terrain[shape_index][level], drawable, xwindow->gc_clear, 0, y_size, x_size, y_size, 0, 0); /** OR in new polygon interior **/ XCopyArea (xwindow->display, xwindow->terrain[shape_index][level], drawable, xwindow->gc_or, 0, 0, x_size, y_size, 0, 0); } /** If interior of cell can be seen **/ if (use_full) { /** Set drawing side & value **/ if (cell->side == SIDE_NONE) { hue_on = xwindow->hue_terrain[0]; hue_off = xwindow->hue_mark[0]; value = 0; } else if (cell->side == SIDE_FIGHT) value = 0; else { hue_on = xwindow->hue[cell->side]; hue_off = xwindow->hue_inverse[cell->side]; value = cell->value[cell->side]; } /** compute troop size **/ token_size = shape->troop_to_size[value]; half_token_size = token_size/2; /** If cell is occupied by a single side **/ if (cell->side != SIDE_NONE && cell->side != SIDE_FIGHT) { /** Draw troop **/ if (shape->troop_shape == SHAPE_CIRCLE) XFillArc (xwindow->display, drawable, hue_on, x_draw_center - half_token_size, y_draw_center - half_token_size, token_size, token_size, 0, ANGLE_FULL); else if (shape->troop_shape == SHAPE_SQUARE) XFillRectangle (xwindow->display, drawable, hue_on, x_draw_center - half_token_size, y_draw_center - half_token_size, token_size, token_size); /** Show informative letter in center of cell **/ if (xwindow->draw_letter[cell->side]) XDrawString (xwindow->display, drawable, xwindow->gc_flip, x_draw_center - xwindow->char_width/2, y_draw_center + xwindow->char_height/2, xwindow->letter[cell->side], 1); /** Draw direction vectors **/ if (!Config->enable[OPTION_HIDDEN][side] || cell->side == side) { if (value == 0) draw_arrows (cell, xwindow, hue_on, hue_off, x_draw_center, y_draw_center, half_token_size, shape, TRUE); else draw_arrows (cell, xwindow, hue_on, hue_off, x_draw_center, y_draw_center, half_token_size, shape, FALSE); } } else if (cell->side == SIDE_FIGHT) { /** Else cell has multiple occupants **/ /** Find two largest troop components of cell **/ side_first = 0; side_second = 0; value_first = 0; value_second = 0; for (k=0; kside_count; k++) { if (cell->value[k] > value_first) { value_second = value_first; side_second = side_first; value_first = cell->value[k]; side_first = k; } else if (cell->value[k] > value_second) { value_second = cell->value[k]; side_second = k; } } /** Determine the size and hues of the two troops **/ hue_on = xwindow->hue[side_first]; token_size = shape->troop_to_size[value_first]; half_token_size = token_size/2; hue_off = xwindow->hue[side_second]; token2_size = shape->troop_to_size[value_second]; half_token2_size = token2_size/2; /** Draw the fighting troops and battle cross **/ if (shape->troop_shape == SHAPE_CIRCLE) { XFillArc (xwindow->display,drawable, hue_on, x_draw_center - half_token_size, y_draw_center - half_token_size, token_size, token_size, 0, ANGLE_FULL); XFillArc (xwindow->display,drawable, hue_off, x_draw_center - half_token2_size, y_draw_center - half_token2_size, token2_size, token2_size, 0, ANGLE_FULL); } else if (shape->troop_shape == SHAPE_SQUARE) { XFillRectangle (xwindow->display, drawable, hue_on, x_draw_center - half_token_size, y_draw_center - half_token_size, token_size, token_size); XFillRectangle (xwindow->display, drawable, hue_off, x_draw_center - half_token2_size, y_draw_center - half_token2_size, token2_size, token2_size); } XDrawLine (xwindow->display, drawable, hue_on, x_draw_center - shape->center_rectangle.x, y_draw_center - shape->center_rectangle.y, x_draw_center + shape->center_rectangle.x, y_draw_center + shape->center_rectangle.y); XDrawLine (xwindow->display, drawable, hue_off, x_draw_center - shape->center_rectangle.x, y_draw_center + shape->center_rectangle.y, x_draw_center + shape->center_rectangle.x, y_draw_center - shape->center_rectangle.y); } } /** If cell is a town **/ if (cell->angle > 0 && (use_full || (Config->enable[OPTION_BASEMAP][side] && cell->seen[side]))) { /** Set town color **/ if (cell->side < SIDE_VALID_LIMIT) hue_off = xwindow->hue_inverse[cell->side]; else hue_off = xwindow->hue_mark[0]; /** Set town size **/ if (cell->angle < ANGLE_FULL) half_token_size = shape->growth_to_radius[cell->old_growth]; else half_token_size = shape->growth_to_radius[cell->growth]; token_size = half_token_size*2 + 1; XDrawArc (xwindow->display, drawable, hue_off, x_draw_center - half_token_size, y_draw_center - half_token_size, token_size, token_size, 0, cell->angle); XDrawArc (xwindow->display, drawable, hue_off, x_draw_center - half_token_size + 1, y_draw_center - half_token_size + 1, token_size - 2, token_size - 2, 0, cell->angle); } /** If cell is being managed **/ if (cell->manage_update && use_full) draw_manager (cell, xwindow, hue_off, x_center, y_center); /** If cell is marching **/ if (cell->any_march && cell->march_side == side) draw_march_arrows (cell, side, xwindow, x_draw_center, y_draw_center, shape, MARCH_ACTIVE); if (cell->march[side]) draw_march_arrows (cell, side, xwindow, x_draw_center, y_draw_center, shape, cell->march[side]); /** Copy cell back to window, if necessary **/ if (copy_method != COPY_NONE) XCopyArea (xwindow->display, drawable, xwindow->window, xwindow->hue_terrain[0], x_draw_corner, y_draw_corner, x_size, y_size, x_corner, y_corner); } /****************************************************************************** draw_blank_cell (cell, player) Draw a single blank polygon. ******************************************************************************/ draw_blank_cell (cell, player, use_terrain) cell_type *cell; int player, use_terrain; { int side; xwindow_type *xwindow; shape_type *shape; xwindow = XWindow[player]; side = Config->player_to_side[player]; shape = Board->shapes[side][cell->shape_index]; shape->points[0].x = cell->x_center[side] - shape->center_vertex.x; shape->points[0].y = cell->y_center[side] - shape->center_vertex.y; if (use_terrain) XFillPolygon (xwindow->display, xwindow->window, xwindow->hue_terrain[cell->level], shape->points, shape->point_count-1, Convex, CoordModePrevious); else XFillPolygon (xwindow->display, xwindow->window, xwindow->hue_terrain[Config->level_max+1], shape->points, shape->point_count-1, Convex, CoordModePrevious); if (Config->enable[OPTION_GRID][side]) XDrawLines (xwindow->display, xwindow->window, xwindow->hue_mark[0], shape->points, shape->point_count, CoordModePrevious); else XDrawLines (xwindow->display, xwindow->window, xwindow->hue_terrain[cell->level], shape->points, shape->point_count, CoordModePrevious); } /****************************************************************************** draw_arrows (cell, xwindow, hue_on, hue_off, x_center, y_center, half_troop_size, shape, is_halved) Draw direction vectors for on , with color and inverse color . The cell center is defined by the coords (,), with indicating just that. Current cell shape is . If , just draw mini-vector. ******************************************************************************/ draw_arrows (cell, xwindow, hue_on, hue_off, x_center, y_center, half_troop_size, shape, is_halved) cell_type *cell; xwindow_type *xwindow; GC hue_on, hue_off; int x_center, y_center, half_troop_size, is_halved; shape_type *shape; { int k; XPoint *source, *dester; /** For each possible direction **/ for (k=0; kdirection_count; k++) { /** If direction vector active **/ if (cell->dir[k]) { /** Determine which vector array should be used **/ if (is_halved) { source = shape->arrow_source[k][1]; dester = shape->arrow_dester[k][1]; } else { source = shape->arrow_source[k][0]; dester = shape->arrow_dester[k][0]; } /** Draw basic direction vector **/ XDrawLine (xwindow->display, xwindow->drawable, hue_on, x_center + source[0].x, y_center + source[0].y, x_center + dester[0].x, y_center + dester[0].y); XDrawLine (xwindow->display, xwindow->drawable, hue_on, x_center + source[2].x, y_center + source[2].y, x_center + dester[2].x, y_center + dester[2].y); XDrawLine (xwindow->display, xwindow->drawable, hue_on, x_center + source[1].x, y_center + source[1].y, x_center + dester[1].x, y_center + dester[1].y); #if USE_INVERT /** Draw inset vector with inverse hue **/ if (is_halved) { XDrawLine (xwindow->display, xwindow->drawable, hue_on, x_center + source[1].x, y_center + source[1].y, x_center + dester[1].x, y_center + dester[1].y); } else { source = shape->arrow_source_x[half_troop_size][k]; dester = shape->arrow_dester_x[half_troop_size][k]; XDrawLine (xwindow->display, xwindow->drawable, hue_off, x_center + source[0].x, y_center + source[0].y, x_center + dester[0].x, y_center + dester[0].y); /** XDrawLine (xwindow->display, xwindow->drawable, hue_on, x_center + source[1].x, y_center + source[1].y, x_center + dester[1].x, y_center + dester[1].y); **/ } #endif } } } /****************************************************************************** draw_march_arrows (cell, march_side, xwindow, x_center, y_center, shape, march_type) Draw march vectors for on , with color determined by . The cell center is defined by the coordinates (,). Current cell shape is . indicates passive or active marching. ******************************************************************************/ draw_march_arrows (cell, march_side, xwindow, x_center, y_center, shape, march_type) cell_type *cell; int march_side; xwindow_type *xwindow; int x_center, y_center, march_type; shape_type *shape; { int k; XPoint *source, *dester; /** If not a HALT command **/ if (cell->march_dir[march_side] != MARCH_HALT) { /** Set direction **/ k = cell->march_dir[march_side]; source = shape->march_source[k]; dester = shape->march_dester[k]; /** Draw march vectors **/ XDrawLine (xwindow->display, xwindow->drawable, xwindow->hue[march_side], x_center + source[0].x, y_center + source[0].y, x_center + dester[0].x, y_center + dester[0].y); XDrawLine (xwindow->display, xwindow->drawable, xwindow->hue[march_side], x_center + source[1].x, y_center + source[1].y, x_center + dester[1].x, y_center + dester[1].y); XDrawLine (xwindow->display, xwindow->drawable, xwindow->hue[march_side], x_center + source[2].x, y_center + source[2].y, x_center + dester[2].x, y_center + dester[2].y); XDrawLine (xwindow->display, xwindow->drawable, xwindow->hue[march_side], x_center + source[3].x, y_center + source[3].y, x_center + dester[3].x, y_center + dester[3].y); } /** Draw passive rectangle if appropriate **/ if (march_type == MARCH_PASSIVE) XDrawRectangle (xwindow->display, xwindow->drawable, xwindow->hue[march_side], x_center - Config->march_size, y_center - Config->march_size, 2*Config->march_size, 2*Config->march_size); } /****************************************************************************** draw_manager (cell, xwindow, hue_off, x_center, y_center) Draw icons which indicate how is being managed. ******************************************************************************/ draw_manager (cell, xwindow, hue_off, x_center, y_center) cell_type *cell; xwindow_type *xwindow; GC hue_off; int x_center, y_center; { switch (cell->manage_update) { case MANAGE_CONSTRUCTION: XDrawString (xwindow->display, xwindow->drawable, hue_off, x_center - 3*xwindow->char_width/2 + 1, y_center +xwindow->char_height/2, "BLD", 3); break; case MANAGE_ARTILLERY: XDrawString (xwindow->display, xwindow->drawable, hue_off, x_center - 3*xwindow->char_width/2 + 1, y_center +xwindow->char_height/2, "GUN", 3); break; case MANAGE_PARATROOP: XDrawString (xwindow->display, xwindow->drawable, hue_off, x_center - 3*xwindow->char_width/2 + 1, y_center +xwindow->char_height/2, "PAR", 3); break; case MANAGE_FILL: XDrawString (xwindow->display, xwindow->drawable, hue_off, x_center - 3*xwindow->char_width/2 + 1, y_center +xwindow->char_height/2, "FIL", 3); break; case MANAGE_DIG: XDrawString (xwindow->display, xwindow->drawable, hue_off, x_center - 3*xwindow->char_width/2 + 1, y_center + xwindow->char_height/2, "DIG", 3); break ; } } /****************************************************************************** draw_shell (cell, player, source_side) Draw a shell in of hue given by for . ******************************************************************************/ draw_shell (cell, player, source_side) cell_type *cell; int player, source_side; { int side, shell_size; static long xrand, yrand; shape_type *shape; side = Config->player_to_side[player]; shape = Board->shapes[side][cell->shape_index]; /** Determine shell size and position **/ shell_size = (int)(shape->size_bound.y * SHELL_FRACTION); xrand = (xrand+2938345)%(shape->size_rectangle.x-shell_size); yrand = (yrand+2398321)%(shape->size_rectangle.y-shell_size); /** Draw shell **/ XFillArc (XWindow[player]->display, XWindow[player]->window, XWindow[player]->hue[source_side], cell->x_center[side] + xrand - shape->center_rectangle.x, cell->y_center[side] + yrand - shape->center_rectangle.y, shell_size, shell_size, 0, ANGLE_FULL); } /****************************************************************************** draw_chute (cell, player, source_side) Draw a parachute in of hue given by for . ******************************************************************************/ draw_chute (cell, player, source_side) cell_type *cell; int player, source_side; { int side, chute_size, half_chute_size, x_center, y_center; static long xrand, yrand; shape_type *shape; side = Config->player_to_side[player]; shape = Board->shapes[side][cell->shape_index]; /** Determine chute size and position **/ chute_size = (int)(shape->size_bound.y * CHUTE_FRACTION); half_chute_size = chute_size/2; xrand = (xrand+2938345)%(shape->size_rectangle.x - chute_size); yrand = (yrand+2398321)%(shape->size_rectangle.y - chute_size - half_chute_size); x_center = cell->x_center[side] + xrand - shape->center_rectangle.x; y_center = cell->y_center[side] + yrand - shape->center_rectangle.y; /** Draw semicircle **/ XFillArc (XWindow[player]->display, XWindow[player]->window, XWindow[player]->hue[source_side], x_center, y_center, chute_size, chute_size, 0, ANGLE_HALF); /** Draw shrouds **/ XDrawLine (XWindow[player]->display, XWindow[player]->window, XWindow[player]->hue[source_side], x_center, y_center + half_chute_size, x_center + half_chute_size, y_center + chute_size); XDrawLine (XWindow[player]->display, XWindow[player]->window, XWindow[player]->hue[source_side], x_center + half_chute_size, y_center + half_chute_size, x_center + half_chute_size, y_center + chute_size); XDrawLine (XWindow[player]->display, XWindow[player]->window, XWindow[player]->hue[source_side], x_center + chute_size - 1, y_center + half_chute_size, x_center + half_chute_size, y_center + chute_size); } /****************************************************************************** draw_message (text, textcount, new_side, current_player) Print the latest message to the screen. The message is purposely allowed to flash in order to attract attention. Further attention can be called by use of CTRL_G to ring the bell. ******************************************************************************/ draw_message (text, textcount, new_side, current_player) char text[]; int textcount, new_side, current_player; { int i, player, side, blank_line, old_length, scroll, scroll_and_print; static old_side=0, very_first=TRUE, first_time[MAX_PLAYERS]; char line[MAX_LINE]; /** Initialize message stuff **/ if (very_first) { for (i=0; iplayer_to_side[current_player]; #if !USE_MULTITEXT /**** copy old message ****/ strcpy (old_message, Config->message_all); if (new_side != old_side) strcpy (Config->message_all, ""); #else old_length = strlen (Config->message_single[current_player]); #endif /** Get out if control, shift, or meta **/ if (textcount==0) return; text[textcount] = 0; /** If typing something for the first time, remove initial message **/ if (first_time[current_player]) { strcpy (Config->message_single[current_player], ""); first_time[current_player] = FALSE; blank_line = TRUE; } /** Find out what player typed **/ switch (text[0]) { /** Backspace **/ case BACKSPACE: case DELETE: #if USE_MULTITEXT if (strlen (Config->message_single[current_player]) > 0) Config->message_single[current_player] [(strlen (Config->message_single[current_player]))-1] = '\0'; /** = Config->message_all[(strlen (Config->message_single[current_player]))]; **/ #else if (strlen(Config->message_all) > 0) Config->message_all[(strlen(Config->message_all))-1] = Config->message_all[(strlen (Config->message_all))]; #endif break; /** Newline **/ case RETURN: #if USE_MULTITEXT strcpy (Config->message_single[current_player], ""); blank_line = TRUE; #else scroll = TRUE; #endif break; /** Quit **/ case CTRL_C: case CTRL_Q: first_time[current_player] = TRUE; remove_player (current_player); return; break; /** Dump game stats **/ case CTRL_P: game_stats (); dump_board (Config->file_store_map, FALSE); break; /** Switch to next side (cheat) **/ case CTRL_E: break; /** Quit game but keep watching **/ case CTRL_W: /** Disable horizon **/ XWindow[current_player]->watch = TRUE; if (Config->enable_all[OPTION_HORIZON]) { Config->enable[OPTION_HORIZON][side] = FALSE; draw_board (current_player, TRUE); } first_time[current_player] = TRUE; sprintf (line, "%s has quit the game", Config->side_to_hue_name[side]); draw_message (line, strlen (line), side, current_player); for (player=0; playerplayer_count; player++) if (XWindow[player]->open) XBell (XWindow[player]->display, BELL_VOLUME); break; /** Sound bell on all displays (annoying) **/ case CTRL_G: for (player=0; playerplayer_count; player++) if (XWindow[player]->open) XBell (XWindow[player]->display, BELL_VOLUME); break; /** Space **/ case SPACE: /** Determine whether text should scroll **/ #if USE_MULTITEXT if ((strlen (Config->message_single[current_player]) + 1) > MAX_TEXT) scroll = TRUE; else strcat (Config->message_single[current_player], " "); #else if ((strlen (Config->message_all) + 1) > MAX_TEXT) scroll = TRUE; else strcat (Config->message_all, " "); #endif break; /** Normal character **/ default: /** Determine whether text should scroll **/ #if USE_MULTITEXT if ((strlen (Config->message_single[current_player]) + strlen(text)) > MAX_TEXT) scroll = TRUE; else strcat (Config->message_single[current_player], text); #else if ((strlen (Config->message_all) + strlen(text)) > 511) scroll = TRUE; else strcat (Config->message_all, text); #endif break; } #if USE_MULTITEXT if (old_length > strlen (Config->message_single[current_player])+2) blank_line = TRUE; #else if (new_side != old_side) scroll_and_print = TRUE; #endif /** Show the message string on all displays **/ for (player=0; playerplayer_count; player++) { if (!XWindow[player]->open) continue; #if !USE_MULTITEXT /** Scroll bottom text line up **/ if (scroll || scroll_and_print) { XDrawImageString (XWindow[player]->display, XWindow[player]->window, XWindow[player]->hue[old_side], Config->text_offset, XWindow[player]->text_y_pos[0], Blank, strlen(Blank)); XDrawImageString (XWindow[player]->display, XWindow[player]->window, XWindow[player]->hue[old_side], Config->text_offset, XWindow[player]->text_y_pos[0], old_message, strlen(old_message)); XDrawImageString (XWindow[player]->display, XWindow[player]->window, XWindow[player]->hue[new_side], Config->text_offset, XWindow[player]->text_y_pos[1], Blank, strlen(Blank)); } /** Show new text line **/ if (scroll_and_print || !scroll) { XDrawImageString (XWindow[player]->display, XWindow[player]->window, XWindow[player]->hue[new_side], Config->text_offset, XWindow[player]->text_y_pos[1], Blank, strlen(Blank)); XDrawImageString (XWindow[player]->display, XWindow[player]->window, XWindow[player]->hue[new_side], Config->text_offset, XWindow[player]->text_y_pos[1], Config->message_all, strlen(Config->message_all)); } #else /** Show new text line **/ if (scroll_and_print || !scroll) { if (blank_line) XDrawImageString (XWindow[player]->display, XWindow[player]->window, XWindow[player]->hue_inverse[new_side], Config->text_offset, XWindow[player]->text_y_pos[current_player], Blank, strlen(Blank)); if (player == current_player) sprintf (line, "%s > %s_ ", XWindow[current_player]->display_name, Config->message_single[current_player]); else sprintf (line, "%s > %s ", XWindow[current_player]->display_name, Config->message_single[current_player]); XDrawImageString (XWindow[player]->display, XWindow[player]->window, XWindow[player]->hue_inverse[new_side], Config->text_offset, XWindow[player]->text_y_pos[current_player], line, strlen(line)); } #endif } #if !USE_MULTITEXT if (scroll_and_print || !scroll) old_side=new_side; #endif /** Blank out message if scroll occurred **/ if (scroll) strcpy (Config->message_all, ""); } #if USE_TIMER /****************************************************************************** draw_timer (running_time, player) Draw short text string which indicates the elapsed game time. ******************************************************************************/ draw_timer (running_time, player) unsigned long running_time; int player; { char line[MAX_LINE]; sprintf (line, "%02u:%02u", running_time/60, running_time%60); XDrawImageString (XWindow[player]->display, XWindow[player]->window, XWindow[player]->hue_mark[0], TIMER_OFFSET, XWindow[player]->text_y_pos[0], line, strlen(line)); /** Would be nice, but could slow things down **/ /** XSync (XWindow[player]->display, 0); **/ } #endif