/*
 * Dire_Storm
 * Gunner DPS Calculator
 * 11 July 2016
 */
 
#include <iostream>
#include <iomanip>
#include <string>
 
const int weapons = 33;
 
struct Gun{ // Gunner's weapon
    std::string name; // Name of gun
    int AT_min;       // Minimum ATtack damage
    int AT_max;       // Maximum ATtack damage
    int AGI_min;      // Fastest rate of fire (minimum number of frames between shots)
    int AGI_max;      // Slowest rate of fire (maximum number of frames between shots)
    int PC;           // Projectile count
};
 
struct Character{ // Gunner character
    int STR; // STRength stat in Gunner
    int DEX; // DEXterity stat in Gunner
};
 
// Sets values to each Gun (Gun catalogue)
void setGuns(Gun Guns[]){
    Guns[0].name = "Gun";
    Guns[0].AT_min = 2;
    Guns[0].AT_max = 6;
    Guns[0].AGI_min = 20;
    Guns[0].AGI_max = 30;
    Guns[0].PC = 1;
 
    Guns[1].name = "Handgun";
    Guns[1].AT_min = 8;
    Guns[1].AT_max = 12;
    Guns[1].AGI_min = 20;
    Guns[1].AGI_max = 30;
    Guns[1].PC = 1;
 
    Guns[2].name = "Submachine-gun";
    Guns[2].AT_min = 4;
    Guns[2].AT_max = 8;
    Guns[2].AGI_min = 5;
    Guns[2].AGI_max = 10;
    Guns[2].PC = 1;
 
    Guns[3].name = "Shotgun";
    Guns[3].AT_min = 1;
    Guns[3].AT_max = 20;
    Guns[3].AGI_min = 50;
    Guns[3].AGI_max = 60;
    Guns[3].PC = 5;
 
    Guns[4].name = "Rifle";
    Guns[4].AT_min = 20;
    Guns[4].AT_max = 40;
    Guns[4].AGI_min = 50;
    Guns[4].AGI_max = 60;
    Guns[4].PC = 1;
 
    /*Guns[5].name = "Grenade";
    Guns[5].AT_min = 8;
    Guns[5].AT_max = 12;
    Guns[5].AGI_min = 70;
    Guns[5].AGI_max = 80;
    Guns[5].PC = 1;*/
 
    /*Guns[6].name = "Laser Gun";
    Guns[6].AT_min = 8;
    Guns[6].AT_max = 12;
    Guns[6].AGI_min = 20;
    Guns[6].AGI_max = 30;
    Guns[6].PC = 1;*/
 
    /*Guns[7].name = "Bazooka";
    Guns[7].AT_min = 40;
    Guns[7].AT_max = 60;
    Guns[7].AGI_min = 80;
    Guns[7].AGI_max = 90;
    Guns[7].PC = 1;*/
 
    Guns[8].name = "Homing Laser";
    Guns[8].AT_min = 8;
    Guns[8].AT_max = 12;
    Guns[8].AGI_min = 20;
    Guns[8].AGI_max = 30;
    Guns[8].PC = 2;
 
    Guns[9].name = "Beretta";
    Guns[9].AT_min = 24;
    Guns[9].AT_max = 36;
    Guns[9].AGI_min = 20;
    Guns[9].AGI_max = 30;
    Guns[9].PC = 1;
 
    Guns[10].name = "Uzi";
    Guns[10].AT_min = 12;
    Guns[10].AT_max = 24;
    Guns[10].AGI_min = 5;
    Guns[10].AGI_max = 10;
    Guns[10].PC = 1;
 
    Guns[11].name = "Remington";
    Guns[11].AT_min = 1;
    Guns[11].AT_max = 40;
    Guns[11].AGI_min = 50;
    Guns[11].AGI_max = 60;
    Guns[11].PC = 7;
 
    Guns[12].name = "Sniper Rifle";
    Guns[12].AT_min = 60;
    Guns[12].AT_max = 80;
    Guns[12].AGI_min = 50;
    Guns[12].AGI_max = 60;
    Guns[12].PC = 1;
 
    /*Guns[13].name = "Grenade Launcher";
    Guns[13].AT_min = 12;
    Guns[13].AT_max = 24;
    Guns[13].AGI_min = 70;
    Guns[13].AGI_max = 80;
    Guns[13].PC = 1;*/
 
    /*Guns[14].name = "Laser Beam Gun";
    Guns[14].AT_min = 16;
    Guns[14].AT_max = 24;
    Guns[14].AGI_min = 20;
    Guns[14].AGI_max = 30;
    Guns[14].PC = 1;*/
 
    /*Guns[15].name = "Cannon";
    Guns[15].AT_min = 80;
    Guns[15].AT_max = 120;
    Guns[15].AGI_min = 80;
    Guns[15].AGI_max = 90;
    Guns[15].PC = 1;*/
 
    Guns[16].name = "Homing Laser Beam";
    Guns[16].AT_min = 8;
    Guns[16].AT_max = 12;
    Guns[16].AGI_min = 20;
    Guns[16].AGI_max = 30;
    Guns[16].PC = 5;
 
    Guns[17].name = "3-Round Burst";
    Guns[17].AT_min = 24;
    Guns[17].AT_max = 36;
    Guns[17].AGI_min = 20;
    Guns[17].AGI_max = 30;
    Guns[17].PC = 3;
 
    Guns[18].name = "Missile";
    Guns[18].AT_min = 300;
    Guns[18].AT_max = 500;
    Guns[18].AGI_min = 160;
    Guns[18].AGI_max = 180;
    Guns[18].PC = 1;
 
    Guns[19].name = "Mini Uzi";
    Guns[19].AT_min = 12;
    Guns[19].AT_max = 24;
    Guns[19].AGI_min = 5;
    Guns[19].AGI_max = 10;
    Guns[19].PC = 2;
 
    Guns[20].name = "Scattergun";
    Guns[20].AT_min = 1;
    Guns[20].AT_max = 80;
    Guns[20].AGI_min = 50;
    Guns[20].AGI_max = 60;
    Guns[20].PC = 9;
 
    Guns[21].name = "Hunting Gun";
    Guns[21].AT_min = 140;
    Guns[21].AT_max = 160;
    Guns[21].AGI_min = 50;
    Guns[21].AGI_max = 60;
    Guns[21].PC = 1;
 
    /*Guns[22].name = "M9 Grenade";
    Guns[22].AT_min = 18;
    Guns[22].AT_max = 48;
    Guns[22].AGI_min = 20;
    Guns[22].AGI_max = 30;
    Guns[22].PC = 1;*/
 
    /*Guns[23].name = "Power Laser Gun";
    Guns[23].AT_min = 24;
    Guns[23].AT_max = 36;
    Guns[23].AGI_min = 20;
    Guns[23].AGI_max = 30;
    Guns[23].PC = 1;*/
 
    /*Guns[24].name = "Napalm Bomb";
    Guns[24].AT_min = 0;
    Guns[24].AT_max = 0;
    Guns[24].AGI_min = 160;
    Guns[24].AGI_max = 180;
    Guns[24].PC = 1;*/
 
    /*Guns[25].name = "Wave Cannon";
    Guns[25].AT_min = 120;
    Guns[25].AT_max = 180;
    Guns[25].AGI_min = 80;
    Guns[25].AGI_max = 90;
    Guns[25].PC = 1;*/
 
    Guns[26].name = "Pierce Homing";
    Guns[26].AT_min = 12;
    Guns[26].AT_max = 16;
    Guns[26].AGI_min = 20;
    Guns[26].AGI_max = 30;
    Guns[26].PC = 7;
 
    Guns[27].name = "Magnum";
    Guns[27].AT_min = 80;
    Guns[27].AT_max = 120;
    Guns[27].AGI_min = 20;
    Guns[27].AGI_max = 30;
    Guns[27].PC = 1;
 
    Guns[28].name = "Micro Uzi";
    Guns[28].AT_min = 16;
    Guns[28].AT_max = 32;
    Guns[28].AGI_min = 5;
    Guns[28].AGI_max = 10;
    Guns[28].PC = 3;
 
    Guns[29].name = "Triple Shotgun";
    Guns[29].AT_min = 1;
    Guns[29].AT_max = 120;
    Guns[29].AGI_min = 50;
    Guns[29].AGI_max = 60;
    Guns[29].PC = 15;
 
    Guns[30].name = "Rail Gun";
    Guns[30].AT_min = 300;
    Guns[30].AT_max = 320;
    Guns[30].AGI_min = 50;
    Guns[30].AGI_max = 60;
    Guns[30].PC = 1;
 
    /*Guns[31].name = "Napalm Gun";
    Guns[31].AT_min = 26;
    Guns[31].AT_max = 96;
    Guns[31].AGI_min = 70;
    Guns[31].AGI_max = 80;
    Guns[31].PC = 1;*/
 
    /*Guns[32].name = "Slow Laser Gun";
    Guns[32].AT_min = 32;
    Guns[32].AT_max = 48;
    Guns[32].AGI_min = 20;
    Guns[32].AGI_max = 30;
    Guns[32].PC = 1;*/
}
 
// Sets values to the Gunner character
void getStats(Character &Gunner1, int &LVL){
    std::cout << "Enter characters' level: ";
    std::cin >> LVL;
    std::cout << LVL << std::endl;
    Gunner1.STR = LVL - 1; // Evenly distribute STR and DEX
    Gunner1.DEX = LVL - 1;
}
 
 
// Calculates DPS for each gun equipped on the gunner character
// How to get DPS: (AT + STR*2%) * (AGI / 2%*DEX)
void calcDPS(Character Gunner1, Gun Guns[], int LVL){
    float DPS;                    // Damage per 60 frames
    float DPS_max = 0;            // Maximum DPS
    int DPS_max_STR, DPS_max_DEX; // STR and DEX allocation for maximum DPS
    int AGImin, AGImax;           // Minimum and maximum ATtack damage
    float AGI;                    // Average AGIlity (number of frames between shots)
    int ATmin, ATmax;             // Minimum and maximum ATtack damage
    float AT;                     // Average ATtack damage
    int range = (LVL - 1) * 2;    // Range of stats to calculate (currently set to go from 0 to max)
 
    for (int i = 0; i < weapons; i++){    // Runs for the number of weapons
 
        if (Guns[i].name == "") continue; // Skip over commented out Guns
 
        for (int k = 0; k <= range; k++){ // Loop for going through full range of STR/DEX
 
            // Calculates average AT
            ATmin = Guns[i].AT_min * (1 + 0.02 * (Gunner1.STR - (range/2 - k))); // Minimum AT calculation
            ATmax = Guns[i].AT_max * (1 + 0.02 * (Gunner1.STR - (range/2 - k))); // Maximum AT calculation
            AT = (ATmin + ATmax) / 2.;                                           // Average AT calculation
 
            // Calculates average AGI
            AGImin = Guns[i].AGI_min / (1 + 0.02 * (Gunner1.DEX + range/2 - k)); // Minimum AGI calculation
            if (AGImin < 5) AGImin = 5;                                          // AGImin caps at 5
            AGImax = Guns[i].AGI_max / (1 + 0.02 * (Gunner1.DEX + range/2 - k)); // Maximum AGI calculation
            if (AGImax < 10) AGImax = 10;                                        // AGImin caps at 10
            AGI = (AGImin + AGImax) / 2.;                                        // Average AGI calculation
 
            // Calculates average DPS
            DPS = AT * (60 / AGI);
 
            // Calculates maximum DPS
            if (DPS > DPS_max){
                DPS_max = DPS;                             // Store maximum DPS
                DPS_max_STR = Gunner1.STR - (range/2 - k); // Store STR parameter of maximum DPS
                DPS_max_DEX = Gunner1.DEX + (range/2 - k); // Store DEX parameter of maximum DPS
            }
        }
 
        // Outputs table of optimum STR/DEX allocation for maximum DPS of each Gun
        std::cout << "DPS max for " << std::setw(17) << Guns[i].name << ": ";
        std::cout << "STR " << std::setw(3) << DPS_max_STR;           // STR
        std::cout << "  DEX " << std::setw(3) << DPS_max_DEX;         // DEX
        std::cout << "  DPS = " << DPS_max * Guns[i].PC << std::endl; // DPS
        DPS_max = DPS_max_STR = DPS_max_DEX = 0;                      // Reset maximums
    }
    std::cout << std::endl;
}
 
int main(){
    Character Gunner1; // Gunner character
    Gun Guns[weapons]; // Array of guns to calculate
    int LVL;           // Level of your team
 
    setGuns(Guns);
 
    getStats(Gunner1, LVL);
    while (LVL){
        calcDPS(Gunner1, Guns, LVL);
        getStats(Gunner1, LVL);
    }
 
    return 0;
}