#include #include #include //#include #include #include #include //#include // // GCSET space combat game second pre-alpha version(under revision) // Being written by David M. "DaMiT" Turover // // To convert from DOS-workable to Unix-workable, rem the // include for dos.h, include unistd.h, and change all sleep // functions to usleep(x000000) where x is the number of seconds to sleep. // No other functions should need to be modified. // // Wanted done in this version: // // More than three ships per side! -*Done*; Now 4 ships per side // // More than one type of ship // // Move the beginning code out of main and into its // own little function -*Done* // // Get rid of some of the obsolete commentedout code, // probably will save upwards of 5k or more -*Done* // -*Undone* =P // -*Redone* // -*Reundone* // // In assign function, integrate the assign code for Your Ship into // the generic assignment code, and keep eyes open for similar bloat // -*Done* // // Find time between school crap to get some work done on it // after the semester starts -*can't be done* // // New objectives: // // Get rid of some global variables by making locals and passing // pointers to the locals instead of the whole variable.. Could do this // to firing and target. -*Done* // // Rework the computer targeting functions into one function, the second // one is only(and always) called once from the first already, might as // well be one function. -*Done* // // Get rid of all instances of recursion; Instead of having the program // jump back and forth between routines, encase in while loops that // are break controlled by values from returned functions // // Modify either the GC's values or fire(), the bridge is too good a target // -*Done* // // Fix the testing function to allow exit to run function when called // from beginning of game // // // Actually been done in this version: // // // Created "theship", an array of pointers directly to the ship structs, // allowing a pair of while loops to take care of most ship functions // instead of having to make a different if loop for each ship // // Added shipon, name and type values to the ship struct, thereby // making fshipon, fship1name, fship1type, and all similar values obsolete // Corralling these rogue values will make adding new ships far easier // // Made an array "numon" of length Max_Num_Sides. This array effectively // replaces numfr and numen, and allows for somewhat shorter code when // dealing with spawning the ships. It also will make things slightly // easier when battles of more than two sides are implemented. // // Created a new function, startnew, which contains all the setup code // for a new game that used to be in main. This doesn't change anything // now, but it will be nice to have already done it when I implement // preconfigured quests. // // Created a new function, quitfree, to free all malloced data. // // Changed the number of guns for the Generic Cruiser from 200 to 250 // Average gametime is down to 55-60 turns from 70-75.. Much better // Also changed the GC's armour points from 10k to 7.5k, reduced gameplay // time by about another dozen or so turns, then tweaked the firing function // and added some more turns back onto the gamelength. Changed the gc's gun // to-hit modifier to make it slightly harder to target a ship's guns. // // Broke 60k worth of code, 10/22/98. Willing to bet most of it's comments. // -*Note: Actually, only about 18k of it is the beginning remmage. - 10/31 // // Encased most of the startnew function inside a break-controlled while loop, // removed two instances of recursion, all apparent bugs caused by this fixed // // Added str values to ship struct, which will reflect the ship strength. // Created array of pointers baseship to the values of the original ships' // structures, the array is intended to be referenced by a ship's str number. // Wrote code to output ships' stats in percent after the battle. // Removed maxarm and maxeng from the ship struct // // Added an extra ship per side by incrementing maxperside, then adding the // ships, and then their pointers in theship[]. Not too hard, and most of the // code seemed to hold up. // // Cleaned up some "if 1 else if 2" code in youfire function. // // Broke 60k of code again(going the other way this time =), 10/31/98 // Highest was 62k. Filesize continues to fluctuate like the stock market. // 59.4k after this comment. 18k before revision. // // Created a method whereby the computer will pass up dead ships in its // targeting sequence. // // Changed firing, target, and lock to local variables. Made all shipcheck // variables local, shortened the variable name. Made thoseguys local. Added // "side" value to ship struct and provisions to set it in assign and testing. // // Added ability for user to return from "pick target on enemy ship" screen // // Got rid of some floats in the fire function // // // Being done currently: // // Making guns harder to hit at 50% strength and below // // Adding scenario creation capability to the testing function // // // History: // GCSET comes from the name of a scrap of pseudocode that I typed // out in a period of great(for me) insight and inspiration. The // quasi-code was the basis of the code to assign the ship types // to each ship. In theory, it would SET the ships to be Generic // Cruisers. =) After I got home I downloaded the scrap of code // from the server to my home machine and started working on this. // // The original assign code has long since been changed and removed, // but the name remains the same.(I can't come up with a better one) // // This game will always remain ascii text based for two reasons: // // 1: So that one does not need to have it on their machine, they // can telnet to a machine that has it and play it. // // 2: I don't know how to do graphics yet =7 // // The very first version of the game was playable in June '98, and // was simply up to three generic cruisers on one side vs the same // on the other. Little further work was done on the program until // August due to school concerns and other projects. // // // In August I decided to add some comments to this program including // some ideas for things to do in the next few versions. And that's how // the beginning documentation turned from 25 lines into what has // been described as a novel. In late August I began to rework some // of the innards of the code so that a few while loops would be able // to replace a multitude of if statements. I saw this as being nessecary // to the capability of adding more ships, as each additional ship would // otherwise require multiple if statements just for that ship in several // functions. In doing this, I screwed up the code far beyond understanding. // // In late August I also started taking some heavy courses at school, // and didn't get much chance to work on the program until my first // relatively free weekend in mid-October, when I finally got the program // to go from beginning to end without crashing again(and without // any null pointer assignments =) // // // In late October I found enough time to make several additional // modifications to the program. // // // Ideas for once I get the thing working on its own: // // These ideas were originally one-liners, but were // expounded upon in the August revision. // // More ships than the Generic Cruiser // // Ideas for new ships: // Missile Frigate: Will have missiles for weapons, which will depend // heavily on the enemy's engine status for its hit chance. It will // have low HP values across the board, although it will be able to // inflict about as much damage as a Generic Cruiser given optimum // conditions. Optimum conditions doesn't happen too often. // Light\Heavy Cruisers: They will be somewhat different from the // Generic class in that the Light will have more engines and less // armour, and the Heavy will be vice versa. They will be configured // in a way that the Light will have a slight disadvantage against // a Generic, while the Heavy will have a slight advantage. // Dreadnought: Will be the ubermunchkiny ship with lots of armour // and weapons and such. Will make mincemeat out of a Generic Cruiser // and will be possibly able to take on 2 on its own. Will also be // very difficult to miss, with low to-hit mods. // Carrier: Will be implemented when fightercraft are implemented. // It will have heavy armour, perhaps more than its max armour value // to make it difficult to inflict damage. Will have minimal shipbased // weaponry, and be equal to or slightly weaker than a Generic Cruiser // in a slugfest. It will be just as hard to miss as a Dreadnought. // Destroyer: Will be implemented when having multiple weapons on one // ship becomes possible. It will have missiles like the Missile Frigate // and standard weaponry like the GC. It will have about 3/4 the armour // of a GC. // Transport: Once mission sets \ quests are implemented, some of them // will involve making sure a Transport or two survives the entire // set. The Transports will have heavy armour and little else, maybe // 50-75 total offensive power. // // Different weapons on different ships // Later: Different weapons on the same ship // // Weapon ideas: // Standard Lasers: What is simply called "guns" now // Turbo(or Heavy)lasers: Do 2 damage each, act like standards otherwise // Missiles: Will do 10 damage each, and the target's dodge will // have 1.5 times the effect on hit% as it does on standard lasers // Torpedoes: Will do upwards of 35 damage each, and target's // dodge will have twice the effect. // Wouldn't torpedoes and missiles be basically the same thing in // space? I will have to come up with better names for this stuff. // Bolt cannon: Superstrong cannon, does about 50 damage and not // heavily effected by dodge, but has inherently poor targeting // Fighters\bombers: Discussed in a seperate comment block // // I will have to make a new variable for the absolute hits, as opposed // to the number of hit damage. // // Further ideas on this subject: // The weapons could vary in damage by 10% // Each weapon's personal mods and name and everything can be a // part of a struct // Each ship could carry a max of, say, five weapons, and will have // an array of pointers to the weapon struct. // The damage system for guns will have to be redesigned so that it is // possible for a ship to lose more than just standard lasers when // hit. Also, the more damage done to "guns" without taking out a // higher weapon, the more likely it should be for that weapon to be // taken out in the next hit. And vice versa, if too many higher // weapons are destroyed, there is less chance of more being destroyed // in the next shot. The guns variable will be useful for this // // Each weapon will have its own weapmod, // rather than a single one for the whole ship. // // Fighters: Make slots for miniships, goes along with multiple weapons // // The fighters will not be controlled by new slots, but as long as there // is just the standard fighter there will be variables fswarm and eswarm // that will each contain the number of friendly and enemy fighters. // When the fighters have their attack round, the firing fighters will // get a 50% chance of attacking an enemy fighter for the number of // targets available, frinstance 12 attacking vs 8 enemy, the first // 8 attacking get the chance of engaging an enemy fighter. They will // have a 50% chance of downing the fighter if they attack it, and a // 25% chance of being defeated. Or 40\20. Maybe 50\16. // Fighters attacking enemy ships, either failing their dogfight roll // or not getting the chance, will do about 10 damage, and will have // a hard time breaking through armour. The entire swarm will concentrate // fire on one ship. // Torpedo fighters and bombers are also possibility. Each would require // int values for the number who haven't fired, the number who have fired // once, et cetera, down to the ones who are winchester. The fighters' // dogfight roll will have to be modified so they have a chance of // attacking the bombers. When the bombers fire, the ones that are out // of ammo will go first, and they will either land or try to dogfight. // Then the ones with one bomb/missile left will fire, and their number // will be added to the number of winchesters, and then voided. Then the // ones with two weapons left, and so on. // Bombers will cause significantly more damage than fighters, maybe // 50 for the torpedoers and 100 for the heavy bombers. // Any fighter\bomber\whatever attacking an enemy ship will have to roll // to see whether it either was destroyed before firing(10% or 33% if // busywith points to fighters), destroyed after firing(10% or 33%), or // hit the ship and survived. Fighters will not miss a ship. // If there is a single carrier in the friendly fleet, then the fighters // will be 75% inclined to target its busywith when targeting. If there // are multiple carriers in the friendly fleet, the fighters will // randomly pick the busywith of either ship. // // Time delayed weapons (Missiles? Self destruct?) // Crew and life support, shuttle/beam invade option // Weapons that hit multiple targets // A method of scoring and recording kills // Weapons with limited ammo, goes along with missiles and fighters // Create difficulty levels with "AI" that will be more likely to // use different tactics in different situations // Possible "quest mode" where your fleet fights several other // fleets one after each other, without repairing/reloading // // Going along with this idea, the ability to have premade battles. // At the beginning of the game, user is asked whether to start // a new battle or to use a premade battle. If he chooses the first // choice, then run a function which will use the setup code that is // currently in main, plus will start checkstarter and assign. If // the second choice is chosen, a new function will assign the number // of enemies and their respective values, a different function for // each preset battle. In the future, set it up so that each preset // battle function is its own file, and is read when called for. This // could allow for saving of battles. // // More than 3 ships on either side, needed SOON // // Also, better\random ship names // Possibly rewrite it to run on BBSes.. Gotta figure out how first // Create a way to give orders to computer ships and have them follow // the orders or choose to disobey given the situation, possible orders // would be the sort of thing to get a ship to assist a friendly or to // get several friendlies to gang up on an enemy. Once this works, get // the computer's lead ship to be able to give orders as well. // // // Maneuvering tactics to change chance of hitting/being hit // Possible tactics: Agressive, Standard, Evasive, Defensive, Suicidal. // The effects of these tactics could be modified by the busywith value // (see below) // They will also be highly affected by the target ship's tactics // A "busywith" value for each ship that will represent the ship that // it is currently busy slugging it out with. Computer controlled ships // will make a roll and have a high chance of attacking this ship. // When created, busywith will have two accompanying values: lastfiredat // and lasthitby. If both are the same ship, then busywith is assigned // to that value if it isn't already. // The busywith roll will also be modified by lasthitby of the ship that // is being fired at. If it is not the firing ship, then there will be // more of a chance of the firing ship breaking off and attacking someone // else, especially if the firing ship's lasthitby is different from // its busywith. In this instance, if the ship fails its busywith roll // and breaks off, it will roll for lasthitby. Failing this, it will // attack a random ship, not counting the busywith and lasthitby values, // and busywith will become null. // This will not become very useful until I make some more ship slots, so // it might be a while before it becomes implemented. // // Maybe rework it to make it possible to win a 2 on 3, but will have // to do this without making it too munchkiny.. Would be close to // impossible given the current system // // // Possibly allow ships' values to waver from 10% less than standard // to 5% greater than standard -- MAYBE. This idea could theoretically // screw up a lot of the gameplay and be difficult to implement correctly. // An alternative could be, when saving player records becomes possible, // to have the ship stats waver according to the player's experience like // on the old Star Trek game I used to play on the TRaSh-80. So with this // a low enough experienced player would be able to win a 2 on 3. Also, the // curve of the possible modification range should slow down as a player // becomes more experienced, and a player should be able to reset his // stats. // Here's a really bad idea: // Make an HTML version // // Have variables inside the ship struct for the last battle plan, // then allow the repetition of the plan with one key. Also output // what the battle plan is at the firing screen // // // Known Bugs: \ // 08 // / // // // // // A low reactor takes hits when firing at the engines. Low armour does // NOT take hits when aimed at, while it should be picking up all spare... // // Thanks go out to: // // Eric Nagler for the C++ book he wrote. While the one I was // reading from beforehand didn't have jack on how to reference // variables, he had them at the front of the third chapter. // // Bluefoot, Shadur and Arsenal for being very patient and // helping me get some of the bugs out of this code. // // Keebler for cluing me in to the srand function. // // Jeremy Wyman for being the only guy in the JC lab that knows // enough to help me with my programming. // /* Cruiser Types */ struct ship{ // Basic ship structure. Contains variables for: char type[32]; // Type of ship, in string form char name[32]; // Name of ship int arm; // Current armour value(HP left) int guns; // Current number of guns operational \ gun HP points left int brid; // Number of hitpoints left in the ship's bridge int eng; // Number of HP left in the engines int reac; // HP left in the reactor int shipon; // Ship on\off toggle int str; // Type of ship, in int form(strength value) int side; // Which side it is on int mod; // General to-hit modifier(dodge ability) int engmod; // Modifier to hit engines int gunmod; // Modifier to hit guns int reacmod; // Modifier to hit reactor core room int bridmod; // Modifier to hit bridge int weapmod; // Damage modifier, may be rewritten\taken out }; /* Generic Cruiser */ const ship gc = { // Stats for the Generic Cruiser: /* gc.type */ "Generic Cruiser", /* gc.name */ "No Markings", /* gc.arm */ 7500, /* gc.gun */ 250, /* gc.brid */ 100, /* gc.eng */ 1000, /* gc.react */ 750, /* gc.shipon */ 1, /* gc.str */ 7, /* gc.side */ 0, /* gc.mod */ 4, /* gc.engmod */ 6, /* gc.gunmod */ 17, /* gc.reacmod */ 16, /* gc.bridmod */ 21, /* gc.weapmod */ 1, }; /* Garbage Scow, used for testing */ const ship scow = { /* type */ "Garbage scow", /* name */ "Unmarked Craft", /* arm */ 1234, /* gun */ 27, /* brid */ 13, /* eng */ 123, /* react */ 75, /* shipon */ 0, /* str */ 0, /* side */ 0, /* mod */ 6, /* engmod */ 6, /* gunmod */ 12, /* reacmod */ 16, /* bridmod */ 21, /* weapmod */ 1, }; //Friendly ship assignments// // The ships are given the Scow's values for testing purposes and // to de-junk their data ship fship1=scow; ship fship2=scow; ship fship3=scow; ship fship4=scow; //Hostile ship assignments// ship eship1=scow; ship eship2=scow; ship eship3=scow; ship eship4=scow; const int Max_Per_Side = 3; // Maximum ships per side (starting at 0 acourse) const int Max_Num_Sides = 1; // Maximum number of sides(from 0) // Defining a block of // pointers to the ships ship *theship[Max_Num_Sides+1][Max_Per_Side+1]={ {&fship1,&fship2,&fship3,&fship4}, // Friendly ships {&eship1,&eship2,&eship3,&eship4} // Unfriendly ships }; // Defining a block of // pointers to the original ship types const ship *baseship[16]={ &scow, // 0 &gc, // 1 &gc, // 2 &gc, // 3 &gc, // 4 &gc, // 5 &gc, // 6 &gc, // 7 &gc, // 8 &gc, // 9 &gc, // 10 &gc, // 11 &gc, // 12 &gc, // 13 &gc, // 14 &gc // 15 }; int numon[Max_Num_Sides+1]; // Number of ships on a particular side // Each side gets its own spot in the array char firstchoice; // Input used when player chooses which // type of ship to use const int min_assign = 1; // Minimum number designation // that a cruiser can be assigned to const int max_assign = 1; // Maximum designation // Raise this as more cruisers added const int var = 1; // Max cruiser value to go up or down randomly // for cruiser spawning int Qon; // Omniscient Mode toggle // Displays ship's stats when firing int turnspassed; // Number of turns that have passed in the game time_t t; // *-current system time for seeding the rand function // Prototyping functions void startnew(); // Setup function for new game int testing(); // Function for testing stuff void assign(); // Assigning the cruisers' values before choice to engage int getanumber(); // function to return a semi random number for // assigning cruisers void run(); // Get the game going already // All the good stuff starts here int youfire(ship*); // Pick a target void eeniemeenie(int &,int &); // Picking targets for compu controlled ships void fire(ship *,ship *,char &); // Battle function void itsdead(ship *); // Aptly named function to dispose of desceased ships void quitfree(int); // Function to quit the program and dealloc everything // Done declaring everything //////////////////////////////////////////////////////////////////////////// // // // // //////////////////////////////////////////////////////////////////////////// void main(){ cout << "\n\n\n\nCruisers"; // Sorry excuse for a splash page startnew(); // Run the startnew function while (1){ run(); } } // End of main function // *********************** // /* Start New Game function */ // *********************** // void startnew(){ const char mostfirstchoice = '1'; // Maxmimum number of ship types int uord = 0; // Boolean to choose whether algorithm adds or subtracts char engyorn; // Input (y)es or (n)o to engage enemy while(1){ // Looping the beginning stuff numon[0] = 0; numon[1] = 0; // Asking player what cruiser he wants cout << "\nWhat kind of star cruiser will you be piloting?"; cout << "\nCrusiers available:"; cout << "\n1) Generic Cruiser"; cout << "\n\nPick one: "; cin >> firstchoice; // Getting input if(firstchoice == 'x'){ while(testing() != 0); // Enter test function upon 'x' input } if(firstchoice > mostfirstchoice || firstchoice <= '0'){ cout << "\nSorry, you must choose a number between 1 and " << mostfirstchoice; continue; } else if(firstchoice == '1'){ cout << "\nYou have picked the Generic Cruiser"; } //++++++ Getting the numbers of ships on each side +++++++// srand((unsigned) time(&t)); // Seeding the rand function // Getting number of friendlies numon[0] = (rand() % ((Max_Per_Side+1))+ 1); // Declaring number of // friendlies here // Getting numbers of ships on all other sides // Should work for more than two sides, though // that has not yet been implemented for(int i = 1; i <= Max_Num_Sides; i++){ // Function will work // until it runs out of sides uord = (rand() % 2); // Choosing whether to pick a random // number above or below the number // on the last side. // 0 is lower, and 1 is higher if (uord == 0){ numon[i]= (numon[i-1] - (int)(rand() % ((numon[i-1] / 3) + 1))); // This function will set // the number of ships on this side // equal to the number of ships on the // last side checked, minus a random // number that is up to a third the // ships on the last side, rounded up if(numon[i] <= 0){ // If this dumps the number of ships to numon[i] = 1; // or below zero, jack it back up to one } } else if(uord == 1){ numon[i]= (numon[i-1] + (rand() % ((numon[i-1] / 3) + 1)) ); // Same as above, except random up to // a third of the last side is added // instead of subtracted if(numon[i] >= Max_Per_Side+1){ // If this pushes the number past numon[i] = Max_Per_Side+1; // the maximum, move it back } } } // Done setting ships per side // Telling the player the odds // All the if/elses are for grammatical accuracy cout << "\nYou have "; if (numon[0] > 2){ cout << ( numon[0] - 1 ) << " wingmen."; } else if ( numon[0] == 1 ){ cout << "no wingmen."; } else if (numon[0] == 2){ cout << "one wingman."; } cout << "\nThere "; if (numon[1] == 1){ cout << "is "; } else{ cout << "are "; } cout << numon[1] << " enemy ship"; if (numon[1] == 1){ cout << '.'; } else if (numon[1] > 1){ cout << "s."; } // Finished with oddstelling, // Now asking player to confirm engagement cout << "\nDo you wish to engage the enemy? (Y/n)"; cin >> engyorn; if (toupper(engyorn) == 'N'){ // If player chickens out... cout << "\nDo you wish to quit?"; cin >> engyorn; if(toupper(engyorn) == 'Y'){ quitfree(0); } else{ continue; } } else{ break; } } // End of while loop // Waking up all the ships int shipfof = 0; // Setting counter variables to 0 int shipnum = 0; // ***- The debugger skips this line and goes to // ***- the last line in the while statement // Set to loop through sides while(shipfof <= Max_Num_Sides){ // Set to loop through ships // while looping through the sides while(shipnum <= Max_Per_Side && shipnum <=(numon[shipfof] - 1)){ // Loop makes sure that not only is the shipnum below the // number of ships on the side, but also that the shipnum // is below the max number of ships on any side. // Turn on the ship's shipon and increment shipnum theship[shipfof][shipnum]->shipon = 1; shipnum++; } // Increment side to check and reset number of ship to check shipfof++; shipnum = 0; } assign(); // Run the assign function when done with everything else } // // End start new function // **************** // /* Testing function */ // **************** // // Note: The testing function is poorly documented. // It is not instrumental to the function of the game, // I plan to be the only one really using it, // the average user isn't supposed to know about it, // and I don't give a damn if I have to rewrite it from the // ground up, as I probably will when I decide to test // another of the game's facets. int testing(){ // Currently being tested: // the theship multidimsional array // the shipon values ship *thatship; int xcoord=1; // v Coords. int ycoord=1; // ^ Not the beer char yorn; while(xcoord != 666 || xcoord != 27){ // Tried looping the couts, caused more problems than I solved // will have to try again when I have more time cout << "\nWelcome to the testing grounds.\n" << theship[0][0]->shipon << ' ' << theship[1][0]->shipon << " " << fship1.shipon << ' ' << eship1.shipon << " Totals:" << '\n' << theship[0][1]->shipon << ' ' << theship[1][1]->shipon << " " << fship2.shipon << ' ' << eship2.shipon << " Us: " << numon[0] <<'\n' << theship[0][2]->shipon << ' ' << theship[1][2]->shipon << " " << fship3.shipon << ' ' << eship3.shipon << " Them: " << numon[1] <<'\n' << theship[0][3]->shipon << ' ' << theship[1][3]->shipon << " " << fship4.shipon << ' ' << eship4.shipon << "\nInput side of ship to toggle(0 for friendly, 27 to exit): "; cin >> xcoord; if(xcoord == 27){ return 0; } if(xcoord == 666){ quitfree(0); } if(xcoord > 1){ cout << "Over maximum number of sides, reverting to maximum\n"; xcoord = 1; } cout << "Input number of ship to toggle(0,1,2): "; cin >> ycoord; if(ycoord > (Max_Per_Side)){ cout << "Over maximum number of ships, reverting to maximum\n"; ycoord = (Max_Per_Side); } thatship=theship[xcoord][ycoord]; if(thatship->shipon == 0){ cout << "Turning on " << thatship->name << endl; thatship->shipon += 1; numon[xcoord]++; } else if(thatship->shipon == 1){ cout << "Turning off " << thatship->name << endl; thatship->shipon -= 1; numon[xcoord]--; } else{ cout << "\nTesting Error: Ship " << xcoord << " , " << ycoord << ':' << "\nshipon value " << thatship->shipon << " out of range"; quitfree(1); } cout << thatship->type << " type\n"; cout << thatship->name << " name\n"; cout << thatship->arm << " arm\n"; cout << thatship->guns << " guns\n"; cout << thatship->brid << " brid\n"; cout << thatship->eng << " eng\n"; cout << thatship->reac << " reac\n"; cout << thatship->mod << " mod\n"; cout << thatship->engmod << " engmod\n"; cout << thatship->gunmod << " gunmod\n"; cout << thatship->reacmod << " reacmod\n"; cout << thatship->bridmod << " bridmod\n"; cout << thatship->weapmod << " weapmod\n"; cout << thatship->shipon << " shipon\n"; cout << "Reset ship?[y/N] "; cin >> yorn; yorn = toupper(yorn); if(yorn == 'Y'){ cout << "Ship types: \n(1)Generic Cruiser\n(2)Garbage Scow\n:"; cin >> ycoord; // Recycling ycoord as shipstrength switch(ycoord){ case 1:{ if(!thatship->shipon){ numon[xcoord]++; } memcpy(thatship,&gc,sizeof(gc)); break; } case 2:{ if(!thatship->shipon){ numon[xcoord]++; } memcpy(thatship,&scow,sizeof(scow)); thatship->shipon = 1; break; } default:{ cout << "Bad value " << ycoord << ';'; break; } thatship->side = xcoord; } } } return 1; } //* End testing function *// // // ************************** // /* Assigning generic cruisers */ // ************************** // void assign(){ ship *thisship; // Pointer to the current ship being fooled around with // Doesn't help program, greatly improves readability int strnum = 0; // variable strength of ships int shipfof = 0; int shipnum = 0; // Creating char string for adding ship's number to its name // Mostly for telling the ships apart // It might be removed from the game when real names are implemented, // or it and "(side) ship # (whatever)" might be added before the // type and name when listing ships char* whatever = ((char*)malloc(2)); memset(whatever,0,sizeof(whatever)); // The memset fixes a bug whereby a byte of garbage was appended to // whatever every additional line the program read through // Looking through the sides while(shipfof <= Max_Num_Sides){ // Looking through the individual ships // on the side being looked at while(shipnum <= Max_Per_Side){ thisship = theship[shipfof][shipnum]; if (thisship->shipon == 1){ strnum = getanumber(); // get a number for strength memcpy(thisship,baseship[strnum],sizeof(ship)); if(shipfof == 0){ // If it's a friendly ship, if(shipnum == 0){ // and if it's your ship, // Call it Your Ship strcpy(thisship->name,"Your Ship"); } else{ // Else, if it isn't yours // (and still a friendly) whatever[0] = (char)(shipnum + 49); // "whatever" is given the char value of // the shipnum + 49 // this converts the int to the correct // ascii value for the char strcpy(thisship->name,"Friendly Ship "); // Start the string off with "Friendly Ship " // and append the char value of the // ship's number to it strcat(thisship->name,whatever); } } else if(shipfof == 1){ // If it's an enemy ship, // do the same as above, // except call it an Enemy // ship instead of friendly whatever[0] = (char)(shipnum + 49); strcpy(thisship->name,"Enemy Ship "); strcat(thisship->name,whatever); } else{ cout << "Error: Still in assign loop above max FOF value"; quitfree(1); } } thisship->side = shipfof; // Setting the ship's side shipnum++; // increment shipnum } shipnum=0; // reset shipnum shipfof++; // add one to the checkFOF value } free(whatever); // freeing whatever block } // End of assigning function // // Number fetching function, // A minor function used as part of assignations // and not anywhere else IIRC // Used to assign the strength number // of cruiser to be given to a ship // Confirmed to work alone, 6/11/98 // Bug: The error checking code for numbers greater or lower // than min/max assign does not work int getanumber(){ int anum = 0; // Local variable. A number. // It is what will be returned // if the function works right if (rand() % 2 == 0){ // Rand will return either 1 or 0. // 0 will mean vary to the negative, // while 1 will vary to the positive anum = ((firstchoice-48) - (rand() % (var + 1))); // a random number from zero to the maximum // allowed variation is subtracted from // the player's choice of ship if(anum < min_assign){ // If the subtraction dumps anum below return min_assign; // minimum allowed assign, then return } // min assign instead of anum else return anum; // If everything's okay, return anum } else{ // If uord is 1 instead of 0 anum = ((firstchoice-48) + (rand() % (var + 1))); // Similar function to above // except the random number is // added instead of subtracted if(anum > max_assign){ // Similar error protection return max_assign; // in regards to max assign } else return anum; } } /* End of assignations and getanumber */ // ***************** // /* Main run function */ // ***************** // // // This function is ran after everything is assigned and in place. // It will launch the functions for ship targeting, which in turn // launch firing functions. void run(){ int shipfof = 0; // Resetting scfof and int shipnum = 0; // num variables // Checking by sides while(shipfof <= Max_Num_Sides){ // Checking ships in sides while(shipnum <= Max_Per_Side){ // If the ship being checked has // its shipon value set to true if(theship[shipfof][shipnum]->shipon == 1){ if(shipnum == 0 && shipfof == 0){ // If checking your ship ship *thisship = theship[shipfof][shipnum]; while(youfire(thisship)); // run the manual firing function. } // I might create a variable inside the ship struct // for human players. This will be for if a player does // not want to be ship 0 on side 0. Being in a variable // position will come with the implementation of over // three sides, quest files, and some other stuff, and // will become of great importance when multiplayer // is implemented // If the ship doesn't belong to a human player, else{ eeniemeenie(shipfof, shipnum); // Run the comp firing function } } shipnum++; // Increment the ship check number } shipfof++; // Increment the ship FoF and shipnum = 0; // reset the value of shipnum } turnspassed++; // And another turn has passed.... } // End Main Run Function // // ************************ // /* Target Aquiring Function */ // ************************ // int youfire(ship *yourship){ char youfireat; // number of ship you are firing at ship *target; char lock = 0; int thoseguys = 1; // Side number 1 is "those guys" // Will not need to add more complicated code // until more than two sides are implemented. // And then, it will be a number that is // input and atoi'd int shipnum = 0; // resetting shipnum int shipfof = 1; // and setting fof to 1 cout << "\n"; cout << "Select a ship to target:\n"; while (shipnum <= Max_Per_Side){ if (theship[shipfof][shipnum]->shipon != 0) { // If an enemy ship exists, // list it as an option cout << '(' << (shipnum + 1) << ") " << theship[shipfof][shipnum]->type << ' ' << theship[shipfof][shipnum]->name << endl; } shipnum++; } cout << "\n(R) Retreat"; // Quick way to end the game, // and nicer than ^C cout << "\n\n[" << turnspassed << "]:"; // Prompt includes turn number // in addition to simple colon cin >> youfireat; youfireat=toupper(youfireat); if (youfireat == 'X'){ // exit to testing area while(testing() != 0); return 1; } if (youfireat == 'R'){ // Retreat; Ends program quitfree(0); } else if (youfireat == 'Q'){ // The 'Q' mode toggle if (Qon == 0){ // If you're not a Q Qon = 1; // you are now cout << "You now are omniscient"; } else if (Qon == 1){ // And if you are already, Qon = 0; // turn the toggle off cout << "You are no longer omniscient"; } return 1; // Repeat this function } /* Now for aquiring the target */ youfireat -= 49; // sets '1' to 0 target = theship[thoseguys][youfireat]; if(youfireat < 0 || youfireat > Max_Per_Side || !target->shipon){ cout << "Error, bad input \""<< char(youfireat+49) << '\"'; return 1; } /* Locking onto an area of the enemy ship */ while (1){ cout << "\n\n\n\nPick a target on the enemy ship:\n\n"; cout << "(1) No particular target\n"; // AKA "Just hit the damn thing" cout << "(2) Engines\n"; cout << "(3) Reactor Room\n"; cout << "(4) Gun Emplacements\n"; cout << "(5) Bridge\n\n"; cin >> lock; // input a value for the specific target location lock -= 48; if ((lock < 1 || lock > 5 )&& toupper(lock+48) != 'Q' ){ cout << "There are only five targets on the enemy ship;" << "\n\"" << char(lock) << "\" is not a valid target"; continue; } else if(toupper(lock+48) == 'Q'){ return 1; } break; } fire(yourship,target,lock); // And now, 700 lines into the program // *cough* make that 1250 -- 10/98 // finally able to fire at the enemy ship =) return 0; } /* End of your targeting */ // ****************************** // /* Drone Target Aquiring Function */ // ****************************** // void eeniemeenie(int &fof, int &num){ int targetnum; // The number of the targeted ship ship* thatship; // These two pointers will get passed to ship* thisship; // fire as the firing and target ships char lock = 0; int thoseguys; thisship = theship[fof][num]; if (fof == 0){ // if it's a friendly ship... thoseguys = 1; // "those guys" is the enemy } else if(fof == 1){ // If it's an enemy ship thoseguys = 0; // "those guys" is us } else{ cout << "\nError: Drone on side " << fof << " unable to target fleet (" << thoseguys << ')'; quitfree(1); } targetnum = rand() % (numon[thoseguys]); // pick a target # int deadpass = 0; for (int x =targetnum; x >= 0; x--){ // getting the number of ships if(!theship[thoseguys][x]->shipon){ // to pass up when targeting deadpass++; } } while(1){ //cout << "\n*- t" << targetnum << " d" << deadpass; // Debugging info targetnum += deadpass; deadpass = 0; if(targetnum > Max_Per_Side){ cout << "\nError: Unable to aquire target ("<< targetnum << ')'; quitfree(0); } thatship = theship[thoseguys][targetnum]; if(!thatship->shipon){ targetnum++; continue; } break; } if(thatship == 0){ cout << "\nError: Could not aquire target " << targetnum << " passed " << deadpass ; quitfree(1); } lock = ((rand() % 5) + 1); // Get a number for lock area if (lock < 1 || lock > 5){ // If locking onto an invalid target area, cout << "Error locking onto enemy target area \"" << char(lock+48) << '"';// Output an error message quitfree(1); // and quit uncerimoniously } fire(thisship, thatship, lock); } /* EndDroneTargetAquiringFunction */ // ****************************** // /* Battle fuction... The fun part */ // ****************************** // void fire(ship *firing , ship *target,char &lock){ // Declaring local variables int hits = 0; // number of unassigned hits on the target ship int starthits = 0; // total number of hits on the target ship int armourhits = 0; // Hits assigned to the armour of target ship int enghits = 0; // Hits assigned to the engines of target ship int reachits = 0; // Hits assigned to the reactor of target ship int gunhits = 0; // Hits assigned to the guns of target ship int bridhits = 0; // Hits assigned to the bridge of target ship int lockmod = 0; float dodge = 0.0; // value of target ship's dodge ability // All locals declared cout << firing->name << " fires at " << target->name << endl; // Q code fixed, ios class conversion routines attempted to add 10/31 if (Qon == 1 || !strcmp(firing->name, fship1.name)){ // The secret Q omniscience... // Also displayed if your ship is firing /**** iomanip goes fubar, segfaults... Only use in DOS ****/ // cout << setw(4) << setfill(' ') << setiosflags(ios::right) cout << firing->arm << " arm " << target->arm << endl << firing->guns << " guns " << target->guns << endl << firing->brid << " brid " << target->brid << endl << firing->eng << " eng " << target->eng << endl << firing->reac << " reac " << target->reac << endl; usleep(1000000); // Give you some time to look at this stuff } /* Setting the specific targeting values */ if (lock == 1 ){ // For attacking "nowhere in particular" lockmod = 0; } else if (lock == 2){ // For attacking engines lockmod = target->engmod; } else if (lock == 3){ // For attacking reactor lockmod = target->reacmod; } else if (lock == 4){ // For attacking guns lockmod = target->gunmod; } else if (lock == 5){ // For attacking bridge lockmod = target->bridmod; } dodge = float (target->eng) / float (baseship[target->str]->eng); // The value given to "dodge" is the target's engines divided by // its maximum engine value. Basically, it is the percent of its // engines that are operational. /* The basic battle algorithm */ hits = int(firing->guns * ((100.0 - ((dodge * 33) + (rand() % 21 - rand() % 6) + target->mod + int (float(lockmod) * dodge + .5))) / 100.0 ) * firing->weapmod); // Okay... // // a random number between 1 and 5 is subtracted from a random number // between 1 and 20, and the result is added to the sum of the target's // mod value plus the lockmod value times the dodge value, rounded up. // Added to the mess is the dodge value times 33. The whole thing is then // subtracted from 100, divided by 100, and then multiplied by the number // of guns on the firing ship, and further multiplied by the firing ships // weapon modifier, and finally turned into an int(rounded down). // starthits = hits; // Recording the total number of hits if (target->arm > hits){ // If the target has more armour //than there are hits, armourhits = int(( float(target->arm) / float(baseship[target->str]->arm)) * hits); // the armour takes a portion of the hits // relative to the percent of armour still // on the ship, compared to its max armour. // Target armour is not reduced here, it does happen later though. } hits = (hits - armourhits); // Subtracting the number of armour hits // from the number of unassigned hits if ( target->eng > (hits / 2) || (lock == 2 && target->eng > 5)){ // If either there are more engine points than half the // number of hits, or the engines were specifically targeted, // or(changed to and) there are more than 5 engine points left // on the target ship, enghits = int (( (45.0 + (float)((lock == 2)* 25) ) / 100.0 ) * hits); // the target ship takes 45% of the hits to its engines, // or 70% if they were specifically targeted target->eng = (target->eng - enghits); // Reducing the target's engines hits = (hits - enghits); } if ( target->reac > (hits / 5) || lock == 3 ){ // If either there are more reactor points than a fifth of // the number of hits, or the reactor was targeted reachits = int (( (45.0 + (float)((lock == 3) * 25)) / 100.0 ) * hits); // the reactor takes 45%(was 50%) of the remaining hits, // or 70%(was 75%) if they it was targeted target->reac = (target->reac - reachits); // Reducing target's reactor pts hits = (hits - reachits); } if ( target->guns > (hits / 4) || (lock == 4 && target->guns > 3)){ // If either there are more gun points than a quarter of the // remaining hits, or the guns were targeted and(changed from // or) there are at least 3 guns left on the ship gunhits = int (( (33.3 + (float)((lock == 4) * 25)) / 100.0 ) /* *(float)(((target->guns > (baseship[target->str]->guns / 2)) * (target->guns / (baseship[target->str]->guns * 100))) )*/ * hits); // the guns take a third of the remaining damage, // or 7/12 if they were targeted target->guns = (target->guns - gunhits); hits = (hits - gunhits); } if ( target->brid > (hits / 5) || lock == 5 ){ // If either there are more bridge points than a fifth of the // remaining hits, or it was targeted, bridhits = int (( (16.6 + (float)((lock == 5) * 25)) / 100.0 ) * hits); // the bridge takes 1/6 (was 30%) of the remaining hits, or // 5/12(was 55%) if it was targeted. target->brid = (target->brid - bridhits); hits = (hits - bridhits); } if (starthits != hits){ // If any damage was doled out, armourhits = (armourhits + hits); // all remaining damage goes to target->arm = (target->arm - armourhits); // the armour. } cout << "\n Damage Totals:\n\n"; // v Displaying the damage totals cout << armourhits << " to hull\n"; // . cout << enghits << " to engines\n"; // . cout << reachits << " to reactor\n"; // . cout << bridhits << " to bridge\n"; // . cout << gunhits << " guns destroyed\n"; // ^ usleep(1000000); // Let the player see what's going on /* Checking for destroyed ships and returning any sub-zero non-crits to values of 2 */ if (target->reac < 1 // If target's reactor is less than 1 || target->brid < 1 // or its bridge || target->arm < 1){ // or its armour itsdead(target); // <-- } if (target->eng < 1){ // If engines are less than 1, target->eng = 2; // reset to value of 2. } // I used to reset them to 1, // but I decided 2 was a nicer number if (target->guns < 1){ // v Same to guns as for engines target->guns =2; // . } // ^ } /* EndBattleFunction */ // ****************** // /* It's Dead Function */ // ****************** // void itsdead(ship *target){ char ryorn; // Yes or no to restart int thoseguys = target->side; target->shipon = 0; cout << target->name << " has been destroyed!\n"; (numon[thoseguys])--; usleep(2000000); if (numon[1] == 0){ // If there's no enemies left... cout << "\n** Congratulations, you" // v Congratulatory message << " have destroyed the enemy" // . << " forces in " // . << (turnspassed + 1) // . << " turns."; // ^ cout << "\n\nShip strength:\n\n"; ship* thisship; // Ship pointer int sstr; // Ship's strength for(int counter = 0; counter <= Max_Per_Side; counter++){ thisship = theship[0][counter]; sstr = thisship->str; if(thisship->shipon){ cout << thisship->name << ": " << (((double(thisship->arm) / double(baseship[sstr]->arm)*.75) // 75% armour + (double(thisship->guns) / double(baseship[sstr]->guns)*.15) // 25% guns + (double(thisship->eng) / double(baseship[sstr]->eng)*.05) // 5% engines + (double(thisship->reac) / double(baseship[sstr]->reac)*.05)) // 5% reactor *100.0) << " \%" << '\n'; } } quitfree(0); // End the program } if (theship[0][0]->shipon == 0){ // If you were destroyed cout << "\n**You have been destroyed after " << (turnspassed + 1) << " turns.\n Better luck next time.\n"; cout << "Do you wish to try again? (Y/n)"; cin >> ryorn; if (ryorn == 'n' || ryorn == 'N'){ quitfree(0); } else if (ryorn == 'y' || ryorn == 'Y'){ main(); // *-Recursion quitfree(0); } } } /* EndIt'sDeadFunction */ // ***************** // /* QuitFree Function */ // ***************** // void quitfree(int exittype){ /* cout << "\n*-Freeing data" << endl;*/ // The malloced strings in this program are: // // "whatever" -- Local to assign function, freed there // The quitfree function takes an int as a parameter // This is for the program to say whether the exit // was normal or not. 0 means a good exit, anything else is bad. if(exittype == 0){ cout << "\n\nExitting the program normally\n"; exit(0); } else { cout << "\nBad exit; email cecrops@sandwich.net with error data"; exit(0); } } /* End QuitFree Function */