/**
  * Verifies character data, ensures all fields are valid.
  */
 public function Attack(Being $AnEnemy, $Spell = true)
 {
     $Result = array();
     $Result['Rounds'] = array();
     $Result['Masteries'] = array();
     $MonsterMasteryChance = 0;
     //Modify AnEnemy if is monster. Make it like a character.
     if (get_class($AnEnemy) == 'Entities\\Monster') {
         //Give our monster some gear!
         $AnEnemy->Equipment = array();
         for ($Index = 0; $Index < 2; $Index++) {
             $Item = new \Entities\Item();
             if ($AnEnemy->Strength > $AnEnemy->Intelligence) {
                 $Item->SlotType = 0;
                 $Item->MasteryType = 2;
                 $Item->ItemClass = $AnEnemy->WeaponClass;
             } else {
                 $Item->SlotType = 3;
                 if (mt_rand(1, 100) < 25) {
                     $Item->MasteryType = 11;
                     //Heal
                 } else {
                     $Item->MasteryType = 6;
                     //Fire
                 }
                 $Item->ItemClass = $AnEnemy->SpellClass;
             }
             $AnEnemy->Equipment[$Index] = $Item;
         }
         if ($AnEnemy->MasteryBonus) {
             $MonsterMasteryChance = $AnEnemy->MasteryBonus;
         }
         $Armor = new \Entities\Item();
         $Armor->SlotType = 1;
         $Armor->ItemClass = $AnEnemy->ArmorClass;
         $AnEnemy->Equipment[2] = $Armor;
     }
     //0 is the player, 1 is the enemy. Loop through to create "Rounds", or rows in the result set.
     for ($Index = 0; $Index < 2; $Index++) {
         $NumWeapons = 0;
         $EnemyArmorClass = 0;
         $Being = null;
         $EnemyBeing = null;
         $DamageType = 0;
         //If this is the enemy...
         if ($Index == 1) {
             $Being = $AnEnemy;
             $EnemyBeing = $this;
             if ($AnEnemy->Strength > $AnEnemy->Intelligence) {
                 $DamageType = 0;
             } else {
                 $DamageType = 1;
             }
         } else {
             $EnemyBeing = $AnEnemy;
             $Being = $this;
             $DamageType = $Spell;
         }
         //Get Armor Class for the attacked
         foreach ($EnemyBeing->Equipment as $AnItem) {
             if ($AnItem->SlotType == 1) {
                 $EnemyArmorClass += $AnItem->ItemClass;
             }
         }
         //Get the attacker's weapons.
         foreach ($Being->Equipment as $AnItem) {
             if (!$Spell) {
                 if ($AnItem->SlotType == 0) {
                     $NumWeapons++;
                 }
             } else {
                 if ($AnItem->SlotType == 3) {
                     $NumWeapons++;
                 }
             }
         }
         //Fill the "Round" with attack data.
         $PlayerRow = array();
         foreach ($Being->Equipment as $AnItem) {
             $DamageStat = 0;
             $HitStat = 0;
             $MissStat = 0;
             $IsWeapon = false;
             $IsHeal = false;
             $AttackType = $DamageType;
             if (!$DamageType) {
                 //If is a weapon
                 if ($AnItem->SlotType == 0) {
                     if ($AnItem->MasteryType != 0) {
                         $AttackType = 0;
                         $IsWeapon = true;
                         $DamageStat = $Being->Strength;
                         $HitStat = $Being->Dexterity;
                         $MissStat = $EnemyBeing->Dexterity;
                     }
                 }
             } else {
                 //If is a spell
                 if ($AnItem->SlotType == 3) {
                     $DamageStat = $Being->Intelligence;
                     $HitStat = $Being->Wisdom;
                     $MissStat = $EnemyBeing->Wisdom;
                     if ($AnItem->MasteryType != 11) {
                         $AttackType = 1;
                         $IsWeapon = true;
                     } else {
                         $AttackType = 2;
                         $IsHeal = true;
                     }
                 }
             }
             //Initiative - shared between all damage types
             $Initiative = 0;
             if ($IsWeapon || $IsHeal) {
                 $InitStat = max($Being->Dexterity, $Being->Wisdom);
                 $EnemyInitStat = max($EnemyBeing->Dexterity, $EnemyBeing->Wisdom);
                 $Initiative = \gauss_ms($InitStat, $InitStat * 0.2) - \gauss_ms($EnemyInitStat, $EnemyInitStat * 0.2);
                 //Damage/Heal calculations
                 $ActualDamage = 0;
                 $IsCritical = false;
                 if ($IsWeapon) {
                     $ActualDamage = 0;
                     $ChanceToHitBonus = 1;
                     $Mastery = 0;
                     if (get_class($Being) == 'Entities\\Character') {
                         $Mastery = $Being->Masteries[$AnItem->MasteryType]['Value'];
                     }
                     $ChanceToHit = $HitStat / $MissStat * 50 * (1 + $Mastery / 100) * $ChanceToHitBonus;
                     if (mt_rand(1, 100) < $ChanceToHit) {
                         $EnemyArmorMastery = 0;
                         if (get_class($EnemyBeing) == 'Entities\\Character') {
                             $EnemyArmorMastery = $EnemyBeing->Masteries[0]['Value'];
                         }
                         $ItemClassBonus = $Being->WeaponClassBonus;
                         if ($DamageType) {
                             $ItemClassBonus = $Being->SpellClassBonus;
                         }
                         $BaseDamage = pow(1.15, $AnItem->ItemClass + $ItemClassBonus - ($EnemyArmorClass + $EnemyBeing->ArmorClassBonus + round($EnemyArmorMastery / 5)));
                         $ActualDamage = \gauss_ms($DamageStat / 3, $DamageStat / 3 * 0.1) * $BaseDamage;
                         $ActualDamage = round($ActualDamage * (1 / max(pow($NumWeapons, 1.5), 1)) / (2 / 3));
                         $CritChance = mt_rand(1, 20 + $Mastery / 10);
                         if ($CritChance > 19) {
                             $IsCritical = true;
                             $ActualDamage = round($ActualDamage * \gauss_ms(3, 0.5));
                         }
                     }
                 } else {
                     if ($IsHeal) {
                         $BaseHeal = $Being->Intelligence / 10;
                         $ActualDamage = round(\gauss_ms($BaseHeal, $BaseHeal * 0.2) * $AnItem->ItemClass / 5);
                     }
                 }
                 //Insert Damage/Heal into Result array ordered by initiative
                 $Inserted = false;
                 $PlayerRow = array('Damage' => $ActualDamage, 'Actor' => $Index, 'Type' => $AttackType, 'MasteryType' => $AnItem->MasteryType, 'Initiative' => $Initiative, 'IsCritical' => $IsCritical);
                 for ($ArrayIndex = 0; $ArrayIndex < count($Result); $ArrayIndex++) {
                     if ($Initiative > @$Result['Rounds'][$ArrayIndex]['Initiative']) {
                         array_splice($Result['Rounds'], $ArrayIndex, 0, array($PlayerRow));
                         $Inserted = true;
                         break;
                     }
                 }
                 if (!$Inserted) {
                     array_push($Result['Rounds'], $PlayerRow);
                 }
             }
         }
     }
     $PlayerWins = false;
     $EnemyWins = false;
     $Index = 0;
     //Clean up and finalize the Result
     while ($Index < count($Result['Rounds'])) {
         if (isset($Result['Rounds'][$Index])) {
             if ($EnemyWins || $PlayerWins) {
                 $Run = true;
                 for ($Index2 = count($Result['Rounds']) - 1; $Index2 >= $Index; $Index2--) {
                     array_pop($Result['Rounds']);
                 }
                 break;
             } else {
                 unset($Result['Rounds'][$Index]['Initiative']);
                 $ArrayItem = $Result['Rounds'][$Index];
                 if ($ArrayItem['Actor'] == 0) {
                     if ($ArrayItem['Type'] == 0 || $ArrayItem['Type'] == 1) {
                         $AnEnemy->Health = max($AnEnemy->Health - $ArrayItem['Damage'], 0);
                     } else {
                         if ($ArrayItem['Type'] == 2) {
                             $this->Health = min($ArrayItem['Damage'] + $this->Health, $this->Vitality);
                         }
                     }
                     //Mastery Gain Check
                     if ($this->Masteries[$ArrayItem['MasteryType']]['Value'] < $this->RacialMasteries[$ArrayItem['MasteryType']]['Max']) {
                         $MasteryCheck = 0 >= $AnEnemy->Health ? 20 + $MonsterMasteryChance : 20;
                         if (mt_rand(1, max(20 + $this->Masteries[$ArrayItem['MasteryType']]['Value'] * 50, 50)) < $MasteryCheck) {
                             $this->Masteries[$ArrayItem['MasteryType']]['Value']++;
                             $Result['Masteries'][] = $ArrayItem['MasteryType'];
                         }
                     }
                 } else {
                     if ($ArrayItem['Type'] == 0 || $ArrayItem['Type'] == 1) {
                         $this->Health = max($this->Health - $ArrayItem['Damage'], 0);
                         //Armor Mastery Gain Check
                         if ($ArrayItem['Damage'] > 0) {
                             if ($this->Masteries[$ArrayItem['MasteryType']]['Value'] < $this->RacialMasteries[$ArrayItem['MasteryType']]['Max']) {
                                 $MasteryCheck = 20 + $ArrayItem['Damage'] / $this->Vitality * 20;
                                 if (mt_rand(1, max(20 + $this->Masteries[0]['Value'] * 50, 50)) < $MasteryCheck) {
                                     $this->Masteries[0]['Value']++;
                                     $Result['Masteries'][] = 0;
                                 }
                             }
                         }
                     } else {
                         if ($ArrayItem['Type'] == 2) {
                             $AnEnemy->Health = min($ArrayItem['Damage'] + $AnEnemy->Health, $AnEnemy->Vitality);
                         }
                     }
                 }
             }
             if ($AnEnemy->Health <= 0) {
                 $PlayerWins = true;
             } else {
                 if ($this->Health <= 0) {
                     $EnemyWins = true;
                 }
             }
         }
         $Index++;
     }
     if (property_exists($AnEnemy, 'Special')) {
         $Result['Special'] = $AnEnemy->Special;
     }
     if ($PlayerWins) {
         $Result['Winner'] = 0;
         if (get_class($AnEnemy) == 'Entities\\Monster') {
             $this->Experience += $AnEnemy->EXPGiven;
             $this->Gold += $AnEnemy->GoldGiven;
             $Result['Gold'] = $AnEnemy->GoldGiven;
             $Result['Experience'] = $AnEnemy->EXPGiven;
             if ($AnEnemy->AlignGood || $AnEnemy->AlignOrder) {
                 if (mt_rand(0, 2500) < 5 + 2500 * $AnEnemy->AlignChanceBonus) {
                     if ($AnEnemy->AlignGood > 0) {
                         $this->AlignGood -= 1;
                         $Result['AlignGood'] = $this->AlignGood;
                     } else {
                         if ($AnEnemy->AlignGood < 0) {
                             $this->AlignGood += 1;
                             $Result['AlignGood'] = $this->AlignGood;
                         }
                     }
                     if ($AnEnemy->AlignOrder > 0) {
                         $this->AlignOrder -= 1;
                         $Result['AlignOrder'] = $this->AlignOrder;
                     } else {
                         if ($AnEnemy->AlignOrder < 0) {
                             $this->AlignOrder += 1;
                             $Result['AlignOrder'] = $this->AlignOrder;
                         }
                     }
                 }
             }
         } else {
             $this->Gold += $AnEnemy->Gold;
             $Result['Gold'] = $AnEnemy->Gold;
             $AnEnemy->Gold = 0;
             if ($AnEnemy->AlignGood >= 0) {
                 $this->AlignGood -= 1;
                 $Result['AlignGood'] = $this->AlignGood;
             } else {
                 if ($AnEnemy->AlignGood < 0) {
                     $this->AlignGood += 1;
                     $Result['AlignGood'] = $this->AlignGood;
                 }
             }
             if ($AnEnemy->AlignOrder >= 0) {
                 $this->AlignOrder -= 1;
                 $Result['AlignOrder'] = $this->AlignOrder;
             } else {
                 if ($AnEnemy->AlignOrder < 0) {
                     $this->AlignOrder += 1;
                     $Result['AlignOrder'] = $this->AlignOrder;
                 }
             }
         }
         $Result['LevelUp'] = $this->LevelUp();
         unset($_SESSION['CurrentFight']);
     } else {
         if ($EnemyWins) {
             $Result['Winner'] = 1;
             $LastReviveTime = 0;
             if (isset($_SESSION['LastReviveTime'])) {
                 $LastReviveTime = $_SESSION['LastReviveTime'];
             }
             $RevivePenaltyMultiplier = 0;
             if ($LastReviveTime + 60 * 5 >= time()) {
                 if (isset($_SESSION['RevivePenaltyMultiplier'])) {
                     $_SESSION['RevivePenaltyMultiplier']++;
                 } else {
                     $_SESSION['RevivePenaltyMultiplier'] = 1;
                 }
             } else {
                 unset($_SESSION['RevivePenaltyMultiplier']);
             }
             $this->Gold = 0;
             unset($_SESSION['CurrentFight']);
         }
     }
     return $Result;
 }
Beispiel #2
0
function random_normal($sine = 0, $percentage = 1)
{
    /*
    Chebyshev rules at least 1 - 1/k2 of the values are within k standard deviations
    from the mean ( ex. 7s 99.99999999974 % ).
    */
    $max = 4;
    do {
        $value = gauss_ms(0, 1);
    } while (abs($value) > $max);
    if ($sine == 0) {
        $value = abs($value);
    }
    if ($percentage > 0) {
        return $value / $max;
    } else {
        return $value;
    }
}
 /**
  * Generate Stats
  *
  * function to generate stats for a mob based on level and bonuses.
  *
  */
 public function GenerateStats()
 {
     $StatSeed = 7;
     $Stats = pow($this->Level + 2, log($this->Level + 3, 42.75)) * 10;
     $StatsHigh = $Stats * 1.1;
     $StdDev = $StatsHigh - $Stats;
     $this->StatBonus = 1;
     $StrengthBonus = 1;
     $DexterityBonus = 1;
     $HealthBonus = 1;
     $IntelligenceBonus = 1;
     $WisdomBonus = 1;
     $this->Special = 0;
     $this->AlignChanceBonus = 0;
     if (mt_rand(0, 100) > 95) {
         $this->Special = $this->RandomSpecial();
     }
     $this->Strength = round(\gauss_ms($Stats, $StdDev) * $StrengthBonus * $this->StatBonus);
     $this->Dexterity = round(\gauss_ms($Stats, $StdDev) * $DexterityBonus * $this->StatBonus);
     $this->Intelligence = round(\gauss_ms($Stats, $StdDev) * $IntelligenceBonus * $this->StatBonus);
     $this->Wisdom = round(\gauss_ms($Stats, $StdDev) * $WisdomBonus * $this->StatBonus);
     $this->Vitality = round(\gauss_ms($Stats, $StdDev) * $HealthBonus * $this->StatBonus);
     $this->Health = $this->Vitality;
     $ExpSeed = 1.1;
     $GoldSeed = 1.01;
     $this->GoldGiven = (pow($this->Level + 8, log($this->Level + 8, 125)) + 7) * $this->GoldBonus;
     $EXPMultiplier = 5;
     $this->EXPGiven = round(pow($this->Level, log($this->Level + 1, 50)) * $EXPMultiplier * $this->ExperienceBonus);
     $GoldStdDev = $this->GoldGiven - $this->GoldGiven * 0.9;
     $ExpStdDev = $this->EXPGiven - $this->EXPGiven * 0.9;
     $this->GoldGiven = round(\gauss_ms($this->GoldGiven, $GoldStdDev));
     $this->EXPGiven = round(\gauss_ms($this->EXPGiven, $ExpStdDev));
 }
 public static function gaussianWeightedRandom($LowValue, $maxRand, $mean = 0.0, $stddev = 2.0)
 {
     //  Adjust a gaussian random value to fit within our specified range
     //      by 'trimming' the extreme values as the distribution curve
     //      approaches +/- infinity
     $rand_val = $LowValue + $maxRand;
     while ($rand_val < $LowValue || $rand_val >= $LowValue + $maxRand) {
         $rand_val = floor(gauss_ms($mean, $stddev) * $maxRand) + $LowValue;
         $rand_val = ($rand_val + $maxRand) / 2;
     }
     return $rand_val;
 }