#include "sc_dart_include"

string ACTUAL_NUM_HIT = "ACTUAL_NUM_HIT";
string ACTUAL_REG_HIT =  "ACTUAL_REG_HIT";

// Ensure that the attacker misses
void ensureHit() {
    //EffectAttackIncrease
}

// Ensure that the attacker hits
void ensureMiss() {
    //EffectModifyAttacks
}

// Return the number to the left of the target
int getClockwise(int target) {
    switch (target) {
        case 20: return 1;
        case 1: return 18;
        case 18: return 4;
        case 4: return 13;
        case 13: return 6;
        case 6: return 10;
        case 10: return 15;
        case 15: return 2;
        case 2: return 17;
        case 17: return 3;
        case 3: return 19;
        case 19: return 7;
        case 7: return 16;
        case 16: return 8;
        case 8: return 11;
        case 11: return 14;
        case 14: return 9;
        case 9: return 12;
        case 12: return 5;
        case 5: return 20;
    }

    return 0;
}

int getAnticlockwise(int target) {
    switch (target) {
        case 1: return 20;
        case 18: return 1;
        case 4: return 18;
        case 13: return 4;
        case 6: return 13;
        case 10: return 6;
        case 15: return 10;
        case 2: return 15;
        case 17: return 2;
        case 3: return 17;
        case 19: return 3;
        case 7: return 19;
        case 16: return 7;
        case 8: return 16;
        case 11: return 8;
        case 14: return 11;
        case 9: return 14;
        case 12: return 14;
        case 5: return 12;
        case 20: return 5;
     }
    return 0;
}

// Determine where the player hit based on their skill
void determineRegionHit(string region, int number, object player) {
   int bonus = calcAttackBonus(player);

   int roll = d20() + bonus;

   int actual_number = 0;
   string actual_region = "";

    // Determine what the player has hit
    // Attempt bullseye
    if (number == BULLSEYE) {
        if (roll >= 19) {
            actual_number = BULLSEYE;
            actual_region = TARGET_REGION_CENTRE;
        }
        else if (roll >= 16) {
            actual_number = RING_25;
            actual_region = TARGET_REGION_CENTRE;
        }
        else if (roll >= 8) {
            actual_number = d20();
            actual_region = TARGET_REGION_NUMBER;
        }
        else if (roll >= 7) {
            actual_number = d20();
            actual_region = TARGET_REGION_TRIPLE;
        }
        else if (roll >= 3) {
            actual_number = d20();
            actual_region = TARGET_REGION_NUMBER;
        }
        else if (roll >= 2) {
            actual_number = d20();
            actual_region = TARGET_REGION_DOUBLE;
        }
        else {
            actual_number = 0;
            actual_region = TARGET_REGION_NUMBER;
        }
    }
    // Attempt 25 ring
    else if (number == RING_25) {
        if (roll >= 18) {
            actual_number = RING_25;
            actual_region = TARGET_REGION_CENTRE;
        }
        else if (roll >= 17) {
            actual_number = BULLSEYE;
            actual_region = TARGET_REGION_CENTRE;
        }
        else if (roll >= 8) {
            actual_number = d20();
            actual_region = TARGET_REGION_NUMBER;
        }
        else if (roll >= 7) {
            actual_number = d20();
            actual_region = TARGET_REGION_TRIPLE;
        }
        else if (roll >= 3) {
            actual_number = d20();
            actual_region = TARGET_REGION_NUMBER;
        }
        else if (roll >= 2) {
            actual_number = d20();
            actual_region = TARGET_REGION_DOUBLE;
        }
        else {
            actual_number = 0;
            actual_region = TARGET_REGION_NUMBER;
        }
    }
    // Go for a number
    else if (region == TARGET_REGION_NUMBER) {
        if (roll >= 12) {
            actual_number = number;
            actual_region = TARGET_REGION_NUMBER;
        }
        else if (roll >= 11) {
            actual_number = number;
            actual_region = TARGET_REGION_TRIPLE;
        }
        else if (roll >= 10) {
            actual_number = number;
            actual_region = TARGET_REGION_DOUBLE;
        }
        else if (roll >= 5){
            int clock = d2();
            if (clock == 1) {
                actual_number = getClockwise(number);
            }
            else {
                actual_number = getAnticlockwise(number);
            }
            actual_region = TARGET_REGION_NUMBER;
        }
        else if (roll >= 4) {
            int clock = d2();
            if (clock == 1) {
                actual_number = getClockwise(number);
            }
            else {
                actual_number = getAnticlockwise(number);
            }
            actual_region = TARGET_REGION_TRIPLE;
        }
        else if (roll >= 3) {
            int clock = d2();
            if (clock == 1) {
                actual_number = getClockwise(number);
            }
            else {
                actual_number = getAnticlockwise(number);
            }
            actual_region = TARGET_REGION_DOUBLE;
        }
        else if (roll >= 2) {
            actual_number = d20();
            actual_region = TARGET_REGION_NUMBER;
        }
        else {
            actual_number = 0;
            actual_region = TARGET_REGION_NUMBER;
        }
    }
    // Go for a double
    else if (region == TARGET_REGION_DOUBLE) {
        if (roll >= 16) {
            actual_number = number;
            actual_region = TARGET_REGION_DOUBLE;
        }
        else if (roll >= 14) {
            int clock = d2();
            if (clock == 1) {
                actual_number = getClockwise(number);
            }
            else {
                actual_number = getAnticlockwise(number);
            }
            actual_region = TARGET_REGION_DOUBLE;
        }
        else if (roll >= 6) {
            int hit = d2();
            if (hit == 1) {
                actual_number = number;
                actual_region = TARGET_REGION_NUMBER;
            }
            else {
                actual_number = 0;
                actual_region = TARGET_REGION_NUMBER;
            }
        }
        else if (roll >= 3) {
            int clock = d2();
            if (clock == 1) {
                actual_number = getClockwise(number);
            }
            else {
                actual_number = getAnticlockwise(number);
            }
            actual_region = TARGET_REGION_NUMBER;
        }
        else if (roll >= 2) {
            actual_number = d20();
            actual_region = TARGET_REGION_NUMBER;
        }
        else {
            actual_number = 0;
            actual_region = TARGET_REGION_NUMBER;
        }
    }
    // Attempt a triple
    else if (region == TARGET_REGION_TRIPLE) {
        if (roll >= 18) {
            actual_number = number;
            actual_region = TARGET_REGION_TRIPLE;
        }
        else if (roll >= 16) {
            int clock = d2();
            if (clock == 1) {
                actual_number = getClockwise(number);
            }
            else {
                actual_number = getAnticlockwise(number);
            }
            actual_region = TARGET_REGION_TRIPLE;
        }
        else if (roll >= 10) {
            actual_number = number;
            actual_region = TARGET_REGION_NUMBER;
        }
        else if (roll >= 4) {
            int clock = d2();
            if (clock == 1) {
                actual_number = getClockwise(number);
            }
            else {
                actual_number = getAnticlockwise(number);
            }
            actual_region = TARGET_REGION_NUMBER;
        }
        else if (roll >= 2) {
            actual_number = d20();
            actual_region = TARGET_REGION_NUMBER;
        }
        else {
            actual_number = 0;
            actual_region = TARGET_REGION_NUMBER;
        }
    }

    SetLocalInt(OBJECT_SELF, ACTUAL_NUM_HIT, actual_number);
    SetLocalString(OBJECT_SELF, ACTUAL_REG_HIT, actual_region);
}

// Provide a description of a target/number combo that was hit by the player
string targetHitToString(string region, int number) {
    object db = getDB();

    string target = "";
    if (number == BULLSEYE) {
        target = "You hit a Bullseye!";
    }
    else if (number == RING_25) {
        target = "You hit the 25 Ring.";
    }
    else if (number == 0) {
        target = "You Missed the board completely!";
    }
    else if (region == TARGET_REGION_NUMBER) {
        target = "You hit Number "+IntToString(number)+".";
    }
    else if (region == TARGET_REGION_DOUBLE) {
        target = "You hit Double "+IntToString(number)+".";
    }
    else if (region == TARGET_REGION_TRIPLE) {
        target = "You hit Triple "+IntToString(number)+".";
    }

    return target;
}

// Determine outcome of dart thrown
void determineOutcome() {
        int score = 0;
        object db = getDB();
        object player;
        int player_turn = GetLocalInt(db, PLAYER_TURN);

        string region = "";
        int number = 0;
        if (player_turn == 1) {
            region = GetLocalString(db, CONTESTANT1_TARGET_REGION);
            number = GetLocalInt(db, CONTESTANT1_TARGET_NUMBER);
            player = GetLocalObject(db,CONTESTANT1);
        }
        else {
            region = GetLocalString(db, CONTESTANT2_TARGET_REGION);
            number = GetLocalInt(db, CONTESTANT2_TARGET_NUMBER);
            player = GetLocalObject(db,CONTESTANT2);
        }

        determineRegionHit(region, number, player);
        number = GetLocalInt(OBJECT_SELF, ACTUAL_NUM_HIT);
        region = GetLocalString(OBJECT_SELF, ACTUAL_REG_HIT);

        // determine score
        if (region == TARGET_REGION_CENTRE) {
            score = number;
        }
        else if (region == TARGET_REGION_NUMBER) {
            score = number;
        }
        else if (region == TARGET_REGION_DOUBLE) {
            score = 2*number;
        }
        else if (region == TARGET_REGION_TRIPLE) {
            score = 3*number;
        }

        int new_score = 0;
        if (player_turn == 1) {
            new_score = GetLocalInt(db, CONTESTANT1_SCORE_THIS);
            new_score = new_score - score;
            SetLocalInt(db, CONTESTANT1_SCORE_THIS, new_score);
        }
        else {
            new_score = GetLocalInt(db, CONTESTANT2_SCORE_THIS);
            new_score = new_score - score;
            SetLocalInt(db, CONTESTANT2_SCORE_THIS, new_score);
        }

        string target = targetHitToString(region, number);

        // If player has gone bust
        if (new_score < 0) {
            target = target + " You have gone bust";

            if (player_turn == 1) {
                new_score = GetLocalInt(db, CONTESTANT1_SCORE);
                SetLocalInt(db, CONTESTANT1_SCORE_THIS, new_score);
            }
            else {
                new_score = GetLocalInt(db, CONTESTANT2_SCORE);
                SetLocalInt(db, CONTESTANT2_SCORE_THIS, new_score);
            }
            // Player's turn is now ended
            SetLocalInt(db, DART_NUMBER,3);
        }
        // If player has won
        else if (new_score == 0) {
            SpeakString(target+" Congratulations, you have won!",TALKVOLUME_TALK);
            object player2 = GetLocalObject(db,CONTESTANT2);
            if (!GetIsPC(player)) {
                SignalEvent(player, NPC_WIN);
            }
            else if (!GetIsPC(player2)) {
                SignalEvent(player, NPC_LOSE);
            }
            GiveGoldToCreature(player, GetLocalInt(db, WAGER) * 2);
            resetVars();
            return;
        }

        int dart_no = GetLocalInt(db, DART_NUMBER);
        // If that was the last dart go to the next player
        if (dart_no == 3) {
            string new_player_name = "";
            if (player_turn == 1) {
                SetLocalInt(db, PLAYER_TURN, 2);
                object player2 = GetLocalObject(db,CONTESTANT2);
                new_player_name = GetName(player2);
                SetLocalInt(db, CONTESTANT1_SCORE, new_score);
                if (!GetIsPC(player2)) {
                    SignalEvent(player2, NPC_START_TURN);
                }
            }
            else {
                SetLocalInt(db, PLAYER_TURN, 1);
                new_player_name = GetName(GetLocalObject(db,CONTESTANT1));
                SetLocalInt(db, CONTESTANT2_SCORE, new_score);
                if (!GetIsPC(player)) {
                    SignalEvent(player, NPC_END_TURN);
                }
            }
            SetLocalInt(db, DART_NUMBER, 1);
            SpeakString(target+" Your score is now "
                +IntToString(new_score)
                +". Your turn has finished. "
                +new_player_name
                +" it is now your turn",TALKVOLUME_TALK);
        }
        else {
            SpeakString(target+" Your score is now "
                +IntToString(new_score)
                +". That was dart "+IntToString(dart_no)+" of 3",TALKVOLUME_TALK);
            dart_no = dart_no + 1;
            SetLocalInt(db, DART_NUMBER, dart_no);
            if (!GetIsPC(player)) {
                SignalEvent(player, NPC_THROW_DART_EVENT);
            }
        }
}

void main()
{
    WriteTimestampedLogEntry("sc_dart_throw called");
    object oPC = GetLastAttacker();
    object oWeapon = GetLastWeaponUsed(oPC);

    WriteTimestampedLogEntry(GetTag(oWeapon));

    if (FindSubString(GetTag(oWeapon), DART_WEAPON_TAG) == -1) {
        SpeakString("Only small darts can be used in a game of darts! Buy some from the referee if you have none",
                TALKVOLUME_TALK);
    }
    else if (!checkPlayerTurn(oPC)) {
        SpeakString("It is not your turn",
            TALKVOLUME_TALK);
    }
    else {
        determineOutcome();
        //FloatingTextStringOnCreature("Your score is now "+IntToString(new_score), ref,FALSE);
    }

    //WriteTimestampedLogEntry("PC to Object" + IntToString(GetReputation(oPC, OBJECT_SELF)));
    //WriteTimestampedLogEntry("Object to PC" + IntToString(GetReputation(OBJECT_SELF, oPC)));

    ClearPersonalReputation(oPC, OBJECT_SELF);
    ClearPersonalReputation(OBJECT_SELF, oPC);
    AdjustReputation(oPC, OBJECT_SELF, 10);

    //WriteTimestampedLogEntry("PC to Object" + IntToString(GetReputation(oPC, OBJECT_SELF)));
    //WriteTimestampedLogEntry("Object to PC" + IntToString(GetReputation(OBJECT_SELF, oPC)));

    ApplyEffectToObject(DURATION_TYPE_PERMANENT,EffectHeal(50), OBJECT_SELF, 0.1);

    ClearAllActions();

}