/* Copyright (C) 1995-2002 FSGames. Ported by Sean Ford and Yan Shosh * * 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 */ //screen.cpp /* ChangeLog buffers: 7/31/02: *deleted some redundant headers. : *load_scenario now looks for all uppercase files in : levels.001 if lowercase file fails buffers: 8/15/02: *load_scenario now checks for uppercase file names in scen/ in case lowercase check fails */ #include "graph.h" #include "smooth.h" #include "gladpack.h" #include "util.h" #include using namespace std; // From picker.cpp extern long calculate_level(unsigned long temp_exp); // Screen window boundries #define MAX_VIEWS 5 #define S_UP 0 //12 //0 #define S_LEFT 0 //12 //0 #define S_DOWN 200 //188 // 200 #define S_RIGHT 320 // 228 #define S_WIDTH (S_RIGHT - S_LEFT) #define S_HEIGHT (S_DOWN - S_UP) //#define BUF_SIZE (unsigned) ((S_DOWN-S_UP)*(S_RIGHT-S_LEFT)) #define VERSION_NUM 2 #define MAX_SPREAD 10 //this controls find_near_foe #define TIME_BONUS (long) 5000 #define LEVEL_BONUS (long) 120 //#define query_keyboard dumb //#define grab_keyboard yuck short load_version_2(FILE *infile, screen * master); short load_version_3(FILE *infile, screen * master); // v.3 scen short load_version_4(FILE *infile, screen * master); // v.4 scen: + names short load_version_5(FILE *infile, screen * master); // v.5 scen: + type short load_version_6(FILE *infile, screen * master, short version=6); // v.6 scen: + title char* get_scen_title(char *filename, screen *master); // get the title char * query_my_map_name(); char my_map_name[40]; FILE * open_misc_file(char *, char *); // These are globals for the packed files .. packfile scenpack; unsigned long random(unsigned long x) { if (x < 1) return 0; return (unsigned long) ( ((unsigned long) rand()) % x); } // ************************************************************ // SCREEN -- graphics routines // // This object is the video graphics object. All display // must pass through this object, and all on-screen objects // are found in this object. // ************************************************************ screen::screen(short howmany):video() { long i, j; const char *qresult; text first_text(this); long left = 66; grab_timer(); grid = NULL; mysmoother = new smoother(); timerstart = query_timer_control(); framecount = 0; oblist = NULL; myobmap = new obmap(200*GRID_SIZE, 200*GRID_SIZE); fxlist = NULL; weaplist = NULL; weapfree = NULL; // control = NULL; first_guy = NULL; //myradar[0] = myradar[1] = NULL; // very important! :) control_hp = 0; scen_num = 1; // default scenario scenario_type = 0; // default, must kill all // Load the palette .. load_and_set_palette("our.pal", newpalette); // load the pixie graphics data shorto memory // shorto memory, you know the !tallo kind draw_button(60, 50, 260, 110, 2, 1); draw_text_bar(64, 54, 256, 62); // header field first_text.write_y(56, "Loading Gladiator..Please Wait", RED, 1); draw_text_bar(64, 64, 256, 106); // draw box for text first_text.write_xy(left, 70, "Loading Graphics...", DARK_BLUE, 1); buffer_to_screen(0, 0, 320, 200); myloader = new loader; first_text.write_xy(left, 70, "Loading Graphics...Done", DARK_BLUE, 1); first_text.write_xy(left, 78, "Loading Gameplay Info...", DARK_BLUE, 1); buffer_to_screen(0, 0, 320, 200); palmode = 0; my_team = 0; topx = 0; topy = 0; end = 0; numobs = 0; timer_wait = 6; // 'moderate' speed setting redrawme = 1; cyclemode = 1; //color cycling on by default score = totalcash = totalscore = 0; for (i=0; i < 4; i++) { m_score[i] = 0; // For Player-v-Player m_totalcash[i] = 0; m_totalscore[i] = 0; } allied_mode = 0; // allied mode is off by default par_value = 1; for (i=0; i < 30; i++) scentext[i][0] = 0; scentextlines = 0; enemy_freeze = 0; level_done = 0; // Load map data from a pixie format load_map_data(pixdata); first_text.write_xy(left, 78, "Loading Gameplay Info...Done", DARK_BLUE, 1); first_text.write_xy(left, 86, "Initializing Display...", DARK_BLUE, 1); buffer_to_screen(0, 0, 320, 200); // Initialize a pixie for each background piece for(i = 0; i < PIX_MAX; i++) back[i] = new pixieN(pixdata[i], this,1); //buffers: after we set all the tiles to use acceleration, we go //through the tiles that have pal cycling to turn of the accel. back[PIX_WATER1]->set_accel(0); back[PIX_WATER2]->set_accel(0); back[PIX_WATER3]->set_accel(0); back[PIX_WATERGRASS_LL]->set_accel(0); back[PIX_WATERGRASS_LR]->set_accel(0); back[PIX_WATERGRASS_UL]->set_accel(0); back[PIX_WATERGRASS_UR]->set_accel(0); back[PIX_WATERGRASS_U]->set_accel(0); back[PIX_WATERGRASS_D]->set_accel(0); back[PIX_WATERGRASS_L]->set_accel(0); back[PIX_WATERGRASS_R]->set_accel(0); back[PIX_GRASSWATER_LL]->set_accel(0); back[PIX_GRASSWATER_LR]->set_accel(0); back[PIX_GRASSWATER_UL]->set_accel(0); back[PIX_GRASSWATER_UR]->set_accel(0); // Set up the viewscreen poshorters numviews = howmany; // # of viewscreens for (i=0; i < MAX_VIEWS; i++) viewob[i] = NULL; if (numviews == 1) { viewob[0] = new viewscreen( S_LEFT, S_UP, S_WIDTH, S_HEIGHT, 0, this); } else if (numviews == 2) { viewob[1] = new viewscreen( T_LEFT_ONE, T_UP_ONE, T_WIDTH, T_HEIGHT, 1, this); viewob[0] = new viewscreen( T_LEFT_TWO, T_UP_TWO, T_WIDTH, T_HEIGHT, 0, this); } else if (numviews == 3) { viewob[1] = new viewscreen( T_LEFT_ONE, T_UP_ONE, T_WIDTH, T_HEIGHT, 1, this); viewob[0] = new viewscreen( T_LEFT_TWO, T_UP_TWO, T_WIDTH, T_HEIGHT, 0, this); viewob[2] = new viewscreen( 112, 16, 100, 168, 2, this); } else if (numviews == 4) { viewob[1] = new viewscreen( T_LEFT_ONE, T_UP_ONE, T_WIDTH, T_HEIGHT, 1, this); viewob[0] = new viewscreen( T_LEFT_TWO, T_UP_TWO, T_WIDTH, T_HEIGHT, 0, this); viewob[2] = new viewscreen( 112, 16, 100, 168, 2, this); viewob[3] = new viewscreen( 112, 16, 100, 168, 3, this); } first_text.write_xy(left, 86, "Initializing Display...Done", DARK_BLUE, 1); first_text.write_xy(left, 94, "Initializing Sound...", DARK_BLUE, 1); buffer_to_screen(0, 0, 320, 200); // Init the sound data qresult = cfg.query("sound", "sound"); if (!qresult || (qresult && !strcmp(qresult, "on"))) // sound is on { soundp = new soundob(); first_text.write_xy(left, 94, "Initializing Sound...Done", DARK_BLUE, 1); } else { soundp = new soundob(1); // turn sound off first_text.write_xy(left, 94, "Initializing Sound...Skipped", DARK_BLUE, 1); } buffer_to_screen(0, 0, 320, 200); // Let's set the special names for all walkers .. for (i=0; i < NUM_FAMILIES; i++) for (j=0; j < NUM_SPECIALS; j++) { strcpy(special_name[i][j], "NONE"); strcpy(alternate_name[i][j], "NONE"); } strcpy(special_name[FAMILY_SOLDIER][1], "CHARGE"); strcpy(special_name[FAMILY_SOLDIER][2], "BOOMERANG"); strcpy(special_name[FAMILY_SOLDIER][3], "WHIRLWIND"); strcpy(special_name[FAMILY_SOLDIER][4], "DISARM"); strcpy(special_name[FAMILY_BARBARIAN][1], "Hurl Boulder"); strcpy(special_name[FAMILY_BARBARIAN][2], "Exploding Boulder"); strcpy(special_name[FAMILY_ELF][1], "ROCKS"); strcpy(special_name[FAMILY_ELF][2], "BOUNCING ROCKS"); strcpy(special_name[FAMILY_ELF][3], "LOTS OF ROCKS"); strcpy(special_name[FAMILY_ELF][4], "MEGA ROCKS"); strcpy(special_name[FAMILY_ARCHER][1], "FIRE ARROWS"); strcpy(special_name[FAMILY_ARCHER][2], "BARRAGE"); strcpy(special_name[FAMILY_ARCHER][3], "EXPLODING BOLT"); strcpy(special_name[FAMILY_MAGE][1], "TELEPORT"); strcpy(alternate_name[FAMILY_MAGE][1], "TELEPORT MARKER"); strcpy(special_name[FAMILY_MAGE][2], "WARP SPACE"); strcpy(special_name[FAMILY_MAGE][3], "FREEZE TIME"); strcpy(special_name[FAMILY_MAGE][4], "ENERGY WAVE"); strcpy(special_name[FAMILY_MAGE][5], "HEARTBURST"); strcpy(special_name[FAMILY_ARCHMAGE][1], "TELEPORT"); strcpy(alternate_name[FAMILY_ARCHMAGE][1], "TELEPORT MARKER"); strcpy(special_name[FAMILY_ARCHMAGE][2], "HEARTBURST"); strcpy(alternate_name[FAMILY_ARCHMAGE][2], "CHAIN LIGHTNING"); strcpy(special_name[FAMILY_ARCHMAGE][3], "SUMMON IMAGE"); strcpy(alternate_name[FAMILY_ARCHMAGE][3], "SUMMON ELEMENTAL"); strcpy(special_name[FAMILY_ARCHMAGE][4], "MIND CONTROL"); //strcpy(alternate_name[FAMILY_ARCHMAGE][4], "SUMMON ELEMENTAL"); strcpy(special_name[FAMILY_CLERIC][1], "HEAL"); strcpy(alternate_name[FAMILY_CLERIC][1], "MYSTIC MACE"); strcpy(special_name[FAMILY_CLERIC][2], "RAISE UNDEAD"); strcpy(alternate_name[FAMILY_CLERIC][2], "TURN UNDEAD"); strcpy(special_name[FAMILY_CLERIC][3], "RAISE GHOST"); strcpy(alternate_name[FAMILY_CLERIC][3], "TURN UNDEAD"); strcpy(special_name[FAMILY_CLERIC][4], "RESSURECT"); strcpy(special_name[FAMILY_DRUID][1], "GROW TREE"); strcpy(special_name[FAMILY_DRUID][2], "SUMMON FAERIE"); strcpy(special_name[FAMILY_DRUID][3], "REVEAL"); strcpy(special_name[FAMILY_DRUID][4], "PROTECTION"); strcpy(special_name[FAMILY_THIEF][1], "DROP BOMB"); strcpy(special_name[FAMILY_THIEF][2], "CLOAK"); strcpy(special_name[FAMILY_THIEF][3], "TAUNT ENEMY"); strcpy(alternate_name[FAMILY_THIEF][3], "CHARM OPPONENT"); strcpy(special_name[FAMILY_THIEF][4], "POISON CLOUD"); strcpy(special_name[FAMILY_GHOST][1], "SCARE"); strcpy(special_name[FAMILY_FIREELEMENTAL][1], "STARBURST"); strcpy(special_name[FAMILY_ORC][1], "HOWL"); strcpy(special_name[FAMILY_ORC][2], "EAT CORPSE"); strcpy(special_name[FAMILY_SMALL_SLIME][1], "GROW"); strcpy(special_name[FAMILY_MEDIUM_SLIME][1], "GROW"); strcpy(special_name[FAMILY_SLIME][1], "SPLIT"); strcpy(special_name[FAMILY_SKELETON][1], "TUNNEL"); } screen::~screen() { int i; release_timer(); delete soundp; delete myloader; delete mysmoother; for (i = 0; i < PIX_MAX; i++) { if(pixdata[i]) delete pixdata[i]; // Zardus: FIXME: this should be here cause it leaks, but this makes it segfault if (back[i]) delete back[i]; } soundp = NULL; cleanup(1); //make sure we've cleaned up } void screen::cleanup(short howmany) { long i; oblink *here, *templink; walker *who; numviews = howmany; // # of viewscreens for (i=0; i < MAX_VIEWS; i++) { if (viewob[i]) delete (viewob[i]); viewob[i] = NULL; } if (grid) { // Zardus: PORT: this segfaults while deleting grid! //buffers: commented free() so openglad will cleanly exit //delete grid; grid = NULL; } if (oblist) { here = oblist; while (here->next) { templink = here; if (templink->ob) { delete templink->ob; templink->ob = NULL; } here = here->next; delete templink; templink = NULL; } if (here->ob) { delete here->ob; here->ob = NULL; } delete here; here = NULL; } oblist = NULL; if (weaplist) { here = weaplist; while (here->next) { templink = here; if (templink->ob) { delete templink->ob; templink->ob = NULL; } here = here->next; delete templink; templink = NULL; } if (here->ob) { delete here->ob; here->ob = NULL; } delete here; here = NULL; } weaplist = NULL; if (fxlist) { here = fxlist; while (here->next) { templink = here; if (templink->ob) { delete templink->ob; templink->ob = NULL; } here = here->next; delete templink; templink = NULL; } if (here->ob) { delete here->ob; here->ob = NULL; } delete here; here = NULL; } fxlist = NULL; while (weapfree) { who = weapfree; weapfree = weapfree->cachenext; //cachenext points to next ob delete who; who = NULL; } weapfree = NULL; if (myobmap) { delete myobmap; myobmap = NULL; } } void screen::reset(short howmany) { long i; if (!mysmoother) mysmoother = new smoother(); mysmoother->mygrid = NULL; // Set up the viewscreen poshorters numviews = howmany; // # of viewscreens // Clean stuff up cleanup(howmany); if (numviews == 1) { viewob[0] = new viewscreen( S_LEFT, S_UP, S_WIDTH, S_HEIGHT, 0, this); } else if (numviews == 2) { viewob[1] = new viewscreen( T_LEFT_ONE, T_UP_ONE, T_WIDTH, T_HEIGHT, 1, this); viewob[0] = new viewscreen( T_LEFT_TWO, T_UP_TWO, T_WIDTH, T_HEIGHT, 0, this); } else if (numviews == 3) { viewob[1] = new viewscreen( T_LEFT_ONE, T_UP_ONE, T_WIDTH, T_HEIGHT, 1, this); viewob[0] = new viewscreen( T_LEFT_TWO, T_UP_TWO, T_WIDTH, T_HEIGHT, 0, this); viewob[2] = new viewscreen( 112, 16, 100, 168, 2, this); } else if (numviews == 4) { viewob[1] = new viewscreen( T_LEFT_ONE, T_UP_ONE, T_WIDTH, T_HEIGHT, 1, this); viewob[0] = new viewscreen( T_LEFT_TWO, T_UP_TWO, T_WIDTH, T_HEIGHT, 0, this); viewob[2] = new viewscreen( 112, 16, 100, 168, 2, this); viewob[3] = new viewscreen( 112, 16, 100, 168, 3, this); } end = 0; redrawme = 1; score = totalcash = totalscore = 0; for (i=0; i < 4; i++) { m_score[i] = 0; m_totalcash[i] = 0; m_totalscore[i] = 0; } timerstart = query_timer_control(); framecount = 0; enemy_freeze = 0; myobmap = new obmap(200*GRID_SIZE, 200*GRID_SIZE); fxlist = oblist = NULL; first_guy = NULL; control_hp = 0; scen_num = 1; // default scenario scenario_type = 0; // default, must kill all palmode = 0; my_team = 0; topx = 0; topy = 0; end = 0; numobs = 0; redrawme = 1; score = totalcash = totalscore = 0; for (i=0; i < 4; i++) { m_score[i] = 0; m_totalcash[i] = 0; m_totalscore[i] = 0; } allied_mode = 0; // allied mode is off by default par_value = 1; for (i=0; i < 30; i++) scentext[i][0] = 0; scentextlines = 0; } short screen::query_grid_passable(short x, short y, walker *ob) { long i,j; // short xsize=ob->sizex, ysize=ob->sizey; long xtrax = 1; long xtray = 1; long xtarg; //the for loop target long ytarg; //the for loop target long dist; // NOTE: we're going to shrink dimensions by one in each.. //long xover = (long) (x+ob->sizex-1), yover = (long) (y+ob->sizey-1); long xover = (long) (x+ob->sizex), yover = (long) (y+ob->sizey); // Again, this is for shrinking ... //x+=1; //y+=1; if (x < 0 || y < 0 || xover >= pixmaxx || yover >= pixmaxy) return 0; // Are we ethereal? if (ob->stats->query_bit_flags(BIT_ETHEREAL) ) return 1; //moved up to avoid unneeded calculation // Zardus: PORT: Does the grid exist? if (!grid) return 0; // Check if our butt hangs over shorto next grid square if (!((xover)%GRID_SIZE)) xtrax = 0; //this should be the rare case if (!((yover)%GRID_SIZE)) xtray = 0; //this should be the rare case // Check grid squares by simulated grid coords. xtarg = (xover/GRID_SIZE) + xtrax; ytarg = (yover/GRID_SIZE) + xtray; for (i = x/GRID_SIZE; i < xtarg; i++) for (j = y/GRID_SIZE; j < ytarg; j++) { // Check if item in background grid switch (grid[i+maxx*j]) { case PIX_GRASS1: // grass is pass.. case PIX_GRASS2: case PIX_GRASS3: case PIX_GRASS4: case PIX_GRASS_DARK_1: case PIX_GRASS_DARK_2: case PIX_GRASS_DARK_3: case PIX_GRASS_DARK_4: case PIX_GRASS_DARK_LL: case PIX_GRASS_DARK_UR: case PIX_GRASS_DARK_B1: // shadowed edges case PIX_GRASS_DARK_B2: case PIX_GRASS_DARK_BR: case PIX_GRASS_DARK_R1: case PIX_GRASS_DARK_R2: case PIX_GRASS_RUBBLE: case PIX_GRASS1_DAMAGED: case PIX_GRASS_LIGHT_1: // lighter grass case PIX_GRASS_LIGHT_TOP: case PIX_GRASS_LIGHT_RIGHT_TOP: case PIX_GRASS_LIGHT_RIGHT: case PIX_GRASS_LIGHT_RIGHT_BOTTOM: case PIX_GRASS_LIGHT_BOTTOM: case PIX_GRASS_LIGHT_LEFT_BOTTOM: case PIX_GRASS_LIGHT_LEFT: case PIX_GRASS_LIGHT_LEFT_TOP: case PIX_GRASSWATER_LL: // mostly grass case PIX_GRASSWATER_LR: case PIX_GRASSWATER_UL: case PIX_GRASSWATER_UR: case PIX_PAVEMENT1: // floor ok case PIX_PAVEMENT2: case PIX_PAVEMENT3: case PIX_COBBLE_1: // Cobblestone case PIX_COBBLE_2: case PIX_COBBLE_3: case PIX_COBBLE_4: case PIX_FLOOR_PAVEL: // wood/tile ok case PIX_FLOOR_PAVER: case PIX_FLOOR_PAVEU: case PIX_FLOOR_PAVED: case PIX_PAVESTEPS1: // steps case PIX_PAVESTEPS2: case PIX_PAVESTEPS2L: case PIX_PAVESTEPS2R: case PIX_FLOOR1: case PIX_CARPET_LL: // carpet ok case PIX_CARPET_B: case PIX_CARPET_LR: case PIX_CARPET_UR: case PIX_CARPET_U: case PIX_CARPET_UL: case PIX_CARPET_L: case PIX_CARPET_M: case PIX_CARPET_M2: case PIX_CARPET_R: case PIX_CARPET_SMALL_HOR: case PIX_CARPET_SMALL_VER: case PIX_CARPET_SMALL_CUP: case PIX_CARPET_SMALL_CAP: case PIX_CARPET_SMALL_LEFT: case PIX_CARPET_SMALL_RIGHT: case PIX_CARPET_SMALL_TINY: case PIX_DIRT_1: // Dirt paths case PIX_DIRTGRASS_UL1: case PIX_DIRTGRASS_UR1: case PIX_DIRTGRASS_LL1: case PIX_DIRTGRASS_LR1: case PIX_DIRT_DARK_1: // shadowed dirt/grass case PIX_DIRTGRASS_DARK_UL1: case PIX_DIRTGRASS_DARK_UR1: case PIX_DIRTGRASS_DARK_LL1: case PIX_DIRTGRASS_DARK_LR1: case PIX_PATH_1: case PIX_PATH_2: case PIX_PATH_3: case PIX_PATH_4: break; case PIX_TREE_M1: // trees are usually bad, but case PIX_TREE_ML: // we can fly over them case PIX_TREE_MR: case PIX_TREE_MT: case PIX_TREE_T1: if (ob->stats->query_bit_flags(BIT_FORESTWALK) ) break; else if (ob->stats->query_bit_flags(BIT_FLYING) || ob->flight_left) break; else return 0; case PIX_TREE_B1: // Tree bottoms { if (ob->query_order() == ORDER_WEAPON || ob->stats->query_bit_flags(BIT_FORESTWALK) ) break; else if (ob->stats->query_bit_flags(BIT_FLYING) || ob->flight_left) break; else return 0; } case PIX_H_WALL1: // walls bad, but we can "ethereal" case PIX_WALL2: // through them by default case PIX_WALL3: case PIX_WALL_LL: case PIX_WALLTOP_H: return 0;// break; case PIX_WALL4: // Arrow slits case PIX_WALL5: case PIX_WALL_ARROW_GRASS: case PIX_WALL_ARROW_FLOOR: case PIX_WALL_ARROW_GRASS_DARK: { //if (!ob->owner) if (ob->query_order()==ORDER_LIVING) return 0; if (abs(ob->xpos - ob->owner->xpos)> abs(ob->ypos - ob->owner->ypos)) dist = abs(ob->xpos - ob->owner->xpos); else dist = abs(ob->ypos - ob->owner->ypos); dist -= (GRID_SIZE/2); if (dist < GRID_SIZE) dist += GRID_SIZE; if (random(dist/GRID_SIZE)) return 0; } case PIX_WATER1: // Water case PIX_WATER2: case PIX_WATER3: case PIX_WATERGRASS_LL: case PIX_WATERGRASS_LR: case PIX_WATERGRASS_UL: case PIX_WATERGRASS_UR: case PIX_WATERGRASS_U: case PIX_WATERGRASS_L: case PIX_WATERGRASS_R: case PIX_WATERGRASS_D: case PIX_WALLSIDE_L: // v. walls case PIX_WALLSIDE1: case PIX_WALLSIDE_R: case PIX_WALLSIDE_C: case PIX_WALLSIDE_CRACK_C1: case PIX_TORCH1: case PIX_TORCH2: case PIX_TORCH3: case PIX_BRAZIER1: // brazier case PIX_COLUMN1: //Columns case PIX_COLUMN2: case PIX_BOULDER_1: // Rocks case PIX_BOULDER_2: case PIX_BOULDER_3: case PIX_BOULDER_4: { if (ob->query_order() == ORDER_WEAPON) break; else if (ob->stats->query_bit_flags(BIT_FLYING) || ob->flight_left) break; else return 0; } default: return 0; } } return 1; } short screen::query_object_passable(short x, short y, walker *ob) { if (ob->dead) return 1; return myobmap->query_list(ob, x, y); } short screen::query_passable(short x,short y,walker *ob) { if (query_grid_passable(x, y, ob) && query_object_passable(x, y, ob) ) return 1; return 0; } void screen::clear() { unsigned short i; //buffers: PORT: for (i=0;i<64000;i++) //buffers: PORT: { //buffers: PORT: videobuffer[i] = 0; //buffers: PORT: } clearscreen(); //SDL_FillRect(screen,NULL,SDL_MapRGB(screen->format,0,0,0)); for (i=0; i < numviews; i ++) viewob[i]->clear(); } // REDRAW -- This function moves through the data on the grid (map) // finding which grid squares are on screen. For each on // screen, it pashorts the appropriate graphics pixie onto // the screen by calling the function DRAW in PIXIE. short screen::redraw() { short i; for (i=0; i < numviews; i++) viewob[i]->redraw(); return 1; } // REFRESH -- refreshes the viewscreens void screen::refresh() { short i; for (i=0; i < numviews; i++) { viewob[i]->refresh(); } } // ************************** // Useful stuff again // ************************** short screen::input(char input) { // static text mytext; short i; for (i=0; i < numviews; i++) viewob[i]->input(input); return 1; } short screen::act() { oblink *here, *before; here = oblist; static char obmessage[80]; long printed_time = 0; // have we printed message yet? // static short debug = 0; level_done = 2; // unless we find valid foes while looping if (enemy_freeze) enemy_freeze--; if (enemy_freeze == 1) set_palette(ourpalette); while(here) { if (!enemy_freeze) // normal functionality { if (here->ob && !here->ob->dead) { here->ob->in_act = 1; // Zardus: while acting, in_act is set here->ob->act(); here->ob->in_act = 0; if (here->ob && !here->ob->dead) { if (here->ob->team_num != my_team && here->ob->query_order() == ORDER_LIVING) level_done = 0; // Testing .. trying to FORCE foes :) if (here->ob->foe == NULL && here->ob->leader == NULL) here->ob->foe = myscreen->find_far_foe(here->ob); } } here = here->next; } else // enemy livings are frozen { if (!(enemy_freeze%10) && !printed_time) { sprintf(obmessage, "TIME LEFT: %d", enemy_freeze); viewob[0]->set_display_text(obmessage, 10); printed_time = 1; } if (here->ob && !here->ob->dead && ( ( (here->ob->query_order() != ORDER_LIVING) && (here->ob->query_order() != ORDER_GENERATOR) ) || (here->ob->team_num == 0) ) ) { here->ob->act(); if (here->ob && !here->ob->dead) { if (here->ob->team_num != my_team && here->ob->query_order() == ORDER_LIVING) level_done = 0; } } here = here->next; } } // Let the weapons act ... here = weaplist; while(here) { if (here->ob && !here->ob->dead) { here->ob->act(); if (here->ob && !here->ob->dead) { if (here->ob->team_num != my_team && here->ob->query_order() == ORDER_LIVING) level_done = 0; } } here = here->next; } // end of weapons acting // Quickly check the background for exits, etc. here = fxlist; while (here) { if (here->ob && !here->ob->dead) { if (here->ob->query_order() == ORDER_TREASURE && here->ob->query_family() == FAMILY_EXIT && level_done != 0) { level_done = 1; // 0 => foes, 1 => no foes but exit, 2 => no foes or exit } } here = here->next; } if (level_done == 2) return endgame(0); // Make sure we're all pointing to legal targets here = oblist; while (here) { if (here->ob) { if (here->ob->foe && here->ob->foe->dead) here->ob->foe = NULL; if (here->ob->leader && here->ob->leader->dead) here->ob->leader = NULL; if (here->ob->owner && here->ob->owner->dead) here->ob->owner = NULL; if (here->ob->collide_ob && here->ob->collide_ob->dead) here->ob->collide_ob = NULL; } here = here->next; } here = weaplist; while (here) { if (here->ob) { if (here->ob->foe && here->ob->foe->dead) here->ob->foe = NULL; if (here->ob->leader && here->ob->leader->dead) here->ob->leader = NULL; if (here->ob->owner && here->ob->owner->dead) here->ob->owner = NULL; if (here->ob->collide_ob && here->ob->collide_ob->dead) here->ob->collide_ob = NULL; } here = here->next; } // Remove dead objects here = oblist; while (here) { if (here->ob && here->ob->dead) { delete here->ob; here->ob = NULL; } here = here->next; } here = fxlist; while (here) { if (here->ob && here->ob->dead) { //remove_fx_ob(here->ob); delete here->ob; here->ob = NULL; } here = here->next; } here = weaplist; while (here) { if (here->ob && here->ob->dead) { if (!(here->ob->query_order() == ORDER_WEAPON)) { delete here->ob; here->ob = NULL; } else //push the weapon onto the cache list { here->ob->cachenext = weapfree; weapfree = here->ob; here->ob = NULL; } } here = here->next; } // ** Remove empty objects ** // ** First the normal list ** here = oblist; // Make first element clean while (!here->ob) { oblist = oblist->next; delete here; here = oblist; } // Fix rest of elements before = oblist; here = before->next; while (here) { if (!here->ob) //clean element here { before->next = here->next; delete here; here = before->next; } else // else advance { before = here; here = before->next; } } // ** Now the weapons list ** here = weaplist; // Make first element clean while (here && !here->ob) { weaplist = weaplist->next; delete here; here = weaplist; } // Fix rest of weapon elements before = weaplist; if (before) here = before->next; else here = NULL; while (here) { if (!here->ob) //clean element here { before->next = here->next; delete here; here = before->next; } else // else advance { before = here; here = before->next; } } return 1; } walker *screen::add_ob(char order, char family) // atstart == 0 { return add_ob(order, family, 0); } walker *screen::add_ob(char order, char family, short atstart) { oblink *here = NULL; /* ------ ------ | ob | | ob | oblist -> |----- |----- | ------->| --------> Null ------ ------ */ // Point to end of oblink chain if (order == ORDER_WEAPON) return add_weap_ob(order, family); // Going to force at head of list for now, for speed, if it works //if (atstart) // add to the end of the list instead of the end .. if (oblist) { here = new oblink; here->ob = myloader->create_walker(order, family, this); if (!here->ob) return NULL; here->next = oblist; oblist = here; if (order == ORDER_LIVING) numobs++; return here->ob; } else // we're the first and only .. { here = new oblink; here->ob = myloader->create_walker(order, family, this); if (!here->ob) return NULL; here->next = NULL; oblist = here; if (order == ORDER_LIVING) numobs++; return here->ob; } here = oblist; if (oblist) { while(here->next) here = here->next; here->next = new oblink; here = here->next; } else // oblink is null { here = new oblink; oblist = here; } here->next = NULL; here->ob = myloader->create_walker(order, family, this); if (order == ORDER_LIVING) numobs++; return here->ob; } walker *screen::add_ob(walker *newob) { oblink *here = NULL; /* ------ ------ | ob | | ob | oblist -> |----- |----- | ------->| --------> Null ------ ------ */ // Point to end of oblink chain if (newob->query_order() == ORDER_WEAPON) return add_weap_ob(newob); /* here = oblist; if (oblist) { while(here->next) here = here->next; here->next = new oblink; here = here->next; } else // oblink is null { here = new oblink; oblist = here; } */ if (oblist) { here = new oblink; here->ob = newob; here->next = oblist; oblist = here; } else // first element on list { here = new oblink; here->ob = newob; here->next = NULL; oblist = here; } //here->next = NULL; //here->ob = newob; if (newob->query_order() == ORDER_LIVING) numobs++; return here->ob; } walker *screen::add_fx_ob(walker *newob) { oblink *here = NULL; here = fxlist; if (fxlist) { while(here->next) here = here->next; here->next = new oblink; here = here->next; } else // oblink is null { here = new oblink; fxlist = here; } here->next = NULL; here->ob = newob; //numobs++; return here->ob; } walker *screen::add_fx_ob(char order, char family) { oblink *here = NULL; here = fxlist; if (fxlist) { while(here->next) here = here->next; here->next = new oblink; here = here->next; } else // oblink is null { here = new oblink; fxlist = here; } here->next = NULL; here->ob = myloader->create_walker(order, family, this); //numobs++; //here->ob->ignore = 1; return here->ob; } //add an existing weapon to the weapon list walker *screen::add_weap_ob(walker *newob) { oblink *here; // We can add to the front, making things faster .. here = new oblink; here->ob = newob; here->next = weaplist; weaplist = here; // set weaplist to top of list again return here->ob; } walker *screen::add_weap_ob(char order, char family) { oblink *here = new oblink; here->ob = myloader->create_walker(order, family, this); here->next = weaplist; weaplist = here; return here->ob; } //short screen::remove_ob(walker *ob) //{ // return remove_ob(ob, 0); // call with delete allowed //} //removed, to force calling with correct parameters // Delay removal of linked list until end of act // so as to prevent linked list problems short screen::remove_ob(walker *ob, short no_delete) { oblink *here, *prev; if (ob && ob->query_order() == ORDER_LIVING) numobs--; here = weaplist; //most common case if (here) if (here->ob && here->ob == ob) // this is the ob we want { if (!no_delete) { delete here->ob; } weaplist = weaplist->next; delete here; return 1; } prev = here; while (here) { if (here->ob && here->ob == ob) //this is the ob we want { if (!no_delete) { delete here->ob; } prev->next = here->next; // remove this link delete here; return 1; //we found it, at least } prev = here; here = here->next; } here = fxlist; //less common if (here) if (here->ob && here->ob == ob) // this is the ob we want { if (!no_delete) { delete here->ob; } fxlist = fxlist->next; delete here; return 1; } prev = here; while (here) { if (here->ob && here->ob == ob) //this is the ob we want { if (!no_delete) { delete here->ob; } prev->next = here->next; // remove this link delete here; return 1; //we found it, at least } prev = here; here = here->next; } here = oblist; //less common if (here) if (here->ob && here->ob == ob) // this is the ob we want { if (!no_delete) { delete here->ob; } oblist = oblist->next; delete here; return 1; } prev = here; while (here) { if (here->ob && here->ob == ob) //this is the ob we want { if (!no_delete) { delete here->ob; } prev->next = here->next; // remove this link delete here; return 1; //we found it, at least } prev = here; here = here->next; } return 0; } //short screen::remove_fx_ob(walker *ob) //{ // return remove_fx_ob(ob, 0); //} //short screen::remove_fx_ob(walker *ob, short no_delete) //{ // oblink *here; // here = fxlist; // while (here) // { // if (here->ob && here->ob == ob) // { // if (!no_delete) // delete here->ob; // here->ob = NULL; // return 1; // } // here = here->next; // } // return 0; // means we failed //} //remove_fx_ob functionality has been moved to remove_ob short screen::endgame(short ending) { return endgame(ending, -1); } short screen::endgame(short ending, short nextlevel) { char temp[50]; text mytext(this, TEXT_1); unsigned long bonuscash[4] = {0, 0, 0, 0}; oblink *checklist = oblist; walker *target; long test1; char * endkeys = query_keyboard(); int i; unsigned long allscore = 0, allbonuscash = 0; for (i=0; i < 4; i++) allscore += m_score[i]; if (ending == 1) // 1 = lose, for some reason { if (nextlevel == -1) // generic defeat { //buffers: we will port the red pal stuff later //buffers: set_palette(redpalette); draw_dialog(30, 70, 290, 134, "Defeat!"); mytext.write_y(92,"YOUR MEN ARE CRUSHED!", DARK_BLUE, 1); sprintf(temp,"YOUR SCORE IS %ld.\n", allscore); mytext.write_y(100,temp, DARK_BLUE, 1); mytext.write_y(110,"**PRESS 'ESC' TO RETURN TO THE MENUS.**", DARK_BLUE, 1); buffer_to_screen(0, 0, 320, 200); // Zardus: all things should listen to get_input_events() for now until further notice while (!endkeys[SDLK_ESCAPE]) get_input_events(WAIT); end = 1; } else // we're withdrawing to another level { //buffers: we will port the red pal stuff later //buffers: set_palette(redpalette); draw_dialog(30, 70, 290, 134, "Retreat!"); sprintf(temp, "Retreating to Level %d", nextlevel); mytext.write_y(92,temp, DARK_BLUE, 1); sprintf(temp,"(You may take this field later)"); mytext.write_y(100,temp, DARK_BLUE, 1); mytext.write_y(110,"**PRESS 'ESC' TO RETURN TO THE MENUS.**", DARK_BLUE, 1); buffer_to_screen(0, 0, 320, 200); clear_keyboard(); while (!endkeys[SDLK_ESCAPE]) get_input_events(WAIT); //while (query_key() != SDLK_ESCAPE); end = 1; } } else if (ending == SCEN_TYPE_SAVE_ALL) // failed to save a guy { //buffers: we will port the red pal stuff later //buffers: set_palette(redpalette); //draw_button(30,82,290,122,4); draw_dialog(30, 70, 290, 134, "Defeat!"); mytext.write_y(92,"YOU ARE DEFEATED", DARK_BLUE, 1); sprintf(temp,"(YOU FAILED TO KEEP THE NPC'S ALIVE)" ); mytext.write_y(100,temp, DARK_BLUE, 1); mytext.write_y(110,"**PRESS 'ESC' TO RETURN TO THE MENUS.**", DARK_BLUE, 1); buffer_to_screen(0, 0, 320, 200); while (query_key() != SDLK_ESCAPE) ; end = 1; } else if (ending == 0) // we won { //buffers: we will port the red pal stuff later //buffers: set_palette(redpalette); if (levelstatus[scen_num] == 1) // this scenario is completed .. { draw_dialog(30, 70, 290, 134, "Traveling On.."); // Zardus: FIX: what the hell is this supposed to mean? // sprintf(temp,"(Field Already Won)", allscore); sprintf(temp, "(Field Already Won)"); mytext.write_y(100,temp, DARK_BLUE, 1); } else { draw_dialog(30, 70, 290, 134, "Victory!"); mytext.write_y(92,"YOU WIN.", DARK_BLUE, 1); sprintf(temp,"YOUR SCORE IS %ld.\n", allscore); mytext.write_y(100,temp, DARK_BLUE, 1); } mytext.write_y(120,"**PRESS 'ESC' TO CONTINUE.**", DARK_BLUE, 1); // Save the game status to a temp file (savetemp.gtl) for (i=0; i < 4; i++) { m_totalscore[i] += m_score[i]; m_totalcash[i] += (m_score[i]*2); } for (i=0; i < 4; i++) { bonuscash[i] = (m_score[i] * (TIME_BONUS + ((long)par_value * LEVEL_BONUS) - framecount))/(TIME_BONUS + ( ((long)par_value * LEVEL_BONUS)/2)); if (bonuscash[i] < 0 || framecount > TIME_BONUS) // || framecount < 0) bonuscash[i] = 0; m_totalcash[i] += bonuscash[i]; allbonuscash += bonuscash[i]; } if (levelstatus[scen_num] == 1) // already won, no bonus { for (i=0; i < 4; i++) bonuscash[i] = 0; allbonuscash = 0; } sprintf(temp,"YOUR TIME BONUS IS %ld.\n",allbonuscash); mytext.write_y(110,temp, DARK_BLUE, 1); buffer_to_screen(0, 0, 320, 200); // Save the level to disk .. levelstatus[scen_num] = 1; // this scenario is completed .. if (nextlevel != -1) scen_num = (short) (nextlevel-1); // Fake jumping to next level .. save_game("save0", this); // Zardus: FIX: get_input_events should really be used instead of query_key while waiting for // actions while (!endkeys[SDLK_ESCAPE]) get_input_events(WAIT); // pause // Check for guys who have gone up levels if (checklist) // should always be true, but just in case { while (checklist) { if (checklist->ob) target = checklist->ob; else target = NULL; if (target && target->team_num==0 && target->query_order()==ORDER_LIVING && !target->dead && target->myguy && target->myguy->level != calculate_level(target->myguy->exp) ) // check for living guy on our team, with guy pointer { //draw_button(30,82,290,132,4); if (target->myguy->level < calculate_level(target->myguy->exp)) { draw_dialog(30, 70, 290, 134, "Congratulations!"); sprintf(temp, "%s reached level %ld", target->myguy->name, calculate_level(target->myguy->exp) ); } else // we lost levels :> { draw_dialog(30, 70, 290, 134, "Alas!"); sprintf(temp, "%s fell to level %ld", target->myguy->name, calculate_level(target->myguy->exp) ); } mytext.write_y(100,temp, DARK_BLUE, 1); test1 = calculate_level(target->myguy->exp) - 1; if ( !(test1%3) ) // we're on a special-gaining level { test1 = (test1 / 3) + 1; // this is the special # if ( (test1 <= 4) // raise this when we have more than 4 specials && (strcmp(special_name[target->query_family()][test1], "NONE") ) ) { sprintf(temp, "New Ability: %s!", special_name[target->query_family()][test1]); mytext.write_y(110, temp, DARK_BLUE, 1); } } mytext.write_y(120,"PRESS ESC TO CONTINUE", DARK_BLUE, 1); buffer_to_screen(0, 0, 320, 200); clear_keyboard(); wait_for_key(SDLK_ESCAPE); //while (query_key() != SDLK_ESCAPE); } checklist = checklist->next; } // end of while checklist } // end of full 'check for raised levels' routine end = 1; } return 1; } walker *screen::find_near_foe(walker *ob) { short targx, targy; oblink *here; short spread=1,xchange=0; short loop=0; short resolution = myobmap->obmapres; if (!ob) { printf("no ob in find near foe.\n"); return NULL; } targx = ob->xpos; targy = ob->ypos; spread = 1; while (spread < MAX_SPREAD) { for (loop=0;loop=pixmaxx) return find_far_foe(ob); //right edge of screen } else { targy += resolution; //changex is odd if (targy<=0) return find_far_foe(ob); //top of screen if (targy>=pixmaxy) return find_far_foe(ob); //bottom of screen } here = myobmap->obmap_get_list(targx,targy); while(here) //go through the list we received { if (here->ob && !(here->ob->dead) && (ob->is_friendly(here->ob)==0) && (random(here->ob->invisibility_left/20)==0) ) { if (here->ob->query_order() == ORDER_LIVING || here->ob->query_order() == ORDER_GENERATOR) //done separately since they are logically more significant return here->ob; // this should be a valid foe } here=here->next; }//end inner while }//end for xchange++; //change whether we do x or y in each for loop if (!(xchange%2)) { resolution = (short) (-resolution); // reverse direction around the search every other for spread++; // increase the search width every other for } }//end while //failure return find_far_foe(ob); } walker *screen::find_far_foe(walker *ob) { short targx, targy; long distance, tempdistance; oblink *here; walker *foe, *endfoe; if (!ob) { printf("no ob in find far foe.\n"); return NULL; } here = oblist; // Get list of all screen objects // Get our current coordinates targx = ob->xpos; targy = ob->ypos; // Set our 'default' foe to NULL endfoe = NULL; distance = 10000; ob->stats->last_distance = 10000; while (here) { if (here->ob && !here->ob->dead) foe = here->ob; // For easier referencing else foe = NULL; // Check for valid objects .. if (foe && (ob->is_friendly(foe)==0) ) { if ( (foe->query_order() == ORDER_LIVING || foe->query_order() == ORDER_GENERATOR) && (!(random(here->ob->invisibility_left/20))) ) { tempdistance = ob->distance_to_ob(foe); if (tempdistance < distance) { distance = tempdistance; endfoe = foe; } } } here = here->next; } return endfoe; } char* screen::get_scen_title(char *filename, screen *master) { FILE *infile = NULL; char temptext[10] = "XXX"; char tempfile[80] = "x.x"; char versionnumber = 0; enum {notfound, file, pack} gotit = notfound; static char buffer[30]; // Open the pixie-pack, if not already done ... if (!scenpack.opened()) { if (scenpack.open("levels.001") == -1) // not in current directory { return "none"; } } strcpy(tempfile, filename); strcat(tempfile, ".fss"); // Zardus: first get the file from scen/, then the packfile if ((infile = open_misc_file(tempfile, "scen/"))) gotit = file; else if (scenpack.opened()) { infile = scenpack.get_subfile(tempfile); if (infile) gotit = pack; else return "none"; } // Are we a scenario file? fread(temptext, 3, 1, infile); if (strcmp(temptext, "FSS")) { return "none"; } // Check the version number fread(&versionnumber, 1, 1, infile); if (versionnumber < 6) return "none"; // Discard the grid name ... fread(buffer, 8, 1, infile); // Return the title, 30 bytes fread(buffer, 30, 1, infile); if (gotit == file) fclose(infile); return buffer; } //buffers: the file finding and loading code is pretty ugly... i should //buffers: rewrite it... short load_scenario(char * filename, screen * master) { FILE *infile = NULL; char temptext[10] = "XXX"; char versionnumber = 0; long gotit; short tempvalue; string thefile(filename); // Open the pixie-pack, if not already done ... if (!scenpack.opened()) { if (scenpack.open("levels.001") == -1) // doesn't exist { load_and_set_palette("our.pal", myscreen->ourpalette); printf("Cannot open levels resource file!\n"); release_keyboard(); exit(0); } } //buffers: first look for the scenario in scen/, then in levels.001 //buffers: the file thefile += ".fss"; lowercase(thefile); gotit = 0; // Zaradus: much much better this way if ( (infile = open_misc_file((char *)thefile.c_str(), "scen/"))) { gotit = 1; } printf("Looking for %s\n", thefile.c_str()); //buffers: second, try to get the file from levels.001 if(!infile && scenpack.opened()) if ((infile = scenpack.get_subfile((char *)thefile.c_str()))) gotit = 1; if(gotit == 0 || !infile) { //printf("DEBUG: scenario %s was not found in levels.001 or in scen/ -- EXITING\n",temp); return 0; } // Are we a scenario file? fread(temptext, 3, 1, infile); if (strcmp(temptext, "FSS")) { printf("File %s is not a scenario!\n", filename); return 0; } master->scenario_type = 0; // default unless overridden strcpy(master->scenario_title, "none"); // default // Check the version number fread(&versionnumber, 1, 1, infile); switch (versionnumber) { case 2: tempvalue = load_version_2(infile, master); if (!gotit) fclose(infile); return tempvalue; //break; case 3: tempvalue = load_version_3(infile, master); if (!gotit) fclose(infile); return tempvalue; //break; case 4: tempvalue = load_version_4(infile, master); if (!gotit) fclose(infile); return tempvalue; //break; case 5: tempvalue = load_version_5(infile, master); if (!gotit) fclose(infile); return tempvalue; case 6: tempvalue = load_version_6(infile, master); if (!gotit) fclose(infile); return tempvalue; case 7: tempvalue = load_version_6(infile, master, 7); if (!gotit) fclose(infile); return tempvalue; case 8: tempvalue = load_version_6(infile, master, 8); if (!gotit) fclose(infile); return tempvalue; default: printf("Scenario %s is version-level %d, and cannot be read.\n", filename, versionnumber); if (!gotit) fclose(infile); //return 0; break; } return 1; } short load_version_2(FILE *infile, screen * master) { short currentx, currenty; unsigned char temporder, tempfamily; unsigned char tempteam; char tempfacing, tempcommand; char tempreserved[20]; short listsize; short i; walker * new_guy; char newgrid[12] = "grid.pix"; // default grid // Format of a scenario object list file version 2 is: // 3-byte header: 'FSS' // 1-byte version # // ----- (above is already determined by now) // 8-byte string = grid name to load // 2-bytes (short) = total objects to follow // List of n objects, each of 7-bytes of form: // 1-byte ORDER // 1-byte FAMILY // 2-byte short xpos // 2-byte short ypos // 1-byte TEAM // 1-byte facing // 1-byte command // --- // 11 bytes reserved //printf("LV2: START\n"); // Get grid file to load fread(newgrid, 8, 1, infile); //buffers: PORT: make sure grid name is lowercase lowercase((char *)newgrid); strcpy(my_map_name, newgrid); // Determine number of objects to load ... fread(&listsize, 2, 1, infile); //gotoxy(1,1); //printf("Objects in file: %d ", listsize); //wait_for_key(SDLK_SPACE); // Now read in the objects one at a time for (i=0; i < listsize; i++) { fread(&temporder, 1, 1, infile); fread(&tempfamily, 1, 1, infile); fread(¤tx, 2, 1, infile); fread(¤ty, 2, 1, infile); fread(&tempteam, 1, 1, infile); fread(&tempfacing, 1, 1, infile); fread(&tempcommand, 1, 1, infile); fread(tempreserved, 11, 1, infile); if (temporder == ORDER_TREASURE) new_guy = master->add_fx_ob(temporder, tempfamily); // create new object else new_guy = master->add_ob(temporder, tempfamily); // create new object if (!new_guy) { printf("Error creating object!\n"); wait_for_key(SDLK_SPACE); return 0; } new_guy ->setxy(currentx, currenty); // printf("X: %d Y: %d \n", currentx, currenty); new_guy ->team_num = tempteam; } //printf("Read %d objects.\n", listsize); //wait_for_key(SDLK_SPACE); //fclose(infile); // Now read the grid file to our master screen .. strcat(newgrid, ".pix"); master->grid = read_pixie_file(newgrid); master->maxx = master->grid[1]; master->maxy = master->grid[2]; master->pixmaxx = master->maxx * GRID_SIZE; master->pixmaxy = master->maxy * GRID_SIZE; master->grid += 3; //printf("LV2: read grid %s\n", newgrid); //wait_for_key(SDLK_SPACE); // This is a hack because we don't know where else it is loaded. // if (master->myradar[0]) // { // printf("LV2: deleting old radar\n"); // delete master->myradar; // printf("LV2: deleted old radar\n"); // } // if (master->numviews == 1) // master->myradar[0] = new radar(master->grid, master->maxx, master->maxy, // 249, 145, 0, master); // else // { // master->myradar[0] = new radar(master->grid, master->maxx, master->maxy, // 249, 10, 0, master); // master->myradar[1] = new radar(master->grid, master->maxx, master->maxy, // 249-153, 10, 1, master); // } // printf("Read grid file\n"); // wait_for_key(SDLK_SPACE); return 1; } // Version 3 scenarios have a block of text which can be displayed // at the start, etc. Format is // # of lines, // 1-byte character width // n bytes specified from above short load_version_3(FILE *infile, screen * master) { short currentx, currenty; unsigned char temporder, tempfamily; unsigned char tempteam; char tempfacing, tempcommand; char templevel; char tempreserved[20]; short listsize; short i; walker * new_guy; char newgrid[12] = "grid.pix"; // default grid char oneline[80]; char numlines, tempwidth; // Format of a scenario object list file version 2 is: // 3-byte header: 'FSS' // 1-byte version # // ----- (above is already determined by now) // 8-byte string = grid name to load // 2-bytes (short) = total objects to follow // List of n objects, each of 7-bytes of form: // 1-byte ORDER // 1-byte FAMILY // 2-byte short xpos // 2-byte short ypos // 1-byte TEAM // 1-byte facing // 1-byte command // 1-byte level // --- // 10 bytes reserved // 1-byte # of lines of text to load // List of n lines of text, each of form: // 1-byte character width of line // m bytes == characters on this line // Get grid file to load fread(newgrid, 8, 1, infile); //buffers: PORT: make sure grid name is lowercase lowercase((char *)newgrid); strcpy(my_map_name, newgrid); // Determine number of objects to load ... fread(&listsize, 2, 1, infile); // Now read in the objects one at a time for (i=0; i < listsize; i++) { fread(&temporder, 1, 1, infile); fread(&tempfamily, 1, 1, infile); fread(¤tx, 2, 1, infile); fread(¤ty, 2, 1, infile); fread(&tempteam, 1, 1, infile); fread(&tempfacing, 1, 1, infile); fread(&tempcommand, 1, 1, infile); fread(&templevel, 1, 1, infile); fread(tempreserved, 10, 1, infile); if (temporder == ORDER_TREASURE) // new_guy = master->add_fx_ob(temporder, tempfamily); // create new object new_guy = master->add_ob(temporder, tempfamily, 1); // add to top of list else new_guy = master->add_ob(temporder, tempfamily); // create new object if (!new_guy) { printf("Error creating object!\n"); wait_for_key(SDLK_SPACE); return 0; } new_guy->setxy(currentx, currenty); new_guy->team_num = tempteam; new_guy->stats->level = templevel; } // Now get the lines of text to read .. fread(&numlines, 1, 1, infile); master->scentextlines = numlines; //master->(*scentext) = new char(numlines); for (i=0; i < numlines; i++) { fread(&tempwidth, 1, 1, infile); fread(oneline, tempwidth, 1, infile); oneline[tempwidth] = 0; strcpy(master->scentext[i], oneline); } //fclose(infile); // Now read the grid file to our master screen .. strcat(newgrid, ".pix"); master->grid = read_pixie_file(newgrid); master->maxx = master->grid[1]; master->maxy = master->grid[2]; master->pixmaxx = master->maxx * GRID_SIZE; master->pixmaxy = master->maxy * GRID_SIZE; master->grid += 3; // This is a hack because we don't know where else it is loaded. // if (master->myradar[0]) // { // } // if (master->numviews == 1) // master->myradar[0] = new radar(master->grid, master->maxx, master->maxy, // 249, 145, 0, master); // else // { // master->myradar[0] = new radar(master->grid, master->maxx, master->maxy, // 249, 10, 0, master); // master->myradar[1] = new radar(master->grid, master->maxx, master->maxy, // 249-153, 10, 1, master); // } return 1; } // Version 4 scenarios include a 12-byte name for EVERY walker.. short load_version_4(FILE *infile, screen * master) { short currentx, currenty; unsigned char temporder, tempfamily; unsigned char tempteam; char tempfacing, tempcommand; char templevel; char tempreserved[20]; short listsize; short i; walker * new_guy; char newgrid[12] = "grid.pix"; // default grid char oneline[80]; char numlines, tempwidth; char tempname[12]; // Format of a scenario object list file version 4 is: // 3-byte header: 'FSS' // 1-byte version # // ----- (above is already determined by now) // 8-byte string = grid name to load // 2-bytes (short) = total objects to follow // List of n objects, each of 7-bytes of form: // 1-byte ORDER // 1-byte FAMILY // 2-byte short xpos // 2-byte short ypos // 1-byte TEAM // 1-byte facing // 1-byte command // 1-byte level // 12-bytes name // --- // 10 bytes reserved // 1-byte # of lines of text to load // List of n lines of text, each of form: // 1-byte character width of line // m bytes == characters on this line // Get grid file to load fread(newgrid, 8, 1, infile); //buffers: PORT: make sure grid name is lowercase lowercase((char *)newgrid); strcpy(my_map_name, newgrid); // Determine number of objects to load ... fread(&listsize, 2, 1, infile); // Now read in the objects one at a time for (i=0; i < listsize; i++) { fread(&temporder, 1, 1, infile); fread(&tempfamily, 1, 1, infile); fread(¤tx, 2, 1, infile); fread(¤ty, 2, 1, infile); fread(&tempteam, 1, 1, infile); fread(&tempfacing, 1, 1, infile); fread(&tempcommand, 1, 1, infile); fread(&templevel, 1, 1, infile); fread(tempname, 12, 1, infile); fread(tempreserved, 10, 1, infile); if (temporder == ORDER_TREASURE) //new_guy = master->add_ob(temporder, tempfamily, 1); // add to top of list new_guy = master->add_fx_ob(temporder, tempfamily); else new_guy = master->add_ob(temporder, tempfamily); // create new object if (!new_guy) { printf("Error creating object!\n"); wait_for_key(SDLK_SPACE); return 0; } new_guy->setxy(currentx, currenty); new_guy->team_num = tempteam; new_guy->stats->level = templevel; strcpy(new_guy->stats->name, tempname); if (strlen(tempname) > 1) //chad 5/25/95 new_guy->stats->set_bit_flags(BIT_NAMED, 1); } // Now get the lines of text to read .. fread(&numlines, 1, 1, infile); master->scentextlines = numlines; //master->(*scentext) = new char(numlines); for (i=0; i < numlines; i++) { fread(&tempwidth, 1, 1, infile); fread(oneline, tempwidth, 1, infile); oneline[tempwidth] = 0; strcpy(master->scentext[i], oneline); } //fclose(infile); // Now read the grid file to our master screen .. strcat(newgrid, ".pix"); master->grid = read_pixie_file(newgrid); master->maxx = master->grid[1]; master->maxy = master->grid[2]; master->pixmaxx = master->maxx * GRID_SIZE; master->pixmaxy = master->maxy * GRID_SIZE; master->grid += 3; // This is a hack because we don't know where else it is loaded. // if (master->myradar[0]) // { // } // if (master->numviews == 1) // master->myradar[0] = new radar(master->grid, master->maxx, master->maxy, // 249, 145, 0, master); // else // { // master->myradar[0] = new radar(master->grid, master->maxx, master->maxy, // 249, 10, 0, master); // master->myradar[1] = new radar(master->grid, master->maxx, master->maxy, // 249-153, 10, 1, master); // } return 1; } // end load_version_4 // Version 5 scenarios include a 1-byte 'scenario-type' specifier after // the grid name. short load_version_5(FILE *infile, screen * master) { short currentx, currenty; unsigned char temporder, tempfamily; unsigned char tempteam; char tempfacing, tempcommand; char templevel; char tempreserved[20]; short listsize; short i; walker * new_guy; char newgrid[12] = "grid.pix"; // default grid char new_scen_type; // read the scenario type char oneline[80]; char numlines, tempwidth; char tempname[12]; oblink *here; // Format of a scenario object list file version 5 is: // 3-byte header: 'FSS' // 1-byte version # // ----- (above is already determined by now) // 8-byte string = grid name to load // 1-byte char = scenario type, default is 0 // 2-bytes (short) = total objects to follow // List of n objects, each of 7-bytes of form: // 1-byte ORDER // 1-byte FAMILY // 2-byte short xpos // 2-byte short ypos // 1-byte TEAM // 1-byte facing // 1-byte command // 1-byte level // 12-bytes name // --- // 10 bytes reserved // 1-byte # of lines of text to load // List of n lines of text, each of form: // 1-byte character width of line // m bytes == characters on this line // Get grid file to load fread(newgrid, 8, 1, infile); //buffers: PORT: make sure grid name is lowercase lowercase((char *)newgrid); strcpy(my_map_name, newgrid); // Get the scenario type information fread(&new_scen_type, 1, 1, infile); master->scenario_type = new_scen_type; // Determine number of objects to load ... fread(&listsize, 2, 1, infile); // Now read in the objects one at a time for (i=0; i < listsize; i++) { fread(&temporder, 1, 1, infile); fread(&tempfamily, 1, 1, infile); fread(¤tx, 2, 1, infile); fread(¤ty, 2, 1, infile); fread(&tempteam, 1, 1, infile); fread(&tempfacing, 1, 1, infile); fread(&tempcommand, 1, 1, infile); fread(&templevel, 1, 1, infile); fread(tempname, 12, 1, infile); fread(tempreserved, 10, 1, infile); if (temporder == ORDER_TREASURE) new_guy = master->add_fx_ob(temporder, tempfamily); else new_guy = master->add_ob(temporder, tempfamily); // create new object if (!new_guy) { printf("Error creating object! Press Space\n"); wait_for_key(SDLK_SPACE); //fclose(infile); return 0; } new_guy->setxy(currentx, currenty); new_guy->team_num = tempteam; new_guy->stats->level = templevel; strcpy(new_guy->stats->name, tempname); if (strlen(tempname) > 1) //chad 5/25/95 new_guy->stats->set_bit_flags(BIT_NAMED, 1); } // Now get the lines of text to read .. fread(&numlines, 1, 1, infile); master->scentextlines = numlines; //master->(*scentext) = new char(numlines); for (i=0; i < numlines; i++) { fread(&tempwidth, 1, 1, infile); fread(oneline, tempwidth, 1, infile); oneline[tempwidth] = 0; strcpy(master->scentext[i], oneline); } //fclose(infile); // Now read the grid file to our master screen .. strcat(newgrid, ".pix"); master->grid = read_pixie_file(newgrid); master->maxx = master->grid[1]; master->maxy = master->grid[2]; master->pixmaxx = master->maxx * GRID_SIZE; master->pixmaxy = master->maxy * GRID_SIZE; master->grid += 3; if (!mysmoother) mysmoother = new smoother(); mysmoother->set_target(master); // Fix up doors, etc. here = master->weaplist; while (here) { if (here->ob && here->ob->query_family()==FAMILY_DOOR) { if (mysmoother && mysmoother->query_genre_x_y(here->ob->xpos/GRID_SIZE, (here->ob->ypos/GRID_SIZE)-1)==TYPE_WALL) { here->ob->set_frame(1); // turn sideways .. } } here = here->next; } return 1; } // end load_version_5 // Version 6 includes a 30-byte scenario title after the grid name. // Also load version 7 and 8 here, since it's a simple change .. short load_version_6(FILE *infile, screen * master, short version) { short currentx, currenty; unsigned char temporder, tempfamily; unsigned char tempteam; char tempfacing, tempcommand; char templevel; short shortlevel; char tempreserved[20]; short listsize; short i; walker * new_guy; char newgrid[12] = "grid.pix"; // default grid char new_scen_type; // read the scenario type char oneline[80]; char numlines, tempwidth; char tempname[12]; oblink *here; char scentitle[30]; short temp_par; // Format of a scenario object list file version 6/7 is: // 3-byte header: 'FSS' // 1-byte version # // ----- (above is already determined by now) // 8-byte string = grid name to load // 30-byte scenario title (ver 6+) // 1-byte char = scenario type, default is 0 // 2-bytes par-value, v.8+ // 2-bytes (short) = total objects to follow // List of n objects, each of 7-bytes of form: // 1-byte ORDER // 1-byte FAMILY // 2-byte short xpos // 2-byte short ypos // 1-byte TEAM // 1-byte facing // 1-byte command // 1-byte level // 2 bytes in version 7+ // 12-bytes name // --- // 10 bytes reserved // 1-byte # of lines of text to load // List of n lines of text, each of form: // 1-byte character width of line // m bytes == characters on this line // Get grid file to load fread(newgrid, 8, 1, infile); // Zardus: FIX: make sure they're lowercased lowercase((char *)newgrid); strcpy(my_map_name, newgrid); // Get scenario title, if it exists for (i=0; i < strlen(scentitle); i++) scentitle[i] = 0; fread(scentitle, 30, 1, infile); strcpy(master->scenario_title, scentitle); // Get the scenario type information fread(&new_scen_type, 1, 1, infile); master->scenario_type = new_scen_type; if (version >= 8) { fread(&temp_par, 2, 1, infile); master->par_value = temp_par; } // else we're using the value of the level .. // Determine number of objects to load ... fread(&listsize, 2, 1, infile); // Now read in the objects one at a time for (i=0; i < listsize; i++) { fread(&temporder, 1, 1, infile); fread(&tempfamily, 1, 1, infile); fread(¤tx, 2, 1, infile); fread(¤ty, 2, 1, infile); fread(&tempteam, 1, 1, infile); fread(&tempfacing, 1, 1, infile); fread(&tempcommand, 1, 1, infile); if (version >= 7) fread(&shortlevel, 2, 1, infile); else fread(&templevel, 1, 1, infile); fread(tempname, 12, 1, infile); fread(tempreserved, 10, 1, infile); if (temporder == ORDER_TREASURE) new_guy = master->add_fx_ob(temporder, tempfamily); else new_guy = master->add_ob(temporder, tempfamily); // create new object if (!new_guy) { printf("Error creating object! Press Space\n"); wait_for_key(SDLK_SPACE); //fclose(infile); return 0; } new_guy->setxy(currentx, currenty); new_guy->team_num = tempteam; if (version >= 7) new_guy->stats->level = shortlevel; else new_guy->stats->level = templevel; strcpy(new_guy->stats->name, tempname); if (strlen(tempname) > 1) //chad 5/25/95 new_guy->stats->set_bit_flags(BIT_NAMED, 1); } // Now get the lines of text to read .. fread(&numlines, 1, 1, infile); master->scentextlines = numlines; //master->(*scentext) = new char(numlines); for (i=0; i < numlines; i++) { fread(&tempwidth, 1, 1, infile); fread(oneline, tempwidth, 1, infile); oneline[tempwidth] = 0; strcpy(master->scentext[i], oneline); } //fclose(infile); // Now read the grid file to our master screen .. strcat(newgrid, ".pix"); master->grid = read_pixie_file(newgrid); master->maxx = master->grid[1]; master->maxy = master->grid[2]; master->pixmaxx = master->maxx * GRID_SIZE; master->pixmaxy = master->maxy * GRID_SIZE; master->grid += 3; if (!mysmoother) mysmoother = new smoother(); mysmoother->set_target(master); // Fix up doors, etc. here = master->weaplist; while (here) { if (here->ob && here->ob->query_family()==FAMILY_DOOR) { if (mysmoother && mysmoother->query_genre_x_y(here->ob->xpos/GRID_SIZE, (here->ob->ypos/GRID_SIZE)-1)==TYPE_WALL) { here->ob->set_frame(1); // turn sideways .. } } here = here->next; } return 1; } // end load_version_5 char * query_my_map_name() { return my_map_name; } // Look for the first non-dead instance of a given walker .. walker * screen::first_of(unsigned char whatorder, unsigned char whatfamily, int team_num) { oblink * here = oblist; if (!here) return NULL; while (here) { if (here->ob && !here->ob->dead) { if (here->ob->query_order() == whatorder && here->ob->query_family()== whatfamily) { if (team_num == -1 || team_num == here->ob->team_num) return here->ob; } } here = here->next; } return NULL; } walker * screen::get_new_control() { oblink * here; here = oblist; while(here) { if (here->ob && here->ob->query_order() == ORDER_LIVING && here->ob->query_act_type() != ACT_CONTROL && here->ob->team_num == my_team) break; here = here->next; } if (!here) { endgame(1); return NULL; } return NULL; } void screen::draw_panels(short howmany) { short i; // Force a memory clear .. clearbuffer(); if (howmany) howmany = howmany; for (i=0; i < numviews; i++) if ( (viewob[i]->prefs[PREF_VIEW] == PREF_VIEW_FULL) || numviews == 4 ) ; // do nothing else { draw_button(viewob[i]->xloc-4, viewob[i]->yloc-3, viewob[i]->endx+3, viewob[i]->endy+3, 3, 1); draw_box(viewob[i]->xloc-1, viewob[i]->yloc-1, viewob[i]->endx, viewob[i]->endy, 0, 0,1); } redraw(); // repaint the screen area .. buffer_to_screen(0, 0, 320, 200); } // This can be slow, so don't call it much walker * screen::find_nearest_blood(walker *who) { oblink *here; long distance, newdistance; walker *returnob = NULL; here = fxlist; if (!who) return NULL; distance = 800; while (here) { if (here->ob && here->ob->query_order() == ORDER_TREASURE && here->ob->query_family() == FAMILY_STAIN && !here->ob->dead) { newdistance = (unsigned long) who->distance_to_ob_center(here->ob); if (newdistance < distance) { distance = newdistance; returnob = here->ob; } } here = here->next; } return returnob; } oblink* screen::find_in_range(oblink *somelist, long range, short *howmany, walker *ob) { oblink *here; oblink *newlist, *newhere; short obx, oby; unsigned long distance; if (!somelist || !ob) { *howmany = 0; return NULL; } obx = (short) (ob->xpos + (ob->sizex/2) ); // center of object oby = (short) (ob->ypos + (ob->sizey/2) ); here = somelist; newlist = NULL; *howmany = 0; while (here) { if (here->ob && !here->ob->dead) { distance = (unsigned long) ob->distance_to_ob(here->ob); if (distance <= (unsigned long) range) { if (newlist) // existing list .. { newhere = newlist; while(newhere->next) newhere = newhere->next; newhere->next = new oblink; newhere = newhere->next; } else // new list is null, first on the list { newhere = new oblink; newlist = newhere; } newhere->next = NULL; newhere->ob = here->ob; *howmany = (short) (*howmany + 1); } // end of valid distance check } // end of valid here->ob check here = here->next; } // end of while loop return newlist; } walker* screen::find_nearest_player(walker *ob) { oblink *here; walker *returnob = NULL; unsigned long distance = 32000; unsigned long tempdistance; if (!ob) return NULL; here = oblist; while (here) { if (here->ob && (here->ob->user != -1) ) { tempdistance = ob->distance_to_ob(here->ob); if (tempdistance < distance) { distance = tempdistance; returnob = here->ob; } } here = here->next; } return returnob; } oblink* screen::find_foes_in_range(oblink *somelist, long range, short *howmany, walker *ob) { oblink *here; oblink *newlist, *newhere; unsigned long distance; if (!somelist || !ob) { *howmany = 0; return NULL; } here = somelist; newlist = NULL; *howmany = 0; while (here) { if (here->ob && !here->ob->dead && (here->ob->query_order() == ORDER_LIVING || here->ob->query_order() == ORDER_GENERATOR) && (ob->is_friendly(here->ob) == 0) ) { distance = (unsigned long) ob->distance_to_ob(here->ob); if (distance <= (unsigned long) range) { if (newlist) // existing list .. { newhere = newlist; while(newhere->next) newhere = newhere->next; newhere->next = new oblink; newhere = newhere->next; } else // new list is null, first on the list { newhere = new oblink; newlist = newhere; } newhere->next = NULL; newhere->ob = here->ob; *howmany = (short) (*howmany + 1); } // end of valid distance check } // end of valid here->ob check here = here->next; } // end of while loop return newlist; } oblink* screen::find_friends_in_range(oblink *somelist, long range, short *howmany, walker *ob) { oblink *here; oblink *newlist, *newhere; short obx, oby; unsigned long distance; if (!somelist || !ob) { *howmany = 0; return NULL; } obx = (short) (ob->xpos + (ob->sizex/2) ); // center of object oby = (short) (ob->ypos + (ob->sizey/2) ); here = somelist; newlist = NULL; *howmany = 0; while (here) { if (here->ob && !here->ob->dead && here->ob->query_order() == ORDER_LIVING && ( ob->is_friendly(here->ob) ) ) { distance = (unsigned long) ob->distance_to_ob(here->ob); if (distance <= (unsigned long) range) { if (newlist) // existing list .. { newhere = newlist; while(newhere->next) newhere = newhere->next; newhere->next = new oblink; newhere = newhere->next; } else // new list is null, first on the list { newhere = new oblink; newlist = newhere; } newhere->next = NULL; newhere->ob = here->ob; *howmany = (short) (*howmany + 1); } // end of valid distance check } // end of valid here->ob check here = here->next; } // end of while loop return newlist; } oblink* screen::find_foe_weapons_in_range(oblink *somelist, long range, short *howmany, walker *ob) { oblink *here; oblink *newlist, *newhere; unsigned long distance; if (!somelist || !ob) { *howmany = 0; return NULL; } here = somelist; newlist = NULL; *howmany = 0; while (here) { if (here->ob && !here->ob->dead && (here->ob->query_order() == ORDER_WEAPON) && ( ob->is_friendly(here->ob) ) ) { distance = (unsigned long) ob->distance_to_ob(here->ob); if (distance <= (unsigned long) range) { if (newlist) // existing list .. { newhere = newlist; while(newhere->next) newhere = newhere->next; newhere->next = new oblink; newhere = newhere->next; } else // new list is null, first on the list { newhere = new oblink; newlist = newhere; } newhere->next = NULL; newhere->ob = here->ob; *howmany = (short) (*howmany + 1); } // end of valid distance check } // end of valid here->ob check here = here->next; } // end of while loop return newlist; } // Uses pixel coordinates char screen::damage_tile(short xloc, short yloc) // damage the specified tile { short xover, yover; short gridloc; xover = (short) (xloc / GRID_SIZE); yover = (short) (yloc / GRID_SIZE); if (xover < 0 || yover < 0) return 0; if (xover >= maxx || yover >= maxy) return 0; gridloc = (short) (yover*maxx+xover); switch (grid[gridloc]) { case PIX_GRASS1: // grass case PIX_GRASS2: case PIX_GRASS3: case PIX_GRASS4: grid[gridloc] = PIX_GRASS1_DAMAGED; break; default: break; } return grid[gridloc]; } void screen::do_notify(char *message, walker *who) { short i,sent=0; for(i=0;icontrol == who) { viewob[i]->set_display_text(message,STANDARD_TEXT_TIME); sent = 1; } } if (!sent) for (i=0; i < numviews; i++) viewob[i]->set_display_text(message,STANDARD_TEXT_TIME); } void screen::report_mem() { meminfo Memory; // Zardus: PORT: this is aparently an incomplete type: union REGS regs; // Same here: struct SREGS sregs; char memreport[80]; // Zardus: PORT: Undeclared because of problems above: regs.x.eax = 0x00000500; // Same here: memset( &sregs, 0, sizeof(sregs) ); // See two lines up: sregs.es = FP_SEG( &Memory ); // See three lines up: regs.x.edi = FP_OFF( &Memory ); // See two lines up: (plus sounds like a dos thing): int386x( DPMI_INT, ®s, ®s, &sregs ); // Them: //sprintf(memreport, "Largest Block: %lu bytes", // Memory.LargestBlockAvail); //viewob[0]->set_display_text(memreport, STANDARD_TEXT_TIME); sprintf(memreport, "Free Linear address: %u pages", Memory.FreeLinAddrSpace); // printf(memreport); // printf("\n"); viewob[0]->set_display_text(memreport, 25); /* printf( "Largest available block (in bytes): %lu\n", MemInfo.LargestBlockAvail ); printf( "Maximum unlocked page allocation: %lu\n", MemInfo.MaxUnlockedPage ); printf( "Pages that can be allocated and locked: " "%lu\n", MemInfo.LargestLockablePage ); printf( "Total linear address space including " "allocated pages: %lu\n", MemInfo.LinAddrSpace ); printf( "Number of free pages available: %lu\n", MemInfo.NumFreePagesAvail ); printf( "Number of physical pages not in use: %lu\n", MemInfo.NumPhysicalPagesFree ); printf( "Total physical pages managed by host: %lu\n", MemInfo.TotalPhysicalPages ); printf( "Free linear address space (pages): %lu\n", MemInfo.FreeLinAddrSpace ); printf( "Size of paging/file partition (pages): %lu\n", MemInfo.SizeOfPageFile ); */ }