Adds buff effects for regeneration and minions

This commit adds support for regeneration (both regen and deregen) and
minions (for both goodguy or badguy - or both at the same time). It also
adds tests to ensure correct code workflow.
This commit is contained in:
Basilius Sauter
2016-06-06 09:29:31 +02:00
parent 7b609e3b5c
commit a53ab601f5
11 changed files with 860 additions and 90 deletions
Generated
+39 -36
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "29eaae94cbc5b621aa6d3addeb2bb310",
"hash": "ae66861589f917620e6ca83a84e235cd",
"content-hash": "cba343f753537b39dd63a0580b9c2630",
"packages": [
{
@@ -104,16 +104,16 @@
},
{
"name": "composer/composer",
"version": "1.1.1",
"version": "1.1.2",
"source": {
"type": "git",
"url": "https://github.com/composer/composer.git",
"reference": "48156b0fd9888bf528fbe9c9cba6963223cdd584"
"reference": "b2cf67b1a575d7e648c742be2454339232ef32b2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/composer/zipball/48156b0fd9888bf528fbe9c9cba6963223cdd584",
"reference": "48156b0fd9888bf528fbe9c9cba6963223cdd584",
"url": "https://api.github.com/repos/composer/composer/zipball/b2cf67b1a575d7e648c742be2454339232ef32b2",
"reference": "b2cf67b1a575d7e648c742be2454339232ef32b2",
"shasum": ""
},
"require": {
@@ -177,20 +177,20 @@
"dependency",
"package"
],
"time": "2016-05-17 11:25:44"
"time": "2016-05-31 18:48:12"
},
{
"name": "composer/semver",
"version": "1.4.0",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "84c47f3d8901440403217afc120683c7385aecb8"
"reference": "03c9de5aa25e7672c4ad251eeaba0c47a06c8b98"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/84c47f3d8901440403217afc120683c7385aecb8",
"reference": "84c47f3d8901440403217afc120683c7385aecb8",
"url": "https://api.github.com/repos/composer/semver/zipball/03c9de5aa25e7672c4ad251eeaba0c47a06c8b98",
"reference": "03c9de5aa25e7672c4ad251eeaba0c47a06c8b98",
"shasum": ""
},
"require": {
@@ -239,7 +239,7 @@
"validation",
"versioning"
],
"time": "2016-03-30 13:16:03"
"time": "2016-06-02 09:04:51"
},
{
"name": "composer/spdx-licenses",
@@ -1776,16 +1776,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "3.3.3",
"version": "4.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "44cd8e3930e431658d1a5de7d282d5cb37837fd5"
"reference": "900370c81280cc0d942ffbc5912d80464eaee7e9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/44cd8e3930e431658d1a5de7d282d5cb37837fd5",
"reference": "44cd8e3930e431658d1a5de7d282d5cb37837fd5",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/900370c81280cc0d942ffbc5912d80464eaee7e9",
"reference": "900370c81280cc0d942ffbc5912d80464eaee7e9",
"shasum": ""
},
"require": {
@@ -1799,7 +1799,7 @@
},
"require-dev": {
"ext-xdebug": ">=2.1.4",
"phpunit/phpunit": "~5"
"phpunit/phpunit": "^5.4"
},
"suggest": {
"ext-dom": "*",
@@ -1809,7 +1809,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.3.x-dev"
"dev-master": "4.0.x-dev"
}
},
"autoload": {
@@ -1835,7 +1835,7 @@
"testing",
"xunit"
],
"time": "2016-05-27 16:24:29"
"time": "2016-06-03 05:03:56"
},
{
"name": "phpunit/php-file-iterator",
@@ -2020,16 +2020,16 @@
},
{
"name": "phpunit/phpunit",
"version": "5.3.4",
"version": "5.4.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "00dd95ffb48805503817ced06399017df315fe5c"
"reference": "f5726a0262e5f74f8e9cf03128798b64160c441d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/00dd95ffb48805503817ced06399017df315fe5c",
"reference": "00dd95ffb48805503817ced06399017df315fe5c",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f5726a0262e5f74f8e9cf03128798b64160c441d",
"reference": "f5726a0262e5f74f8e9cf03128798b64160c441d",
"shasum": ""
},
"require": {
@@ -2041,11 +2041,11 @@
"myclabs/deep-copy": "~1.3",
"php": "^5.6 || ^7.0",
"phpspec/prophecy": "^1.3.1",
"phpunit/php-code-coverage": "^3.3.0",
"phpunit/php-code-coverage": "^4.0",
"phpunit/php-file-iterator": "~1.4",
"phpunit/php-text-template": "~1.2",
"phpunit/php-timer": "^1.0.6",
"phpunit/phpunit-mock-objects": "^3.1",
"phpunit/phpunit-mock-objects": "^3.2",
"sebastian/comparator": "~1.1",
"sebastian/diff": "~1.2",
"sebastian/environment": "~1.3",
@@ -2065,7 +2065,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.3.x-dev"
"dev-master": "5.4.x-dev"
}
},
"autoload": {
@@ -2091,30 +2091,33 @@
"testing",
"xunit"
],
"time": "2016-05-11 13:28:45"
"time": "2016-06-03 09:59:50"
},
{
"name": "phpunit/phpunit-mock-objects",
"version": "3.1.3",
"version": "3.2.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference": "151c96874bff6fe61a25039df60e776613a61489"
"reference": "0dc8fd8e87e0366c22b6c25d1f43c4e2e66847b3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/151c96874bff6fe61a25039df60e776613a61489",
"reference": "151c96874bff6fe61a25039df60e776613a61489",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/0dc8fd8e87e0366c22b6c25d1f43c4e2e66847b3",
"reference": "0dc8fd8e87e0366c22b6c25d1f43c4e2e66847b3",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": ">=5.6",
"phpunit/php-text-template": "~1.2",
"sebastian/exporter": "~1.2"
"php": "^5.6 || ^7.0",
"phpunit/php-text-template": "^1.2",
"sebastian/exporter": "^1.2"
},
"conflict": {
"phpunit/phpunit": "<5.4.0"
},
"require-dev": {
"phpunit/phpunit": "~5"
"phpunit/phpunit": "^5.4"
},
"suggest": {
"ext-soap": "*"
@@ -2122,7 +2125,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1.x-dev"
"dev-master": "3.2.x-dev"
}
},
"autoload": {
@@ -2147,7 +2150,7 @@
"mock",
"xunit"
],
"time": "2016-04-20 14:39:26"
"time": "2016-06-04 05:52:19"
},
{
"name": "sebastian/code-unit-reverse-lookup",
+40 -34
View File
@@ -193,7 +193,7 @@ class Battle
}
}
return $count;
return $count+1;
}
/**
@@ -210,41 +210,30 @@ class Battle
$playerBuffStartEvents = $this->player->getBuffs()->activate(Buff::ACTIVATE_ROUNDSTART);
$monsterBuffStartEvents = $this->monster->getBuffs()->activate(Buff::ACTIVATE_ROUNDSTART);
do {
$offenseTurnEvents = $firstDamageRound & self::DAMAGEROUND_PLAYER ? $this->turn($this->player, $this->monster) : new ArrayCollection();
$defenseTurnEvents = $firstDamageRound & self::DAMAGEROUND_MONSTER ? $this->turn($this->monster, $this->player) : new ArrayCollection();
$events = new ArrayCollection(array_merge($offenseTurnEvents->toArray(), $defenseTurnEvents->toArray()));
$eventsToAdd = new ArrayCollection();
if ($this->player->getBuffs()->hasBuffsInUse() || $this->monster->getBuffs()->hasBuffsInUse()) {
// If there are active buffs, we still need to count the round even if there has not been any damage done.
$damageHasBeenDone = true;
$offenseTurnEvents = $firstDamageRound & self::DAMAGEROUND_PLAYER ? $this->turn($this->player, $this->monster) : new ArrayCollection();
$defenseTurnEvents = $firstDamageRound & self::DAMAGEROUND_MONSTER ? $this->turn($this->monster, $this->player) : new ArrayCollection();
$events = new ArrayCollection(array_merge($offenseTurnEvents->toArray(), $defenseTurnEvents->toArray()));
$eventsToAdd = new ArrayCollection();
foreach($events as $event) {
$event->apply();
$eventsToAdd->add($event);
if ($this->player->getHealth() <= 0) {
$deathEvent = new DeathEvent($this->player);
$this->result = self::RESULT_PLAYERDEATH;
break;
}
foreach($events as $event) {
$event->apply();
if ($event instanceof DamageEvent && $event->getDamage() !== 0) {
$damageHasBeenDone = true;
}
$eventsToAdd->add($event);
if ($this->player->getHealth() <= 0) {
$deathEvent = new DeathEvent($this->player);
$this->result = self::RESULT_PLAYERDEATH;
break;
}
if ($this->monster->getHealth() <= 0) {
$deathEvent = new DeathEvent($this->monster);
$this->result = self::RESULT_MONSTERDEATH;
break;
}
if ($this->monster->getHealth() <= 0) {
$deathEvent = new DeathEvent($this->monster);
$this->result = self::RESULT_MONSTERDEATH;
break;
}
} while($damageHasBeenDone === false);
}
$this->round++;
$playerBuffEndEvents = $this->player->getBuffs()->expireOneRound();
@@ -381,6 +370,23 @@ class Battle
// Add the damage event
$events->add(new DamageEvent($attacker, $defender, $damage));
return $events;
// Do all the other buff effects. Modifiers are calculated separatly and do not need activation
$attackersBuffStartEvents = $attackersBuffs->activate(Buff::ACTIVATE_OFFENSE);
$defendersBuffStartEvents = $defendersBuffs->activate(Buff::ACTIVATE_DEFENSE);
$attackersDirectBuffEvents = $attackersBuffs->processDirectBuffs(Buff::ACTIVATE_OFFENSE, $this->game, $attacker, $defender);
$defendersDirectBuffEvents = $defendersBuffs->processDirectBuffs(Buff::ACTIVATE_DEFENSE, $this->game, $defender, $attacker);
//$attackersDamageDependentBuffEvents = $attackersBuffs->processDamageDependentBuffs(Buff::ACTIVATE_OFFENSE);
//$defendersDamageDependentBuffEvents = $defendersBuffs->processDamageDependentBuffs(Buff::ACTIVATE_DEFENSE);
return new ArrayCollection(
array_merge(
$attackersBuffStartEvents->toArray(),
$attackersDirectBuffEvents->toArray(),
$defendersBuffStartEvents->toArray(),
$defendersDirectBuffEvents->toArray(),
$events->toArray()
)
);
}
}
+105 -2
View File
@@ -9,12 +9,16 @@ use Doctrine\Common\Collections\{
};
use LotGD\Core\Exceptions\{
ArgumentException
ArgumentException,
BuffListAlreadyActivatedException
};
use LotGD\Core\Models\{
Buff,
Character,
BattleEvents\BuffMessageEvent
FighterInterface,
BattleEvents\BuffMessageEvent,
BattleEvents\RegenerationBuffEvent,
BattleEvents\MinionDamageEvent
};
@@ -381,4 +385,103 @@ class BuffList
$this->calculateModifiers();
return $this->goodguyInvulnurable;
}
public function processDirectBuffs(
int $activation,
Game $game,
FighterInterface $goodguy,
FighterInterface $badguy
): Collection {
$events = [];
foreach ($this->activeBuffs[$activation] as $buff) {
// Add good guy regeneration
if ($buff->getGoodguyRegeneration() !== 0) {
$events[] = new RegenerationBuffEvent(
$goodguy,
$buff->getGoodguyRegeneration(),
$buff->getEffectSucceedsMessage(),
$buff->getNoEffectMessage()
);
}
// Add bad guy regeneration
if ($buff->getBadguyRegeneration() !== 0) {
$events[] = new RegenerationBuffEvent(
$badguy,
$buff->getGoodguyRegeneration(),
$buff->getEffectSucceedsMessage(),
$buff->getNoEffectMessage()
);
}
// Minion buff
if ($buff->getNumberOfMinions() > 0) {
/* @var $n int */
$n = $buff->getNumberOfMinions();
/* @var $attacksOne bool */
$attacksOne = ($buff->getMinionMinGoodguyDamage() || $buff->getMinionMaxGoodguyDamage() !== 0)
|| ($buff->getMinionMinBadguyDamage() || $buff->getMinionMaxBadguyDamage() !== 0);
/* @var $attacksBoth bool */
$attacksBoth = ($buff->getMinionMinGoodguyDamage() || $buff->getMinionMaxGoodguyDamage() !== 0)
&& ($buff->getMinionMinBadguyDamage() || $buff->getMinionMaxBadguyDamage() !== 0);
// Faulty buff - if minions attack no one, it's better to have no minions at all. Or they will just do... nothing.
if ($attacksOne === false) {
$n = 0;
}
// Add a minion event for every single minion
for ($i = 0; $i < $n; $i++) {
// If the buff is setup to attack both good and badguy, we throw a dice to decide who the minion attacks
/* @var $who int Who the minion attacks. 1: Goodguy, 2: Badguy */
if ($attacksBoth === true) {
if ($game->getDiceBag()->chance(0.5)) {
$who = 1;
}
else {
$who = -1;
}
}
elseif ($buff->getMinionMaxGoodguyDamage() !== 0 || $buff->getMinionMinGoodguyDamage() !== 0) {
$who = 1;
}
else {
$who = -1;
}
if ($who === 1) {
// Minion does damage to the goodguy
$damage = $game->getDiceBag()->normal($buff->getMinionMinGoodguyDamage(), $buff->getMinionMaxGoodguyDamage());
$target = $goodguy;
}
else {
// Minion does damage to the badguy
$damage = $game->getDiceBag()->normal($buff->getMinionMinBadguyDamage(), $buff->getMinionMaxBadguyDamage());
$target = $badguy;
}
if ($damage < 0) {
$message = $buff->getEffectFailsMessage();
}
elseif ($damage > 0) {
$message = $buff->getEffectSucceedsMessage();
}
else {
$message = $buff->getNoEffectMessage();
}
$events[] = new MinionDamageEvent(
$target,
(int)round($damage, 0),
$message
);
}
}
}
return new ArrayCollection(
$events
);
}
}
+13
View File
@@ -68,6 +68,19 @@ abstract class BasicEnemy implements FighterInterface
return $this->health;
}
/**
* Sets the enemy's current health
* @param int $health
*/
public function setHealth(int $health)
{
$this->health = $health;
if ($this->health < 0) {
$this->health = 0;
}
}
/**
* Does damage to the entity.
* @param int $damage
+4
View File
@@ -23,6 +23,10 @@ class BattleEvent
public function decorate(Game $game): string
{
if ($this->applied === false) {
throw new BattleEventException("Buff needs to get applied before decoration.");
}
return "";
}
}
@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Models\BattleEvents;
use LotGD\Core\Exceptions\BattleEventException;
use LotGD\Core\Models\FighterInterface;
/**
* BattleEvent
*/
class MinionDamageEvent extends BattleEvent
{
protected $target;
protected $damage;
protected $message;
public function __construct(
FighterInterface $target,
int $damage,
string $message
) {
$this->target = $target;
$this->damage = $damage;
$this->message = $message;
}
public function decorate(Game $game): string
{
parent::decorate();
return str_replace(
[
"{target}",
"{amount}",
],
[
$this->target->getDisplayName(),
$this->damage,
],
$this->message
);
}
public function apply()
{
parent::apply();
$this->target->setHealth($this->target->getHealth() - $this->damage);
}
}
@@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Models\BattleEvents;
use LotGD\Core\Exceptions\BattleEventException;
use LotGD\Core\Models\FighterInterface;
/**
* BattleEvent
*/
class RegenerationBuffEvent extends BattleEvent
{
protected $target;
protected $regeneration;
protected $effectMessage;
protected $noEffectMessage;
public function __construct(
FighterInterface $target,
int $regeneration,
string $effectMessage,
string $noEffectMessage
) {
$this->target = $target;
$this->regeneration = $regeneration;
$this->effectMessage = $effectMessage;
$this->noEffectMessage = $noEffectMessage;
}
public function decorate(Game $game): string
{
parent::decorate();
if ($this->regeneration === 0) {
return str_replace(
"{target}",
$target->getDisplayName(),
$this->noEffectMessage
);
}
else {
return str_replace(
[
"{target}",
"{amount}"
],
[
$target->getDisplayName(),
$this->regeneration,
],
$this->effectMessage
);
}
}
public function apply()
{
parent::apply();
$healthLacking = $this->target->getMaxHealth() - $this->target->getHealth();
$healthLeft = $this->target->getHealth();
if ($this->regeneration > 0) {
// Healing
if ($healthLacking === 0) {
$this->regeneration = 0;
}
elseif ($healthLacking < $this->regeneration) {
$this->regeneration = $healthLacking;
}
}
else {
// Damaging
if ($healthLeft === 0) {
$this->regeneration = 0;
}
elseif ($healthLeft < -1*$this->regeneration) {
$this->regeneration = - $healthLeft;
}
}
$this->target->setHealth($this->target->getHealth() + $this->regeneration);
}
}
+8 -7
View File
@@ -85,7 +85,7 @@ class Buff
* @var int
* @Column(type="integer")
*/
private $activateAt = self::ACTIVATE_NONE;
private $activateAt;
/**
* True if the buff survives a new day
* @var bool
@@ -264,6 +264,7 @@ class Buff
private $required = [
"slot",
"activateAt",
];
/**
@@ -310,11 +311,11 @@ class Buff
}
$this->{$attribute} = $value;
foreach($this->required as $required) {
if (is_null($this->$required)) {
throw new ArgumentException("{$required} needs to be inside of the buffArray!");
}
}
foreach($this->required as $required) {
if (is_null($this->$required)) {
throw new ArgumentException("{$required} needs to be inside of the buffArray!");
}
}
}
@@ -453,7 +454,7 @@ class Buff
return $this->activateAt == self::ACTIVATE_NONE ? true : false;
}
else {
return ($this->activateAt & $flag > 0) === 1;
return ($this->activateAt & $flag) == true;
}
}
+1
View File
@@ -22,5 +22,6 @@ interface FighterInterface
public function getDefense(Game $game, bool $ignoreBuffs = false): int;
public function damage(int $damage);
public function heal(int $heal);
public function setHealth(int $amount);
public function getBuffs(): BuffList;
}
+5
View File
@@ -40,6 +40,11 @@ trait MockCharacter
throw new IsNullException();
}
public function setHealth(int $amount)
{
throw new IsNullException();
}
public function damage(int $damage)
{
throw new IsNullException();
+510 -11
View File
@@ -14,7 +14,12 @@ use LotGD\Core\{
Models\Monster
};
use LotGD\Core\Models\BattleEvents\{
BuffMessageEvent
BuffMessageEvent,
CriticalHitEvent,
DamageEvent,
DeathEvent,
MinionDamageEvent,
RegenerationBuffEvent
};
use LotGD\Core\Tests\ModelTestCase;
@@ -291,19 +296,19 @@ class BattleTest extends ModelTestCase
$expectedEvents = [
BuffMessageEvent::class, // Activation round
\LotGD\Core\Models\BattleEvents\DamageEvent::class, // Round 1
\LotGD\Core\Models\BattleEvents\DamageEvent::class,
DamageEvent::class, // Round 1
DamageEvent::class,
BuffMessageEvent::class, // message every round
\LotGD\Core\Models\BattleEvents\DamageEvent::class, // Round 2
\LotGD\Core\Models\BattleEvents\DamageEvent::class,
DamageEvent::class, // Round 2
DamageEvent::class,
BuffMessageEvent::class, // message every round
\LotGD\Core\Models\BattleEvents\DamageEvent::class, // Round 3
\LotGD\Core\Models\BattleEvents\DamageEvent::class,
DamageEvent::class, // Round 3
DamageEvent::class,
BuffMessageEvent::class, // message expires
\LotGD\Core\Models\BattleEvents\DamageEvent::class, // Round 4
\LotGD\Core\Models\BattleEvents\DamageEvent::class,
\LotGD\Core\Models\BattleEvents\DamageEvent::class, // Round 5
\LotGD\Core\Models\BattleEvents\DamageEvent::class,
DamageEvent::class, // Round 4
DamageEvent::class,
DamageEvent::class, // Round 5
DamageEvent::class,
];
$numOfEvents = count($battle->getEvents());
@@ -311,6 +316,413 @@ class BattleTest extends ModelTestCase
$this->assertInstanceOf($expectedEvents[$i], $battle->getEvents()[$i]);
}
}
public function testBattleRegenerationBuff()
{
$battle = $this->provideBuffBattleParticipants(new Buff([
"slot" => "test",
"rounds" => 2,
"goodguyRegeneration" => 100,
"badguyRegeneration" => 100,
"activateAt" => Buff::ACTIVATE_WHILEROUND,
]), 1);
$battle->getPlayer()->setHealth(1);
$battle->getMonster()->setHealth(1);
$battle->fightNRounds(3);
$this->assertGreaterThan(1, $battle->getPlayer()->getHealth());
$this->assertGreaterThan(1, $battle->getPlayer()->getHealth());
$expectedEvents = [
RegenerationBuffEvent::class, // Round 1, offense
RegenerationBuffEvent::class,
DamageEvent::class,
RegenerationBuffEvent::class, // Round 1, defense
RegenerationBuffEvent::class,
DamageEvent::class,
RegenerationBuffEvent::class, // Round 2, offense
RegenerationBuffEvent::class,
DamageEvent::class,
RegenerationBuffEvent::class, // Round 2, defense
RegenerationBuffEvent::class,
DamageEvent::class,
DamageEvent::class, // Round 3, offense
DamageEvent::class,
];
$numOfEvents = count($expectedEvents);
for ($i = 0; $i < $numOfEvents; $i++) {
$this->assertInstanceOf($expectedEvents[$i], $battle->getEvents()[$i]);
}
}
public function testBattleDegenerationBuff()
{
$battle = $this->provideBuffBattleParticipants(new Buff([
"slot" => "test",
"rounds" => 2,
"goodguyRegeneration" => -250,
"badguyRegeneration" => -250,
"activateAt" => Buff::ACTIVATE_WHILEROUND,
]), 1);
$battle->getPlayer()->setHealth(2000);
$battle->getMonster()->setHealth(2000);
$battle->fightNRounds(3);
// Test that the difference is, indeed, -250 per turn, resulting in 1000 lost.
$this->assertLessThanOrEqual(1000, $battle->getPlayer()->getHealth());
$this->assertLessThanOrEqual(1000, $battle->getPlayer()->getHealth());
$expectedEvents = [
RegenerationBuffEvent::class, // Round 1, offense
RegenerationBuffEvent::class,
DamageEvent::class,
RegenerationBuffEvent::class, // Round 1, defense
RegenerationBuffEvent::class,
DamageEvent::class,
RegenerationBuffEvent::class, // Round 2, offense
RegenerationBuffEvent::class,
DamageEvent::class,
RegenerationBuffEvent::class, // Round 2, defense
RegenerationBuffEvent::class,
DamageEvent::class,
DamageEvent::class, // Round 3, offense
DamageEvent::class,
];
$numOfEvents = count($expectedEvents);
for ($i = 0; $i < $numOfEvents; $i++) {
$this->assertInstanceOf($expectedEvents[$i], $battle->getEvents()[$i]);
}
}
public function testBattleDegenerationBuffDoubleKO()
{
// What happens at a tie?
$battle = $this->provideBuffBattleParticipants(new Buff([
"slot" => "test",
"rounds" => 2,
"goodguyRegeneration" => -250,
"badguyRegeneration" => -250,
"activateAt" => Buff::ACTIVATE_WHILEROUND,
]), 1);
$battle->getPlayer()->setHealth(1000);
$battle->getMonster()->setHealth(1000);
$numOfRounds = $battle->fightNRounds(3);
$this->assertSame(2, $numOfRounds);
$this->assertSame($battle->getPlayer(), $battle->getLoser());
$this->assertSame($battle->getMonster(), $battle->getWinner());
$this->assertTrue($battle->isOver());
}
public function testBattleMinionGoodguyDamageBuff()
{
$battle = $this->provideBuffBattleParticipants(new Buff([
"slot" => "test",
"rounds" => 2,
"numberOfMinions" => 2,
"minionMinGoodguyDamage" => 100,
"minionMaxGoodguyDamage" => 100,
"effectSucceedsMessage" => "The Minion hits you for {damage}.",
"effectFailsMessage" => "The Minion heals you for {damage}.",
"noEffectMessage" => "The Minion does nothing.",
"activateAt" => Buff::ACTIVATE_WHILEROUND,
]), 1);
$battle->getPlayer()->setHealth(2000);
$battle->getMonster()->setHealth(2000);
$battle->fightNRounds(3);
$this->assertLessThanOrEqual(2000 - 800, $battle->getPlayer()->getHealth());
$this->assertGreaterThan(2000 - 800, $battle->getMonster()->getHealth());
$expectedEvents = [
// Round 1, offense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 1, defense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 2, offense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 2, defense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 3
DamageEvent::class,
DamageEvent::class,
];
$numOfEvents = count($expectedEvents);
for ($i = 0; $i < $numOfEvents; $i++) {
$this->assertInstanceOf($expectedEvents[$i], $battle->getEvents()[$i]);
}
}
public function testBattleMinionGoodguyHealBuff()
{
$battle = $this->provideBuffBattleParticipants(new Buff([
"slot" => "test",
"rounds" => 2,
"numberOfMinions" => 2,
"minionMinGoodguyDamage" => -100,
"minionMaxGoodguyDamage" => -100,
"effectSucceedsMessage" => "The Minion hits you for {damage}.",
"effectFailsMessage" => "The Minion heals you for {damage}.",
"noEffectMessage" => "The Minion does nothing.",
"activateAt" => Buff::ACTIVATE_WHILEROUND,
]), 1);
$battle->getPlayer()->setHealth(2000);
$battle->getMonster()->setHealth(2000);
$battle->fightNRounds(3);
$this->assertGreaterThanOrEqual(2000, $battle->getPlayer()->getHealth());
$this->assertLessThanOrEqual(2000, $battle->getMonster()->getHealth());
$expectedEvents = [
// Round 1, offense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 1, defense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 2, offense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 2, defense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 3
DamageEvent::class,
DamageEvent::class,
];
$numOfEvents = count($expectedEvents);
for ($i = 0; $i < $numOfEvents; $i++) {
$this->assertInstanceOf($expectedEvents[$i], $battle->getEvents()[$i]);
}
}
public function testBattleMinionBadguyDamageBuff()
{
$battle = $this->provideBuffBattleParticipants(new Buff([
"slot" => "test",
"rounds" => 2,
"numberOfMinions" => 2,
"minionMinBadguyDamage" => 100,
"minionMaxBadguyDamage" => 100,
"effectSucceedsMessage" => "The Minion hits you for {damage}.",
"effectFailsMessage" => "The Minion heals you for {damage}.",
"noEffectMessage" => "The Minion does nothing.",
"activateAt" => Buff::ACTIVATE_WHILEROUND,
]), 1);
$battle->getPlayer()->setHealth(2000);
$battle->getMonster()->setHealth(2000);
$battle->fightNRounds(3);
$this->assertLessThanOrEqual(2000 - 800, $battle->getMonster()->getHealth());
$this->assertGreaterThan(2000 - 800, $battle->getPlayer()->getHealth());
$expectedEvents = [
// Round 1, offense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 1, defense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 2, offense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 2, defense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 3
DamageEvent::class,
DamageEvent::class,
];
$numOfEvents = count($expectedEvents);
for ($i = 0; $i < $numOfEvents; $i++) {
$this->assertInstanceOf($expectedEvents[$i], $battle->getEvents()[$i]);
}
}
public function testBattleMinionBadguyHealBuff()
{
$battle = $this->provideBuffBattleParticipants(new Buff([
"slot" => "test",
"rounds" => 2,
"numberOfMinions" => 2,
"minionMinBadguyDamage" => -100,
"minionMaxBadguyDamage" => -100,
"effectSucceedsMessage" => "The Minion hits you for {damage}.",
"effectFailsMessage" => "The Minion heals you for {damage}.",
"noEffectMessage" => "The Minion does nothing.",
"activateAt" => Buff::ACTIVATE_WHILEROUND,
]), 1);
$battle->getPlayer()->setHealth(2000);
$battle->getMonster()->setHealth(2000);
$battle->fightNRounds(3);
$this->assertGreaterThanOrEqual(2000, $battle->getMonster()->getHealth());
$this->assertLessThanOrEqual(2000, $battle->getPlayer()->getHealth());
$expectedEvents = [
// Round 1, offense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 1, defense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 2, offense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 2, defense
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 3
DamageEvent::class,
DamageEvent::class,
];
$numOfEvents = count($expectedEvents);
for ($i = 0; $i < $numOfEvents; $i++) {
$this->assertInstanceOf($expectedEvents[$i], $battle->getEvents()[$i]);
}
}
public function testBattleMinionBothAndBoth()
{
$battle = $this->provideBuffBattleParticipants(new Buff([
"slot" => "test",
"rounds" => 1,
"numberOfMinions" => 10,
"minionMinBadguyDamage" => -100,
"minionMaxBadguyDamage" => 100,
"minionMinGoodguyDamage" => -100,
"minionMaxGoodguyDamage" => 100,
"effectSucceedsMessage" => "The Minion hits you for {damage}.",
"effectFailsMessage" => "The Minion heals you for {damage}.",
"noEffectMessage" => "The Minion does nothing.",
"activateAt" => Buff::ACTIVATE_WHILEROUND,
]), 1);
$battle->getPlayer()->setHealth(10000);
$battle->getMonster()->setHealth(10000);
$battle->fightNRounds(3);
$this->assertGreaterThanOrEqual(10000 - 100*20, $battle->getPlayer()->getHealth());
$this->assertGreaterThanOrEqual(10000 - 100*20, $battle->getMonster()->getHealth());
$this->assertLessThanOrEqual(10000 + 100*20, $battle->getPlayer()->getHealth());
$this->assertLessThanOrEqual(10000 + 100*20, $battle->getMonster()->getHealth());
$expectedEvents = [
// Round 1, offense
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 1, defense
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
MinionDamageEvent::class,
DamageEvent::class,
// Round 2, offense
DamageEvent::class,
// Round 2, defense
DamageEvent::class,
// Round 3
DamageEvent::class,
DamageEvent::class,
];
$numOfEvents = count($expectedEvents);
for ($i = 0; $i < $numOfEvents; $i++) {
$this->assertInstanceOf($expectedEvents[$i], $battle->getEvents()[$i]);
}
}
public function testBattleInfiniteBuff()
{
$battle = $this->provideBuffBattleParticipants(new Buff([
"slot" => "test",
"rounds" => -1,
"startMessage" => "Infinite Buff starts",
"roundMessage" => "Infinite Buff is still active",
"endMessage" => "Infinite Buff should never end",
"activateAt" => Buff::ACTIVATE_ROUNDSTART,
]), 1);
$battle->fightNRounds(3);
$this->assertBuffEventMessageExists($battle->getEvents(), "Infinite Buff starts", 1);
$this->assertBuffEventMessageExists($battle->getEvents(), "Infinite Buff is still active", 2);
$this->assertBuffEventMessageExists($battle->getEvents(), "Infinite Buff should never end", 0, 0);
$expectedEvents = [
BuffMessageEvent::class, // Activation round
DamageEvent::class, // Round 1
DamageEvent::class,
BuffMessageEvent::class, // message every round
DamageEvent::class, // Round 2
DamageEvent::class,
BuffMessageEvent::class, // message every round
DamageEvent::class, // Round 3
DamageEvent::class,
];
$numOfEvents = count($expectedEvents);
for ($i = 0; $i < $numOfEvents; $i++) {
$this->assertInstanceOf($expectedEvents[$i], $battle->getEvents()[$i]);
}
}
public function testBattleBuffPlayerGoodguyModifier()
{
@@ -454,6 +866,7 @@ class BattleTest extends ModelTestCase
"slot" => "test3",
"rounds" => 1,
"goodguyAttackModifier" => 13.4,
"activateAt" => BUFF::ACTIVATE_NONE,
]));
$modifier = $player->getBuffs()->getGoodguyAttackModifier();
@@ -482,6 +895,7 @@ class BattleTest extends ModelTestCase
"slot" => "test3",
"rounds" => 1,
"goodguyDefenseModifier" => 0,
"activateAt" => BUFF::ACTIVATE_NONE,
]));
$modifier = $player->getBuffs()->getGoodguyDefenseModifier();
@@ -510,6 +924,7 @@ class BattleTest extends ModelTestCase
"slot" => "test3",
"rounds" => 1,
"goodguyDamageModifier" => 3.5,
"activateAt" => BUFF::ACTIVATE_NONE,
]));
$modifier = $player->getBuffs()->getGoodguyDamageModifier();
@@ -538,6 +953,7 @@ class BattleTest extends ModelTestCase
"slot" => "test3",
"rounds" => 1,
"badguyAttackModifier" => 13.4,
"activateAt" => BUFF::ACTIVATE_NONE,
]));
$modifier = $player->getBuffs()->getBadguyAttackModifier();
@@ -566,6 +982,7 @@ class BattleTest extends ModelTestCase
"slot" => "test3",
"rounds" => 1,
"badguyDefenseModifier" => 0,
"activateAt" => BUFF::ACTIVATE_NONE,
]));
$modifier = $player->getBuffs()->getBadguyDefenseModifier();
@@ -594,9 +1011,91 @@ class BattleTest extends ModelTestCase
"slot" => "test3",
"rounds" => 1,
"badguyDamageModifier" => 3.5,
"activateAt" => BUFF::ACTIVATE_NONE,
]));
$modifier = $player->getBuffs()->getBadguyDamageModifier();
$this->assertEquals(2.5, $modifier, '', 0.001);
}
public function testBuffActivatedAt()
{
$buff = new Buff([
"slot" => "test",
"activateAt" => Buff::ACTIVATE_ROUNDSTART,
]);
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_NONE));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_ROUNDSTART));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_OFFENSE));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_DEFENSE));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_ROUNDEND));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_ANY));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_WHILEROUND));
$buff = new Buff([
"slot" => "test",
"activateAt" => Buff::ACTIVATE_OFFENSE,
]);
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_NONE));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_ROUNDSTART));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_OFFENSE));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_DEFENSE));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_ROUNDEND));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_ANY));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_WHILEROUND));
$buff = new Buff([
"slot" => "test",
"activateAt" => Buff::ACTIVATE_DEFENSE,
]);
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_NONE));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_ROUNDSTART));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_OFFENSE));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_DEFENSE));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_ROUNDEND));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_ANY));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_WHILEROUND));
$buff = new Buff([
"slot" => "test",
"activateAt" => Buff::ACTIVATE_ROUNDEND,
]);
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_NONE));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_ROUNDSTART));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_OFFENSE));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_DEFENSE));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_ROUNDEND));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_ANY));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_WHILEROUND));
$buff = new Buff([
"slot" => "test",
"activateAt" => Buff::ACTIVATE_WHILEROUND,
]);
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_NONE));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_ROUNDSTART));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_OFFENSE));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_DEFENSE));
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_ROUNDEND));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_ANY));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_WHILEROUND));
$buff = new Buff([
"slot" => "test",
"activateAt" => Buff::ACTIVATE_ANY,
]);
$this->assertFalse($buff->getsActivatedAt(Buff::ACTIVATE_NONE));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_ROUNDSTART));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_OFFENSE));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_DEFENSE));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_ROUNDEND));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_ANY));
$this->assertTrue($buff->getsActivatedAt(Buff::ACTIVATE_WHILEROUND));
}
}