home *** CD-ROM | disk | FTP | other *** search
Wrap
/* * atanks - obliterate each other with oversize weapons * Copyright (C) 2002,2003 Thomas Hudson,Juraj Michalek * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include <dirent.h> #include "globals.h" #include "menu.h" #include "button.h" #include "team.h" #include "files.h" #include "satellite.h" #include "update.h" #include "network.h" #include "land.h" #include "floattext.h" #include "explosion.h" #include "beam.h" #include "missile.h" #include "decor.h" #include "teleport.h" #include "sky.h" #include "gameloop.h" #ifdef THREADS #include <pthread.h> #endif #ifdef NETWORK #include "client.h" #endif enum cmdTokens { ARGV_NOTHING_EXPECTED, ARGV_GFX_DEPTH, ARGV_SCREEN_WIDTH, ARGV_SCREEN_HEIGHT, ARGV_DATA_DIR, ARGV_CONFIG_DIR }; #define SWITCH_HELP "-h" #define SWITCH_FULL_SCREEN "-fs" #define SWITCH_WINDOWED "--windowed" #define SWITCH_NOSOUND "--nosound" #define SWITCH_DATADIR "--datadir" #define SWITCH_CONFIGDIR "-c" #define SWITCH_NO_CONFIG "--noconfig" int screen_mode = GFX_AUTODETECT_WINDOWED; // BITMAP *create_gradient_strip (const gradient *gradient, int length); // int draw_circlesBG (GLOBALDATA *global, BITMAP *dest, int x, int y, int width, int height, bool image); using namespace std; void fpsadd() { fps = frames; frames = 0; } void clockadd() { cclock++; } END_OF_FUNCTION(clockadd) /***************************************************************************** drawMenuBackground Draws a 600x400 centered box, fills it with some random lines or circles. Someday, we should make this more generic; have it take the box dimensions as an input parameter. *****************************************************************************/ void drawMenuBackground (GLOBALDATA *global, ENVIRONMENT *env, int itemType, int tOffset, int numItems) { rectfill (env->db, global->halfWidth - 300, global->menuBeginY, // 100, global->halfWidth + 300, global->menuEndY, // global->screenHeight - 100, makecol (0,79,0)); rect (env->db, global->halfWidth - 300, global->menuBeginY, // 100, global->halfWidth + 300, global->menuEndY, // global->screenHeight - 100, makecol (128,255,128)); drawing_mode (DRAW_MODE_TRANS, NULL, 0, 0); env->current_drawing_mode = DRAW_MODE_TRANS; set_trans_blender (0, 0, 0, 15); for (int tCount = 0; tCount < numItems; tCount++) { int radius, xpos, ypos; switch (itemType) { case BACKGROUND_CIRCLE: // circles radius = (int)((perlin1DPoint (1.0, 5, (tOffset * 0.02) + tCount + 423346, 0.5, 8) + 1) / 2 * 40); xpos = global->halfWidth + (int)(perlin1DPoint (1.0, 3, (tOffset * 0.02) + tCount + 232662, 0.3, 6) * 250); ypos = global->halfHeight + (int)(perlin1DPoint (1.0, 2, (tOffset * 0.02) + tCount + 42397, 0.3, 6) * (global->halfHeight - 100)); circlefill (env->db, xpos, ypos, radius, makecol (200,255,200)); break; case BACKGROUND_LINE: // Horz lines radius = (int)((perlin1DPoint (1.0, 5, (tOffset * 0.02) + tCount + 423346, 0.5, 8) + 1) / 2 * 40); xpos = global->halfWidth + (int)(perlin1DPoint (1.0, 3, (tOffset * 0.02) + tCount + 232662, 0.3, 6) * 250); rectfill (env->db, xpos - radius / 2, 101, xpos + radius / 2, global->screenHeight - 101, makecol (200,255,200)); break; case BACKGROUND_BLANK: default: break; } } solid_mode (); env->current_drawing_mode = DRAW_MODE_SOLID; } void initialisePlayers (GLOBALDATA *global) { int z; for (z = 0; z < global->numPlayers; z++) { global->players[z]->money = (int)global->startmoney; global->players[z]->score = 0; // global->players[z]->initialise (); // global->players[z]->type_saved = global->players[z]->type; if (((int)global->players[z]->type != HUMAN_PLAYER) && (global->players[z]->preftype == PERPLAY_PREF)) { global->players[z]->generatePreferences(); } global->players[z]->initialise(); global->players[z]->type_saved = global->players[z]->type; } } void wait_for_input() { do { LINUX_SLEEP; } while ((!keypressed()) && (!mouse_b)); flush_inputs(); } int pickColor (int left, int top, int width, int height, int x, int y) { int r, g, b; double value, saturation; double hue = ((double)(x - left) / width) * 360; double hPos = (double)(y - top) / height; if (hPos > 0.5) { value = 1.0 - ((hPos - 0.5) * 2); saturation = 1.0; } else { value = 1.0; saturation = hPos * 2; } hsv_to_rgb (hue, saturation, value, &r, &g, &b); return (makecol (r, g, b)); } void colorBar (ENVIRONMENT *env, int left, int top, int width, int height) { int right = left + width; int bottom = top + height; for (int x = left; x < right; x++) { for (int y = top; y < bottom; y++) { putpixel (env->db, x, y, pickColor (left, top, width, height, x, y)); } } } int textEntryBox (GLOBALDATA *global, ENVIRONMENT *env, int modify, int x, int y, char *text, unsigned int textLength) { int ke = 0; int fontWidth = text_length (font, (char *)"Z"); int fontHeight = text_height (font); int leftX = x - (fontWidth * textLength / 2); int rightX = x + (fontWidth * textLength / 2); int boxWidth = fontWidth * textLength; // char tempText[textLength + 1]; char * tempText; int flashCount = 0; int lx = mouse_x, ly = mouse_y; tempText = (char *)calloc(textLength + 1, sizeof(char)); if (!tempText) { // Die hard! cerr << "ERROR: Unable to allocate " << (textLength + 1) << " bytes in textEntryBox() !!!" << endl; // exit (1); } if (! text) text = (char *)""; rectfill (env->db, leftX, y - 2, rightX, y + fontHeight + 2, WHITE); rect (env->db, leftX, y - 2, rightX, y + fontHeight + 2, BLACK); if (!modify) { textout_centre_ex (env->db, font, text, x, y, BLACK, -1); } env->make_update (leftX - 2, y - 4, fontWidth * textLength + 4, fontHeight + 6); env->do_updates (); if (!modify) { return (boxWidth); } strncpy (tempText, text, textLength + 1); while (((ke >> 8) != KEY_ENTER && (ke >> 8) != KEY_ESC && (ke >> 8) != KEY_ENTER_PAD) || strlen (tempText) < 1) { int tWidth = text_length (font, tempText); LINUX_SLEEP; rectfill (env->db, leftX, y - 2, rightX, y + fontHeight + 2, WHITE); rect (env->db, leftX, y - 2, rightX, y + fontHeight + 2, BLACK); //rectfill (screen, x - (tWidth / 2), y, x + (tWidth / 2) + 10, y + text_height (font), (flashCount < 5)?WHITE:BLACK); textout_centre_ex (env->db, font, tempText, x, y, BLACK, -1); rectfill (env->db, x + (tWidth / 2) + 2, y, x + (tWidth / 2) + 10, y + text_height (font), (flashCount < 25)?WHITE:BLACK); env->make_update (leftX - 2, y - 4, fontWidth * textLength + 4, fontHeight + 6); env->make_update (mouse_x, mouse_y, ((BITMAP *) (global->misc[0]))->w, ((BITMAP *) (global->misc[0]))->h); env->make_update (lx, ly, ((BITMAP *) (global->misc[0]))->w, ((BITMAP *) (global->misc[0]))->h); lx = mouse_x; ly = mouse_y; if (! global->os_mouse) show_mouse (NULL); if (keypressed ()) { ke = readkey (); } else { ke = 0; } if ((ke >> 8) == KEY_BACKSPACE) { tempText[strlen (tempText) - 1] = 0; rectfill (screen, x - (tWidth / 2), y, x + (tWidth / 2) + 10, y + text_height (font), WHITE); env->make_update (x - (tWidth / 2) - 2, y - 2, tWidth + 14, text_height (font) + 4); } else if ((ke & 0xff) >= 32 && strlen (tempText) < textLength) { tempText[strlen (tempText)] = ke & 0xff; tempText[strlen (tempText) + 1] = 0; //textprintf (screen, font, x + text_length (font, tempText), y, WHITE, (char *)"%c", ke & 0xff); } else env->do_updates (); if (! global->os_mouse) show_mouse (screen); rest (1); flashCount++; flashCount = flashCount % 50; } if ((ke >> 8) != KEY_ESC) strncpy (text, tempText, textLength); flush_inputs (); free(tempText); return (boxWidth); } void credits (GLOBALDATA *global, ENVIRONMENT *env) { char dataDir[2048]; TEXTBLOCK *my_text; sprintf (dataDir, "%s/credits.txt", global->dataDir); my_text = new TEXTBLOCK(dataDir); scrollTextList (global, env, my_text ); delete my_text; } /* * Save all players to a text file. */ int savePlayers_Text(GLOBALDATA *global, FILE *my_file) { int count = 0; while (count < global->numPermanentPlayers) { global->allPlayers[count]->saveToFile_Text(my_file); count++; } return TRUE; } int loadPlayers_Text (GLOBALDATA *global, ENVIRONMENT *env, FILE *file) { int count, max; int status = TRUE; PLAYER *new_player; max = global->numPermanentPlayers; global->allPlayers = (PLAYER **) malloc (sizeof(PLAYER*) * max); if (! global->allPlayers) { perror("atanks.cc: Failed to allocate memory for allPlayers in loadPlayers_Text"); return FALSE; } count = 0; while (status) { // global->allPlayers[count] = new PLAYER(global, env, file, true); new_player = new PLAYER(global, env); if (! new_player) { perror( (char *)"atanks.cc: Failed to allocate memory for players in loadPlayers_Text"); return FALSE; } status = new_player->loadFromFile_Text(file); if (status) { global->allPlayers[count] = new_player; count++; if (count == max) { max += 5; global->allPlayers = (PLAYER**) realloc(global->allPlayers, sizeof(PLAYER *) * max); } } else free(new_player); } // end of while status global->numPermanentPlayers = count; return TRUE; } void newgame (GLOBALDATA *global, ENVIRONMENT *env) { int objCount; TANK *tank; env->initialise (); global->initialise (); // if a game should be loaded, try it or deny loading of the game if ( (global->load_game) && (!Load_Game(global, env)) ) global->load_game = false; // Now check back whether to load a game if (!global->load_game) initialisePlayers (global); // There must not be any tanks! for (objCount = 0; (tank = (TANK*)env->getNextOfClass (TANK_CLASS, &objCount)) && tank; objCount++) { tank->player = NULL; // To avoid violent death! delete(tank); } // This is always true here, as a newly started game is handled like a loaded one: global->bIsGameLoaded = true; } // This function draws the background for most screens int draw_circlesBG (GLOBALDATA *global, BITMAP *dest, int x, int y, int width, int height, bool image) { // int largestCircle, circleCount; // BITMAP *drawTo = dest; // try to prevent crashes on 64-bit systems by avoiding this function if (! global->draw_background) { rectfill(dest, 0, 0, global->screenWidth - 1, global->screenHeight - 1, BLACK); return 0; } if ( (image) && (global->misc[17]) ) stretch_blit(global->misc[17], dest, 0, 0, global->misc[17]->w, global->misc[17]->h, 0, 0, global->screenWidth, global->screenHeight); else rectfill(dest, 0, 0, global->screenWidth - 1, global->screenHeight - 1, DARK_GREEN); /* if (global->cacheCirclesBG) { if (!global->gfxData.circlesBG) { global->gfxData.circlesBG = create_bitmap (width, height); drawTo = global->gfxData.circlesBG; } else { blit (global->gfxData.circlesBG, dest, 0, 0, 0, 0, width, height); return (0); } } else { drawTo = dest; } largestCircle = (int)(global->halfWidth * (4.0/3.0)); if (largestCircle > 1000) largestCircle = 1000; // perhaps avoid crash on large screens global->gfxData.circle_gradient_strip = create_gradient_strip (circles_gradient, largestCircle); for (circleCount = largestCircle; circleCount > 0; circleCount -= 2) circlefill (drawTo, width/2, height/2, circleCount, getpixel (global->gfxData.circle_gradient_strip, 0, largestCircle - circleCount)); if (global->cacheCirclesBG) draw_circlesBG (global, dest, x, y, width, height); */ return (0); } ENVIRONMENT *init_game_settings (GLOBALDATA *global) { int count, x, y, z; ENVIRONMENT *env; double expSize, disperseSize; // char dataDir[2048]; int colour_theme = (int) global->colour_theme; int status; #ifdef WIN32 if (global->full_screen == FULL_SCREEN_TRUE) global->os_mouse = FALSE; #endif status = allegro_init (); if (status) { printf("Unable to start Allegro.\n"); return NULL; } set_window_title( "Atomic Tanks"); // before we get started, make sure if we are using // full screen mode to ignore width and height settings if (global->full_screen == FULL_SCREEN_TRUE) { status = get_desktop_resolution(& (global->screenWidth), & (global->screenHeight) ); if (status < 0) { global->screenWidth = 800; global->screenHeight = 600; } screen_mode = GFX_AUTODETECT_FULLSCREEN; } // check for X pressed on the window bar LOCK_FUNCTION(close_button_handler); set_close_button_callback(close_button_handler); if (! global->colourDepth) global->colourDepth = desktop_color_depth(); if ( (global->colourDepth != 16) && (global->colourDepth != 32) ) global->colourDepth = 16; set_color_depth (global->colourDepth); if (global->width_override) { global->screenWidth = global->width_override; global->halfWidth = global->screenWidth / 2; } if (global->height_override) { global->screenHeight = global->height_override; global->halfHeight = global->screenHeight / 2; } if (set_gfx_mode (screen_mode, global->screenWidth, global->screenHeight, 0, 0) < 0) { perror( "set_gfx_mode"); // exit (1); status = set_gfx_mode(screen_mode, 800, 600, 0, 0); if ( status < 0 ) exit(1); global->screenWidth = 800; global->screenHeight = 600; global->halfWidth = 400; global->halfHeight = 300; } #ifdef WIN32 if (global->full_screen == FULL_SCREEN_TRUE) set_display_switch_mode(SWITCH_BACKAMNESIA); else set_display_switch_mode(SWITCH_BACKGROUND); #endif if (install_keyboard () < 0) { perror ( "install_keyboard failed"); exit (1); } if (install_timer () < 0) { perror ( "install_timer failed"); exit (1); } if (install_mouse () < 0) { perror ( "install_mouse failed"); // exit (1); } // check to see if we want sound if (global->sound > 0.0) { /* // don't stop program if no sound since the game can be played without if (install_sound (DIGI_AUTODETECT, MIDI_NONE, NULL) < 0) fprintf (stderr, "install_sound: %s", allegro_error); } */ int sound_type = DIGI_AUTODETECT; #ifdef LINUX switch ( (int) global->sound_driver ) { case SOUND_OSS: sound_type = DIGI_OSS; break; case SOUND_ESD: sound_type = DIGI_ESD; break; case SOUND_ARTS: sound_type = DIGI_ARTS; break; case SOUND_ALSA: sound_type = DIGI_ALSA; break; case SOUND_JACK: sound_type = DIGI_JACK; break; default: sound_type = DIGI_AUTODETECT; break; } #endif #ifdef UBUNTU if (sound_type == DIGI_AUTODETECT) sound_type = DIGI_OSS; #endif if (detect_digi_driver(sound_type)) { if (install_sound (sound_type, MIDI_NONE, NULL) < 0) { fprintf (stderr, "install_sound: failed initialising sound\n"); fprintf (stderr, "Please try selecting a different Sound Driver from the Options menu.\n"); } } else fprintf (stderr, "detect_digi_driver detected no sound device\n"); } // end of we want sound LOCK_VARIABLE(cclock); LOCK_FUNCTION(clockadd); // if (install_int_ex (clockadd, BPS_TO_TIMER (FRAMES_PER_SECOND)) < 0) { if (install_int_ex (clockadd, BPS_TO_TIMER(global->frames_per_second)) < 0) { perror ( "install_int_ex"); exit (1); } if (install_int (fpsadd, 1000) < 0) { perror ( "install_int"); exit (1); } srand (time (0)); WHITE = makecol (255, 255, 255); BLACK = makecol (0, 0, 0); PINK = makecol (255, 0, 255); RED = makecol (255, 0, 0); GREEN = makecol (0, 255, 0); DARK_GREEN = makecol(0, 80, 0); BLUE = makecol (0, 0, 255); PURPLE = makecol (200, 0, 200); YELLOW = makecol (255, 255, 0); global->Load_Bitmaps(); global->Load_Fonts(); if (! global->os_mouse) show_mouse(NULL); blit ((BITMAP *) global->title[0], screen, 0, 0, global->halfWidth - 320, global->halfHeight - 240, 640, 480); if (! global->os_mouse) show_mouse (screen); global->Load_Sounds(); for (count = 0; count < ALL_LANDS; count++) global->gfxData.land_gradient_strips[count] = NULL; for (count = 0; count < ALL_SKIES; count++) global->gfxData.sky_gradient_strips[count] = NULL; global->gfxData.explosion_gradient_strip = create_gradient_strip (explosion_gradients[colour_theme], 200); // for (count = 0; count < 2; count++) // global->gfxData.explosion_gradient_strips[count] = create_gradient_strip (explosion_gradients[count], 200); expSize = 0; disperseSize = 0; for (count = 0; count < EXPLOSIONFRAMES; count++) { global->gfxData.explosions[count] = create_bitmap (214, 214); if (count == 0) { expSize = 25; disperseSize = 0; } else if (count < EXPLODEFRAMES - 4) expSize += (107 - expSize) / 3; else if (count < EXPLODEFRAMES) expSize--; else if (count == EXPLODEFRAMES) disperseSize = 25; else disperseSize += (107 - disperseSize) / 2; clear_to_color (global->gfxData.explosions[count], PINK); for (y = (int)expSize; y > disperseSize; y--) { double value; value = pow ((double)y / expSize, count / 4 + 1); circlefill (global->gfxData.explosions[count], 107, 107, y, getpixel (global->gfxData.explosion_gradient_strip, 0, (int)(value * 200))); } if (disperseSize) circlefill (global->gfxData.explosions[count], 107, 107, (int)disperseSize, PINK); } expSize = 0; disperseSize = 0; for (count = 0; count < EXPLOSIONFRAMES; count++) { global->gfxData.flameFront[count] = create_bitmap (600, 30); if (count == 0) { expSize = 10; disperseSize = 0; } else if (count < EXPLODEFRAMES - 4) expSize += (300 - expSize) / 3; else if (count < EXPLODEFRAMES) expSize--; else if (count == EXPLODEFRAMES) disperseSize = 10; else disperseSize += (300 - disperseSize) / 2; clear_to_color (global->gfxData.flameFront[count], PINK); for (y = (int)expSize; y > disperseSize; y--) { double value; value = pow ((double)y / expSize, count / 4 + 1); ellipsefill (global->gfxData.flameFront[count], 300, 15, y, y / 20, getpixel (global->gfxData.explosion_gradient_strip, 0, (int)(value * 200))); } if (disperseSize) ellipsefill (global->gfxData.flameFront[count], 300, 15, (int)disperseSize, (int)disperseSize / 16, PINK); } global->gfxData.topbar = create_bitmap (global->screenWidth, MENUHEIGHT); global->gfxData.topbar_gradient_strip = create_gradient_strip (topbar_gradient, 100); if (!global->ditherGradients) { for (count = 0; count < MENUHEIGHT; count++) { float adjCount = (100.0 / MENUHEIGHT) * count; line (global->gfxData.topbar, 0, count, global->screenWidth - 1, count, getpixel (global->gfxData.topbar_gradient_strip, 0, (int)adjCount)); } } else { for (x = 0; x < global->screenWidth; x++) { for (y = 0; y < MENUHEIGHT; y++) { float adjY = (100.0 / MENUHEIGHT) * y; int offset; if ((adjY < 2) || (adjY > 100 - 2)) offset = 0; else offset = rand () % 4 - 2; putpixel (global->gfxData.topbar, x, y, getpixel (global->gfxData.topbar_gradient_strip, 0, (int)adjY + offset)); } } } global->gfxData.stuff_bar[0] = create_bitmap (STUFF_BAR_WIDTH, STUFF_BAR_HEIGHT); global->gfxData.stuff_bar[1] = create_bitmap (STUFF_BAR_WIDTH, STUFF_BAR_HEIGHT); global->gfxData.stuff_icon_base = create_bitmap (STUFF_BAR_WIDTH/10, STUFF_BAR_HEIGHT); clear_to_color (global->gfxData.stuff_bar[0], PINK); clear_to_color (global->gfxData.stuff_bar[1], PINK); clear_to_color (global->gfxData.stuff_icon_base, PINK); global->gfxData.stuff_bar_gradient_strip = create_gradient_strip (stuff_bar_gradient, STUFF_BAR_WIDTH); for (x = 0; x < STUFF_BAR_WIDTH; x++) { for (y = 0; y < STUFF_BAR_HEIGHT; y++) { double sides_dist = 0.1, circle_dist; circle_dist = vector_length_f ((float)x-(STUFF_BAR_WIDTH - 75), (float)y - (STUFF_BAR_HEIGHT/2 - 2), 0); if (circle_dist < 75) circle_dist = 1 - (circle_dist / 75.0); else circle_dist = 0; if (x < (STUFF_BAR_HEIGHT/2 - 2)) sides_dist -= 0.1 - ((float)x / 150.0); else if (x > STUFF_BAR_WIDTH - (STUFF_BAR_HEIGHT/2 - 2)) sides_dist -= ((float)(x - (STUFF_BAR_WIDTH - (STUFF_BAR_HEIGHT/2 - 2))) / 150.0); if (y < STUFF_BAR_HEIGHT/2 - 2) sides_dist -= 0.1 - ((float)(y) / 150.0); else sides_dist -= ((float)(y - (STUFF_BAR_HEIGHT/2 - 2)) / 150.0); sides_dist -= circle_dist * circle_dist; if (sides_dist > ((double)x / 1000.0)) sides_dist = ((double)x / 1000.0); if (sides_dist < 0) sides_dist = 0; if (circle_dist > 1) circle_dist = 1; if (x < STUFF_BAR_WIDTH/10) putpixel (global->gfxData.stuff_icon_base, x, y, getpixel (global->gfxData.stuff_bar_gradient_strip, 0, (int)((sides_dist + circle_dist) * (STUFF_BAR_WIDTH-1)))); if (y < STUFF_BAR_HEIGHT - 5) { putpixel (global->gfxData.stuff_bar[0], x, y, getpixel (global->gfxData.stuff_bar_gradient_strip, 0, (int)((sides_dist + circle_dist) * (STUFF_BAR_WIDTH-1)))); putpixel (global->gfxData.stuff_bar[1], x, y, getpixel (global->gfxData.stuff_bar_gradient_strip, 0, (int)((sides_dist + circle_dist + 0.05) * (STUFF_BAR_WIDTH-1)))); } } } if (! global->os_mouse ) { set_mouse_sprite ((BITMAP *) global->misc[0]); set_mouse_sprite_focus (0, 0); } global->window.x = 0; global->window.y = 0; global->window.w = 0; global->window.h = 0; for (z = 0; z < MAXUPDATES; z++) { global->updates[z].x = 0; global->updates[z].y = 0; global->updates[z].w = 0; global->updates[z].h = 0; } env = new ENVIRONMENT (global); if (!env) { perror ( "atanks.cc: Allocating env in init_game_settings"); exit (1); } clear_to_color (env->db, BLACK); global->env = env; return (env); } int options (GLOBALDATA *global, ENVIRONMENT *env, MENUDESC *menu); int createNewPlayer (GLOBALDATA *global, ENVIRONMENT *env) { PLAYER *newPlayer = global->createNewPlayer (env); if (!newPlayer) { perror ( "atanks.cc: Failed allocating memory in createNewPlayer"); // exit (1); } options (global, env, (MENUDESC*)newPlayer->menudesc); return (-1); } int destroyPlayer (GLOBALDATA *global, ENVIRONMENT *env, void *data) { int optionsRetVal; char sureMessage[200]; PLAYER *tempPlayer = (PLAYER*)data; MENUDESC areYouSureMenu = { "Are You Sure?", 0, NULL, TRUE, TRUE}; sprintf (sureMessage, "This player (%s) will be permanently deleted", tempPlayer->getName ()); errorMessage = sureMessage; errorX = global->halfWidth - text_length (font, errorMessage) / 2; errorY = 170; optionsRetVal = options (global, env, &areYouSureMenu); if (optionsRetVal >> 8 != KEY_ESC) { global->destroyPlayer (tempPlayer); return (-2); } return (KEY_SPACE << 8); } int displayPlayerName (ENVIRONMENT *env, int x, int y, void *data) { PLAYER *player = (PLAYER*)data; char *name = player->getName (); int textHeight = text_height (font); int textLength = text_length (font, name); if ((int)player->type == HUMAN_PLAYER) { int radius = 5; circlefill (env->db, x - textLength - textHeight / 2 - 2, y + textHeight / 2, radius, makecol (200, 100, 255)); circle (env->db, x - textLength - textHeight / 2 - 2, y + textHeight / 2, radius, BLACK); } else { rectfill (env->db, x - textLength - 2 - ((int)player->type * 3), y + textHeight - 10, x - textLength - 2, y + textHeight - 2, makecol (100, 255, 100)); rect (env->db, x - textLength - 2 - ((int)player->type * 3), y + textHeight - 10, x - textLength - 2, y + textHeight - 2, BLACK); for (int lineCount = 1; lineCount < player->type; lineCount++) { vline (env->db, x - textLength - 2 - (lineCount * 3), y + textHeight - 2, y + textHeight - 10, BLACK); } } textout_ex (env->db, font, name, x - textLength, y, player->color, -1); return (0); } int options (GLOBALDATA *global, ENVIRONMENT *env, MENUDESC *menu) { MENUENTRY *opts; BUTTON *reset_button = NULL; int selected_index = 0, my_key = 0; int numEntries; const char *title; int ke, z; int mouseLeftPressed; char *reset_text, *back_text; #include "menucontent.h" if (global->language == LANGUAGE_GERMAN) { reset_text = "Alles zurucksetzen"; back_text = "Zuruck"; } else { reset_text = "Rest All"; back_text = "Back"; } if (!menu) { menu = &mainMenu; reset_button = new BUTTON(global, env, global->halfWidth - 5 - text_length (font, menu->title), global->menuBeginY + 70, // 170, reset_text, (BITMAP *) global->misc[7], (BITMAP *) global->misc[7], (BITMAP *) global->misc[8]); } opts = menu->entries; numEntries = menu->numEntries; title = menu->title; char name_buff[64]; char format_buff[64]; int done, lb; int stop = 0; int *updateoption; updateoption = (int *)calloc(numEntries, sizeof(int)); if (!updateoption) { // Die hard! cerr << "ERROR: Unable to allocate " << numEntries << " bytes in options() !!!" << endl; // exit (1); } BUTTON *but_okay = NULL, *but_quit = NULL; if (menu->okayButton) { int xpos = global->halfWidth - 80; if (menu->quitButton) xpos -= 80; // but_okay = new BUTTON (global, env, xpos, global->halfHeight + 160, "Okay", (BITMAP*)global->misc[7], (BITMAP*)global->misc[7], (BITMAP*)global->misc[8]); but_okay = new BUTTON (global, env, xpos, global->menuBeginY + 360 , "Okay", (BITMAP*)global->misc[7], (BITMAP*)global->misc[7], (BITMAP*)global->misc[8]); if (!but_okay) { perror ( "atanks.cc: Failed allocating memory for but_okay in options"); // exit (1); } } if (menu->quitButton) { int xpos = global->halfWidth - 80; if (menu->okayButton) xpos += 80; but_quit = new BUTTON (global, env, xpos, global->menuBeginY + 360, back_text, (BITMAP*)global->misc[7], (BITMAP*)global->misc[7], (BITMAP*)global->misc[8]); // but_quit = new BUTTON (global, env, xpos, global->halfHeight + 160, back_text, (BITMAP*)global->misc[7], (BITMAP*)global->misc[7], (BITMAP*)global->misc[8]); if (!but_quit) { perror ( "atanks.cc: Failed allocating memory for but_quit in options"); // exit (1); } } mouseLeftPressed = done = lb = env->mouseclock = cclock = 0; fi = 1; for (z = 0; z < numEntries; z++) { updateoption[z] = 1; } flush_inputs (); do { LINUX_SLEEP; while (cclock > 0) { cclock--; my_key = 0; if ( keypressed() ) { my_key = readkey(); my_key = my_key >> 8; if (my_key == KEY_DOWN) { selected_index++; if (selected_index >= numEntries) selected_index = 0; my_key = 0; } else if (my_key == KEY_UP) { selected_index--; if (selected_index < 0) selected_index = numEntries - 1; my_key = 0; } else if (my_key == KEY_ENTER_PAD) my_key = KEY_ENTER; for (z = 0; z < numEntries; z++) updateoption[z] = TRUE; fi = TRUE; } // end of a key was pressed if (!lb && mouse_b & 1) { env->mouseclock = 0; mouseLeftPressed = 1; } else { mouseLeftPressed = 0; } lb = (mouse_b & 1) ? 1 : 0; if ( ((mouse_b & 1 || mouse_b & 2) && !env->mouseclock) || (my_key) ) { for (z = 0; z < numEntries; z++) { int midX = opts[z].x; int midY = opts[z].y; if (opts[z].type == OPTION_MENUTYPE) { sprintf (name_buff, "-> %s", opts[z].name); if ( ((!opts[z].viewonly) && mouse_x > midX - text_length (font, name_buff) && mouse_x < midX && mouse_y >= midY && mouse_y < midY + 10) || ( (my_key == KEY_SPACE) && (selected_index == z)) ) { int optsRetVal = options (global, env, (MENUDESC*)opts[z].value); if (optsRetVal < 0) { return (optsRetVal + 1); } fi = 1; for (z = 0; z < numEntries; z++) { updateoption[z] = 1; } my_key = selected_index = 0; } } else if (opts[z].type == OPTION_ACTIONTYPE) { sprintf (name_buff, "-> %s", opts[z].name); if ( ((!opts[z].viewonly) && mouse_x > midX - text_length (font, name_buff) && mouse_x < midX && mouse_y >= midY && mouse_y < midY + 10) || ( (my_key == KEY_SPACE) && (selected_index == z) ) ) { int (*action) (GLOBALDATA*, ENVIRONMENT*, void*) = (int (*)(GLOBALDATA*, ENVIRONMENT*, void*))opts[z].value; int actionRetVal = action (global, env, opts[z].data); if (actionRetVal) return (actionRetVal); } } else if (opts[z].type == OPTION_TEXTTYPE) { int my_text_length; strcmp(opts[z].name, "Name") ? my_text_length = 11 : my_text_length = NAME_LENGTH; int boxWidth; if (! strcmp(opts[z].name, "Server address") ) my_text_length = ADDRESS_LENGTH; if (my_text_length == NAME_LENGTH) boxWidth = textEntryBox (global, env, FALSE, midX + 100, midY, (char*)opts[z].value, my_text_length); else if (my_text_length == ADDRESS_LENGTH) boxWidth = textEntryBox(global, env, FALSE, midX + 70, midY, (char*) opts[z].value, my_text_length); else boxWidth = textEntryBox (global, env, FALSE, midX + 50, midY, (char*)opts[z].value, my_text_length); if ( ((!opts[z].viewonly) && mouse_x > midX - text_length (font, name_buff) && mouse_x < midX + 50 + boxWidth && mouse_y >= midY && mouse_y < midY + 10) || ( (selected_index == z) && (my_key == KEY_SPACE) ) ) { if (my_text_length == NAME_LENGTH) textEntryBox (global, env, TRUE, midX + 100, midY, (char*)opts[z].value, my_text_length); else if (my_text_length == ADDRESS_LENGTH) textEntryBox(global, env, TRUE, midX + 70, midY, (char *)opts[z].value, my_text_length); else textEntryBox (global, env, TRUE, midX + 50, midY, (char*)opts[z].value, my_text_length); updateoption[z] = 1; } } else if (opts[z].type == OPTION_COLORTYPE) { if ((!opts[z].viewonly) && mouse_x > midX && mouse_x < midX + 100 && mouse_y >= midY && mouse_y < midY + 15) { *(int*)opts[z].value = pickColor (midX, midY, 100, 15, mouse_x, mouse_y); updateoption[z] = 1; } colorBar (env, midX, midY, 100, 15); rectfill (env->db, midX + 110, midY, midX + 130, midY + 10, *(int*)opts[z].value); rect (env->db, midX + 110, midY, midX + 130, midY + 10, BLACK); } else if (opts[z].type == OPTION_TOGGLETYPE) { int tlen = text_length (font, name_buff); int thgt = text_height (font); int temp_counter; if ( (mouseLeftPressed && (!opts[z].viewonly) && mouse_x > midX - tlen / 2 && mouse_x < midX + tlen / 2 && mouse_y >= midY && mouse_y < midY + thgt) || ( (my_key == KEY_SPACE) && (selected_index == z) ) ) { if (*opts[z].value == 0) *opts[z].value = 1; else *opts[z].value = 0; mouseLeftPressed = 1; // updateoption[z] = 1; // Crude, but hopefulyl useful for (temp_counter = 0; temp_counter < numEntries; temp_counter++) updateoption[temp_counter] = 1; } } else { if (!opts[z].viewonly) { if (mouse_x >= midX + 100 && mouse_x < midX + 110 && mouse_y >= midY && mouse_y < midY + 10) { if (mouse_b & 1) *opts[z].value -= opts[z].increment; else if (mouse_b & 2) *opts[z].value -= opts[z].increment * 10; updateoption[z] = 1; } if (mouse_x >= midX + 112 && mouse_x < midX + 122 && mouse_y >= midY && mouse_y < midY + 10) { if (mouse_b & 1) *opts[z].value += opts[z].increment; else if (mouse_b & 2) *opts[z].value += opts[z].increment * 10; updateoption[z] = 1; } if ( (my_key == KEY_RIGHT) && (selected_index == z) ) { *opts[z].value += opts[z].increment; updateoption[z] = 1; } else if ( (my_key == KEY_LEFT) && (selected_index == z) ) { *opts[z].value -= opts[z].increment; updateoption[z] = 1; } // This if block is a nasty hack to get the tank // styles to redraw on the Players menu. if (updateoption[z]) { int my_counter; for (my_counter = 0; my_counter < numEntries; my_counter++) updateoption[my_counter] = TRUE; fi = TRUE; } /*if (mouse_x >= midX + 134 && mouse_x < midY + 154 && mouse_y >= midY && mouse_y < midY + 10) { *opts[z].value = opts[z].defaultv; updateoption[z] = 1; }*/ if (*opts[z].value > opts[z].max) { *opts[z].value = opts[z].min; } if (*opts[z].value < opts[z].min) { *opts[z].value = opts[z].max; } } } } } env->mouseclock++; if (env->mouseclock > 10) { env->mouseclock = 0; } } env->make_update (mouse_x, mouse_y, ((BITMAP *) (global->misc[0]))->w, ((BITMAP *) (global->misc[0]))->h); env->make_update (lx, ly, ((BITMAP *) (global->misc[0]))->w, ((BITMAP *) (global->misc[0]))->h); lx = mouse_x; ly = mouse_y; if (! global->os_mouse) show_mouse (NULL); // draw menu stuff if (fi) { drawMenuBackground (global, env, BACKGROUND_BLANK, rand (), 400); textout_ex (env->db, font, title, global->halfWidth - 3 - text_length (font, title), global->menuBeginY + 50, BLACK, -1); textout_ex (env->db, font, title, global->halfWidth - 5 - text_length (font, title), global->menuBeginY + 50, WHITE, -1); for (z = 0; z < numEntries; z++) { int midX = opts[z].x; int midY = opts[z].y; char my_pointer[2]; if (z == selected_index) strcpy(my_pointer, "*"); else my_pointer[0] = '\0'; if (opts[z].type == OPTION_TOGGLETYPE) { int color = (*opts[z].value)?WHITE:BLACK; int radius = text_length(font, opts[z].name) / 2; int y_radius = text_height(font); if (y_radius > 8) y_radius = 8; ellipsefill (env->db, midX, midY + text_height (font) / 2, radius, y_radius, color); textout_ex(env->db, font, my_pointer, (midX - radius) - 40 , midY, WHITE, -1); } if (opts[z].displayFunc) { if (opts[z].type == OPTION_TOGGLETYPE) { opts[z].displayFunc (env, midX + text_length (font, opts[z].name) / 2, midY, opts[z].data); } else if (opts[z].type == OPTION_MENUTYPE) { opts[z].displayFunc (env, midX, midY, opts[z].data); sprintf(name_buff, "%s", my_pointer); textout_ex(env->db, font, name_buff, midX - 125, midY, WHITE, -1); } else if (opts[z].type == OPTION_SPECIALTYPE) { opts[z].displayFunc(env, midX + text_length(font, opts[z].name) / 2, midY, opts[z].value ); sprintf (name_buff, "%s %s:", my_pointer, opts[z].name); textout_ex (env->db, font, name_buff, midX - text_length (font, name_buff), midY, opts[z].color, -1); if (!opts[z].viewonly) { draw_sprite_v_flip (env->db, (BITMAP *) global->misc[6], midX + 100, midY); draw_sprite (env->db, (BITMAP *) global->misc[6], midX + 112, midY); } } } else if (opts[z].type == OPTION_MENUTYPE) { sprintf (name_buff, "%s -> %s", my_pointer, opts[z].name); textout_ex (env->db, font, name_buff, midX - text_length (font, name_buff), midY, opts[z].color, -1); } else if (opts[z].type == OPTION_ACTIONTYPE) { sprintf (name_buff, "%s -> %s", my_pointer, opts[z].name); textout_ex (env->db, font, name_buff, midX - text_length (font, name_buff), midY, opts[z].color, -1); } else if (opts[z].type == OPTION_TEXTTYPE) { sprintf (name_buff, "%s %s:", my_pointer, opts[z].name); textout_ex (env->db, font, name_buff, midX - text_length (font, name_buff), midY, opts[z].color, -1); } else if (opts[z].type == OPTION_COLORTYPE) { sprintf (name_buff, "%s %s:", my_pointer, opts[z].name); textout_ex (env->db, font, name_buff, midX - text_length (font, name_buff), midY, opts[z].color, -1); } else if (opts[z].type == OPTION_TOGGLETYPE) { sprintf (name_buff, "%s %s", my_pointer, opts[z].name); textout_centre_ex (env->db, font, name_buff, midX, midY, opts[z].color, -1); } else { sprintf (name_buff, "%s %s:", my_pointer, opts[z].name); textout_ex (env->db, font, name_buff, midX - text_length (font, name_buff), midY, opts[z].color, -1); if (!opts[z].viewonly) { draw_sprite_v_flip (env->db, (BITMAP *) global->misc[6], midX + 100, midY); draw_sprite (env->db, (BITMAP *) global->misc[6], midX + 112, midY); } } if (my_pointer[0]) env->make_update(midX - 200, midY - 20, 400, 40); } // end of for loop if (but_okay) but_okay->draw (env->db); if (but_quit) but_quit->draw (env->db); if (reset_button) reset_button->draw(env->db); } // end of if fi for (z = 0; z < numEntries; z++) { int midX = opts[z].x; int midY = opts[z].y; if (updateoption[z]) { updateoption[z] = 0; if (opts[z].type == OPTION_TOGGLETYPE) { int color = (*opts[z].value)?WHITE:BLACK; int text_tall = text_height(font); if (text_tall > 8) text_tall = 8; ellipsefill (env->db, midX, midY + text_height (font) / 2, text_length (font, opts[z].name) / 2, text_tall, color); } if (opts[z].displayFunc) { if (opts[z].type == OPTION_TOGGLETYPE) { opts[z].displayFunc (env, midX + text_length (font, opts[z].name) / 2, midY, opts[z].data); } else if (opts[z].type == OPTION_MENUTYPE) { opts[z].displayFunc (env, midX, midY, opts[z].data); } env->make_update (midX - 200, midY - text_height (font), 450, 50); env->do_updates(); } else if (opts[z].type != OPTION_MENUTYPE && opts[z].type != OPTION_ACTIONTYPE) { if (opts[z].type == OPTION_DOUBLETYPE) { sprintf (format_buff, opts[z].format, *opts[z].value); textEntryBox (global, env, FALSE, midX + 50, midY, format_buff, 11); } else if (opts[z].type == OPTION_TEXTTYPE) { textEntryBox (global, env, FALSE, midX + 100, midY, (char*)opts[z].value, NAME_LENGTH); } else if (opts[z].type == OPTION_COLORTYPE) { colorBar (env, midX, midY, 100, 15); rectfill (env->db, midX + 110, midY, midX + 130, midY + 10, *(int*)opts[z].value); rect (env->db, midX + 110, midY, midX + 130, midY + 10, BLACK); } else if (opts[z].type == OPTION_TOGGLETYPE) { sprintf (format_buff, "%s", opts[z].name); textout_centre_ex (env->db, font, format_buff, midX, midY, opts[z].color, -1); } else if (opts[z].specialOpts) { textEntryBox (global, env, FALSE, midX + 50, midY, opts[z].specialOpts[(int) *opts[z].value], 11); } env->make_update (midX - 100, midY - 2, 250, 20); } } } if (fi) { fi = 0; quickChange (global, env->db); } if ( (but_quit && but_quit->isPressed()) || (my_key == KEY_ESC) ) { global->command = GLOBAL_COMMAND_MENU; stop = 1; } if ( (but_okay && but_okay->isPressed()) || (my_key == KEY_ENTER) ) { stop = 2; } if ( (reset_button) && (reset_button->isPressed() ) ) { // RESET all options! env->Reset_Options(); global->Reset_Options(); } if (but_okay) but_okay->draw (env->db); if (but_quit) but_quit->draw (env->db); if (reset_button) reset_button->draw(env->db); if (! global->os_mouse) show_mouse(env->db); if (global->close_button_pressed) stop = 1; env->do_updates (); } // while ((!keypressed ()) && (!stop) ); while (! stop); if (!stop) ke = readkey (); else if (stop == 2) ke = KEY_ENTER << 8; else ke = KEY_ESC << 8; flush_inputs(); if (but_quit) delete but_quit; if (but_okay) delete but_okay; if ( reset_button ) delete reset_button; free(updateoption); return (ke); } int editPlayers (GLOBALDATA *global, ENVIRONMENT *env) { int optionsRetVal; // int rows = (global->screenHeight - 400) / 15; int rows = (global->screenHeight - 2 * global->menuBeginY - 200) / 15; int columns = (global->numPermanentPlayers / rows) + 1; rows = (rows / columns) + 1; MENUENTRY *playersOpts; MENUDESC playersMenu; // playersOpts = new MENUENTRY[1 + global->numPermanentPlayers]; playersOpts = (MENUENTRY *) calloc( global->numPermanentPlayers + 1, sizeof(MENUENTRY)); if (!playersOpts) { perror ( "atanks.cc: Failed allocating memory for playersOpts in editPlayers"); return 0; // exit (1); } playersOpts[0].name = "Create New"; playersOpts[0].displayFunc = NULL; playersOpts[0].color = WHITE; playersOpts[0].value = (double*)createNewPlayer; playersOpts[0].data = NULL; playersOpts[0].type = OPTION_ACTIONTYPE; playersOpts[0].viewonly = FALSE; playersOpts[0].x = global->halfWidth - 3; // playersOpts[0].y = global->halfHeight - 68 - 15; playersOpts[0].y = global->menuBeginY + 117; playersMenu.title = "Players"; playersMenu.numEntries = 1 + global->numPermanentPlayers; playersMenu.entries = playersOpts; playersMenu.quitButton = TRUE; playersMenu.okayButton = FALSE; for (int count = 0; count < global->numPermanentPlayers; count++) { MENUENTRY *opt = &playersOpts[1 + count]; opt->name = global->allPlayers[count]->getName (); opt->displayFunc = displayPlayerName; opt->data = global->allPlayers[count]; opt->color = global->allPlayers[count]->color; opt->value = (double*)global->allPlayers[count]->menudesc; opt->type = OPTION_MENUTYPE; opt->viewonly = FALSE; opt->x = global->halfWidth - (((count % columns) - (columns / 2)) * 90) - (((columns + 1) % 2) * 45); // opt->y = global->halfHeight - 68 + ((count / columns) * 15); opt->y = global->menuBeginY + 132 + ((count / columns) * 15); } optionsRetVal = options (global, env, &playersMenu); // delete playersOpts; free(playersOpts); return (optionsRetVal); } int selectPlayers (GLOBALDATA *global, ENVIRONMENT *env) { MENUENTRY roundOpt = { global->ingame->complete_text[1], NULL, WHITE, (double*)&global->rounds, NULL, "%2.0f", 1, MAX_ROUNDS, 1, 5, NULL, OPTION_DOUBLETYPE, FALSE, global->halfWidth - 3, global->menuBeginY + 82 }; MENUENTRY gamename = { global->ingame->complete_text[2], NULL, WHITE, (double *) global->game_name, NULL, "%s", 0, 0, 0, 0, NULL, OPTION_TEXTTYPE, FALSE, global->halfWidth - 3, global->menuBeginY + 100 }; MENUENTRY loadgame, campaign; int save_game_exists; int optionsRetVal, z; // int rows = (global->screenHeight - 400) / 15; int rows = (global->screenHeight - 2 * global->menuBeginY - 200) / 15; int columns = (global->numPermanentPlayers / rows) + 1; int playerCount = 0; int number_saved_games = 0; struct dirent **saved_game_names; char **game_list = NULL; MENUENTRY *playersOpts; MENUDESC playersMenu; MENUENTRY load_game_entry; // find saved games saved_game_names = Find_Saved_Games(global, &number_saved_games); if ( (saved_game_names) && ( number_saved_games ) ) { int count; // move the names into a char list game_list = (char **) calloc( number_saved_games, sizeof(char *) ); for (count = 0; count < number_saved_games; count++) { game_list[count] = saved_game_names[count]->d_name; // clear trailign extension if ( strchr(game_list[count], '.') ) strchr(game_list[count], '.')[0] = '\0'; } global->saved_game_list = game_list; // set up menu for selecting saved games load_game_entry.name = global->ingame->complete_text[3]; load_game_entry.displayFunc = NULL; load_game_entry.color = WHITE; load_game_entry.value = (double *) &global->saved_game_index; load_game_entry.data = NULL; load_game_entry.format = "%s"; load_game_entry.min = 0; load_game_entry.max = number_saved_games - 1; load_game_entry.increment = 1; load_game_entry.defaultv = 0; load_game_entry.specialOpts = global->saved_game_list; load_game_entry.type = OPTION_SPECIALTYPE; load_game_entry.viewonly = FALSE; load_game_entry.x = global->halfWidth; load_game_entry.y = global->menuBeginY + 120; } rows = (rows / columns) + 1; // playersOpts = new MENUENTRY[global->numPermanentPlayers + 4]; playersOpts = (MENUENTRY *) calloc( global->numPermanentPlayers + 5, sizeof(MENUENTRY) ); if (!playersOpts) { perror ( "atanks.cc: Failed allocating memory for playersOpts in selectPlayers"); // exit (1); } loadgame.name = global->ingame->complete_text[4]; loadgame.displayFunc = NULL; loadgame.data = &global->load_game; loadgame.color = WHITE; loadgame.value = (double *) &global->load_game; loadgame.type = OPTION_TOGGLETYPE; loadgame.viewonly = FALSE; loadgame.x = global->halfWidth - 50; loadgame.y = global->menuBeginY + 140; campaign.name = global->ingame->complete_text[5]; campaign.displayFunc = NULL; campaign.data = &global->campaign_mode; campaign.color = WHITE; campaign.value = (double *) &global->campaign_mode; campaign.type = OPTION_TOGGLETYPE; campaign.viewonly = FALSE; campaign.x = global->halfWidth + 50; campaign.y = global->menuBeginY + 140; playersMenu.title = global->ingame->complete_text[0]; playersMenu.numEntries = global->numPermanentPlayers + 5; playersMenu.entries = playersOpts; playersMenu.quitButton = TRUE; playersMenu.okayButton = TRUE; for (int count = 0; count < global->numPermanentPlayers; count++) { MENUENTRY *opt = &playersOpts[count]; opt->name = global->allPlayers[count]->getName (); opt->displayFunc = displayPlayerName; opt->data = global->allPlayers[count]; opt->color = global->allPlayers[count]->color; opt->value = (double*)&global->allPlayers[count]->selected; opt->type = OPTION_TOGGLETYPE; opt->viewonly = FALSE; opt->x = global->halfWidth - (((count % columns) - (columns / 2)) * 90) - (((columns + 1) % 2) * 45); // opt->y = 265 + ( (count / columns) * 15 ); opt->y = global->menuBeginY + 165 + ( (count / columns) * 15); } memcpy (&playersOpts[global->numPermanentPlayers], &roundOpt, sizeof (MENUENTRY)); memcpy (&playersOpts[global->numPermanentPlayers + 1], &gamename, sizeof (MENUENTRY)); memcpy (&playersOpts[global->numPermanentPlayers + 2], &loadgame, sizeof (MENUENTRY)); memcpy (&playersOpts[global->numPermanentPlayers + 3], &campaign, sizeof (MENUENTRY)); if ((number_saved_games) && (game_list) ) memcpy (&playersOpts[global->numPermanentPlayers + 4], &load_game_entry, sizeof(MENUENTRY)); do { optionsRetVal = options (global, env, &playersMenu); if ( global->load_game ) { if ( ( global->saved_game_list) && ( global->saved_game_list[ (int) global->saved_game_index ][0] ) ) { memset(global->game_name, '\0', GAME_NAME_LENGTH); strncpy(global->game_name, global->saved_game_list[ (int) global->saved_game_index ], 16); } } if (optionsRetVal >> 8 == KEY_ENTER) { if (! global->load_game ) // trying to play a game { playerCount = 0; global->numPlayers = 0; for (z = 0; z < global->numPermanentPlayers; z++) { if (global->allPlayers[z]->selected) { global->addPlayer (global->allPlayers[z]); playerCount++; } } if ((playerCount < 2) || (playerCount > MAXPLAYERS)) { if (playerCount < 2) errorMessage = global->ingame->complete_text[8]; else if (playerCount > MAXPLAYERS) errorMessage = global->ingame->complete_text[9]; errorX = global->halfWidth - text_length (font, errorMessage) / 2; errorY = global->menuBeginY + 70; optionsRetVal = 0; } else { optionsRetVal = PLAY_GAME; } } // end of trying to start a new game else // start to load an existing game { save_game_exists = Check_For_Saved_Game(global); if (save_game_exists) optionsRetVal = LOAD_GAME; else { optionsRetVal = 0; errorMessage = global->ingame->complete_text[39]; errorX = global->halfWidth - text_length(font, errorMessage) / 2; errorY = global->menuBeginY + 70; } } } // zero means an error occured. // keep running the loop until ESC is pressed or a non-zero value appears } // while (optionsRetVal == 0); while ( (optionsRetVal >> 8 != KEY_ESC) && (optionsRetVal != PLAY_GAME) && (optionsRetVal != LOAD_GAME) ); // delete playersOpts; free(playersOpts); if (optionsRetVal >> 8 == KEY_ESC) optionsRetVal = ESC_MENU; if (saved_game_names) free(saved_game_names); return (optionsRetVal); } void title (GLOBALDATA *global) { if (! global->os_mouse) show_mouse(NULL); blit ((BITMAP *) global->title[0], screen, 0, 0, global->halfWidth - 320, global->halfHeight - 240, 640, 480); if (! global->os_mouse) show_mouse (screen); clear_keybuf (); //wait_for_input(); if (! global->os_mouse) show_mouse (NULL); } int menu (GLOBALDATA *global, ENVIRONMENT *env) { int bf = 0, bfdd = 1, ban, anclock, lb, updateplayers, done, updaterounds, z, zz; int move_text; int seconds_idle = 0; int current_index = 0, max_index = 7; int my_key = 0; int bn = 0; // button number int shift_menu = global->halfHeight - 240; if (shift_menu < 0) shift_menu = -shift_menu; else shift_menu = 0; move_text = 75; if (global->language == LANGUAGE_RUSSIAN) bn += MENUBUTTONS * 2; BUTTON but_play(global, env, global->halfWidth - move_text, global->halfHeight - 235 + shift_menu, NULL, (BITMAP*)global->button[bn], (BITMAP*)global->button[bn], (BITMAP*)global->button[bn+1]); bn += 2; BUTTON but_help(global, env, global->halfWidth - move_text, global->halfHeight - 185 + shift_menu, NULL, (BITMAP*)global->button[bn], (BITMAP*)global->button[bn], (BITMAP*)global->button[bn+1]); bn += 2; BUTTON but_options(global, env, global->halfWidth - move_text, global->halfHeight - 135 + shift_menu, NULL, (BITMAP*)global->button[bn], (BITMAP*)global->button[bn], (BITMAP*)global->button[bn+1]); bn += 2; BUTTON but_players(global, env, global->halfWidth - move_text, global->halfHeight - 85 + shift_menu, NULL, (BITMAP*)global->button[bn], (BITMAP*)global->button[bn], (BITMAP*)global->button[bn+1]); bn += 2; BUTTON but_credits(global, env, global->halfWidth - move_text, global->halfHeight - 35 + shift_menu, NULL, (BITMAP*)global->button[bn], (BITMAP*)global->button[bn], (BITMAP*)global->button[bn+1]); bn += 2; BUTTON but_quit(global, env, global->halfWidth - move_text, global->halfHeight + 65 + shift_menu, NULL, (BITMAP*)global->button[bn], (BITMAP*)global->button[bn], (BITMAP*)global->button[bn+1]); bn += 2; BUTTON but_network(global, env, global->halfWidth - move_text, global->halfHeight + 15 + shift_menu, NULL, (BITMAP*)global->button[bn], (BITMAP*)global->button[bn], (BITMAP*)global->button[bn+1]); BUTTON *button[MENUBUTTONS] = {&but_play, &but_help, &but_options, &but_players, &but_credits, &but_network, &but_quit }; ban = -1; cclock = global->updateCount = lx = ly = anclock = env->mouseclock = 0; lb = updateplayers = done = updaterounds = 0; fi = global->stopwindow = 1; while (!done) { if ( global->Check_Time_Changed() ) { seconds_idle++; if (seconds_idle > DEMO_WAIT_TIME) { done = 1; global->command = GLOBAL_COMMAND_DEMO; } } // LINUX_SLEEP; LINUX_REST; while (cclock > 0) { cclock--; zz = 0; for (z = 0; z < MENUBUTTONS; z++) { if (button[z]->isMouseOver ()) { if (ban > -1 && ban != z) { button[z]->draw (env->db); //env->make_update (button[ban]->location.x, button[ban]->location.y, button[ban]->location.w, button[ban]->location.h); } ban = z; zz = 1; break; } } if (!zz) { bf = 0; bfdd = 1; } if (!lb && mouse_b & 1) env->mouseclock = 0; lb = (mouse_b & 1) ? 1 : 0; if (mouse_b & 1) { for (z = 0; z < MENUBUTTONS; z++) { if (button[z]->isPressed ()) { if (z == 0) global->command = GLOBAL_COMMAND_PLAY; else if (z == 1) global->command = GLOBAL_COMMAND_HELP; else if (z == 2) global->command = GLOBAL_COMMAND_OPTIONS; else if (z == 3) global->command = GLOBAL_COMMAND_PLAYERS; else if (z == 4) global->command = GLOBAL_COMMAND_CREDITS; else if (z == 5) global->command = GLOBAL_COMMAND_NETWORK; else if (z == 6) global->command = GLOBAL_COMMAND_QUIT; done = 1; } } } env->mouseclock++; if (env->mouseclock > 10) env->mouseclock = 0; } if (updaterounds) { updaterounds = 0; env->make_update (global->halfWidth + 27, global->halfHeight + 198, 32, 32); } if (! global->os_mouse) show_mouse (NULL); if (fi) { draw_circlesBG (global, env->db, 0, 0, global->screenWidth, global->screenHeight, true); //textout (env->db, font, (char *)"Rounds: ", global->halfWidth - 45, global->halfHeight + 200, BLACK); //draw_sprite_v_flip (env->db, (BITMAP *) global->gfxData.M[6].dat, global->halfWidth - 60, global->halfHeight + 199); //draw_sprite (env->db, (BITMAP *) global->gfxData.M[6].dat, global->halfWidth + 64, global->halfHeight + 199); for (z = 0; z < MENUBUTTONS; z++) { button[z]->draw (env->db); if (z == current_index) { // int delta_width = (global->language == LANGUAGE_RUSSIAN) ? 20 : 0; // if (global->language == LANGUAGE_GERMAN) delta_width = 20; // draw rectangle around selected option rect(env->db, global->halfWidth - move_text - 8, global->halfHeight - 240 + (50 * current_index) + shift_menu, global->halfWidth + move_text + 8, // - delta_width, global->halfHeight - 190 + (50 * current_index) + shift_menu, YELLOW); } } } if (ban > -1) { button[ban]->draw (env->db); //env->make_update (button[ban]->location.x, button[ban]->location.y, button[ban]->location.w, button[ban]->location.h); } //rectfill (env->db, global->halfWidth + 27, global->halfHeight + 198, global->halfWidth + 59, global->halfHeight + 210, WHITE); //rect (env->db, global->halfWidth + 27, global->halfHeight + 198, global->halfWidth + 59, global->halfHeight + 210, BLACK); //textprintf_centre (env->db, font, global->halfWidth + 43, global->halfHeight + 200, BLACK, (char *)"%d", global->rounds); if (! global->os_mouse) show_mouse (env->db); env->make_update (mouse_x, mouse_y, ((BITMAP *) (global->misc[0]))->w, ((BITMAP *) (global->misc[0]))->h); env->make_update (lx, ly, ((BITMAP *) (global->misc[0]))->w, ((BITMAP *) (global->misc[0]))->h); lx = mouse_x; ly = mouse_y; // check for key press if ( keypressed() ) { my_key = readkey(); my_key = my_key >> 8; fi = 2; } if ( ( my_key == KEY_DOWN ) || (my_key == KEY_S) ) { current_index++; if (current_index >= max_index) current_index = 0; } else if ( (my_key == KEY_UP) || (my_key == KEY_W) ) { current_index--; if (current_index < 0) current_index = max_index - 1; } else if ( (my_key == KEY_ENTER) || (my_key == KEY_ENTER_PAD) || (my_key == KEY_SPACE) ) { done = 1; if (current_index == 0) global->command = GLOBAL_COMMAND_PLAY; else if (current_index == 1) global->command = GLOBAL_COMMAND_HELP; else if (current_index == 2) global->command = GLOBAL_COMMAND_OPTIONS; else if (current_index == 3) global->command = GLOBAL_COMMAND_PLAYERS; else if (current_index == 4) global->command = GLOBAL_COMMAND_CREDITS; else if (current_index == 5) global->command = GLOBAL_COMMAND_NETWORK; else if (current_index == 6) global->command = GLOBAL_COMMAND_QUIT; } else if ( (my_key == KEY_Q) || (my_key == KEY_ESC)) { return SIG_QUIT_GAME; } my_key = 0; if (fi > 0) { fi--; change (global, env->db); } if (global->close_button_pressed) return SIG_QUIT_GAME; if ( (global->update_string) && (global->update_string[0]) ) { textout_centre_ex (env->db, font, global->update_string, global->halfWidth - 20, 500, WHITE, -1); env->make_update(50, 450, 300, 50); } if (global->client_message) { textout_centre_ex(env->db, font, global->client_message, global->halfWidth - 20, 520, WHITE, -1); env->make_update(50, 450, 300, 100); } env->do_updates (); } clear_keybuf (); return SIG_OK; } void draw_text_in_box (ENVIRONMENT *env, BOX *region, char *text) { char buffer[1024]; unsigned int lineBegin; int lastSpace = 0; int lineCount; int charCount; int buffCount ; rectfill (env->db, region->x, region->y, region->w, region->h, makecol (0,0,128)); rect (env->db, region->x, region->y, region->w, region->h, makecol (128,128,255)); lineBegin = 0; lineCount = 0; while (lineBegin < strlen (text)) { charCount = 0; buffCount = 0; do { buffer[buffCount] = text[lineBegin + charCount]; buffer[buffCount+1] = 0; if (buffer[buffCount] == ' ') { lastSpace = 0; } else if (buffer[buffCount] == '\n') { lineCount++; charCount++; break; } lastSpace++; buffCount++; charCount++; } while (text[lineBegin + charCount] && (text_length (font, buffer) < region->w - 20)); if ((lastSpace > 0) && (text_length (font, buffer) >= region->w - 20)) { charCount -= lastSpace - 1; buffer[buffCount - lastSpace] = 0; } else { buffer[buffCount] = 0; } textout_ex (env->db, font, buffer, region->x + 5, region->y + (lineCount * text_height (font)) + 5, WHITE, -1); lineBegin = lineBegin + charCount; charCount = 0; lineCount++; } env->make_update (region->x, region->y, region->w, region->h); } void draw_buystuff(GLOBALDATA *global, ENVIRONMENT *env, PLAYER *pl) { int z; env->make_update (0, 0, global->screenWidth, global->screenHeight); if (! global->os_mouse) show_mouse (NULL); draw_circlesBG (global, env->db, 0, 0, global->screenWidth, global->screenHeight, false); draw_sprite (env->db, (BITMAP *) global->misc[DONE_IMAGE], global->halfWidth - 100, global->screenHeight - 50); draw_sprite (env->db, (BITMAP *) global->misc[FAST_UP_ARROW_IMAGE], global->screenWidth - STUFF_BAR_WIDTH - 30, global->halfHeight - 50); draw_sprite (env->db, (BITMAP *) global->misc[UP_ARROW_IMAGE], global->screenWidth - STUFF_BAR_WIDTH - 30, global->halfHeight - 25); draw_sprite (env->db, (BITMAP *) global->misc[DOWN_ARROW_IMAGE], global->screenWidth - STUFF_BAR_WIDTH - 30, global->halfHeight); draw_sprite (env->db, (BITMAP *) global->misc[FAST_DOWN_ARROW_IMAGE], global->screenWidth - STUFF_BAR_WIDTH - 30, global->halfHeight + 25); drawing_mode (DRAW_MODE_TRANS, NULL, 0, 0); env->current_drawing_mode = DRAW_MODE_TRANS; for (z = 0; z < global->halfWidth - 200; z++) { set_trans_blender (0, 0, 0, (int)((double)((double)z / (global->halfWidth - 200)) * 240) + 15); vline (env->db, z, 0, 29, pl->color); } for (z = 0; z < global->halfWidth - 200; z++) { set_trans_blender (0, 0, 0, (int)((double)((double)z / (global->halfWidth - 200)) * 240) + 15); vline (env->db, (global->screenWidth-1) - z, 0, 29, pl->color); } solid_mode (); env->current_drawing_mode = DRAW_MODE_SOLID; textout_ex (env->db, font, global->ingame->complete_text[14], 20, 420, WHITE, -1); textout_ex(env->db, font, global->ingame->complete_text[15], 20, 450, WHITE, -1); textout_ex(env->db, font, global->ingame->complete_text[16], 20, 465, WHITE, -1); } int btps; void draw_weapon_list(GLOBALDATA *global, ENVIRONMENT *env, PLAYER *pl, int *trolley, int scroll, int pressed) { int slot, zzz; double tempbtps = (global->screenHeight - 55) / STUFF_BAR_HEIGHT; int font_diff; (font == global->unicode) ? font_diff = 8 : font_diff = 0; // To be sure it rounds down btps = (int)tempbtps; if (tempbtps < btps) btps--; // go through all items and draw them on the screen with // the amount of items in the trolly for (slot = 1, zzz = scroll; (slot < btps) && (zzz < env->numAvailable); zzz++) { int itemNum = env->availableItems[zzz]; draw_sprite (env->db, (BITMAP *)global->gfxData.stuff_bar[(pressed == itemNum)?1:0], global->screenWidth - STUFF_BAR_WIDTH, slot * STUFF_BAR_HEIGHT); draw_sprite(env->db, (BITMAP *) global->gfxData.stuff_icon_base, global->screenWidth - STUFF_BAR_WIDTH, (slot * STUFF_BAR_HEIGHT)); draw_sprite(env->db, (BITMAP *) global->stock[itemNum], global->screenWidth - STUFF_BAR_WIDTH, (slot * STUFF_BAR_HEIGHT) - 5); env->make_update (global->screenWidth - STUFF_BAR_WIDTH, slot * STUFF_BAR_HEIGHT, STUFF_BAR_WIDTH, STUFF_BAR_HEIGHT + 5); if (itemNum >= WEAPONS) /* Items part */ { textout_ex (env->db, font, item[itemNum - WEAPONS].name, global->screenWidth - STUFF_BAR_WIDTH + 45, (slot * STUFF_BAR_HEIGHT) + 5 - font_diff, BLACK, -1); // Amount in inventory textprintf_ex (env->db, font, global->screenWidth - STUFF_BAR_WIDTH + 45, (slot * STUFF_BAR_HEIGHT) + (STUFF_BAR_HEIGHT/2) - font_diff, BLACK, -1, "%s: %d", global->ingame->complete_text[40], pl->ni[itemNum - WEAPONS]); // Anything in the trolley if (trolley[itemNum] != 0) { int textCol; if (trolley[itemNum] > 0) textCol = makecol (255,255,0); else textCol = makecol (176,0,0); textprintf_ex (env->db, font, global->screenWidth - STUFF_BAR_WIDTH + 45 + text_length (font, "Qty. in inventory: ddd"), (slot * STUFF_BAR_HEIGHT) + (STUFF_BAR_HEIGHT/2) - font_diff, textCol, -1, "%+d", trolley[itemNum]); } sprintf (buf, "$%s", Add_Comma( item[itemNum - WEAPONS].cost ) ); textout_ex (env->db, font, buf, global->screenWidth - 45 - text_length (font, buf), (slot * STUFF_BAR_HEIGHT) + 5 - font_diff, BLACK, -1); sprintf (buf, "for %d", item[itemNum - WEAPONS].amt); textout_ex (env->db, font, buf, global->screenWidth - 45 - text_length (font, buf), (slot * STUFF_BAR_HEIGHT) + (STUFF_BAR_HEIGHT/2) - font_diff, BLACK, -1); } else /* Weapons part */ { textout_ex (env->db, font, weapon[itemNum].name, global->screenWidth - STUFF_BAR_WIDTH + 45, (slot * STUFF_BAR_HEIGHT) + 5 - font_diff, BLACK, -1); textprintf_ex (env->db, font, global->screenWidth - STUFF_BAR_WIDTH + 45, (slot * STUFF_BAR_HEIGHT) + (STUFF_BAR_HEIGHT/2) - font_diff, BLACK, -1, "%s: %d", global->ingame->complete_text[40], pl->nm[itemNum]); // Anything in the trolley if (trolley[itemNum] != 0) { int textCol; if (trolley[itemNum] > 0) textCol = makecol (255,255,0); else textCol = makecol (176,0,0); textprintf_ex (env->db, font, global->screenWidth - STUFF_BAR_WIDTH + 45 + text_length (font, "Qty. in inventory: ddd"), (slot * STUFF_BAR_HEIGHT) + (STUFF_BAR_HEIGHT/2) - font_diff, textCol, -1, "%+d", weapon[itemNum].delay ? trolley[itemNum] / weapon[itemNum].delay : trolley[itemNum]); } sprintf (buf, "$%s", Add_Comma( weapon[itemNum].cost )); textout_ex (env->db, font, buf, global->screenWidth - 45 - text_length (font, buf), (slot * STUFF_BAR_HEIGHT) + 5 - font_diff, BLACK, -1); sprintf (buf, "for %d", weapon[itemNum].amt); textout_ex (env->db, font, buf, global->screenWidth - 45 - text_length (font, buf), (slot * STUFF_BAR_HEIGHT) + (STUFF_BAR_HEIGHT/2) - font_diff, BLACK, -1); } slot++; } } bool buystuff (GLOBALDATA *global, ENVIRONMENT *env) { int pl, done, updatew[THINGS], updatename, pressed, scroll, lb, lastMouse_b; int hoverOver = 0, z, zz, zzz; char buf[50]; int mouse_wheel_previous, mouse_wheel_current; int performed_save_game = FALSE; char description[1024]; BOX area = {20, 60, 300, 400}; int my_cclock; int item_index = 1; int my_key = 0; int cost, amt, inInv; int buy_count = 0; strcpy(description, " "); //avoid compiler warning via initalize lastMouse_b = 0; // check starting position of the mouse wheel mouse_wheel_previous = mouse_z; global->updateCount = cclock = lb = env->mouseclock = 0; fi = global->stopwindow = updatename = scroll = 1; // before we do anything else, put a cap on money for (z = 0; z < global->numPlayers; z++) { if (global->players[z]->money > 1000000000) global->players[z]->money = 1000000000; if (global->players[z]->money < 0) global->players[z]->money = 0; } if (global->bIsGameLoaded) // after the first shopping loop the game isn't fresh anymore #ifdef DEBUG { cout << endl << "===========================================" << endl; cout << "== New or Loaded Game! ==" << endl; cout << "===========================================" << endl << endl; #endif // DEBUG global->bIsGameLoaded = false; #ifdef DEBUG } #endif // DEBUG else if (global->divide_money) { // This only applies if this is not a fresh/loaded game // And if players want to divide the money int iJediMoney = 0; int iJediCount = 0; int iSithMoney = 0; int iSithCount = 0; int iTeamFee = 0; for (z = 0; z < global->numPlayers; z++) { /* if (global->players[z]->money > 1000000000) global->players[z]->money = 1000000000; if (global->players[z]->money < 0) global->players[z]->money = 0; */ // Sum up team money: if (global->players[z]->team == TEAM_JEDI) { iTeamFee = (int)((double)global->players[z]->money * 0.25); if (iTeamFee > MAX_TEAM_AMOUNT) iTeamFee = MAX_TEAM_AMOUNT; iJediMoney += iTeamFee; global->players[z]->money -= iTeamFee; iJediCount++; } if (global->players[z]->team == TEAM_SITH) { iTeamFee = (int)((double)global->players[z]->money * 0.25); if (iTeamFee > MAX_TEAM_AMOUNT) iTeamFee = MAX_TEAM_AMOUNT; iSithMoney += iTeamFee; global->players[z]->money -= iTeamFee; iSithCount++; } } #ifdef DEBUG cout << endl << "Jedi Count: " << iJediCount << " - SitH Count: " << iSithCount << endl; #endif // DEBUG // Now apply the team money: if (iJediCount || iSithCount) { #ifdef DEBUG if (iJediCount) printf( (char *)"The Jedi summed up a pool of %13d bucks!\n", iJediMoney); if (iSithCount) printf( (char *)"The Sith summed up a pool of %13d bucks!\n", iSithMoney); #endif // DEBUG if (iJediCount) iJediMoney = (int)(((double)iJediMoney * 0.90) / (double)iJediCount); if (iSithCount) iSithMoney = (int)(((double)iSithMoney * 0.90) / (double)iSithCount); #ifdef DEBUG if (iJediCount) printf( (char *)"Every Jedi will receive %10d credits out of the pool!\n", iJediMoney); if (iSithCount) printf( (char *)"Every Sith will receive %10d credits out of the pool!\n", iSithMoney); #endif // DEBUG for (z = 0; z < global->numPlayers; z++) { if (global->players[z]->team == TEAM_JEDI) global->players[z]->money += iJediMoney; if (global->players[z]->team == TEAM_SITH) global->players[z]->money += iSithMoney; } } } env->generateAvailableItemsList (); int iMaxBoost = 0; int iMaxScore = 0; for (pl = 0; pl < global->numPlayers; pl++) { int iCurrentBoostLevel = global->players[pl]->getBoostValue(); if (iCurrentBoostLevel > iMaxBoost) iMaxBoost = iCurrentBoostLevel; if (global->players[pl]->score > iMaxScore) iMaxScore = global->players[pl]->score; } for (pl = 0; pl < global->numPlayers; pl++) { int money = global->players[pl]->money; int trolley[THINGS]; memset (trolley, 0, sizeof (int) * THINGS); //have computer players buy stuff if ( (int) global->players[pl]->type != HUMAN_PLAYER) { int pressed = 0; int moneyToSave = 0; // How much money will the player save? int numDmgWeaps = 0; // How many damage dealing weapons apart from small missiles do they have= int numPara = 0; // how many parachutes do we have? int numProj = 0; // How many slick/dimpled projectiles do we have? #ifdef DEBUG cout << "(" << global->players[pl]->getName() << ") Starting to buy:" << endl; if (global->players[pl]->defensive < -0.9) cout << "(True Offensive)" << endl; if ((global->players[pl]->defensive >=-0.9) && (global->players[pl]->defensive < -0.75)) cout << "(Very Offensive)" << endl; if ((global->players[pl]->defensive >=-0.75) && (global->players[pl]->defensive < -0.25)) cout << "(Offensive)" << endl; if ((global->players[pl]->defensive >=-0.25) && (global->players[pl]->defensive < 0.00)) cout << "(Slightly Offensive)" << endl; if (global->players[pl]->defensive == 0.0) cout << "(Neutral)" << endl; if ((global->players[pl]->defensive >0.0) && (global->players[pl]->defensive <= 0.25)) cout << "(Slightly Defensive)"<< endl; if ((global->players[pl]->defensive >0.25) && (global->players[pl]->defensive <= 0.75)) cout << "(Defensive)" << endl; if ((global->players[pl]->defensive >0.75) && (global->players[pl]->defensive <= 0.9)) cout << "(Very Defensive)" << endl; if (global->players[pl]->defensive > 0.9) cout << "(True Defensive)" << endl; cout << "Inventory:" << endl << "----------" << endl; for (int i = 1; i < WEAPONS; i++) { if (global->players[pl]->nm[i]) cout << global->players[pl]->nm[i] << " x " << weapon[i].name << endl; } cout << " - - - - - - -" << endl; for (int i = 1; i < ITEMS; i++) { if (global->players[pl]->ni[i]) cout << global->players[pl]->ni[i] << " x " << item[i].name << endl; } cout << "----------" << endl; #endif // DEBUG // moneysaving will be made possible when: // 1. It's not the first three rounds // 2. It's not the last 5 rounds // and, dynamically: // 3. We have at least 10 parachutes or no gravity // 4. We have at least 5 damage dealing (not small missile) weapons // 5. We have a sum of 50 slick/dimpled projectiles if ( (global->currentround > 5) && ( ( (int) global->rounds - global->currentround) > 3)) { moneyToSave = global->players[pl]->getMoneyToSave(); #ifdef DEBUG cout << "Maximum Money to save: " << moneyToSave << " (I have: " << global->players[pl]->money << ")" << endl; #endif //DEBUG } #ifdef DEBUG else cout << "No money to save this round!!!" << endl; #endif // DEBUG // Check for a minimum of damage dealing weapons and parachutes, then buy until moneyToSave is reached buy_count = 0; do { numPara = global->players[pl]->ni[ITEM_PARACHUTE]; numProj = global->players[pl]->ni[ITEM_SLICKP] + global->players[pl]->ni[ITEM_DIMPLEP]; numDmgWeaps = 0; for (int i = 1; i < WEAPONS; i++) { // start from 1, as 0 is the small missile if (weapon[i].damage > 0) numDmgWeaps += global->players[pl]->nm[i]; } if ( (global->players[pl]->money > moneyToSave) || ( (numPara < 10) && (env->landSlideType > LANDSLIDE_NONE)) || (numDmgWeaps < 8) || (numProj < 50)) { pressed = global->players[pl]->chooseItemToBuy (iMaxBoost); } else pressed = -1; #ifdef DEBUG if (pressed > -1) { cout << "I have bought: "; if (pressed < WEAPONS) cout << weapon[pressed].name; else cout << item[pressed - WEAPONS].name; cout << " (" << global->players[pl]->money << " bucks left)" << endl; } else cout << "Finished, with " << global->players[pl]->money << " Credits left!" << endl; #endif // DEBUG buy_count++; } while ( (pressed != -1) && (buy_count < 100) ); #ifdef DEBUG cout << "============================================" << endl << endl; #endif //DEBUG continue; //go to next player } // end of AI player done = 0; updatename = scroll = 1; pressed = -1; draw_buystuff (global, env, global->players[pl]); for (z = 0; z < THINGS; z++) updatew[z] = 1; while (!done) { LINUX_SLEEP; my_cclock = CLOCK_MAX; while (my_cclock > 0) { LINUX_SLEEP; if (global->close_button_pressed) { clear_keybuf(); return false; } my_cclock--; if (!lb && mouse_b & 1 && mouse_x >= global->halfWidth - 100 && mouse_x < global->halfWidth + 100 && mouse_y >= global->screenHeight - 50 && mouse_y < global->screenHeight - 25) done = 1; if (!lb && mouse_b & 1) env->mouseclock = 0; lb = (mouse_b & 1) ? 1 : 0; my_key = 0; //Keyboard control if ( keypressed() ) { my_key = readkey(); my_key = my_key >> 8; } if ( my_key == KEY_UP || my_key == KEY_W) // && (scroll > 1) // && (!env->mouseclock)) { if (item_index > 1) item_index--; if (scroll > 1) scroll--; for (z = 0; z < THINGS; z++) updatew[z] = 1; } if (my_key == KEY_PGUP || my_key == KEY_R) // && (scroll > 1) // && (!env->mouseclock)) { item_index -= btps / 2; if (item_index < 1) item_index = 1; scroll -= btps / 2; if (scroll < 1) scroll = 1; for (z = 0; z < THINGS; z++) updatew[z] = 1; } if (my_key == KEY_DOWN || my_key == KEY_S) // && (scroll <= env->numAvailable - btps) // && (!env->mouseclock)) { if (item_index < (env->numAvailable - 1)) item_index++; if (scroll <= env->numAvailable - btps) scroll++; for (z = 0; z < THINGS; z++) updatew[z] = 1; } if ((my_key == KEY_PGDN || my_key == KEY_F) && (scroll <= env->numAvailable - btps + 1) ) // && (!env->mouseclock)) { item_index += btps / 2; if (item_index > env->numAvailable - btps) item_index = env->numAvailable - btps; scroll += btps / 2; if (scroll > env->numAvailable - btps + 1) scroll = env->numAvailable - btps + 1; for (z = 0; z < THINGS; z++) updatew[z] = 1; } // make sure the selected item is on the visible screen if (item_index < scroll) item_index = scroll; else if ( item_index > (scroll + btps + 3) ) item_index = scroll + btps + 3; // buy or sell an item if (my_key == KEY_RIGHT || my_key == KEY_D) { pressed = env->availableItems[item_index]; if (pressed >= WEAPONS) { cost = item[pressed - WEAPONS].cost; amt = item[pressed - WEAPONS].amt; inInv = global->players[pl]->ni[pressed - WEAPONS]; } else { cost = weapon[pressed].cost; amt = weapon[pressed].amt; inInv = global->players[pl]->nm[pressed]; } if ((money >= cost) && ( (inInv + trolley[pressed]) < (999 - amt))) { if (trolley[pressed] <= -amt) { if (global->sellpercent > 0.01) { money -= (int)(cost * global->sellpercent); trolley[pressed] += amt; updatename = 1; } } else { money -= cost; trolley[pressed] += amt; updatename = 1; if (inInv + trolley[pressed] > 999) trolley[pressed] = 999; } } pressed = -1; } // end of buying if ( my_key == KEY_LEFT || my_key == KEY_A) { pressed = env->availableItems[item_index]; if (pressed >= WEAPONS) { cost = item[pressed - WEAPONS].cost; amt = item[pressed - WEAPONS].amt; inInv = global->players[pl]->ni[pressed - WEAPONS]; } else { cost = weapon[pressed].cost; amt = weapon[pressed].amt; inInv = global->players[pl]->nm[pressed]; } if (inInv + trolley[pressed] >= amt) { if (trolley[pressed] >= amt) { money += cost; trolley[pressed] -= amt; updatename = 1; } else { if (global->sellpercent > 0.01) { money += (int)(cost * global->sellpercent); trolley[pressed] -= amt; updatename = 1; } } } pressed = -1; } // end of selling // check for adding or removing rounds if ( (my_key == KEY_PLUS_PAD) || (my_key == KEY_EQUALS) ) { if ( (global->rounds < 999) && (! env->mouseclock) ) { global->rounds++; global->currentround++; updatename = 1; } } if ( (my_key == KEY_MINUS_PAD) || (my_key == KEY_MINUS) ) { if ( (global->rounds > 1) && (global->currentround > 1) && (! env->mouseclock) ) { global->rounds--; global->currentround--; updatename = 1; } } // check for saving the game if ( my_key == KEY_F10 ) { int status; if (! performed_save_game) { status = Save_Game(global, env); performed_save_game = TRUE; if (status) snprintf(description, 64, "%s \"%s\".", global->ingame->complete_text[17], global->game_name); else strcpy(description, global->ingame->complete_text[41]); draw_text_in_box (env, &area, description); } } if ( my_key == KEY_ENTER) done = TRUE; // Mouse control // check mouse wheel mouse_wheel_current = mouse_z; if (mouse_wheel_current < mouse_wheel_previous) { scroll++; if (scroll > env->numAvailable - btps + 1) scroll = env->numAvailable - btps + 1; if (scroll > item_index) item_index = scroll; for (z = 0; z < THINGS; z++) updatew[z] = 1; } else if (mouse_wheel_current > mouse_wheel_previous) { scroll--; if (scroll < 1) scroll = 1; if (item_index > scroll + btps) item_index = scroll + btps - 3; for (z = 0; z < THINGS; z++) updatew[z] = 1; } mouse_wheel_previous = mouse_wheel_current; if (mouse_x >= global->screenWidth - STUFF_BAR_WIDTH && mouse_x < global->screenWidth) { int newlyOver; zz = 0; for (z = 1, zzz = scroll; z < btps; z++, zzz++) { if (mouse_y >= z * STUFF_BAR_HEIGHT && mouse_y < (z * STUFF_BAR_HEIGHT) + 30) { zz = 1; break; } } if (zz) newlyOver = env->availableItems[zzz]; else newlyOver = -1; if (hoverOver != newlyOver) { // char description[1024]; // BOX area = {20, 60, 300, 400}; if (newlyOver > -1) { if (newlyOver < WEAPONS) { WEAPON *weap = &weapon[newlyOver]; sprintf (description, "Radius: %d\nYield: %ld\n\n%s", weap->radius, calcTotalPotentialDamage (newlyOver) * weap->spread, weap->description); } else { int itemNum = newlyOver - WEAPONS; ITEM *it = &item[itemNum]; if (itemNum >= ITEM_VENGEANCE && itemNum <= ITEM_FATAL_FURY) { sprintf (description, "Potential Damage: %ld\n\n%s", calcTotalPotentialDamage ((int)it->vals[0]) * (int)it->vals[1], it->description); } else { sprintf (description, "%s", it->description); } } } else { description[0] = 0; } hoverOver = newlyOver; draw_text_in_box (env, &area, description); } } if (mouse_b & 1 && !env->mouseclock) { int scrollArrowPos = global->screenWidth - STUFF_BAR_WIDTH - 30; if (mouse_x >= scrollArrowPos && mouse_x < scrollArrowPos + 24) { if ((mouse_y >= global->halfHeight - 50 && mouse_y < global->halfHeight - 25) && (scroll > 1)) { scroll -= btps / 2; if (scroll < 1) scroll = 1; for (z = 0; z < THINGS; z++) updatew[z] = 1; } if ((mouse_y >= global->halfHeight - 24 && mouse_y < global->halfHeight) && (scroll > 1)) { scroll--; for (z = 0; z < THINGS; z++) updatew[z] = 1; } if ((mouse_y >= global->halfHeight + 1 && mouse_y < global->halfHeight + 25) && (scroll <= env->numAvailable - btps)) { scroll++; for (z = 0; z < THINGS; z++) updatew[z] = 1; } if ((mouse_y >= global->halfHeight + 25 && mouse_y < global->halfHeight + 50) && (scroll <= env->numAvailable - btps + 1)) { scroll += btps / 2; if (scroll > env->numAvailable - btps + 1) scroll = env->numAvailable - btps + 1; for (z = 0; z < THINGS; z++) updatew[z] = 1; } } if (item_index < scroll) item_index = scroll; else if ( item_index > (scroll + btps) ) item_index = scroll + btps - 3; } if (mouse_b & 1 || mouse_b & 2) { int itemButtonClicked = 0; for (int buttonCount = 1, currItem = scroll; buttonCount < btps; buttonCount++, currItem++) { if (mouse_x >= global->screenWidth - STUFF_BAR_WIDTH && mouse_x < global->screenWidth && mouse_y >= buttonCount * STUFF_BAR_HEIGHT && mouse_y < (buttonCount * STUFF_BAR_HEIGHT) + 30) { itemButtonClicked = 1; // Remember which button was pressed if (pressed > -1) updatew[pressed] = 1; pressed = env->availableItems[currItem]; updatew[env->availableItems[currItem]] = 1; } } if (!itemButtonClicked) { if (pressed > -1) updatew[pressed] = 1; pressed = -1; } } if (pressed > -1 && !(mouse_b & 1 || mouse_b & 2)) { // Cost, amount and in-inventory amount // of pressed item // int cost,amt,inInv; bool control_key = false; updatew[pressed] = 1; if ( ( key[KEY_LCONTROL] ) || ( key[KEY_RCONTROL] ) ) control_key = true; if (pressed > WEAPONS - 1) { cost = item[pressed - WEAPONS].cost; amt = item[pressed - WEAPONS].amt; inInv = global->players[pl]->ni[pressed - WEAPONS]; } else { cost = weapon[pressed].cost; amt = weapon[pressed].amt; inInv = global->players[pl]->nm[pressed]; } if (control_key) { cost *= 10; amt *= 10; } if (lastMouse_b & 2) { if (inInv + trolley[pressed] >= amt) { if (trolley[pressed] >= amt) { money += cost; trolley[pressed] -= amt; updatename = 1; } else { if (global->sellpercent > 0.01) { money += (int)(cost * global->sellpercent); trolley[pressed] -= amt; updatename = 1; } } } } else { if ((money >= cost) && ( (inInv + trolley[pressed]) < (999 - amt))) { if (trolley[pressed] <= -amt) { if (global->sellpercent > 0.01) { money -= (int)(cost * global->sellpercent); trolley[pressed] += amt; updatename = 1; } } else { money -= cost; trolley[pressed] += amt; updatename = 1; if (inInv + trolley[pressed] > 999) trolley[pressed] = 999; } } } pressed = -1; } env->mouseclock++; if (env->mouseclock > 5) env->mouseclock = 0; lastMouse_b = mouse_b; } if (! global->os_mouse) show_mouse (NULL); if (fi) { for (int thing = 0; thing < THINGS; thing++) updatew[thing] = 1; } if (updatename) { updatename = 0; // env->make_update (global->halfWidth - 315, 0, 400, 30); env->make_update (global->halfWidth - 315, 0, global->screenWidth - 1, 30); draw_sprite (env->db, (BITMAP *) global->gfxData.stuff_bar[0], global->halfWidth - 200, 0); textprintf_ex (env->db, font, global->halfWidth - 190, 5, BLACK, -1, "%s %d: %s", global->ingame->complete_text[10], pl + 1, global->players[pl]->getName ()); // textprintf_ex (env->db, font, global->halfWidth - 190, 17, BLACK, -1, "Money: $%d", money); textprintf_ex(env->db, font, global->halfWidth - 190, 17, BLACK, -1, "%s: $%s", global->ingame->complete_text[11], Add_Comma(money)); sprintf (buf, "%s: %d/%d", global->ingame->complete_text[12], (int)(global->rounds - global->currentround) + 1, (int)global->rounds); textout_ex (env->db, font, buf, global->halfWidth + 170 - text_length (font, buf), 5, BLACK, -1); sprintf (buf, "%s: %d", global->ingame->complete_text[13], global->players[pl]->score); textout_ex (env->db, font, buf, global->halfWidth + 155 - text_length (font, buf), 17, BLACK, -1); } draw_weapon_list(global, env, global->players[pl], trolley, scroll, (pressed < 0) ? env->availableItems[item_index] : pressed ); env->make_update (mouse_x, mouse_y, ((BITMAP *) (global->misc[0]))->w, ((BITMAP *) (global->misc[0]))->h); env->make_update (lx, ly, ((BITMAP *) (global->misc[0]))->w, ((BITMAP *) (global->misc[0]))->h); lx = mouse_x; ly = mouse_y; if (! global->os_mouse) show_mouse (env->db); if (fi) { change (global, env->db); fi = 0; } else env->do_updates (); } for (int tItem = 0; tItem < WEAPONS; tItem++) global->players[pl]->nm[tItem] += trolley[tItem]; for (int tItem = WEAPONS; tItem < THINGS; tItem++) global->players[pl]->ni[tItem - WEAPONS] += trolley[tItem]; global->players[pl]->money = money; } // clear_keybuf (); for (z = 0; z < global->numPlayers; z++) { int iMoney = global->players[z]->money; int iInterest = 0; float fIntPerc= 0.0; int iLevel = 0; int iInterSum = 0; // The summed up interest #ifdef DEBUG cout << endl << "======================================================" << endl; printf( (char *)"%2d.: %s enters the bank to get interest:\n", (z+1), global->players[z]->getName()); printf( (char *)" Starting Account: %10d\n", global->players[z]->money); cout << "------------------------------------------------------" << endl; #endif // DEBUG while (iMoney && (iLevel < 5)) { // Enter next level iLevel++; fIntPerc = (global->interest - 1.0) / iLevel; iInterest = (int)((float)iMoney * fIntPerc); // The limit is only applicable on the first four levels, in the fifth level interest is fully applied! if ((iInterest > MAX_INTEREST_AMOUNT) && (iLevel < 5)) iInterest = MAX_INTEREST_AMOUNT; // Now sum the interest up and substract the counted money! iInterSum += iInterest; iMoney -= (int)((float)iInterest / fIntPerc); #ifdef DEBUG printf( (char *)" Level %1d: %8d credits are rated,\n", iLevel, (int)(iInterest / fIntPerc)); printf( (char *)" Interest: %8d credits. (%5.2f%%)\n", iInterest, (fIntPerc * 100)); #endif // DEBUG // To get rid of (possible) rounding errors, add a security check: if ((iMoney < (4 * iLevel)) || (iInterest < 1)) iMoney = 0; // With less there won't be any more interest anyway! #ifdef DEBUG printf( (char *)" Unrated : %8d credits left.\n", iMoney); #endif // DEBUG } // Now giv'em their money: #ifdef DEBUG printf( (char *)" Sum: %8d credits.\n", iInterSum); cout << "------------------------------------------------------" << endl; #endif // DEBUG global->players[z]->money += iInterSum; #ifdef DEBUG printf( (char *)" Final Account : %10d\n", global->players[z]->money); cout << "======================================================" << endl; #endif // DEBUG } return true; } #ifdef GETV_IS_EVER_USED double getv (int color) { float h, s, v; int r, g, b; r = getr (color); g = getg (color); b = getb (color); rgb_to_hsv (r, g, b, &h, &s, &v); return (v); } #endif //GETV_IS_EVER_USED void set_level_settings (GLOBALDATA *global, ENVIRONMENT *env) { int taken[MAXPLAYERS]; BITMAP *sky_gradient_strip, *land_gradient_strip; int chosen = 0, chosenCount = 0, peak_height = 0; int z, zz; int objCount; TANK *ltank; int xoffset; // srand (time (NULL)); if (! global->os_mouse) show_mouse (NULL); draw_sprite (screen, (BITMAP *) global->misc[1], global->halfWidth - 120, global->halfHeight + 115); textout_centre_ex (screen, font, global->ingame->complete_text[42], global->halfWidth, global->halfHeight + 120, WHITE, -1); // Choose appropriate gradients for sky and land while ((chosenCount < 60) && !chosen) { global->curland = rand () % LANDS; if (global->colour_theme == COLOUR_THEME_CRISPY) global->curland += LANDS; if (!global->gfxData.land_gradient_strips[global->curland]) global->gfxData.land_gradient_strips[global->curland] = create_gradient_strip (land_gradients[global->curland], (global->screenHeight - MENUHEIGHT)); land_gradient_strip = global->gfxData.land_gradient_strips[global->curland]; global->cursky = rand () % SKIES; if (global->colour_theme == COLOUR_THEME_CRISPY) global->cursky += SKIES; if (!global->gfxData.sky_gradient_strips[global->cursky]) global->gfxData.sky_gradient_strips[global->cursky] = create_gradient_strip (sky_gradients[global->cursky], (global->screenHeight - MENUHEIGHT)); sky_gradient_strip = global->gfxData.sky_gradient_strips[global->cursky]; chosen = 1; for (z = 0; z < global->screenWidth; z++) if (peak_height < env->height[z]) peak_height = (int)env->height[z]; for (z = 0; z <= peak_height; z++) { int skyi, landi; double distance; skyi = getpixel (sky_gradient_strip, 0, (global->screenHeight - MENUHEIGHT - z)); landi = getpixel (land_gradient_strip, 0, z); distance = colorDistance (skyi, landi); if (distance < 30) chosen = 0; } chosenCount++; } if (! global->os_mouse) show_mouse (NULL); draw_sprite (screen, (BITMAP *) global->misc[1], global->halfWidth - 120, global->halfHeight + 155); textout_centre_ex (screen, font, global->ingame->complete_text[43], global->halfWidth, global->halfHeight + 160, WHITE, -1); // It looks like we do not use this anymore xoffset = rand (); //generate_sky (global, env, xoffset, 0, global->screenWidth, global->screenHeight); if (env->sky) { destroy_bitmap(env->sky); env->sky = NULL; } // see if we want a custom background if ( (env->custom_background) && (env->bitmap_filenames) ) { // if ( env->sky) destroy_bitmap(env->sky); env->sky = load_bitmap( env->bitmap_filenames[ rand() % env->number_of_bitmaps ], NULL); } // if we do not have a custom background (or do not want one) create a new background if ( (! env->custom_background) || (! env->sky) ) { // if ( env->sky ) destroy_bitmap(env->sky); #ifdef THREADS // On Linux we will have a thread creating a sky for us in the background // to avoid wait times. If there is not a pre-created sky waiting for us // then fall back to generating one the regular way. if (env->waiting_sky) { env->sky = env->waiting_sky; env->waiting_sky = NULL; } else { #endif env->sky = create_bitmap( global->screenWidth, global->screenHeight - MENUHEIGHT); generate_sky (global, env->sky, sky_gradients[global->cursky], (global->ditherGradients ? GENSKY_DITHERGRAD : 0 ) | (global->detailedSky ? GENSKY_DETAILED : 0 ) ); #ifdef THREADS } #endif } if (! global->os_mouse) show_mouse (NULL); draw_sprite (screen, (BITMAP *) global->misc[1], global->halfWidth - 120, global->halfHeight + 195); textout_centre_ex (screen, font, global->ingame->complete_text[44], global->halfWidth, global->halfHeight + 200, WHITE, -1); #ifdef THREADS // we have threads, so check for pre-main terrain if (env->waiting_terrain) { // we have one waiting, so destroy the current one if (env->terrain) destroy_bitmap(env->terrain); env->terrain = env->waiting_terrain; env->waiting_terrain = NULL; // set this so a new one will be made } else // one is not waiting, so we need to create one now { #endif clear_to_color (env->terrain, PINK); xoffset = rand (); generate_land (global, env, env->terrain, xoffset, 0, global->screenHeight); #ifdef THREADS } // end of else #endif for (z = 0; z < global->numTanks; z++) { taken[z] = 0; } for (objCount = 0; (ltank = (TANK*)env->getNextOfClass (TANK_CLASS, &objCount)) && ltank; objCount++) { for (zz = rand () % global->numTanks; taken[zz]; zz = rand () % global->numTanks) { } taken[zz] = objCount + 1; ltank->x = (zz + 1) * (global->screenWidth / (global->numTanks + 1)); ltank->y = (global->screenHeight - (int)env->height[(int) ltank->x]) - (TANKHEIGHT - TANKSAG); ltank->newRound (); } for (z = 0; z < MAXPLAYERS; z++) env->order[z] = NULL; global->maxNumTanks = global->numTanks; for (objCount = 0; (ltank = (TANK*)env->getNextOfClass (TANK_CLASS, &objCount)) && ltank; objCount++) { for (z = rand () % global->numTanks; env->order[z]; z = rand () % global->numTanks) { } env->order[z] = ltank; } // if (global->turntype != TURN_RANDOM) { if ( (global->turntype != TURN_RANDOM) && (global->turntype != TURN_SIMUL)) { for (int index = 0; index < global->maxNumTanks - 1; index++) { int swap = FALSE; if (global->turntype == TURN_HIGH) { if (env->order[index]->player->score < env->order[index + 1]->player->score) { swap = TRUE; } } else if (global->turntype == TURN_LOW) { if (env->order[index]->player->score > env->order[index + 1]->player->score) { swap = TRUE; } } if (swap) { TANK *tempTank = env->order[index]; env->order[index] = env->order[index + 1]; env->order[index + 1] = tempTank; index = -1; } } } } char *do_winner (GLOBALDATA *global, ENVIRONMENT *env) { int maxscore = -1; int winindex = -1; int i, index, *order; bool multiwinner = false; int fonthgt = text_height(font)+10; int jedi_index = -1, sith_index = -1, neutral_index = -1; // char *my_quote; char *return_string = NULL; return_string = (char *) calloc(256, sizeof(char)); if (! return_string) return NULL; //find the maxscore and print out winner for (i=0;i<global->numPlayers;i++) { if (global->players[i]->score == maxscore) { multiwinner=true; if (global->players[i]->team == TEAM_NEUTRAL) neutral_index = i; } else if (global->players[i]->score > maxscore) { maxscore = global->players[i]->score; winindex=i; multiwinner=false; if (global->players[i]->team == TEAM_NEUTRAL) neutral_index = i; } if (global->players[i]->team == TEAM_JEDI) jedi_index = i; else if (global->players[i]->team == TEAM_SITH) sith_index = i; } //stop mouse during drawing if (! global->os_mouse) show_mouse (NULL); //draw background and winner bitmap draw_circlesBG (global, env->db, 0, 0, global->screenWidth, global->screenHeight, false); draw_sprite (env->db, (BITMAP *) global->misc[9], global->halfWidth - 150, global->halfHeight - 150); //draw winner names and info about all players int boxtop = global->halfHeight-40; int boxleft = global->halfWidth-200; int boxright = global->halfWidth+280; int boxbottom = boxtop +4+(fonthgt*2)+(fonthgt*global->numPlayers); rectfill (env->db, boxleft, boxtop, boxright, boxbottom, BLACK); rect (env->db, boxleft, boxtop, boxright, boxbottom, WHITE); if (multiwinner) { // check for team win if ( global->players[winindex]->team == TEAM_JEDI ) { if ( (sith_index >= 0) && ( (global->players[sith_index]->score == global->players[winindex]->score)) ) snprintf(return_string, 256, "%s", global->ingame->complete_text[48]); else if ( (neutral_index >= 0) && ( (global->players[neutral_index]->score == global->players[winindex]->score) ) ) snprintf(return_string, 256, "%s", global->ingame->complete_text[48]); else snprintf(return_string, 256, "%s", global->ingame->complete_text[45]); } else if ( global->players[winindex]->team == TEAM_SITH ) { if ((jedi_index >= 0) && ((global->players[jedi_index]->score == global->players[winindex]->score))) snprintf(return_string, 256, "%s", global->ingame->complete_text[48]); else if ( (neutral_index >= 0) && ( (global->players[neutral_index]->score == global->players[winindex]->score) ) ) snprintf(return_string, 256, "%s", global->ingame->complete_text[48]); else snprintf(return_string, 256, "%s", global->ingame->complete_text[46]); } else snprintf(return_string, 256, "%s", global->ingame->complete_text[48]); } else snprintf(return_string, 256, "%s: %s", global->ingame->complete_text[47], global->players[winindex]->getName() ); textprintf_centre_ex(env->db, font, global->halfWidth, boxtop + 4, global->players[winindex]->color, -1, "%s", return_string); textout_centre_ex (env->db, font, global->ingame->complete_text[49], global->halfWidth, boxtop+4+fonthgt, WHITE, -1); order = Sort_Scores(global); for (index = 0; index < global->numPlayers; index++) { int i = order[index]; int textypos = (index * 10) + boxtop+4+(fonthgt*2); int money; textprintf_ex (env->db, font, boxleft+10, textypos , global->players[i]->color, -1, "%s:", global->players[i]->getName ()); money = 0; for (int weapNum = 0; weapNum < WEAPONS; weapNum++) { int individValue; if (weapon[weapNum].amt) individValue = weapon[weapNum].cost / weapon[weapNum].amt; else individValue = 0; money += (int)(individValue * global->players[i]->nm[weapNum]); } for (int itemNum = 0; itemNum < ITEMS; itemNum++) { int individValue; if (item[itemNum].amt) individValue = item[itemNum].cost / item[itemNum].amt; else individValue = 0; money += (int)(individValue * global->players[i]->ni[itemNum]); } textprintf_ex (env->db, font, boxleft+190, textypos, WHITE, -1, "%3d $%s %10d :%2d", global->players[i]->score, Add_Comma(money), global->players[i]->kills, global->players[i]->killed); } /* my_quote = global->war_quotes->Get_Random_Line(); if (my_quote) { char *little_string; int start_index = 0, to_index = 0; int total_length = strlen(my_quote); int quote_count = 1; little_string = (char *) calloc( total_length + 1, sizeof(char)); if (little_string) { do { memset(little_string, '\0', total_length + 1); while ((( my_quote[start_index] != ' ' ) || (to_index < 50) ) && (start_index < total_length) ) { little_string[to_index] = my_quote[start_index]; to_index++; start_index++; } textprintf_ex(env->db,font,boxleft, boxbottom + (10 * quote_count), WHITE, -1, "%s", little_string); to_index = 0; quote_count++; while ( (start_index < total_length) && (my_quote[start_index] == ' ') ) start_index++; } while (start_index < total_length); free(little_string); } } //do fade and wait for user keypress change (global, env->db); readkey (); // for (i = 0; i < global->numPlayers; i++) // global->players[i]->type = global->players[i]->type_saved; */ return return_string; } void do_quote(GLOBALDATA *global, ENVIRONMENT *env) { char *my_quote; int fonthgt = text_height(font)+10; int boxleft = global->halfWidth-200; int boxtop = global->halfHeight-40; int boxbottom = boxtop +4+(fonthgt*2)+(fonthgt*global->numPlayers); my_quote = global->war_quotes->Get_Random_Line(); if (my_quote) { char *little_string; int start_index = 0, to_index = 0; int total_length = strlen(my_quote); int quote_count = 1; little_string = (char *) calloc( total_length + 1, sizeof(char)); if (little_string) { do { memset(little_string, '\0', total_length + 1); while ((( my_quote[start_index] != ' ' ) || (to_index < 50) ) && (start_index < total_length) ) { little_string[to_index] = my_quote[start_index]; to_index++; start_index++; } textprintf_ex(env->db,font,boxleft, boxbottom + (10 * quote_count), WHITE, -1, "%s", little_string); to_index = 0; quote_count++; while ( (start_index < total_length) && (my_quote[start_index] == ' ') ) start_index++; } while (start_index < total_length); free(little_string); } } //do fade and wait for user keypress change (global, env->db); readkey (); for (int i = 0; i < global->numPlayers; i++) global->players[i]->type = global->players[i]->type_saved; } //draws indicaation bar void graph_bar (ENVIRONMENT *env, int x, int y, long int col, int actual, int max) { rect (env->db, x, y, x + max + 2, y + 8, BLACK); rectfill (env->db, x + 1, y + 1, x + 1 + actual, y + 7, col); } //draws indication bar - centred void graph_bar_center (ENVIRONMENT *env, int x, int y, long int col, int actual, int max) { rect (env->db, x, y, x + max + 2, y + 8, BLACK); rectfill (env->db, x + 1 + max / 2, y + 1, x + 1 + actual + max / 2, y + 7, col); } //Some global parameters int ord; void loadshields (ENVIRONMENT *env) { TANK *tank; int objCount; for (objCount = 0; (tank = (TANK*)env->getNextOfClass (TANK_CLASS, &objCount)) && tank; objCount++) tank->reactivate_shield (); } void change_wind_strength (ENVIRONMENT *env) { if (env->windvariation == 0.0 || (int)env->windstrength == 0) { return; } else { env->wind = env->lastwind + (double)(rand () % (int)(env->windvariation * 100)) / 100 - (env->windvariation / 2); if (env->wind > (env->windstrength / 2)) { env->wind = env->windstrength / 2; } else if (env->wind < (-env->windstrength / 2)) { env->wind = -env->windstrength / 2; } env->lastwind = env->wind; } // make sure game clients have up to date wind data #ifdef NETWORK char buffer[64]; sprintf(buffer, "WIND %f", env->wind); env->_global->Send_To_Clients(buffer); #endif } TANK *nextturn (GLOBALDATA *global, ENVIRONMENT *env, bool skippingComputerPlay) { TANK *tank = NULL; int ordCurrently = ord; static int do_wind = 0; static int next_wind = 0; int index = 0, lowest_index = 0, lowest_shots = INT_MAX; // check whether there currently *are* active tanks first if (global->numTanks) { // find first tank with lowest number of shots fired while ( index < global->maxNumTanks ) { if ( env->order[index] ) // make sure tank exists { if ( env->order[index]->shots_fired < lowest_shots ) { lowest_shots = env->order[index]->shots_fired; lowest_index = index; } } index++; } // end of looking for low index do { ord++; // coming around to the next turn if (ord >= global->maxNumTanks) { ord = 0; doLaunch(global, env); // launch before we change the wind next_wind = 1; } } while ((!env->order[ord]) && (ord != ordCurrently)); tank = env->order[ord]; global->currTank = tank; if ( tank->shots_fired > lowest_shots ) { tank = env->order[lowest_index]; global->currTank = tank; } // Wind is blowing :-) // change_wind_strength (env); if ( (global->turntype != TURN_SIMUL) || (do_wind) ) { change_wind_strength(env); do_wind = next_wind = 0; } else { do_wind = next_wind; next_wind = 0; } } if (tank) { if (!skippingComputerPlay) { env->make_fullUpdate(); env->do_updates(); } tank->reactivate_shield (); clear_keybuf(); if (global->max_fire_time) { tank->player->time_left_to_fire = global->max_fire_time; tank->player->skip_me = false; } } return tank; } void showRoundEndScoresAt (GLOBALDATA *global, ENVIRONMENT *env, BITMAP *bitmap, int x, int y, int winner) { int z; env->make_update (x - 150, y - 100, 301, 301); rectfill (bitmap, x - 150, y - 100, x + 100, y + 100, BLACK); rect (bitmap, x - 150, y - 100, x + 100, y + 100, WHITE); if (winner == JEDI_WIN) textout_centre_ex (bitmap, font, "Jedi", x - 20, y - 90, WHITE, -1); else if (winner == SITH_WIN) textout_centre_ex (bitmap, font, "Sith", x - 20, y - 90, WHITE, -1); else if (winner == -2) textout_centre_ex (bitmap, font, "Draw", x - 20, y - 90, WHITE, -1); else textprintf_centre_ex (bitmap, font, x - 30, y - 90, global->players[winner]->color, -1, "%s: %s", global->ingame->complete_text[47], global->players[winner]->getName ()); textout_centre_ex (bitmap, font, global->ingame->complete_text[50], x - 30, y - 70, WHITE, -1); for (z = 0; z < global->numPlayers; z++) { textprintf_ex (bitmap, font, x - 140, (z * 10) + y - 50, global->players[z]->color, -1, "%s:", global->players[z]->getName ()); textprintf_ex (bitmap, font, x + 60, (z * 10) + y - 50, WHITE, -1, "%d", global->players[z]->score); } } int setSlideColumnDimensions (GLOBALDATA *global, ENVIRONMENT *env, int x, bool reset) { int pixelHeight; char *done = env->done; int *dropTo = env->dropTo; int *h = env->h; int *fp = env->fp; double *velocity = env->velocity; double *dropIncr = env->dropIncr; if (x < 0 || x > (global->screenWidth-1)) { return (0); } if (reset) { h[x] = 0; fp[x] = 0; dropTo[x] = global->screenHeight - 1; } done[x] = 0; // Calc the top and bottom of the column to slide // Find top-most non-PINK pixel for (pixelHeight = h[x]; pixelHeight < dropTo[x]; pixelHeight++) if (getpixel (env->terrain, x, pixelHeight) != PINK) break; h[x] = pixelHeight; env->surface[x] = pixelHeight; // Find bottom-most PINK pixel for (pixelHeight = dropTo[x]; pixelHeight > h[x]; pixelHeight--) if (getpixel (env->terrain, x, pixelHeight) == PINK) break; dropTo[x] = pixelHeight; // Find bottom-most unsupported pixel for (; pixelHeight >= h[x]; pixelHeight--) if (getpixel (env->terrain, x, pixelHeight) != PINK) break; // If there's some processing to do if ((pixelHeight >= h[x]) && (h[x] < dropTo[x])) { fp[x] = pixelHeight - (int)h[x] + 1; return (0); } else { if (velocity[x]) play_sample ((SAMPLE *) global->sounds[10], (int)((velocity[x] / 10) * 255), (int)((double)(x - global->halfWidth) / global->halfWidth * 128 + 128), 1000 - (int)((double)fp[x] / global->screenHeight) * 1000, 0); h[x] = 0; fp[x] = 0; done[x] = 1; velocity[x] = 0; dropIncr[x] = 0; dropTo[x] = global->screenHeight - 1; return (1); } return (0); } int drawFracture (GLOBALDATA *global, ENVIRONMENT *env, BITMAP *dest, BOX *updateArea, int x, int y, int angle, int width, int segmentLength, int maxRecurse, int recurseDepth) { int branchCount; int x1, x2, x3; int y1, y2, y3; x1 = (int)(x + global->slope[angle][0] * width); y1 = (int)(y + global->slope[angle][1] * width); x2 = (int)(x - global->slope[angle][0] * width); y2 = (int)(y - global->slope[angle][1] * width); x3 = (int)(x + global->slope[angle][1] * segmentLength); y3 = (int)(y + global->slope[angle][0] * segmentLength); triangle (dest, x1, y1, x2, y2, x3, y3, PINK); if (recurseDepth == 0) { updateArea->x = x1; updateArea->y = y1; updateArea->w = x1; updateArea->h = y1; } updateArea->x = MIN (MIN (MIN (x1, x2), x3), updateArea->x); updateArea->y = MIN (MIN (MIN (y1, y2), y3), updateArea->y); updateArea->w = MAX (MAX (MAX (x1, x2), x3), updateArea->w); updateArea->h = MAX (MAX (MAX (y1, y2), y3), updateArea->h); if (recurseDepth < maxRecurse) { for (branchCount = 0; branchCount < 3; branchCount++) { if ((branchCount == 0) || (Noise (x + y + branchCount) < 0)) { int newAngle, reduction; newAngle = (angle + (int)(Noise (x + y + 4) * 30)); while (newAngle < 0) newAngle += 360; newAngle %= 360; reduction = 2; if (branchCount == 1) { newAngle = (int)(angle + 90 + (Noise (x + y + 25 + branchCount) * 22.5)) % 360; reduction = abs ((int)Noise (x + y + 1 + branchCount) * 4 + 3); } else if (branchCount == 2) { newAngle = (int)(angle + 270 + (Noise (x + y + 32 + branchCount) * 22.5)) % 360; reduction = abs ((int)Noise (x + y + 2 + branchCount) * 4 + 3); } drawFracture (global, env, dest, updateArea, x3, y3, newAngle, width / reduction, segmentLength / reduction, maxRecurse, recurseDepth + 1); } } } // Calculate width and height, previously right and bottom if (recurseDepth == 0) { updateArea->w -= updateArea->x; updateArea->h -= updateArea->y; } return (0); } /* void initSurface (GLOBALDATA *global, ENVIRONMENT *env) { int pixelHeight; for (int x = 0; x < global->screenWidth; x++) { for (pixelHeight = 0; pixelHeight < global->screenHeight; pixelHeight++) if (getpixel (env->terrain, x, pixelHeight) != PINK) break; env->surface[x] = pixelHeight; } } */ int slideLand (GLOBALDATA *global, ENVIRONMENT *env) { char *done = env->done; int *dropTo = env->dropTo; int *h = env->h; int *fp = env->fp; double *velocity = env->velocity; double *dropIncr = env->dropIncr; int zz; double land_slide_type = LANDSLIDE_INSTANT; // land-slide, make it fall etc. int allDone = 1; if ( (env->landSlideType == LANDSLIDE_NONE) || (env->landSlideType == LANDSLIDE_TANK_ONLY) ) return (allDone); else if (env->landSlideType == LANDSLIDE_CARTOON) { if (env->time_to_fall > 0) land_slide_type = LANDSLIDE_CARTOON; else land_slide_type = LANDSLIDE_GRAVITY; } else if (env->landSlideType == LANDSLIDE_GRAVITY) land_slide_type = LANDSLIDE_GRAVITY; if (land_slide_type == LANDSLIDE_CARTOON) return (allDone); for (zz = 0; zz < global->screenWidth; zz++) { if (!done[zz]) { allDone = 0; if (land_slide_type == LANDSLIDE_GRAVITY) { if (fp[zz] > 0) { velocity[zz] += env->gravity; dropIncr[zz] += velocity[zz]; if (dropIncr[zz] >= 1) { if (dropIncr[zz] > dropTo[zz] - (h[zz] + fp[zz])) { dropIncr[zz] = dropTo[zz] - (h[zz] + fp[zz]) + 1; } blit (env->terrain, env->terrain, zz, h[zz] - (int)dropIncr[zz], zz, h[zz], 1, fp[zz] + (int)dropIncr[zz]); env->make_bgupdate (zz, h[zz] - (int)dropIncr[zz], 1, fp[zz] + ((int)dropIncr[zz] * 2) + 1); env->make_update (zz, h[zz] - (int)dropIncr[zz], 1, fp[zz] + ((int)dropIncr[zz] * 2) + 1); h[zz] += (int)dropIncr[zz]; dropIncr[zz] -= (int)dropIncr[zz]; } setSlideColumnDimensions (global, env, zz, FALSE); } else { setSlideColumnDimensions (global, env, zz, FALSE); } } else if (land_slide_type == LANDSLIDE_INSTANT) { if (fp[zz] > 0) { env->make_bgupdate (zz, h[zz], 1, dropTo[zz] - h[zz] + 1); env->make_update (zz, h[zz], 1, dropTo[zz] - h[zz] + 1); done[zz] = 1; blit (env->terrain, env->terrain, zz, h[zz], zz, dropTo[zz] - fp[zz] + 1, 1, fp[zz]); vline (env->terrain, zz, h[zz], dropTo[zz] - fp[zz], PINK); } setSlideColumnDimensions (global, env, zz, FALSE); } } } return (allDone); } void drawTopBar (GLOBALDATA *global, ENVIRONMENT *env, BITMAP *dest) { TANK *tank = global->currTank; char *name = ""; int color = 0; int wind_col1 = 0, wind_col2 = 0; static int change_weapon_colour = RED; char *team_name = ""; int time_to_fire = 0; int minus_font = (font == global->unicode) ? 9 : 0; if (tank) { name = global->currTank->player->getName (); color = global->currTank->player->color; team_name = global->currTank->player->Get_Team_Name(); time_to_fire = tank->player->time_left_to_fire; } global->updateMenu = 0; blit (global->gfxData.topbar, dest, 0, 0, 0, 0, global->screenWidth, MENUHEIGHT); if (tank) { textout_ex (dest, font, name, 2, 2 - minus_font, BLACK, -1); textout_ex (dest, font, name, 1, 1 - minus_font, color, -1); textprintf_ex (dest, font, 1, 11 - minus_font, BLACK, -1, "%s", global->ingame->complete_text[18]); graph_bar_center (env, 50, 11, color, -(tank->a - 180) / 2, 180 / 2); // 0 is directly left, 180 points directly right textprintf_ex (dest, font, 150, 11 - minus_font, BLACK, -1, "%d", 180 - (tank->a - 90)); textprintf_ex (dest, font, 1, 21 - minus_font, BLACK, -1, "%s", global->ingame->complete_text[19]); graph_bar (env, 50, 20, color, (tank->p) / (MAX_POWER/90), 90); textprintf_ex (dest, font, 150, 21 - minus_font, BLACK, -1, "%d", tank->p); textprintf_ex (dest, font, 200, 21 - minus_font, BLACK, -1, "%s: %s", global->ingame->complete_text[20], team_name); if (tank->cw < WEAPONS) { int weapon_amount; if (! weapon[tank->cw].delay ) weapon_amount = tank->player->nm[tank->cw]; else weapon_amount = tank->player->nm[tank->cw] / weapon[tank->cw].delay; if (tank->player->changed_weapon) { textprintf_ex (dest, font, 180, 1, change_weapon_colour, -1, "%s: %d", weapon[tank->cw].name, weapon_amount); // tank->player->nm[tank->cw]); if (change_weapon_colour == RED) change_weapon_colour = WHITE; else change_weapon_colour = RED; } else textprintf_ex (dest, font, 180, 1, BLACK, -1,"%s: %d", weapon[tank->cw].name, weapon_amount); } // end of less than WEAPONS else { textprintf_ex (dest, font, 180, 1, BLACK, -1, "%s: %d", item[tank->cw - WEAPONS].name, tank->player->ni[tank->cw - WEAPONS]); } draw_sprite (env->db, (BITMAP *) global->stock[ (tank->cw) ? tank->cw : 1], 700, 1); textprintf_ex (dest, font, 350, 1, BLACK, -1, "$%s", Add_Comma(tank->player->money)); textprintf_ex (dest, font, 350, 12, BLACK, -1, "%s: %d", global->ingame->complete_text[21], tank->player->ni[ITEM_FUEL]); } textprintf_ex ( dest, font, 500, 1 - minus_font, BLACK, -1, "%s %d/%d", global->ingame->complete_text[12], (int)(global->rounds - global->currentround) + 1, (int)global->rounds); if (global->tank_status[0]) textprintf_ex(dest, font, 350, 21, global->tank_status_colour, -1, "%s", global->tank_status); if (env->windstrength > 0) { textprintf_ex (dest, font, 500, 11 - minus_font, BLACK, -1, "%s", global->ingame->complete_text[22]); if (env->wind > 0) { wind_col1 = 1; wind_col2 = 0; } if (env->wind < 0) { wind_col1 = 0; wind_col2 = 1; } rect (dest, 540, 12, (int)(540 + env->windstrength * 4 + 2), 18, BLACK); rectfill (dest, (int)(541 + env->windstrength * 2), 13, (int) (541 + env->wind * 4 + env->windstrength * 2), 17, makecol (200 * wind_col1, 200 * wind_col2, 0)); } if (global->max_fire_time) textprintf_ex( dest, font, 500, 20, BLACK, -1, "Time: %d", time_to_fire); global->stopwindow = 1; env->make_update (0, 0, global->screenWidth, MENUHEIGHT); global->stopwindow = 0; } /* * Calculate the effective damage for a given weapon. * Recursively add the damage of sub-munitions, factor in chaos * and munition density. */ long int calcTotalEffectiveDamage (int weapNum) { WEAPON *weap = &weapon[weapNum]; long int total = 0; if (weap->submunition >= 0) { WEAPON *subm = &weapon[weap->submunition]; // How chaotic is this weapon? double chaosVal=(weap->spreadVariation + weap->speedVariation + subm->countVariation) / 3; double coverage = (weap->numSubmunitions * subm->radius) / (double)weap->radius; total += calcTotalEffectiveDamage (weap->submunition) * weap->numSubmunitions; total = (long int)(total * coverage / weap->numSubmunitions); total -= (long int)((total / 2) * (1.0 - chaosVal)); } else { total += weap->damage; } return (total); } /* * Calculate the potential damage for a given weapon. * Recursively add the damage of sub-munitions. */ long int calcTotalPotentialDamage (int weapNum) { WEAPON *weap = &weapon[weapNum]; long int total = 0; if ( (weap->submunition >= 0) && (weap->numSubmunitions > 0) ) total += calcTotalPotentialDamage (weap->submunition) * weap->numSubmunitions; else total += weap->damage; return (total); } void doNaturals (GLOBALDATA *global, ENVIRONMENT *env) { int chance; if (env->naturals_since_last_shot >= 5) return; if (env->lightning) { chance = (int)(600 / env->lightning) + 100; if (!(rand () % chance)) { BEAM *newbeam; int ca = ((rand () % 160) + (360 - 80)) % 360; newbeam = new BEAM (global, env, rand () % global->screenWidth, 0, ca, SML_LIGHTNING + (rand () % (int)env->lightning)); if (newbeam) { newbeam->player = NULL; env->naturals_since_last_shot++; } else perror ( "atanks.cc: Failed allocating memory for newbeam in doNaturals"); } } // end of lightning // only create meteors if we are not in aim mode on simul turn type if ( (global->turntype == TURN_SIMUL) && (env->stage == STAGE_AIM) ) return; if (env->meteors) { chance = (int)(600 / env->meteors) + 100; if (!(rand () % chance)) { MISSILE *newmis; int ca = ((rand () % 160) + (360 - 80)) % 360; double mxv = global->slope[ca][0] * 5; double myv = global->slope[ca][1] * 5; newmis = new MISSILE(global, env, rand () % global->screenWidth, 0, mxv, myv, SML_METEOR + (rand () % (int)env->meteors)); if (newmis) { newmis->player = NULL; env->naturals_since_last_shot++; } else perror ( "atanks.cc: Failed allocating memory for newmis in doNaturals"); } } if (env->falling_dirt_balls) { chance = (int) (600 / env->falling_dirt_balls) + 100; if (! (rand() % chance) ) { MISSILE *newmis; int ca = ((rand() % 100) + (360 - 80) ) % 360; double mxv = global->slope[ca][0] * 5; double myv = global->slope[ca][1] * 5; newmis = new MISSILE(global, env, rand() % global->screenWidth, 0, mxv, myv, DIRT_BALL + ( rand() % (int) env->falling_dirt_balls) ); if (newmis) { newmis->player = NULL; env->naturals_since_last_shot++; } else perror( "atanks.cc: Failed to allocate memory for falling dirt ball in doNaturals"); } } } #ifdef OLD_GAMELOOP void game (GLOBALDATA *global, ENVIRONMENT *env) { int tanksfall; int tanklife, tlt, dclock; int lb, ca; int allDone, anyExploding, anyTeleporting, anyLaserFiring; int roundEndCount = 0; bool nextTankSelected = false; int humanPlayers = 0; int skippingComputerPlay = FALSE; int team_won = NO_WIN; bool bWinnerIsCredited = false; int my_class; VIRTUAL_OBJECT *my_object; TANK **tank, *ltank; MISSILE *missile; TELEPORT *teleport; DECOR *decor; BEAM *beam; EXPLOSION *explosion; FLOATTEXT *floattext; static SATELLITE *satellite = NULL; int bCount; int z, zz, z4; int objCount, count; int AI_clock = 0; global->computerPlayersOnly = FALSE; tank = &global->currTank; for (int doneCount = 0; doneCount < global->screenWidth; doneCount++) env->done[doneCount] = 0; // initSurface (global, env); // init surface[] env->newRound (); // set wall colour switch (env->current_wallType) { case WALL_RUBBER: env->wallColour = GREEN; break; case WALL_STEEL: env->wallColour = RED; break; case WALL_SPRING: env->wallColour = BLUE; break; case WALL_WRAP: env->wallColour = YELLOW; break; } if (env->dBoxedMode == 2.0) { if (rand() % 2) global->bIsBoxed = true; else global->bIsBoxed = false; } else if (env->dBoxedMode == 1.0) global->bIsBoxed = true; else if (env->dBoxedMode == 0.0) global->bIsBoxed = false; // Set Max velocity global->dMaxVelocity = (double)MAX_POWER * (100.0 / (double)global->frames_per_second) / 100.0; if ((env->current_wallType == WALL_SPRING) && !global->bIsBoxed) // In non-boxed the Spring Wall is allowed to have at least twice the normal velocity global->dMaxVelocity *= 2.0; if (global->bIsBoxed) // In boxed Mode, there is four times the normal max velocity allowed (or it won't be fun!) global->dMaxVelocity *= 4.0; for (count = 0; count < global->numPlayers; count++) global->players[count]->newRound (); /* Unfortunately, ENVIRONMENT can't call uppon FLOATTEXT::newRound due to circular dependencies. Thus we have to do that here: */ for (int objCount = 0; objCount < MAX_OBJECTS; objCount++) { if (env->objects[count] && (env->objects[count]->isSubClass(FLOATTEXT_CLASS))) ((FLOATTEXT *)env->objects[count])->newRound(); } buystuff (global, env); if (global->close_button_pressed) { global->command = GLOBAL_COMMAND_QUIT; return; } for (count = 0; count < global->numPlayers; count++) global->players[count]->exitShop (); set_level_settings (global, env); for (objCount = 0; (ltank = (TANK*)env->getNextOfClass (TANK_CLASS, &objCount)) && ltank; objCount++) { ltank->newRound (); if ((int)ltank->player->type == HUMAN_PLAYER) { humanPlayers++; } } if (!humanPlayers) { global->computerPlayersOnly = TRUE; //if ((int)global->skipComputerPlay >= SKIP_AUTOPLAY) // skippingComputerPlay = TRUE; } cclock = lx = ly = tanksfall = 0; env->stage = STAGE_AIM; tlt = global->updateCount = dclock = global->stopwindow = 0; env->realm = env->am = 0; ca = 0; lb = env->mouseclock = env->pclock = 0; ord = 0; *tank = env->order[0]; for (objCount = 0; (ltank = (TANK*)env->getNextOfClass (TANK_CLASS, &objCount)) && ltank; objCount++) { ltank->flashdamage = 0; ltank->boost_up_shield (); } winner = tanklife = -1; fi = global->updateMenu = 1; global->window.x = 0; global->window.y = 0; global->window.w = (global->screenWidth-1); global->window.h = (global->screenHeight-1); bCount = 0; if ((int)env->windstrength != 0) env->wind = (float)(rand () % (int)env->windstrength) - (env->windstrength / 2); else env->wind = 0; env->lastwind = env->wind; if ( (env->satellite) && (! satellite) ) satellite = new SATELLITE(global, env); if (satellite) satellite->Init(); global->iHumanLessRounds = -1; #ifdef DEBUG_AIM_SHOW global->bASD = false; #endif global->background_music = global->Load_Background_Music(); if (global->background_music) play_sample((SAMPLE *) global->background_music, 255, 128, 1000, TRUE); while (1) { LINUX_SLEEP; if (global->close_button_pressed) { global->command = GLOBAL_COMMAND_QUIT; return; } while (cclock > 0 || skippingComputerPlay) { cclock--; if (!lb && mouse_b & 1) env->mouseclock = 0; lb = (mouse_b & 1) ? 1 : 0; bCount += 360/32; z4 = 0; anyExploding = 0; anyTeleporting = 0; anyLaserFiring = 0; env->am = 0; objCount = 0; my_object = env->objects[objCount]; // keep track of how long we have been skipping AI if (skippingComputerPlay) { // advance clock if ( global->Check_Time_Changed() ) AI_clock++; if (AI_clock > MAX_AI_TIME) { int player_index = 0; // kill all remaining tanks while (player_index < global->numPlayers) { if ( ( global->players[player_index] ) && ( global->players[player_index]->tank ) ) global->players[player_index]->tank->l = 0; player_index++; } } } // end of AI clock code while (objCount < MAX_OBJECTS) { if (my_object) { my_class = my_object->getClass(); //for (objCount = 0; (decor = (DECOR*)env->getNextOfClass (DECOR_CLASS, &objCount)) && decor; objCount++) if (my_class == DECOR_CLASS) { decor = (DECOR *) my_object; decor->applyPhysics (); if (decor->destroy) { decor->requireUpdate (); decor->update (); delete decor; } } // for (objCount = 0; (explosion = (EXPLOSION*)env->getNextOfClass (EXPLOSION_CLASS, &objCount)) && explosion; objCount++) else if (my_class == EXPLOSION_CLASS) { explosion = (EXPLOSION *) my_object; if (explosion->bIsWeaponExplosion) anyExploding++; explosion->explode (); explosion->applyPhysics (); if (explosion->destroy) { explosion->requireUpdate (); explosion->update (); delete explosion; anyExploding--; } } // for (objCount = 0; (teleport = (TELEPORT*)env->getNextOfClass (TELEPORT_CLASS, &objCount)) && teleport; objCount++) else if (my_class == TELEPORT_CLASS) { teleport = (TELEPORT *) my_object; anyTeleporting++; teleport->applyPhysics (); if (teleport->destroy) { teleport->requireUpdate (); teleport->update (); delete teleport; anyTeleporting--; // It's done! tanksfall = 1; } } // env->am = 0; // for (objCount = 0; (missile = (MISSILE*)env->getNextOfClass (MISSILE_CLASS, &objCount)) && missile; objCount++) else if (my_class == MISSILE_CLASS) { TANK *shooting_tank = NULL; BEAM *defense_beam = NULL; int angle_to_fire; missile = (MISSILE *) my_object; env->am++; missile->hitSomething = 0; missile->applyPhysics (); missile->triggerTest (); shooting_tank = missile->Check_SDI(global); if (shooting_tank) { (shooting_tank->x < missile->x) ? angle_to_fire = 135 : angle_to_fire = 225; defense_beam = new BEAM(global, env, shooting_tank->x, shooting_tank->y - 10, angle_to_fire, SML_LAZER); missile->trigger(); } if (missile->destroy) { missile->requireUpdate (); missile->update (); delete missile; tanksfall = 1; } } // for (objCount = 0; (beam = (BEAM*)env->getNextOfClass (BEAM_CLASS, &objCount)) && beam; objCount++) else if (my_class == BEAM_CLASS) { beam = (BEAM *) my_object; // As bots should not target while a laser is shot: anyLaserFiring ++; beam->applyPhysics (); if (beam->destroy) { beam->requireUpdate (); beam->update (); delete beam; anyLaserFiring--; // It's done! tanksfall = 1; } } // for (objCount = 0; (floattext = (FLOATTEXT*)env->getNextOfClass (FLOATTEXT_CLASS, &objCount)) && floattext; objCount++) else if (my_class == FLOATTEXT_CLASS) { floattext = (FLOATTEXT *) my_object; floattext->applyPhysics (); if (floattext->destroy) { floattext->requireUpdate(); floattext->update(); delete floattext; env->make_fullUpdate(); // ...kill remaining texts! } } } // end of if we have an object objCount++; my_object = env->objects[objCount]; } // end of going through virtual objects #ifdef NETWORK for (int counter = 0; counter < global->numPlayers; counter++) { if (global->players[counter]->type == NETWORK_CLIENT) { global->players[counter]->Get_Network_Command(); global->players[counter]->Execute_Network_Command(FALSE); } } #endif if (satellite) satellite->Move(); if (!anyExploding) { doNaturals (global, env); if (satellite) satellite->Shoot(); } allDone = slideLand (global, env); if (tanksfall && (env->stage != STAGE_ENDGAME)) { for (objCount = 0; (ltank = (TANK*)env->getNextOfClass (TANK_CLASS, &objCount)) && ltank; count--, objCount++) { ltank->pen = 0; ltank->applyPhysics (global); if (ltank->l <= 0 && !anyExploding) { ltank->explode (); if (ltank->creditTo) { if (ltank->player != ltank->creditTo) //enemy destroyed { ltank->creditTo->money += (int)global->scoreUnitDestroyBonus; } else //self destroy - ugh foolish one :)) { ltank->creditTo->money -= (int)global->scoreUnitSelfDestroy; if (ltank->creditTo->money < 0) ltank->creditTo->money = 0; } ltank->creditTo = NULL; } if (ltank->destroy) { if ((int)ltank->player->type == HUMAN_PLAYER) humanPlayers--; ltank->Destroy(); delete(ltank); ltank = NULL; // should not be used anymore, setting NULL for later IF's to checks if ((!skippingComputerPlay) || (global->numTanks <= 1)) env->make_fullUpdate(); if (!humanPlayers) { int iMostIntelligentPlayer = 0; int iNumPlayers = 0; for (int i = 0; i < global->numPlayers; i++) { int iType = 0; if (global->players[i]->tank) { if (global->players[i]->tank->l > 0) { iType = (int) global->players[i]->type; iNumPlayers++; } } if (iType > iMostIntelligentPlayer) iMostIntelligentPlayer = iType; } // If the most intelligent player is more stupid than deadly, raise them all! if ( (iMostIntelligentPlayer < (int) DEADLY_PLAYER) && (iMostIntelligentPlayer >= (int) USELESS_PLAYER) && (iNumPlayers > 1)) for (int i = 0; i < global->numPlayers; i++) { if (global->players[i]->tank) { if (global->players[i]->tank->l > 0) global->players[i]->setComputerValues ( (int) DEADLY_PLAYER - iMostIntelligentPlayer); } } #ifdef DEBUG if ((iMostIntelligentPlayer >= (int)USELESS_PLAYER) && (iNumPlayers > 1)) { cout << endl << "===========================================================" << endl; cout << "Round without human players!" << endl; cout << "Most intelligent player has Skill level " << iMostIntelligentPlayer << endl; cout << "Raised all players by " << ((int)DEADLY_PLAYER - iMostIntelligentPlayer) << " Skill Level(s)" << endl; cout << "===========================================================" << endl << endl; } #endif //DEBUG // Initialize iHumanLessRounds if not done already if (global->iHumanLessRounds < 0) global->iHumanLessRounds = iNumPlayers * 16; } if (!*tank && global->numTanks) { *tank = nextturn (global, env, skippingComputerPlay); while (! *tank) *tank = nextturn (global, env, skippingComputerPlay); (*tank)->fs = 0; nextTankSelected = true; } team_won = Team_Won(global); if ( (global->numTanks <= 1) || ( team_won ) ) { skippingComputerPlay = FALSE; cclock = 0; env->stage = STAGE_ENDGAME; global->currTank = NULL; fi = 1; global->window.x = 0; global->window.y = 0; global->window.w = (global->screenWidth-1); global->window.h = (global->screenHeight-1); winner = -2; if (team_won) winner = team_won; else if (global->numTanks > 0) { for (z = 0; z < global->numPlayers; z++) { if (global->players[z]->tank) winner = z; } } for (objCount = 0; (floattext = (FLOATTEXT*)env->getNextOfClass (FLOATTEXT_CLASS, &objCount)) && floattext; objCount++) { floattext->newRound(); } bCount = 0; global->updateMenu = 1; for (z = 0; z < global->numPlayers; z++) global->players[z]->played++; } } } // adjust chess style clock (only if tank wasn't destroyed) if ( ( global->max_fire_time > 0.0 ) && ( ltank ) && ( ltank->player->type == HUMAN_PLAYER ) && (! env->stage ) ) { if ( global->Check_Time_Changed() ) { int ran_out_of_time; ran_out_of_time = ltank->player->Reduce_Time_Clock(); if (ran_out_of_time && !nextTankSelected) { ltank->player->skip_me = true; *tank = nextturn (global, env, skippingComputerPlay); while (! *tank) *tank = nextturn (global, env, skippingComputerPlay); (*tank)->fs = 0; nextTankSelected = true; } global->updateMenu = 1; } } if ( ( ltank ) && ( ltank->fire_another_shot ) ) { if (! (ltank->fire_another_shot % VOLLY_DELAY)) ltank->activateCurrentSelection(); ltank->fire_another_shot--; if (! ltank->fire_another_shot) env->stage = 0; } } } if (env->stage == 1) { if ((env->am == 0) && allDone && !anyExploding) { tanksfall = 0; env->stage = 2; } } if (env->stage == 2) { zz = 0; for (objCount = 0; (ltank = (TANK*)env->getNextOfClass (TANK_CLASS, &objCount)) && ltank; count--, objCount++) { zz += ltank->applyPhysics (global); } if (zz == global->numTanks) { tanksfall = 1; } zz = 0; if (tanksfall) { for (objCount = 0; (ltank = (TANK*)env->getNextOfClass (TANK_CLASS, &objCount)) && ltank; objCount++) { ltank->pen = 0; if (ltank->l > 0) zz++; } } if (zz == global->numTanks) { if (((int)global->skipComputerPlay > SKIP_NONE) && (!humanPlayers) && (!global->computerPlayersOnly)) { skippingComputerPlay = TRUE; #ifdef NETWORK int index = 0, network_clients = 0; while ( (index < global->numPlayers) && (! network_clients) ) { if (global->players[index]->type == NETWORK_CLIENT) network_clients++; else index++; } if (network_clients) skippingComputerPlay = FALSE; #endif if (skippingComputerPlay) { draw_sprite (env->db, (BITMAP *) global->misc[1], global->halfWidth - 120, global->halfHeight + 155); textout_centre_ex (env->db, font, global->ingame->complete_text[51], global->halfWidth, global->halfHeight + 160, WHITE, -1); draw_sprite (screen, (BITMAP *) global->misc[1], global->halfWidth - 120, global->halfHeight + 155); textout_centre_ex (screen, font, global->ingame->complete_text[51], global->halfWidth, global->halfHeight + 160, WHITE, -1); } } env->stage = STAGE_AIM; winner = -2; for (z = 0; z < global->numPlayers; z++) { if (global->players[z]->tank && winner >= 0) winner = -1; if (global->players[z]->tank && winner == -2) winner = z; } if (winner >= 0) { global->players[winner]->score++; } if (winner == -1) { if ((!nextTankSelected || !tank) && global->numTanks) { *tank = nextturn (global, env, skippingComputerPlay); while (! *tank) *tank = nextturn (global, env, skippingComputerPlay); (*tank)->fs = 0; } nextTankSelected = false; } if ((!humanPlayers) && (!global->computerPlayersOnly)) { global->iHumanLessRounds--; #ifdef DEBUG cout << endl << global->iHumanLessRounds << " Rounds left for the bots to play... " << endl; #endif // DEBUG if ((!global->iHumanLessRounds) && (winner < 1)) { #ifdef DEBUG cout << endl << "=======================" << endl; cout << "Bots have FINISHED!... " << endl; cout << "=======================" << endl << endl; #endif // DEBUG global->iHumanLessRounds = -1; team_won = NO_WIN; // will be determined later skippingComputerPlay = FALSE; cclock = 0; winner = -2; if (global->numTanks > 0) { // The most healthy player wins int iMaxHealth = 1; int iHealth = 0; for (z = 0; z < global->numPlayers; z++) { #ifdef DEBUG cout << z << ".: \"" << global->players[z]->getName() << "\" "; #endif // DEBUG if (global->players[z]->tank) { iHealth = global->players[z]->tank->l + global->players[z]->tank->sh; if (iHealth > iMaxHealth) { #ifdef DEBUG cout << "has most health! (" << iHealth << ")" << endl; #endif // DEBUG iMaxHealth = iHealth; winner = z; } else if (iHealth == iMaxHealth) winner = -2; // Equal Health == draw! #ifdef DEBUG else cout << "is too weak! (" << iHealth << " max: " << iMaxHealth << ")" << endl; #endif // DEBUG } #ifdef DEBUG else cout << "has no tank!" << endl; #endif // } #ifdef DEBUG cout << "winner is player " << winner << " - \""; if (winner > 0) cout << global->players[winner]->getName(); else cout << "draw"; cout << "\"" << endl; #endif // DEBUG if (winner > -1) { if (global->players[winner]->team == TEAM_JEDI) { team_won = JEDI_WIN; winner = JEDI_WIN; } if (global->players[winner]->team == TEAM_SITH) { team_won = SITH_WIN; winner = SITH_WIN; } } } #ifdef DEBUG cout << "Final Decision:" << endl; if (winner > -1) { cout << "\""; if (winner < 10) cout << global->players[winner]->getName(); if (winner == JEDI_WIN) cout << "Team Jedi"; if (winner == SITH_WIN) cout << "Team Sith"; cout << "\" has won!" << endl; } else cout << "Round Draw!" << endl; #endif // DEBUG } } if (winner >= 0 || winner == -2) { env->stage = STAGE_ENDGAME; global->currTank = NULL; fi = 1; global->window.x = 0; global->window.y = 0; global->window.w = (global->screenWidth-1); global->window.h = (global->screenHeight-1); } bCount = 0; global->updateMenu = 1; } } dclock++; if (dclock > 2) { dclock = 0; for (objCount = 0; (ltank = (TANK*)env->getNextOfClass (TANK_CLASS, &objCount)) && ltank; objCount++) { if (ltank->flashdamage) { if (ltank->flashdamage > 25 || ltank->l < 1) { ltank->damage = 0; ltank->flashdamage = 0; ltank->requireUpdate (); } } } } env->pclock++; if (env->pclock > 10) env->pclock = 0; if (*tank && !anyTeleporting && !anyLaserFiring) { // if ((*tank)->player->controlTank() == -1) int status = (*tank)->player->controlTank(); if (status == -1) return; else if ( (status == -2) && (!humanPlayers) ) { skippingComputerPlay = TRUE; } } else if (global->computerPlayersOnly && ((int)global->skipComputerPlay >= SKIP_HUMANS_DEAD)) { if (env->stage == STAGE_ENDGAME) return; } else if ((keypressed () || mouse_b) && !fi) { if (keypressed ()) k = readkey (); else k = 0; if ((env->stage == STAGE_ENDGAME) && (roundEndCount >= WAIT_AT_END_OF_ROUND) && (mouse_b || k >> 8 == KEY_ENTER || k >> 8 == KEY_ESC || k >> 8 == KEY_SPACE)) return; } env->mouseclock++; if (env->mouseclock > 10) env->mouseclock = 0; } frames++; global->stopwindow = 1; env->make_update (mouse_x, mouse_y, ((BITMAP *) (global->misc[0]))->w, ((BITMAP *) (global->misc[0]))->h); env->make_update (lx, ly, ((BITMAP *) (global->misc[0]))->w, ((BITMAP *) (global->misc[0]))->h); global->stopwindow = 0; lx = mouse_x; ly = mouse_y; set_clip_rect (env->db, 0, 0, (global->screenWidth-1), (global->screenHeight-1)); if (! global->os_mouse) show_mouse (NULL); if (global->updateMenu) { set_clip_rect (env->db, 0, 0, (global->screenWidth-1), MENUHEIGHT - 1); drawTopBar (global, env, env->db); } set_clip_rect (env->db, 0, MENUHEIGHT, (global->screenWidth-1), (global->screenHeight-1)); if (fi) { blit (env->sky, env->db, global->window.x, global->window.y - MENUHEIGHT, global->window.x, global->window.y, (global->window.w - global->window.x) + 1, (global->window.h - global->window.y) + 1); masked_blit (env->terrain, env->db, global->window.x, global->window.y, global->window.x, global->window.y, (global->window.w - global->window.x) + 1, (global->window.h - global->window.y) + 2); } else { env->replaceCanvas (); } for (objCount = 0, count = 0; (ltank = (TANK*)env->getNextOfClass (TANK_CLASS, &objCount)) && ltank; count++, objCount++) { if (env->stage < STAGE_ENDGAME) { if (*tank == ltank) { ltank->draw (env->db, (int)(global->slope[bCount % 360][0] * 4)); ltank->requireUpdate (); } else { ltank->draw (env->db, 0); } ltank->update (); } ltank->framelyAccounting (); } objCount = 0; my_object = env->objects[objCount]; while (objCount < MAX_OBJECTS) { if (my_object) { my_class = my_object->getClass(); // for (objCount = 0; (missile = (MISSILE*)env->getNextOfClass (MISSILE_CLASS, &objCount)) && missile; objCount++) if (my_class == MISSILE_CLASS) { missile = (MISSILE *) my_object; missile->draw (env->db); missile->update (); } // for (objCount = 0; (beam = (BEAM*)env->getNextOfClass (BEAM_CLASS, &objCount)) && beam; objCount++) else if (my_class == BEAM_CLASS) { beam = (BEAM *) my_object; beam->draw (env->db); beam->update (); } // for (objCount = 0; (explosion = (EXPLOSION*)env->getNextOfClass (EXPLOSION_CLASS, &objCount)) && explosion; objCount++) else if (my_class == EXPLOSION_CLASS) { explosion = (EXPLOSION *) my_object; explosion->draw (env->db); explosion->update (); } // for (objCount = 0; (teleport = (TELEPORT*)env->getNextOfClass (TELEPORT_CLASS, &objCount)) && teleport; objCount++) else if (my_class == TELEPORT_CLASS) { teleport = (TELEPORT *) my_object; if (teleport->object) teleport->draw (env->db); teleport->update (); } // for (objCount = 0; (decor = (DECOR*)env->getNextOfClass (DECOR_CLASS, &objCount)) && decor; objCount++) else if (my_class == DECOR_CLASS) { decor = (DECOR *) my_object; decor->draw (env->db); decor->update (); } // for (objCount = 0; (floattext = (FLOATTEXT*)env->getNextOfClass (FLOATTEXT_CLASS, &objCount)) && floattext; objCount++) else if (my_class == FLOATTEXT_CLASS) { floattext = (FLOATTEXT *) my_object; floattext->draw (env->db); floattext->requireUpdate (); floattext->update (); } } // end of if we have an object objCount++; my_object = env->objects[objCount]; } // end of going through objects if (satellite) satellite->Draw(env->db); if (env->stage == STAGE_ENDGAME) { if (roundEndCount < WAIT_AT_END_OF_ROUND + 1) roundEndCount++; if (roundEndCount >= WAIT_AT_END_OF_ROUND) { // check to see if the winner is still alive int tank_index = 0; int alive = false; while ( (! alive) && (tank_index < global->numPlayers) ) { if ( ( global->players[tank_index]->tank ) &&( global->players[tank_index]->tank->l > 0) ) { alive = true; } tank_index++; } // moving this below so dead players lose credit // if (! alive) // { // winner = -2; // } if (! alive && bWinnerIsCredited) { // The score needs to be reduced, of course: int count; int iTeamCount = 0; int iTeamBonus = 0; if (winner == JEDI_WIN) // de-credit jedi team { for (count = 0; count < global->numPlayers; count++) { if (global->players[count]->team == TEAM_JEDI) { global->players[count]->score--; global->players[count]->won--; iTeamCount++; } } } else if (winner == SITH_WIN) // de-credit sith team { for (count = 0; count < global->numPlayers; count++) { if (global->players[count]->team == TEAM_SITH) { global->players[count]->score--; global->players[count]->won--; iTeamCount++; } } } else if (winner >= 0) // de-credit the (ex-)winner { global->players[winner]->score--; global->players[winner]->won--; global->players[winner]->money -= (int)global->scoreRoundWinBonus; } // If it's a team, take away their money now! if (iTeamCount) { iTeamBonus = (int)(global->scoreRoundWinBonus / iTeamCount); for (count = 0; count < global->numPlayers; count++) if ( ((winner==JEDI_WIN) && (global->players[count]->team == TEAM_JEDI)) ||((winner==SITH_WIN) && (global->players[count]->team == TEAM_SITH)) ) global->players[count]->money -= iTeamBonus; } winner = -2; bWinnerIsCredited = false; // Or it will be substracted on every loop... } if (! alive) { winner = -2; } // if we have a winner, give them credit if (alive && (winner >= 0) && (roundEndCount == WAIT_AT_END_OF_ROUND) && !bWinnerIsCredited) { int count; int iTeamCount = 0; int iTeamBonus = 0; if (winner == JEDI_WIN) // credit jedi team { for (count = 0; count < global->numPlayers; count++) { if (global->players[count]->team == TEAM_JEDI) { global->players[count]->score++; global->players[count]->won++; iTeamCount++; } } } else if (winner == SITH_WIN) // credit sith team { for (count = 0; count < global->numPlayers; count++) { if (global->players[count]->team == TEAM_SITH) { global->players[count]->score++; global->players[count]->won++; iTeamCount++; } } } else // credit the winner { global->players[winner]->score++; global->players[winner]->won++; global->players[winner]->money += (int)global->scoreRoundWinBonus; } // If it's a team, do give them their money now! if (iTeamCount) { iTeamBonus = (int)(global->scoreRoundWinBonus / iTeamCount); for (count = 0; count < global->numPlayers; count++) if ( ((winner==JEDI_WIN) && (global->players[count]->team == TEAM_JEDI)) ||((winner==SITH_WIN) && (global->players[count]->team == TEAM_SITH)) ) global->players[count]->money += iTeamBonus; } bWinnerIsCredited = true; } if ( roundEndCount >= WAIT_AT_END_OF_ROUND ) showRoundEndScoresAt (global, env, env->db, global->screenWidth/2, global->screenHeight/2, winner); // when we get here and it is a demo, we should bail out if (global->demo_mode) return; } } // This four values are used to reduce access to global and increase readability (Easier to debug this way!) int iLeft = 0; int iRight = global->screenWidth - 1; int iTop = MENUHEIGHT; int iBottom = global->screenHeight - 1; set_clip_rect (env->db, 0, 0, iRight, iBottom); vline(env->db, iLeft, iTop, iBottom, env->wallColour); // Left edge vline(env->db, iRight, iTop, iBottom, env->wallColour); // right edge hline(env->db, iLeft, iBottom, iRight, env->wallColour);// bottom edge if (global->bIsBoxed) hline(env->db, iLeft, iTop, iRight, env->wallColour);// top edge if (! global->os_mouse) show_mouse (env->db); if (fi) { while (keypressed ()) { readkey (); } fi = 0; // if (env->fog) { // clear_to_color (screen, makecol (128,128,128)); // } else { quickChange (global, env->db); // } } else { env->do_updates (); global->window.x = global->screenWidth; global->window.y = global->screenHeight; global->window.w = -1; global->window.h = -1; } #ifdef DEBUG_AIM_SHOW if (!global->bASD) global->bASD = true; // Now it is allowed to be true #endif } } #endif // old gameloop void print_text_help() { cout << "-h\tThis screen\n" << "-fs\tFull screen\n" << "--windowed\tRun in a window\n" << "-w <width> or --width <width>\tSpecify the screen width in pixels\n" << "-t <height> --tall <height>\tSpecify the screen height in pixels\n" << "\tAdjust the screen size at your own risk (default is 800x600)\n" << "-d <depth> or --depth <depth>\tCurrently either 16 or 32\n" << "--datadir <data directory>\t Path to the data directory\n" << "-c <config directory>\t Path to config and saved game directory\n" << "--noconfig\t Do not load game settings from the config file.\n" << "--nosound\t Disable sound\n" << "--noname\t Do not show player name above tank\n" << "--nonetwork\t Do not allow the game to accept network connection.\n" << "--nobackground\t Do not display the green menu background.\n" << "--nothread\t Do not use threads to perform background tasks.\n" << "--thread\t Do use threads to perform background tasks.\n"; } void print_text_initmsg() { printf ( "Atomic Tanks Version %s (-h for help)\n", VERSION); printf ( "Authors: \tTom Hudson (rewrite, additions, improvements)\n"); printf ( "\t\tStevante Software (original design)\n"); printf ( "\t\tKota543 Software (fixes and updates)\n"); printf ( "\t\tJesse Smith (additions, fixes and updates)\n"); printf ( "\t\tSven Eden (ai rewrite, additions, fixes and updates)\n\n"); // putchar ('\n'); } void endgame_cleanup (GLOBALDATA *global, ENVIRONMENT *env) { while (global->numPlayers > 0) { if (global->players[0]->tank) delete(global->players[0]->tank); // make sure networked clients say good-bye and return to old AI level if (global->players[0]->type >= NETWORK_CLIENT) global->players[0]->type = global->players[0]->previous_type; global->players[0]->tank = NULL; global->removePlayer(global->players[0]); } for (int objCount = 0; objCount < MAX_OBJECTS; objCount++) { if (env->objects[objCount]) { delete(env->objects[objCount]); env->objects[objCount] = NULL; } } } /* This function calls the functions which save data to a text file. The function requires the global data, environment and the path to the config file name. The function returns TRUE on success and FALSE on failure. -- Jesse */ int Save_Game_Settings_Text(GLOBALDATA *global, ENVIRONMENT *env, char *text_file) { FILE *my_file; my_file = fopen(text_file, (char *)"w"); if (! my_file) { perror ( "Error trying to open text file for writing.\n"); return FALSE; } global->saveToFile_Text (my_file); env->saveToFile_Text (my_file); savePlayers_Text (global, my_file); fclose (my_file); return TRUE; } /* This function detects changes to the global settings (mouse and sound) and, if a change has happened, makes the required changes to the game environment. The function returns TRUE. -- Jesse */ int Change_Settings(double old_mouse, double old_sound, double new_mouse, double new_sound, void *mouse_image) { BITMAP *my_mouse_image = (BITMAP *) mouse_image; // first, check for a change in the sound settings if (old_sound != new_sound) { if (new_sound > 0.0) // we turned ON sound { if (detect_digi_driver(DIGI_AUTODETECT)) { if (install_sound (DIGI_AUTODETECT, MIDI_NONE, NULL) < 0) fprintf (stderr, "install_sound: failed turning on sound\n"); } else fprintf (stderr, "detect_digi_driver found no sound device\n"); // if (install_sound (DIGI_AUTODETECT, MIDI_NONE, NULL) < 0) // { // fprintf (stderr, "install_sound: %s", allegro_error); // } } else if (new_sound == 0.0) // we turned OFF sound { remove_sound(); } } // check for a change in mouse settings if (old_mouse != new_mouse) { if (new_mouse > 0.0) // use OS cursor { set_mouse_sprite(NULL); show_os_cursor(MOUSE_CURSOR_ARROW); } else if (new_mouse == 0.0) // use Allgero cursor { set_mouse_sprite (my_mouse_image); set_mouse_sprite_focus (0, 0); } } return TRUE; } /* This function catches the close command, usually given by the user pressing the close window button. We'll try to clean-up. Note: This function causes the app to hang in Windows. Make this compile on non-Windows systems only. */ void close_button_handler(void) { // allegro_exit(); // exit(0); my_global->close_button_pressed = true; } int main (int argc, char **argv) { int signal; int status; string tmp; ENVIRONMENT *env = NULL; GLOBALDATA *global = NULL; ifstream configFile; char fullPath[2048]; bool load_config_file = true; bool bLoadingSuccess = false; cmdTokens nextToken = ARGV_NOTHING_EXPECTED; double temp_mouse, temp_sound; // I wish I was not using these int menu_action; int playerCount, player_index; #ifdef NETWORK SEND_RECEIVE_TYPE *send_receive = NULL; int client_socket = -1; #endif bool allow_network = true, allow_thread = false; double music_place_holder; double full_screen = FULL_SCREEN_EITHER; quit_right_now = false; global = new GLOBALDATA (); if (!global) { perror ( "Allocating global"); exit (1); } my_global = global; print_text_initmsg(); // try to find data dir if (! global->Find_Data_Dir() ) printf("Could not find data dir.\n"); if (argc >= 2) /* Parse command-line switches */ { for (int argument = 1; argument < argc; argument++) { tmp = argv[argument]; if (nextToken == ARGV_GFX_DEPTH) { global->colourDepth = strtol (tmp.c_str(), NULL, 10); if (global->colourDepth != 16 && global->colourDepth != 32) { cout << "Invalid graphics depth, only 16 or 32 are valid\n"; print_text_help(); return 0; } nextToken = ARGV_NOTHING_EXPECTED; } else if (nextToken == ARGV_SCREEN_WIDTH) { global->screenWidth = strtol (tmp.c_str(), NULL, 10); if (global->screenWidth < 512) { cout << "Width too small (minimum 512)\n"; return 0; } global->width_override = global->screenWidth; global->halfWidth = global->screenWidth / 2; nextToken = ARGV_NOTHING_EXPECTED; } else if (nextToken == ARGV_SCREEN_HEIGHT) { global->screenHeight = strtol (tmp.c_str(), NULL, 10); if (global->screenHeight < 320) { cout << "Height too small (minimum 320)\n"; return 0; } global->height_override = global->screenHeight; global->halfHeight = global->screenHeight / 2; nextToken = ARGV_NOTHING_EXPECTED; } else if (nextToken == ARGV_DATA_DIR) { // Would use strndup, but the win compiler // doesn't know of it. if (strlen (tmp.c_str()) > 2048) { cout << "Datadir path too long:\n" << "\"" << tmp << "\"\n\n" << "Maximum length 2048 characters\n"; return 0; } global->dataDir = strdup (tmp.c_str()); nextToken = ARGV_NOTHING_EXPECTED; } else if (nextToken == ARGV_CONFIG_DIR) { if (strlen (tmp.c_str()) > 2048) { cout << "Configdir path too long:\n" << "\"" << tmp << "\"\n\n" << "Maximum length 2048 characters\n"; return 0; } global->configDir = strdup ( tmp.c_str() ); nextToken = ARGV_NOTHING_EXPECTED; } if ( (tmp == SWITCH_HELP) || (tmp == "--help") ) { print_text_help(); return 0; } else if (tmp == SWITCH_FULL_SCREEN) { screen_mode = GFX_AUTODETECT_FULLSCREEN; full_screen = FULL_SCREEN_TRUE; } else if (tmp == SWITCH_WINDOWED) { screen_mode = GFX_AUTODETECT_WINDOWED; full_screen = FULL_SCREEN_FALSE; } else if (tmp == "-d" || tmp == "--depth") { nextToken = ARGV_GFX_DEPTH; } else if (tmp == "-w" || tmp == "--width") { nextToken = ARGV_SCREEN_WIDTH; } else if (tmp == "-t" || tmp == "--tall") { nextToken = ARGV_SCREEN_HEIGHT; } else if (tmp == "--datadir") { nextToken = ARGV_DATA_DIR; } else if (tmp == "-c") { nextToken = ARGV_CONFIG_DIR; } else if (tmp == "--noconfig") { nextToken = ARGV_NOTHING_EXPECTED; load_config_file = false; } else if (tmp == "--nosound") { nextToken = ARGV_NOTHING_EXPECTED; global->sound = 0.0; } else if (tmp == "--noname") { nextToken = ARGV_NOTHING_EXPECTED; global->name_above_tank = FALSE; } else if (tmp == "--nonetwork") { allow_network = false; nextToken = ARGV_NOTHING_EXPECTED; } else if (tmp == "--nobackground") { global->draw_background = FALSE; nextToken = ARGV_NOTHING_EXPECTED; } else if (tmp == "--nothread") { allow_thread = false; nextToken = ARGV_NOTHING_EXPECTED; } else if (tmp == "--thread") { allow_thread = true; nextToken = ARGV_NOTHING_EXPECTED; } } if (nextToken != ARGV_NOTHING_EXPECTED) { cout << "Expecting an argument to follow " << tmp << endl; return 0; } } if (! global->configDir) { global->configDir = global->Get_Config_Path(); // copy the file over, if we did not yet if (!Copy_Config_File(global)) { // If it did not work, look whether the directory already exists: DIR * pDestDir; pDestDir = opendir(global->configDir); if (!pDestDir) printf( "An error has occured trying to set up Atomic Tank folders.\n"); else { closedir(pDestDir); pDestDir = NULL; } } } // end of no config file on the command line memset(fullPath, '\0', sizeof(fullPath)); FILE *old_config_file = NULL; snprintf(fullPath, sizeof(fullPath) - 1, "%s/atanks-config.txt", global->configDir); old_config_file = fopen(fullPath, "r"); if (old_config_file) { global->loadFromFile_Text(old_config_file); // over-ride full screen setting with command line if ( (full_screen == FULL_SCREEN_TRUE) || (full_screen == FULL_SCREEN_FALSE) ) global->full_screen = full_screen; env = init_game_settings(global); if (global->os_mouse) show_os_cursor(MOUSE_CURSOR_ARROW); global->Load_Text_Files(); env->loadFromFile_Text(old_config_file); loadPlayers_Text(global, env, old_config_file); fclose(old_config_file); bLoadingSuccess = true; } if (!bLoadingSuccess) // no config file found or failed to load { global->numPermanentPlayers = 0; if ( (full_screen == FULL_SCREEN_TRUE) || (full_screen == FULL_SCREEN_FALSE) ) global->full_screen = full_screen; env = init_game_settings (global); global->Load_Text_Files(); if (global->os_mouse) show_os_cursor(MOUSE_CURSOR_ARROW); char *defaultNames[] = { "Caesar", "Alex", "Hatshepsut", "Patton", "Napoleon", "Attila", "Catherine", "Hannibal", "Stalin", "Mao" }; PLAYER *tempPlayer; tempPlayer = global->createNewPlayer (env); tempPlayer->setName ( global->ingame->complete_text[52] ); options (global, env, (MENUDESC*)tempPlayer->menudesc); for (int count = 0; count < 10; count++) { tempPlayer = global->createNewPlayer (env); tempPlayer->type = rand () % (LAST_PLAYER_TYPE - 1) + 1; tempPlayer->setName (defaultNames[count]); tempPlayer->generatePreferences(); } } status = Load_Weapons_Text(global); if (! status) { printf( "An error occured trying to read weapons file.\n"); exit(1); } snprintf(fullPath, sizeof(fullPath) - 1, "%s/atanks-config.txt", global->configDir); global->temp_screenWidth = global->screenWidth; global->temp_screenHeight = global->screenHeight; global->halfWidth = global->screenWidth / 2; global->halfHeight = global->screenHeight / 2; global->menuBeginY = (global->screenHeight - 400) / 2; if (global->menuBeginY < 0) global->menuBeginY = 0; global->menuEndY = global->screenHeight - global->menuBeginY; title (global); env->bitmap_filenames = Find_Bitmaps(global, & (env->number_of_bitmaps) ); env->my_sky_gradients = (const gradient **) sky_gradients; env->my_land_gradients = (const gradient **) land_gradients; Create_Music_Folder(global); #ifdef THREADS if (allow_thread) { pthread_t sky_thread, terrain_thread; pthread_create( &sky_thread, NULL, Generate_Sky_In_Background, (void *) env); pthread_create( &terrain_thread, NULL, Generate_Land_In_Background, (void *) env); } // end of allowing threads #endif // new networking area #ifdef THREADS #ifdef NETWORK pthread_t network_thread; if (global->check_for_updates) { global->update_string = Check_For_Update("projects.sourceforge.net", "version.txt", "atanks.sourceforge.net", VERSION); } if ( (global->enable_network) && (allow_network) ) { send_receive = (SEND_RECEIVE_TYPE *) calloc(1, sizeof(SEND_RECEIVE_TYPE)); if (! send_receive) printf("Could not create networking data.\n"); } else send_receive = NULL; if (send_receive) { send_receive->listening_port = (int) global->listen_port; send_receive->global = global; // quit option already cleared by calloc call pthread_create( &network_thread, NULL, Send_And_Receive, (void *) send_receive); } #endif #endif do { //show the main menu global->command = GLOBAL_COMMAND_MENU; signal = menu (global, env); if (global->client_message) { free(global->client_message); global->client_message = NULL; } // did the user signal to quit the game if (signal == SIG_QUIT_GAME) global->command = GLOBAL_COMMAND_QUIT; //determine which menu item is selected switch (global->command) { case GLOBAL_COMMAND_HELP: scrollTextList (global, env, global->instructions); break; case GLOBAL_COMMAND_OPTIONS: // save old settings temp_mouse = global->os_mouse; temp_sound = global->sound; options(global, env, NULL); if (! Save_Game_Settings_Text(global, env, fullPath)) { perror ( "atanks.cpp: Failed to save game settings from atanks::main()!"); } // check for changes to settings Change_Settings(temp_mouse, temp_sound, global->os_mouse, global->sound, global->misc[0]); global->Change_Font(); global->Update_Player_Menu(); break; case GLOBAL_COMMAND_PLAYERS: //loop until done editing players where return value is not ESC do { status = editPlayers(global, env); } while ( (status != KEY_ESC << 8) && (status != KEY_ENTER << 8) ); break; case GLOBAL_COMMAND_CREDITS: credits(global, env); break; case GLOBAL_COMMAND_QUIT: break; case GLOBAL_COMMAND_NETWORK: #ifdef NETWORK client_socket = Setup_Client_Socket(global->server_name, global->server_port); if (client_socket >= 0) { int keep_playing = TRUE; printf("Ready to play networked\n"); while (keep_playing) { keep_playing = Game_Client(global, env, client_socket); } Clean_Up_Client_Socket(client_socket); } else printf("Unable to connect to server %s, port %s.\n", global->server_name, global->server_port); #else printf("This version of Atanks is not compiled to handle network games.\n"); #endif break; case GLOBAL_COMMAND_DEMO: global->demo_mode = true; global->load_game = false; music_place_holder = global->play_music; global->play_music = 0.0; // set up a bunch of players (non-human, less than 10) playerCount = 0; global->numPlayers = 0; for (player_index = 0; player_index < global->numPermanentPlayers; player_index++) { if ( (global->allPlayers[player_index]->type > HUMAN_PLAYER) && (playerCount < MAXPLAYERS) ) { global->addPlayer (global->allPlayers[player_index]); playerCount++; } } player_index = (int) global->skipComputerPlay; global->skipComputerPlay = SKIP_NONE; global->currentround = 1; // might add more later while ( (global->currentround > 0) && (! global->close_button_pressed) ) { game(global, env); if ((global->command == GLOBAL_COMMAND_QUIT) || (global->command == GLOBAL_COMMAND_MENU)) break; global->currentround--; // skipping winner screen for now } endgame_cleanup(global, env); global->demo_mode = false; global->skipComputerPlay = player_index; global->play_music = music_place_holder; break; default: //must have commanded to play game menu_action = selectPlayers(global, env); if (menu_action == ESC_MENU) break; //selected players, start new game else { // make sure the game has a name if (! global->game_name[0]) strcpy(global->game_name,global->ingame->complete_text[53] ); newgame (global, env); // play the game for the selected number of rounds // for (global->currentround = (int)global->rounds; global->currentround > 0; global->currentround--) if (! global->load_game) global->currentround = (int) global->rounds; while ( (global->currentround > 0) && (! global->close_button_pressed) ) { game (global, env); // play a round if (global->background_music) { stop_sample(global->background_music); destroy_sample(global->background_music); global->background_music = NULL; } // if user selected to quit or return to main menu during game play if ((global->command == GLOBAL_COMMAND_QUIT) || (global->command == GLOBAL_COMMAND_MENU)) { #ifdef NETWORK global->Send_To_Clients("CLOSE"); #endif break; } global->currentround--; #ifdef NETWORK if (global->currentround != 0) // end of the round global->Send_To_Clients("ROUNDEND"); #endif } // only show winner if finished all rounds if ( (global->currentround == 0) && (! global->close_button_pressed) ) { char buffer[256], *my_player; // strcpy(buffer, "GAMEEND"); // global->Send_To_Clients(buffer); my_player = do_winner (global, env); if (my_player) { snprintf(buffer, 256, "GAMEEND The game went to %s.", my_player); free(my_player); } else strcpy(buffer, "GAMEEND"); #ifdef NETWORK global->Send_To_Clients(buffer); #endif do_quote(global, env); } endgame_cleanup (global, env); } // end of start new game break; } // end of menu switch } while ( (global->command != GLOBAL_COMMAND_QUIT) ); // print out if there is an update if ( (global->update_string) && (global->update_string[0]) ) { cout << global->update_string << endl; free(global->update_string); global->update_string = NULL; } #ifdef THREADS #ifdef NETWORK if (send_receive) { send_receive->shut_down = TRUE; // sleep(1); LINUX_REST; // we should probably wait and do a join here, but if the network thread does not // finish after a full second, then something has gone wrong anyway and we should move on.... free(send_receive); } #endif #endif if (! Save_Game_Settings_Text(global, env, fullPath)) { // This is a very critical issue, but as we are ending here, we just report it perror ( "atanks.cpp: Failed to save game settings from atanks::main()!"); allegro_exit (); cout << "See http://atanks.sourceforge.net for the latest news and downloads." << endl; return(1); } else { Save_Game_Settings_Text(global, env, fullPath); allegro_exit (); cout << "See http://atanks.sourceforge.net for the latest news and downloads." << endl; return(0); } } END_OF_MAIN () /* Adding function here to avoid patch incompatibilties. This function should launch all items from all of the living tanks. */ void doLaunch(GLOBALDATA *global, ENVIRONMENT *env) { // If we're in simultaneous mode, launch all selections int i; int savestage = env->stage; TANK *tank; if (global->turntype != TURN_SIMUL) return; for (i = 0; i < global->maxNumTanks; i++) { tank = env->order[i]; if (tank) { if (! tank->player->skip_me) tank->activateCurrentSelection(); else tank->player->skip_me = false; tank->player->time_left_to_fire = global->max_fire_time; } } env->stage = savestage; } // load a colour from a file bool popColo(int &aData, ifstream &ifsFile) { bool bResult = false; if (ifsFile.is_open()) { int iColor = 0; ifsFile >> iColor; // reads the next found number if (ifsFile.good()) { // Now transform to color: aData = makecol((iColor & 0x00ff0000) >> 16, (iColor & 0x0000ff00) >> 8, iColor & 0x000000ff ); bResult = true; } } return bResult; } int *Sort_Scores(GLOBALDATA *global) { static int order[MAXPLAYERS]; int counter; bool made_change = true; int temp; for (counter = 0; counter < global->numPlayers; counter++) order[counter] = counter; // bubble sort while (made_change) { made_change = false; counter = 0; // check for swap while (counter < (global->numPlayers - 1) ) { if ( global->players[ order[counter] ]->score < global->players[ order[counter + 1] ]->score ) { temp = order[counter]; order[counter] = order[counter + 1]; order[counter + 1] = temp; made_change = true; } counter++; } // end of check for swaps } // end of bubble sort return order; } // Client version of the game // Really, this loop should do some basic things. // 1. Find out what the landscape should look like from the server. // 2. Place tanks on the battle field // 3. Create missiles, beam weapons and such when the server asks us to // 4. Get input from the player and forward it to the server. // 5. Clean up at the end of the round. // // Function return TRUE if everything went well or FALSE // if an error occured. #ifdef NETWORK int Game_Client(GLOBALDATA *global, ENVIRONMENT *env, int socket_number) { int surface_x = 1, tank_position = 1, team_number = 1, name_number = 1; int weapon_number = 1, item_number = 1, tank_health = 1; int end_of_round = FALSE, keep_playing = FALSE; int game_stage = CLIENT_VERSION; char buffer[BUFFER_SIZE]; int incoming; int my_key; int time_clock = 0; int screen_update = FALSE; int count; // generic counter int stuff_going_down = FALSE; // explosions, missiles etc on the screen VIRTUAL_OBJECT *my_object; BEAM *beam; EXPLOSION *explosion; MISSILE *missile; TELEPORT *teleport; FLOATTEXT *floattext; int my_class, object_count; bool fired = false; global->dMaxVelocity = (double)MAX_POWER * (100.0 / (double)global->frames_per_second) / 100.0; clear_to_color (env->terrain, PINK); // get terrain ready clear_to_color(env->db, BLACK); // clean up old text for (count = 0; (floattext = (FLOATTEXT*)env->getNextOfClass (FLOATTEXT_CLASS, &count)) && floattext; count++) { floattext->newRound(); delete floattext; } Create_Sky(env, global); // so we have a background strcpy(buffer, "VERSION"); write(socket_number, buffer, strlen(buffer)); while (! end_of_round) { // check for waiting input from the server incoming = Check_For_Incoming_Data(socket_number); if (incoming) { int bytes_read; memset(buffer, '\0', BUFFER_SIZE); bytes_read = read(socket_number, buffer, BUFFER_SIZE); if (bytes_read > 0) { // do something with this input if (! strncmp(buffer, "CLOSE", 5) ) { end_of_round = TRUE; keep_playing = FALSE; printf("Got close message.\n"); global->client_message = global->ingame->complete_text[81]; } else if (! strncmp(buffer, "NOROOM", 6) ) { end_of_round = TRUE; keep_playing = FALSE; printf("The server is full or the game has not started. Please try again later.\n"); global->client_message = global->ingame->complete_text[80]; } else if (! strncmp(buffer, "GAMEEND", 7) ) { end_of_round = TRUE; keep_playing = FALSE; printf("The game is over.\n"); if ( strlen(buffer) > 7) global->client_message = strdup(& (buffer[8])) ; else global->client_message = strdup(global->ingame->complete_text[82]); } else if (! strncmp(buffer, "ROUNDEND", 8) ) { end_of_round = TRUE; keep_playing = TRUE; printf("Round is over.\n"); } else // not a special command, parse it { if ( Parse_Client_Data(global, env, buffer) ) { if (game_stage < CLIENT_PLAYING) game_stage++; // Request more information if (game_stage < CLIENT_PLAYING) { switch (game_stage) { case CLIENT_SCREEN: strcpy(buffer, "SCREEN"); break; case CLIENT_WIND: strcpy(buffer, "WIND"); break; case CLIENT_NUMPLAYERS: strcpy(buffer, "NUMPLAYERS"); break; case CLIENT_TANK_POSITION: strcpy(buffer, "TANKPOSITION 0"); break; case CLIENT_SURFACE: strcpy(buffer, "SURFACE 0"); break; case CLIENT_WHOAMI: strcpy(buffer, "WHOAMI"); screen_update = TRUE; break; case CLIENT_WEAPONS: strcpy(buffer, "WEAPON 0"); break; case CLIENT_ITEMS: strcpy(buffer, "ITEM 0"); break; case CLIENT_ROUNDS: strcpy(buffer, "ROUNDS"); break; case CLIENT_TEAMS: strcpy(buffer, "TEAMS 0"); global->updateMenu = TRUE; break; case CLIENT_WALL_TYPE: strcpy(buffer, "WALLTYPE"); break; case CLIENT_BOXED: strcpy(buffer, "BOXED"); break; case CLIENT_NAME: strcpy(buffer, "PLAYERNAME 0"); break; case CLIENT_TANK_HEALTH: strcpy(buffer, "HEALTH 0"); break; default: buffer[0] = '\0'; } write(socket_number, buffer, strlen(buffer)); } // end of getting more info } // our game stage went up else // we got data, but our game stage did not go up { if (fired) { if ( (global->client_player) && (global->client_player->tank) ) { fired = false; if (global->client_player->tank->cw < WEAPONS) sprintf(buffer, "WEAPON %d", global->client_player->tank->cw); else sprintf(buffer, "ITEM %d", global->client_player->tank->cw - WEAPONS); write(socket_number, buffer, strlen(buffer)); } } else if (game_stage == CLIENT_SURFACE) { sprintf(buffer, "SURFACE %d", surface_x); write(socket_number, buffer, strlen(buffer)); surface_x++; } else if (game_stage == CLIENT_ITEMS) { sprintf(buffer, "ITEM %d", item_number); write(socket_number, buffer, strlen(buffer)); item_number++; } else if (game_stage == CLIENT_TANK_POSITION) { sprintf(buffer, "TANKPOSITION %d", tank_position); write(socket_number, buffer, strlen(buffer)); tank_position++; if (tank_position >= global->numPlayers) tank_position = 0; } else if (game_stage == CLIENT_TANK_HEALTH) { sprintf(buffer, "HEALTH %d", tank_health); write(socket_number, buffer, strlen(buffer)); tank_health++; if (tank_health >= global->numPlayers) tank_health = 0; } else if (game_stage == CLIENT_TEAMS) { sprintf(buffer, "TEAMS %d", team_number); write(socket_number, buffer, strlen(buffer)); team_number++; } else if (game_stage == CLIENT_NAME) { sprintf(buffer, "PLAYERNAME %d", name_number); write(socket_number, buffer, strlen(buffer)); name_number++; } else if (game_stage == CLIENT_WEAPONS) { sprintf(buffer, "WEAPON %d", weapon_number); write(socket_number, buffer, strlen(buffer)); weapon_number++; } else if (game_stage == CLIENT_PLAYING) { time_clock++; if (time_clock > 1) // check positions every few inputs { time_clock = 0; if (surface_x < global->screenWidth) { game_stage = CLIENT_SURFACE; sprintf(buffer, "SURFACE %d", surface_x); write(socket_number, buffer, strlen(buffer)); surface_x++; } else { game_stage = CLIENT_TANK_POSITION; tank_position = 1; strcpy(buffer, "TANKPOSITION 0"); write(socket_number, buffer, strlen(buffer)); } // game stage stuff } } // end of playing commands } } // end of we got something besides the close command } else // connection was broken { close(socket_number); printf("Server closed connection.\n"); end_of_round = TRUE; } } object_count = 0; while (object_count < MAX_OBJECTS) { my_object = env->objects[object_count]; if (my_object) { my_class = my_object->getClass(); if (my_class == BEAM_CLASS) { beam = (BEAM *) my_object; beam->applyPhysics(); if (beam->destroy) { beam->requireUpdate(); beam->update(); delete beam; } stuff_going_down = TRUE; } else if (my_class == MISSILE_CLASS) { missile = (MISSILE *) my_object; missile->hitSomething = 0; missile->applyPhysics(); missile->triggerTest(); if (missile->destroy) { missile->requireUpdate(); missile->update(); delete missile; } stuff_going_down = TRUE; } else if (my_class == EXPLOSION_CLASS) { explosion = (EXPLOSION *) my_object; explosion->explode (); explosion->applyPhysics (); if (explosion->destroy) { explosion->requireUpdate (); explosion->update (); delete explosion; } stuff_going_down = TRUE; } else if (my_class == TELEPORT_CLASS) { teleport = (TELEPORT *) my_object; teleport->applyPhysics (); if (teleport->destroy) { teleport->requireUpdate (); teleport->update (); delete teleport; time_clock = 2; } stuff_going_down = TRUE; } else if (my_class == FLOATTEXT_CLASS) { floattext = (FLOATTEXT *) my_object; floattext->applyPhysics (); if (floattext->destroy) { floattext->requireUpdate(); floattext->update(); delete floattext; } } else if (my_class == DECOR_CLASS) { DECOR *decor = (DECOR *) my_object; decor->applyPhysics (); if (decor->destroy) { decor->requireUpdate (); decor->update (); delete decor; } } } // end of got valid object object_count++; } slideLand(global, env); // update everything on the screen if (global->updateMenu) { set_clip_rect (env->db, 0, 0, (global->screenWidth-1), MENUHEIGHT - 1); drawTopBar (global, env, env->db); } set_clip_rect (env->db, 0, MENUHEIGHT, (global->screenWidth-1), (global->screenHeight-1)); if (screen_update) { blit (env->sky, env->db, global->window.x, global->window.y - MENUHEIGHT, global->window.x, global->window.y, (global->window.w - global->window.x) + 1, (global->window.h - global->window.y) + 1); masked_blit (env->terrain, env->db, global->window.x, global->window.y, global->window.x, global->window.y, (global->window.w - global->window.x) + 1, (global->window.h - global->window.y) + 2); drawTopBar(global, env, env->db); int iLeft = 0; int iRight = global->screenWidth - 1; int iTop = MENUHEIGHT; int iBottom = global->screenHeight - 1; set_clip_rect (env->db, 0, 0, iRight, iBottom); vline(env->db, iLeft, iTop, iBottom, env->wallColour); // Left edge vline(env->db, iRight, iTop, iBottom, env->wallColour); // right edge hline(env->db, iLeft, iBottom, iRight, env->wallColour);// bottom edge if (global->bIsBoxed) hline(env->db, iLeft, iTop, iRight, env->wallColour);// top edge env->make_update(0, 0, global->screenWidth, global->screenHeight); } else { env->replaceCanvas (); } for (count = 0; count < global->numPlayers; count++) { if ( (global->players[count]) && (global->players[count]->tank) ) { global->players[count]->tank->draw(env->db, 0); global->players[count]->tank->update(); } } // env->do_updates(); screen_update = TRUE; object_count = 0; while (object_count < MAX_OBJECTS) { my_object = env->objects[object_count]; if (my_object) { my_class = my_object->getClass(); if (my_class == BEAM_CLASS) { beam = (BEAM *) my_object; beam->draw (env->db); beam->update (); } else if (my_class == MISSILE_CLASS) { missile = (MISSILE *) my_object; missile->draw(env->db); missile->update(); } else if (my_class == EXPLOSION_CLASS) { explosion = (EXPLOSION *) my_object; explosion->draw (env->db); explosion->update (); } else if (my_class == TELEPORT_CLASS) { teleport = (TELEPORT *) my_object; if (teleport->object) teleport->draw (env->db); teleport->update (); } else if (my_class == DECOR_CLASS) { DECOR *decor = (DECOR *) my_object; decor->draw(env->db); decor->update(); } else if (my_class == FLOATTEXT_CLASS) { floattext = (FLOATTEXT *) my_object; floattext->draw (env->db); floattext->requireUpdate (); floattext->update (); } } // end of valid object object_count++; } // end of while updating objects env->do_updates(); // check for input from the user if ( keypressed() ) { my_key = readkey(); my_key = my_key >> 8; if (my_key == KEY_SPACE) { Client_Fire(global->client_player, socket_number); fired = true; } else if (my_key == KEY_ESC) { end_of_round = TRUE; close(socket_number); } else if (my_key == KEY_UP) { Client_Power(global->client_player, CLIENT_UP); } else if (my_key == KEY_DOWN) { Client_Power(global->client_player, CLIENT_DOWN); } else if (my_key == KEY_LEFT) { Client_Angle(global->client_player, CLIENT_LEFT); } else if (my_key == KEY_RIGHT) { Client_Angle(global->client_player, CLIENT_RIGHT); } else if ( (my_key == KEY_Z) || (my_key == KEY_BACKSPACE) ) { Client_Cycle_Weapon(global->client_player, CYCLE_BACK); } else if ( (my_key == KEY_C) || (my_key == KEY_TAB) ) { Client_Cycle_Weapon(global->client_player, CYCLE_FORWARD); global->updateMenu = TRUE; } screen_update = FALSE; global->updateMenu = TRUE; } // pause for a moment // if (game_stage < CLIENT_PLAYING) if (stuff_going_down) { LINUX_SLEEP; stuff_going_down = FALSE; } } // we should clean up here for (count = 0; count < global->numPlayers; count++) { if (global->players[count]->tank) { delete global->players[count]->tank; global->players[count]->tank = NULL; } } return keep_playing; } #endif