/* 
    BattleRPG Copyright (C) 2007-2008 Nico de Vries.

    This file is part of BattleRPG.

    BattleRPG 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 3 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, see http://www.gnu.org/licenses/.
*/

class BattlePersistentPlayerBuildDatabase extends Object config (BattlePersistentPlayerBuildDatabase);
// The player build database does not refer to classes but to ID's which are defined in UTBattleRPG.INI.
// This allows server administrators to replace a class without having to edit the player build database.

struct ABILITYLEVEL { 
  var name ID;
  var int Level;
};

struct RECORD {
  var name ID;
  var array<ABILITYLEVEL> Abilities;
};

var config array<RECORD> DATABASE;

var BattleRPG BRPG;

function Commit ()
{
  SaveConfig(); // Save the database to disk (useful if the server decides to crash)
}

function int GetPlayerLevel (name ID, int TheAbilityIndex) 
{
  local int i, playerindex, abilityindex;

  playerindex = DATABASE.Find ('ID', ID);
  if (playerindex!=-1) {
    for (i=0; i<DATABASE[playerindex].Abilities.Length; i++) {
      abilityindex = BRPG.DynamicAbilities.Find ('ID', DATABASE[playerindex].Abilities[i].ID);
      if (abilityindex!=-1) {
        if (abilityindex == TheAbilityIndex) return DATABASE[playerindex].Abilities[i].Level;
      }
    }
  }
  return 0;
}

function GetPlayerBuildData (out int PlayerAbilityLevels[100], name ID)
{
  local int i, playerindex, abilityindex;

  playerindex = DATABASE.Find ('ID', ID);
  if (playerindex!=-1) {
    for (i=0; i<DATABASE[playerindex].Abilities.Length; i++) {
      abilityindex = BRPG.DynamicAbilities.Find ('ID', DATABASE[playerindex].Abilities[i].ID);
      if (abilityindex!=-1) {
        // Minimize repnotify type events.
        if (PlayerAbilityLevels[abilityindex] != DATABASE[playerindex].Abilities[i].Level) {
          PlayerAbilityLevels[abilityindex] = DATABASE[playerindex].Abilities[i].Level;
        }
      }
    }
  }
}

function bool PlayerBuildData_Buy_Allowed (PlayerReplicationInfo PRI, int PlayerAbilityLevels[100], int TheAbilityIndex) {
  local BattleAbility BA;
  local BPRIDATA BD;
  local int Available;
  local int i;
  local int j;
  local int k;
  local bool bAllowed;
  local bool bHasAll;

  if (BRPG.AvailableAbilities.Length <= TheAbilityIndex || TheAbilityIndex < 0) return false; // Tip from Shambler against exploits
  BA = BRPG.AvailableAbilities[TheAbilityIndex];

  // Find out if there are requirements, set bAllowed to false if there are 
  bAllowed = true;
  for (i=0; i<BRPG.DynamicAbilityRequirements.Length; i++) { // All requirement specifications
    if (BRPG.DynamicAbilityRequirements[i].This.ID == BRPG.DynamicAbilities[TheAbilityIndex].ID) { // Requirement for this Ability
      if (PlayerAbilityLevels[TheAbilityIndex] == BRPG.DynamicAbilityRequirements[i].This.Level - 1) {
        if (BRPG.DynamicAbilityRequirements[i].Required.Length > 0) { 
          bAllowed = false;
        }
      }
    }
  }

  // If there are requirements, find out of the player meets them, format is (a AND b) OR (c AND d)
  if (!bAllowed) {
    for (i=0; i<BRPG.DynamicAbilityRequirements.Length; i++) { // All requirement specifications
      if (BRPG.DynamicAbilityRequirements[i].This.ID == BRPG.DynamicAbilities[TheAbilityIndex].ID) { // Requirement for this Ability
        if (PlayerAbilityLevels[TheAbilityIndex] == BRPG.DynamicAbilityRequirements[i].This.Level - 1) { // Relevant requirement
          if (BRPG.DynamicAbilityRequirements[i].Required.Length > 0) { 
            bHasAll = true;
            for (j=0; j<BRPG.DynamicAbilityRequirements[i].Required.Length; j++) { // All of these abilities have to be present
              for (k=0; k<BRPG.DynamicAbilities.Length; k++) { // All existing abilities
                if (BRPG.DynamicAbilityRequirements[i].Required[j].ID == BRPG.DynamicAbilities[k].ID) { // Found ability 
                  if (PlayerAbilityLevels[k] < BRPG.DynamicAbilityRequirements[i].Required[j].Level) bHasAll = false; // Check
                }
              }
            }
            if (bHasAll) bAllowed = true;
          }
        }
      }
    }    
  }

  // Find out if the player has something that does not allow him/her to buy this
  for (i=0; i<BRPG.DynamicAbilityRequirements.Length; i++) { // All requirement specifications
    if (BRPG.DynamicAbilityRequirements[i].This.ID == BRPG.DynamicAbilities[TheAbilityIndex].ID) { // Requirement for this Ability
      if (PlayerAbilityLevels[TheAbilityIndex] == BRPG.DynamicAbilityRequirements[i].This.Level - 1) { // Relevant requirement
        if (BRPG.DynamicAbilityRequirements[i].NotAllowedWith.Length > 0) { 
          bHasAll = true;
          for (j=0; j<BRPG.DynamicAbilityRequirements[i].NotAllowedWith.Length; j++) { // All of these abilities have to be present
            for (k=0; k<BRPG.DynamicAbilities.Length; k++) { // All existing abilities
              if (BRPG.DynamicAbilityRequirements[i].NotAllowedWith[j].ID == BRPG.DynamicAbilities[k].ID) { // Found ability 
                if (PlayerAbilityLevels[k] < BRPG.DynamicAbilityRequirements[i].NotAllowedWith[j].Level) bHasAll = false; // Check
              }
            }
          }
          if (bHasAll) bAllowed = false;        
        }
      }
    }
  }

  if (!bAllowed) return false;

  // Can the player buy a level, or are we at the maximum?
  if (PlayerAbilityLevels[TheAbilityIndex] < BA.MaxLevel()) {
    // Can the player afford a level?
    BD = class'BattleStaticFunctions'.static.ReadBPRI (PRI);
    Available = BD.Level * BRPG.RPGDollarsPerLevel;
    for (i=0; i<BRPG.DynamicAbilities.Length; i++) {
      Available -= BRPG.AvailableAbilities[i].TotalCost(PlayerAbilityLevels[i]);
    }
    if (Available >= BA.Cost (PlayerAbilityLevels[TheAbilityIndex]+1)) return true;
  }
  return false;
}

function PlayerBuildData_Buy (name PlayerID, int TheAbilityIndex) {  
  local name AbilityID;
  local int playerindex, abilityindex;
  local RECORD R;
  local ABILITYLEVEL AL;

  if (BRPG.AvailableAbilities.Length <= TheAbilityIndex || TheAbilityIndex < 0) return; // Tip from Shambler against exploits
  AbilityID = BRPG.DynamicAbilities[TheAbilityIndex].ID;
  playerindex = DATABASE.Find ('ID', PlayerID);
  if (playerindex==-1) {
    R.ID = PlayerID;
    DATABASE.AddItem (R);
    playerindex = DATABASE.Find ('ID', PlayerID);
  }
  abilityindex = DATABASE[playerindex].Abilities.Find ('ID', AbilityID);
  if (abilityindex==-1) {
    AL.ID = AbilityID;
    AL.Level = 0;
    DATABASE[playerindex].Abilities.AddItem (AL);
    abilityindex = DATABASE[playerindex].Abilities.Find ('ID', AbilityID);
  }
  DATABASE[playerindex].Abilities[abilityindex].Level++;
}

function PlayerBuildData_SellAll (name PlayerID) {
  local int i;
  local int j;
  local int level;

  for (i=0; i<BRPG.AvailableAbilities.Length; i++) {
    level = GetPlayerLevel (PlayerID, i);
    for (j=0; j < level; j++) {
      PlayerBuildData_Sell (PlayerID, i);
    }
  }
}

function PlayerBuildData_Sell (name PlayerID, int TheAbilityIndex) {  
  local name AbilityID;
  local int playerindex, abilityindex;
  local RECORD R;
  local ABILITYLEVEL AL;

  if (BRPG.AvailableAbilities.Length <= TheAbilityIndex || TheAbilityIndex < 0) return; // Tip from Shambler against exploits
  AbilityID = BRPG.DynamicAbilities[TheAbilityIndex].ID;
  playerindex = DATABASE.Find ('ID', PlayerID);
  if (playerindex==-1) {
    R.ID = PlayerID;
    DATABASE.AddItem (R);
    playerindex = DATABASE.Find ('ID', PlayerID);
  }
  abilityindex = DATABASE[playerindex].Abilities.Find ('ID', AbilityID);
  if (abilityindex==-1) {
    AL.ID = AbilityID;
    AL.Level = 0;
    DATABASE[playerindex].Abilities.AddItem (AL);
    abilityindex = DATABASE[playerindex].Abilities.Find ('ID', AbilityID);
  }
  DATABASE[playerindex].Abilities[abilityindex].Level--;
  if (DATABASE[playerindex].Abilities[abilityindex].Level<0) DATABASE[playerindex].Abilities[abilityindex].Level=0;
}

defaultproperties
{
  Name="BattlePersistentPlayerDatabase"
}