/* 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 */ #include "graph.h" #include "smooth.h" #include "util.h" short next_scenario = 1; FILE * open_misc_file(char *, char *); FILE * open_misc_file(char *, char *, char *); short load_saved_game(char *filename, screen *myscreen) { char scenfile[20]; guy *temp_guy; walker *temp_walker, *replace_walker; oblink * here; short myord, myfam; int multi_team = 0; int i; // First load the team list .. if (!load_team_list(filename, myscreen)) { printf("Error loading saved game %s.\n", filename); release_keyboard(); exit(0); } // Determine the scenario name to load sprintf(scenfile, "scen%d", next_scenario); // And our default par value .. myscreen->par_value = next_scenario; // And load the scenario .. if (!load_scenario(scenfile, myscreen)) { myscreen->par_value = 1; load_scenario("scen0", myscreen); myscreen->scen_num = 0; mysmoother->set_target(myscreen); } mysmoother->set_target(myscreen); here = myscreen->oblist; while (here) { if (here->ob) here->ob->set_difficulty((unsigned long)here->ob->stats->level); here = here->next; } // Cycle through the team list .. temp_guy = myscreen->first_guy; while (temp_guy) { temp_walker = myscreen->add_ob(ORDER_LIVING, temp_guy->family); temp_walker->myguy = temp_guy; temp_walker->stats->level = temp_guy->level; // Set hitpoints based on stats: temp_walker->stats->max_hitpoints = (short) (10 + (temp_guy->constitution*3 + ((temp_guy->strength)/2) + (short) (25*temp_guy->level)) ); temp_walker->stats->hitpoints = temp_walker->stats->max_hitpoints; // Set damage based on strength and level temp_walker->damage += (temp_guy->strength/4) + temp_guy->level + (temp_guy->dexterity/11); // Set magicpoints based on stats: temp_walker->stats->max_magicpoints = (short) (10 + (temp_guy->intelligence*3) + ( 25 * temp_guy->level) +(short) (temp_guy->dexterity) ); temp_walker->stats->magicpoints = temp_walker->stats->max_magicpoints; // Set our armor level .. temp_walker->stats->armor =(short) ( temp_guy->armor + (temp_guy->dexterity / 14) + temp_guy->level ); // Set the heal delay .. temp_walker->stats->max_heal_delay = REGEN; temp_walker->stats->current_heal_delay = (temp_guy->constitution) + (temp_guy->strength/6) + (temp_guy->level * 2) + 20; //for purposes of calculation only while (temp_walker->stats->current_heal_delay > REGEN) { temp_walker->stats->current_heal_delay -= REGEN; temp_walker->stats->heal_per_round++; } // this takes care of the integer part, now calculate the fraction if (temp_walker->stats->current_heal_delay > 1) { temp_walker->stats->max_heal_delay /= (long) (temp_walker->stats->current_heal_delay + 1); } temp_walker->stats->current_heal_delay = 0; //start off without healing //make sure we have at least a 2 wait, otherwise we should have //calculated our heal_per_round as one higher, and the math must //have been screwed up some how if (temp_walker->stats->max_heal_delay < 2) temp_walker->stats->max_heal_delay = 2; // Set the magic delay .. temp_walker->stats->max_magic_delay = REGEN; temp_walker->stats->current_magic_delay = (long) (temp_guy->intelligence * 45) + (temp_guy->level*60) + (temp_guy->dexterity * 15) + 200; while (temp_walker->stats->current_magic_delay > REGEN) { temp_walker->stats->current_magic_delay -= REGEN; temp_walker->stats->magic_per_round++; } // this takes care of the integer part, now calculate the fraction if (temp_walker->stats->current_magic_delay > 1) { temp_walker->stats->max_magic_delay /= (long) (temp_walker->stats->current_magic_delay + 1); } temp_walker->stats->current_magic_delay = 0; //start off without magic regen //make sure we have at least a 2 wait, otherwise we should have //calculated our magic_per_round as one higher, and the math must //have been screwed up some how if (temp_walker->stats->max_magic_delay < 2) temp_walker->stats->max_magic_delay = 2; //stepsize makes us run faster, max for a non-weapon is 12 temp_walker->stepsize += (temp_guy->dexterity/54); if (temp_walker->stepsize > 12) temp_walker->stepsize = 12; temp_walker->normal_stepsize = temp_walker->stepsize; //fire_frequency makes us fire faster, min is 1 temp_walker->fire_frequency -= (temp_guy->dexterity / 47); if (temp_walker->fire_frequency < 1) temp_walker->fire_frequency = 1; // Fighters: limited weapons if (temp_walker->query_family() == FAMILY_SOLDIER) temp_walker->weapons_left = (short) ((temp_walker->stats->level+1) / 2); // Set our team number .. temp_walker->team_num = temp_guy->teamnum; temp_walker->real_team_num = 255; // Do we have guys on multiple teams? If so, we need // to record it so that we can set the controls of // the viewscreens correctly if (temp_guy->teamnum != 0) multi_team = 1; // First, try to find a marker that's the correct team number .. replace_walker = myscreen->first_of(ORDER_SPECIAL, FAMILY_RESERVED_TEAM, (int)temp_guy->teamnum); // If that doesn't work, though, grab any marker we can .. if (!replace_walker) replace_walker = myscreen->first_of(ORDER_SPECIAL, FAMILY_RESERVED_TEAM); if (replace_walker) { temp_walker->setxy(replace_walker->xpos, replace_walker->ypos); replace_walker->dead = 1; temp_guy = temp_guy->next; } else { // Scatter the overflowing characters.. temp_walker->teleport(); temp_guy = temp_guy->next; } } // Now remove any extra guys .. (set to dead) replace_walker = myscreen->first_of(ORDER_SPECIAL, FAMILY_RESERVED_TEAM); while (replace_walker) { replace_walker->dead = 1; replace_walker = myscreen->first_of(ORDER_SPECIAL, FAMILY_RESERVED_TEAM); } // Remove the links between 'guys' here = myscreen->oblist; while (here) { if (here->ob && here->ob->myguy) here->ob->myguy->next = NULL; here = here->next; } // Have we already done this scenario? if (myscreen->levelstatus[myscreen->scen_num]) { // printf("already done level\n"); here = myscreen->oblist; while (here) { if (here->ob) { myfam = here->ob->query_family(); myord = here->ob->query_order(); if ( ( (here->ob->team_num==0 || here->ob->myguy) && myord==ORDER_LIVING) || //living team member (myord==ORDER_TREASURE && myfam==FAMILY_EXIT) || // exit (myord==ORDER_TREASURE && myfam==FAMILY_TELEPORTER) // teleporters ) { // do nothing; legal guy } else here->ob->dead = 1; } here = here->next; } here = myscreen->weaplist; while (here) { if (here->ob) { myfam = here->ob->query_family(); myord = here->ob->query_order(); if ( (here->ob->team_num==0 && myord==ORDER_LIVING) || //living team member (myord==ORDER_TREASURE && myfam==FAMILY_EXIT) || // exit (myord==ORDER_TREASURE && myfam==FAMILY_TELEPORTER) // teleporters ) { // do nothing; legal guy } else here->ob->dead = 1; } here = here->next; } here = myscreen->fxlist; while (here) { if (here->ob) { myfam = here->ob->query_family(); myord = here->ob->query_order(); if ( (here->ob->team_num==0 && myord==ORDER_LIVING) || //living team member (myord==ORDER_TREASURE && myfam==FAMILY_EXIT) || // exit (myord==ORDER_TREASURE && myfam==FAMILY_TELEPORTER) // teleporters ) { // do nothing; legal guy } else here->ob->dead = 1; } here = here->next; } } // Here we decide if all players are controlling // team 0, or if they're playing competing teams .. if (multi_team) { for (i=0; i < myscreen->numviews; i++) myscreen->viewob[i]->my_team = i; } else { for (i=0; i < myscreen->numviews; i++) myscreen->viewob[i]->my_team = 0; } return 1; } short load_team_list(char * filename, screen *myscreen) { char filler[50] = "GTLGTLGTLGTLGTLGTLGTLGTLGTLGTLGTLGTLGTLGTL"; // for RESERVED FILE *infile; char temp_filename[80]; guy *temp_guy; char temptext[10] = "GTL"; char savedgame[40]; char temp_version = 7; unsigned long newcash; unsigned long newscore = 0; // short numguys; short listsize; short i; char tempname[12] = "FRED"; char guyname[12] = "JOE"; char temp_order, temp_family; short temp_str, temp_dex, temp_con; short temp_short, temp_arm, temp_lev; char numplayers; unsigned long temp_exp; short temp_kills; long temp_level_kills; long temp_td, temp_th, temp_ts; short temp_teamnum; // version 5+ short temp_allied; // v.7+ short temp_registered; // v.7+ // Format of a team list file is: // 3-byte header: 'GTL' // 1-byte version number // 2-bytes registered mark // Versions 7+ // 40-bytes saved game name, version 2 and up // 2-bytes (short) = scenario number // 4-bytes (long)= cash (unsigned) // 4-bytes (long)= score (unsigned) // 4-bytes (long)= cash-B (unsigned) // All alternate scores // 4-bytes (long)= score-B (unsigned) // version 6+ // 4-bytes (long)= cash-C (unsigned) // 4-bytes (long)= score-C (unsigned) // 4-bytes (long)= cash-D (unsigned) // 4-bytes (long)= score-D (unsigned) // 2-bytes Allied mode // Versions 7+ // 2-bytes (short) = # of team members in list // 1-byte number of players // 31-bytes RESERVED // List of n objects, each of 58-bytes of form: // 1-byte ORDER // 1-byte FAMILY // 12-byte name // 2-bytes strength // 2-bytes dexterity // 2-bytes constitution // 2-bytes intelligence // 2-bytes armor // 2-bytes level // 4-bytes unsigned experience // 2-bytes # kills, v.3 // 4-bytes # total levels killed, v.3 // 4-bytes total damage delt, v.4+ // 4-bytes total hits inflicted, v.4+ // 4-bytes total shots made, v.4+ // 2-bytes team number // 2*4 = 8 bytes RESERVED // List of 200 or 500 (max levels) 1-byte scenario-level status //strcpy(temp_filename, scen_directory); strcpy(temp_filename, filename); strcat(temp_filename, ".gtl"); // gladiator team list if ( (infile = open_misc_file(temp_filename, "save/")) == NULL ) { //gotoxy(1, 22); //printf("Error in opening team file: %s\n", filename); return 0; } // Read id header fread(temptext, 3, 1, infile); if ( strcmp(temptext,"GTL")) { fclose(infile); printf("Error, selected file is not a GTL file: %s\n",filename); return 0; //not a gtl file } // Read version number fread(&temp_version, 1, 1, infile); // Versions 7+ have a registered mark .. if (temp_version >= 7) { fread(&temp_registered, 2, 1, infile); } // Do other stuff based on version .. if (temp_version != 1) { if (temp_version >= 2) fread(savedgame, 40, 1, infile); // read and ignore the name else { fclose(infile); printf("Error, selected files is not version one: %s\n",filename); return 0; } } // Read scenario number fread(&next_scenario, 2, 1, infile); myscreen->scen_num = next_scenario; // Read cash fread(&newcash, 4, 1, infile); myscreen->totalcash = newcash; // Read score fread(&newscore, 4, 1, infile); myscreen->totalscore = newscore; // Versions 6+ have a score for each possible team, 0-3 if (temp_version >= 6) { for (i=0; i < 4; i++) { fread(&newcash, 4, 1, infile); myscreen->m_totalcash[i] = newcash; fread(&newscore, 4, 1, infile); myscreen->m_totalscore[i] = newscore; } } // Versions 7+ have the allied information .. if (temp_version >= 7) { fread(&temp_allied, 2, 1, infile); myscreen->allied_mode = temp_allied; } // Get # of guys to read fread(&listsize, 2, 1, infile); // Read (and ignore) the # of players fread(&numplayers, 1, 1, infile); // Read the reserved area, 31 bytes fread(filler, 31, 1, infile); // Okay, we've read header .. now read the team list data .. if (myscreen->first_guy) { delete myscreen->first_guy; // delete the old list of guys myscreen->first_guy = NULL; } // Make a new 'head' guy .. myscreen->first_guy = new guy(); temp_guy = myscreen->first_guy; while (listsize--) { // Get temp values to be read temp_order = ORDER_LIVING; // may be changed later // Read name of current guy... strcpy(guyname, tempname); // Set any chars under 12 not used to 0 .. for (i=(short) strlen(guyname); i < 12; i++) guyname[i] = 0; // Now write all those values fread(&temp_order, 1, 1, infile); fread(&temp_family,1, 1, infile); fread(guyname, 12, 1, infile); fread(&temp_str, 2, 1, infile); fread(&temp_dex, 2, 1, infile); fread(&temp_con, 2, 1, infile); fread(&temp_short, 2, 1, infile); fread(&temp_arm, 2, 1, infile); fread(&temp_lev, 2, 1, infile); fread(&temp_exp, 4, 1, infile); // Below here is version 3 and up.. fread(&temp_kills, 2, 1, infile); // how many kills we have fread(&temp_level_kills, 4, 1, infile); // levels of kills // Below here is version 4 and up .. fread(&temp_td, 4, 1, infile); // total damage fread(&temp_th, 4, 1, infile); // total hits fread(&temp_ts, 4, 1, infile); // total shots fread(&temp_teamnum, 2, 1, infile); // team number // And the filler fread(filler, 8, 1, infile); // Now set the values .. temp_guy->family = temp_family; strcpy(temp_guy->name,guyname); temp_guy->strength = temp_str; temp_guy->dexterity = temp_dex; temp_guy->constitution = temp_con; temp_guy->intelligence = temp_short; temp_guy->armor = temp_arm; temp_guy->level = temp_lev; temp_guy->exp = temp_exp; if (temp_version >=3) { temp_guy->kills = temp_kills; temp_guy->level_kills= temp_level_kills; } else // version 2 or earlier { temp_guy->kills = 0; temp_guy->level_kills= 0; } if (temp_version >= 4) { temp_guy->total_damage = temp_td; temp_guy->total_hits = temp_th; temp_guy->total_shots = temp_ts; } else { temp_guy->total_damage = 0; temp_guy->total_hits = 0; temp_guy->total_shots = 0; } if (temp_version >= 5) { temp_guy->teamnum = temp_teamnum; } else { temp_guy->teamnum = 0; } // Advance to the next guy .. if (listsize) { temp_guy->next = new guy(); temp_guy = temp_guy->next; } } if (temp_version >= 5) fread( (myscreen->levelstatus), 500, 1, infile); else { memset( (myscreen->levelstatus), 0, 500); fread((myscreen->levelstatus), 200, 1, infile); } fclose(infile); return 1; } short save_game(char * filename, screen *myscreen) { char filler[50] = "GTLGTLGTLGTLGTLGTLGTLGTLGTLGTLGTLGTLGTLGTL"; // for RESERVED FILE *outfile; char temp_filename[80]; oblink *here = myscreen->oblist; walker * temp_walker; char savedgame[40]; char temptext[10] = "GTL"; char temp_version = 7; short next_scenario = (short) ( myscreen->scen_num + 1 ); unsigned long newcash = myscreen->totalcash; unsigned long newscore = myscreen->totalscore; // short numguys; short listsize; short i; char guyname[12] = "JOE"; char temp_order, temp_family; short temp_str, temp_dex, temp_con; short temp_short, temp_arm, temp_lev; char numplayers = (char) myscreen->numviews; unsigned long temp_exp; short temp_kills; long temp_level_kills; long temp_td, temp_th, temp_ts; short temp_teamnum; short temp_allied; short temp_registered; // Format of a team list file is: // 3-byte header: 'GTL' // 1-byte version number // 2-bytes Registered or not // Version 7+ // 40-bytes saved-game name, dummy here // 2-bytes (short) = scenario number // 4-bytes (long)= cash (unsigned) // 4-bytes (long)= score (unsigned) // 4-bytes (long)= cash-B (unsigned) // All alternate scores // 4-bytes (long)= score-B (unsigned) // version 6+ // 4-bytes (long)= cash-C (unsigned) // 4-bytes (long)= score-C (unsigned) // 4-bytes (long)= cash-D (unsigned) // 4-bytes (long)= score-D (unsigned) // 2-bytes allied setting // Version 7+ // 2-bytes (short) = # of team members in list // 1-byte number of players // 31-bytes RESERVED // List of n objects, each of 58-bytes of form: // 1-byte ORDER // 1-byte FAMILY // 12-byte name // 2-bytes strength // 2-bytes dexterity // 2-bytes constitution // 2-bytes intelligence // 2-bytes armor // 2-bytes level // 4-bytes unsigned long experience // 2-bytes # kills, v.3+ // 4-bytes # total levels killed, v.3+ // 4-bytes total damage delt, v.4+ // 4-bytes total hits inflicted, v.4+ // 4-bytes total shots made, v.4+ // 2-bytes team number, v.5+ // 2*4 = 8 bytes RESERVED // List of 500 (max scenarios) 1-byte scenario-level status //strcpy(temp_filename, scen_directory); strcpy(temp_filename, filename); strcat(temp_filename, ".gtl"); // gladiator team list if ( (outfile = open_misc_file(temp_filename, "save/", "wb")) == NULL ) // open for write { //gotoxy(1, 22); printf("Error in writing team file %s\n", filename); return 0; } // Write id header fwrite(temptext, 3, 1, outfile); // Write version number fwrite(&temp_version, 1, 1, outfile); // Versions 7+ include a mark for registered or not temp_registered = 1; fwrite(&temp_registered, 2, 1, outfile); // Write the name fwrite(savedgame, 40, 1, outfile); // Write scenario number fwrite(&next_scenario, 2, 1, outfile); // Write cash fwrite(&newcash, 4, 1, outfile); // Write score fwrite(&newscore, 4, 1, outfile); // Versions 6+ have a score for each possible team for (i=0; i < 4; i++) { newcash = myscreen->m_totalcash[i]; fwrite(&newcash, 4, 1, outfile); newscore = myscreen->m_totalscore[i]; fwrite(&newscore, 4, 1, outfile); } // Versions 7+ include the allied mode information temp_allied = myscreen->allied_mode; fwrite(&temp_allied, 2, 1, outfile); // Determine size of team list ... listsize = 0; while (here) { if (here->ob && !here->ob->dead && here->ob->myguy) //if (here->ob && !here->ob->dead && here->ob->myguy && // (here->ob->real_team_num==0 || (here->ob->real_team_num==255 // && here->ob->team_num==0) // ) // ) listsize++; here = here->next; } //gotoxy(1, 22); //printf("Team size: %d ", listsize); fwrite(&listsize, 2, 1, outfile); fwrite(&numplayers, 1, 1, outfile); // Write the reserved area, 31 bytes fwrite(filler, 31, 1, outfile); // Okay, we've written header .. now dump the data .. here = myscreen->oblist; // back to head of list while (here) { if (here->ob && !here->ob->dead && here->ob->myguy) { temp_walker = here->ob; // Get temp values to be saved temp_order = temp_walker->query_order(); // may be changed later temp_family= temp_walker->query_family(); // Write name of current guy... strcpy(guyname, temp_walker->myguy->name); // Set any chars under 12 not used to 0 .. for (i=(short) strlen(guyname); i < 12; i++) guyname[i] = 0; temp_str = temp_walker->myguy->strength; temp_dex = temp_walker->myguy->dexterity; temp_con = temp_walker->myguy->constitution; temp_short = temp_walker->myguy->intelligence; temp_arm = temp_walker->myguy->armor; temp_lev = temp_walker->myguy->level; temp_exp = temp_walker->myguy->exp; // Version 3+ below here temp_kills = temp_walker->myguy->kills; temp_level_kills = temp_walker->myguy->level_kills; // Version 4+ below here temp_td = temp_walker->myguy->total_damage; temp_th = temp_walker->myguy->total_hits; temp_ts = temp_walker->myguy->total_shots; // Version 5+ below here temp_teamnum = temp_walker->myguy->teamnum; // Now write all those values fwrite(&temp_order, 1, 1, outfile); fwrite(&temp_family,1, 1, outfile); fwrite(guyname, 12, 1, outfile); fwrite(&temp_str, 2, 1, outfile); fwrite(&temp_dex, 2, 1, outfile); fwrite(&temp_con, 2, 1, outfile); fwrite(&temp_short, 2, 1, outfile); fwrite(&temp_arm, 2, 1, outfile); fwrite(&temp_lev, 2, 1, outfile); fwrite(&temp_exp, 4, 1, outfile); fwrite(&temp_kills, 2, 1, outfile); fwrite(&temp_level_kills, 4, 1, outfile); fwrite(&temp_td, 4, 1, outfile); fwrite(&temp_th, 4, 1, outfile); fwrite(&temp_ts, 4, 1, outfile); fwrite(&temp_teamnum, 2, 1, outfile); // And the filler fwrite(filler, 8, 1, outfile); } // Advance to the next guy .. here = here->next; } // Write the level status .. fwrite((myscreen->levelstatus), 500, 1, outfile); fclose(outfile); return 1; }