From 7a6a2df0db25840c703358f2d5cffc1be175da53 Mon Sep 17 00:00:00 2001 From: Adam Balan Date: Wed, 9 Oct 2024 17:02:50 -0600 Subject: [PATCH] Added a lot more tests --- .../Models/GlobalEventCraftingInventory.php | 4 +- .../GlobalEventCraftingInventorySlot.php | 6 +- .../UpdateCraftingTasksForFactionLoyalty.php | 10 +- app/Game/Skills/Services/CraftingService.php | 9 +- .../Skills/Services/EnchantItemService.php | 42 ++--- app/Game/Skills/Services/SkillService.php | 35 ++-- .../GlobalEventCraftingInventoryFactory.php | 29 +++ ...lobalEventCraftingInventorySlotFactory.php | 29 +++ .../Traits/CreateGlobalCraftingInventory.php | 14 ++ .../CreateGlobalCraftingInventorySlot.php | 14 ++ .../Skills/Services/CraftingServiceTest.php | 147 ++++++++++++++- .../Skills/Services/DisenchantServiceTest.php | 73 ++++++++ .../Services/EnchantItemServiceTest.php | 169 +++++++++++++++++- .../Skills/Services/EnchantingServiceTest.php | 95 +++++++++- .../Game/Skills/Services/GemServiceTest.php | 28 +++ .../Game/Skills/Services/SkillServiceTest.php | 130 +++++++++++++- 16 files changed, 768 insertions(+), 66 deletions(-) create mode 100644 database/factories/GlobalEventCraftingInventoryFactory.php create mode 100644 database/factories/GlobalEventCraftingInventorySlotFactory.php create mode 100644 tests/Traits/CreateGlobalCraftingInventory.php create mode 100644 tests/Traits/CreateGlobalCraftingInventorySlot.php diff --git a/app/Flare/Models/GlobalEventCraftingInventory.php b/app/Flare/Models/GlobalEventCraftingInventory.php index 1e97a818b..aa3dc3895 100644 --- a/app/Flare/Models/GlobalEventCraftingInventory.php +++ b/app/Flare/Models/GlobalEventCraftingInventory.php @@ -2,7 +2,7 @@ namespace App\Flare\Models; -use Database\Factories\GlobalEventGoalFactory; +use Database\Factories\GlobalEventCraftingInventoryFactory; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -51,6 +51,6 @@ public function character() protected static function newFactory() { - return GlobalEventGoalFactory::new(); + return GlobalEventCraftingInventoryFactory::new(); } } diff --git a/app/Flare/Models/GlobalEventCraftingInventorySlot.php b/app/Flare/Models/GlobalEventCraftingInventorySlot.php index 47be2293f..5468b88b6 100644 --- a/app/Flare/Models/GlobalEventCraftingInventorySlot.php +++ b/app/Flare/Models/GlobalEventCraftingInventorySlot.php @@ -2,6 +2,7 @@ namespace App\Flare\Models; +use Database\Factories\GlobalEventCraftingInventorySlotFactory; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -39,5 +40,8 @@ public function inventory() return $this->belongsTo(GlobalEventCraftingInventory::class, 'global_event_crafting_inventory_id', 'id'); } - protected static function newFactory() {} + protected static function newFactory() + { + return GlobalEventCraftingInventorySlotFactory::new(); + } } diff --git a/app/Game/Skills/Handlers/UpdateCraftingTasksForFactionLoyalty.php b/app/Game/Skills/Handlers/UpdateCraftingTasksForFactionLoyalty.php index a97639374..5c7026c8c 100644 --- a/app/Game/Skills/Handlers/UpdateCraftingTasksForFactionLoyalty.php +++ b/app/Game/Skills/Handlers/UpdateCraftingTasksForFactionLoyalty.php @@ -77,9 +77,9 @@ public function handleCraftingTask(Character $character, Item $item): Character $amountLeft = $task['required_amount'] - $task['current_amount']; if ($amountLeft === 0) { - ServerMessageHandler::sendBasicMessage($character->user, $helpingNpc->npc->real_name.' does not want anymore of this item anymore. "We\'re done with this child. Move on. I got other tasks for you to do! But you since you crafted it ..."'); + ServerMessageHandler::sendBasicMessage($character->user, $helpingNpc->npc->real_name . ' does not want anymore of this item anymore. "We\'re done with this child. Move on. I got other tasks for you to do! But you since you crafted it ..."'); } else { - ServerMessageHandler::sendBasicMessage($character->user, $helpingNpc->npc->real_name.' is elated at your ability to craft: '.$item->affix_name.'. "Thank you child! Only: '.$amountLeft.' Left to go!"'); + ServerMessageHandler::sendBasicMessage($character->user, $helpingNpc->npc->real_name . ' is elated at your ability to craft: ' . $item->affix_name . '. "Thank you child! Only: ' . $amountLeft . ' Left to go!"'); } if ($this->canLevelUpFame($helpingNpc) && $helpingNpc->current_level !== $helpingNpc->max_level) { @@ -151,7 +151,7 @@ protected function handOutCurrencies(Character $character, FactionLoyaltyNpc $fa event(new UpdateTopBarEvent($character->refresh())); - ServerMessageHandler::sendBasicMessage($character->user, 'Your fame with: '.$factionLoyaltyNpc->npc->real_name.' on Plane: '.$factionLoyaltyNpc->npc->gameMap->name); + ServerMessageHandler::sendBasicMessage($character->user, 'Your fame with: ' . $factionLoyaltyNpc->npc->real_name . ' on Plane: ' . $factionLoyaltyNpc->npc->gameMap->name); } /** @@ -170,7 +170,7 @@ protected function handOutXp(Character $character, FactionLoyaltyNpc $factionLoy $this->handlePossibleLevelUp($character); - ServerMessageHandler::sendBasicMessage($character->user, 'Rewarded with: '.number_format($factionLoyaltyNpc->current_level * 1000).' XP.'); + ServerMessageHandler::sendBasicMessage($character->user, 'Rewarded with: ' . number_format($factionLoyaltyNpc->current_level * 1000) . ' XP.'); } /** @@ -205,7 +205,7 @@ protected function rewardTheUniqueItem(Character $character) 'item_id' => $newItem->id, ]); - event(new ServerMessageEvent($character->user, 'You found something of MEDIUM value child. A simple reward: '.$item->affix_name, $slot->id)); + event(new ServerMessageEvent($character->user, 'You found something of MEDIUM value child. A simple reward: ' . $item->affix_name, $slot->id)); } /** diff --git a/app/Game/Skills/Services/CraftingService.php b/app/Game/Skills/Services/CraftingService.php index 6a6f3dc3a..ddb7e049f 100755 --- a/app/Game/Skills/Services/CraftingService.php +++ b/app/Game/Skills/Services/CraftingService.php @@ -95,7 +95,8 @@ public function fetchCraftableItems(Character $character, array $params, bool $m */ public function getCraftingXP(Character $character, string $type): array { - if ($type == 'hammer' || + if ( + $type == 'hammer' || $type == 'bow' || $type == 'stave' || $type === 'gun' || @@ -255,7 +256,8 @@ protected function attemptToCraftItem(Character $character, Skill $skill, Item $ protected function fetchCraftingSkill(Character $character, string $craftingType): Skill { - if ($craftingType === 'hammer' || + if ( + $craftingType === 'hammer' || $craftingType === 'bow' || $craftingType === 'stave' || $craftingType === 'gun' || @@ -266,7 +268,7 @@ protected function fetchCraftingSkill(Character $character, string $craftingType $craftingType = 'weapon'; } - $gameSkill = GameSkill::where('name', ucfirst($craftingType).' Crafting')->first(); + $gameSkill = GameSkill::where('name', ucfirst($craftingType) . ' Crafting')->first(); return Skill::where('game_skill_id', $gameSkill->id)->where('character_id', $character->id)->first(); } @@ -397,7 +399,6 @@ private function attemptToPickUpItem(Character $character, Item $item): bool { if ($this->craftForNpc) { - } if (! $character->isInventoryFull()) { diff --git a/app/Game/Skills/Services/EnchantItemService.php b/app/Game/Skills/Services/EnchantItemService.php index 3d79471b8..f362bbaff 100755 --- a/app/Game/Skills/Services/EnchantItemService.php +++ b/app/Game/Skills/Services/EnchantItemService.php @@ -128,7 +128,7 @@ protected function cloneItem(Item $item, ItemAffix $affix) { $clonedItem = DuplicateItemHandler::duplicateItem($item); - $clonedItem->{'item_'.$affix->type.'_id'} = $affix->id; + $clonedItem->{'item_' . $affix->type . '_id'} = $affix->id; $clonedItem->market_sellable = true; $clonedItem->parent_id = $item->id; $clonedItem->is_mythic = false; @@ -136,26 +136,26 @@ protected function cloneItem(Item $item, ItemAffix $affix) if ($affix->type === 'suffix') { - if (! is_null($clonedItem->itemPrefix)) { - if ($clonedItem->itemPrefix->cost === RandomAffixDetails::MYTHIC) { - $clonedItem->item_prefix_id = null; + if (! is_null($clonedItem->itemSuffix)) { + if ($clonedItem->itemSuffix->cost === RandomAffixDetails::MYTHIC) { + $clonedItem->item_suffix_id = null; } - if ($clonedItem->itemPrefix->cost === RandomAffixDetails::COSMIC) { - $clonedItem->item_prefix_id = null; + if ($clonedItem->itemSuffix->cost === RandomAffixDetails::COSMIC) { + $clonedItem->item_suffix_id = null; } } } if ($affix->type === 'prefix') { - if (! is_null($clonedItem->itemSuffix)) { - if ($clonedItem->itemSuffix->cost === RandomAffixDetails::MYTHIC) { - $clonedItem->item_suffix_id = null; + if (! is_null($clonedItem->itemPrefix)) { + if ($clonedItem->itemPrefix->cost === RandomAffixDetails::MYTHIC) { + $clonedItem->item_prefix_id = null; } - if ($clonedItem->itemSuffix->cost === RandomAffixDetails::COSMIC) { - $clonedItem->item_suffix_id = null; + if ($clonedItem->itemPrefix->cost === RandomAffixDetails::COSMIC) { + $clonedItem->item_prefix_id = null; } } } @@ -170,18 +170,12 @@ protected function cloneItem(Item $item, ItemAffix $affix) */ protected function getCountOfMatchingItems(): int { - // Holy stacks are random, so we want a matching - // item only if this item has no stacks on it. - if ($this->item->appliedHolyStacks()->count() === 0) { - return Item::where('name', $this->item->name) - ->where('item_prefix_id', $this->item->item_prefix_id) - ->where('item_suffix_id', $this->item->item_suffix_id) - ->whereDoesntHave('appliedHolyStacks') - ->whereDoesntHave('sockets') - ->count(); - } - - return 0; + return Item::where('name', $this->item->name) + ->where('item_prefix_id', $this->item->item_prefix_id) + ->where('item_suffix_id', $this->item->item_suffix_id) + ->whereDoesntHave('appliedHolyStacks') + ->whereDoesntHave('sockets') + ->count(); } /** @@ -200,6 +194,6 @@ protected function findMatchingItemId(): int ->whereDoesntHave('appliedHolyStacks') ->whereDoesntHave('sockets') ->first() - ->id; + ->id; } } diff --git a/app/Game/Skills/Services/SkillService.php b/app/Game/Skills/Services/SkillService.php index 4b2b3581c..97cad6dc5 100755 --- a/app/Game/Skills/Services/SkillService.php +++ b/app/Game/Skills/Services/SkillService.php @@ -29,7 +29,8 @@ class SkillService private UpdateCharacterAttackTypesHandler $updateCharacterAttackTypes; - public function __construct(Manager $manager, + public function __construct( + Manager $manager, BasicSkillsTransformer $basicSkillsTransformer, SkillsTransformer $skillsTransformer, UpdateCharacterAttackTypesHandler $updateCharacterAttackTypes @@ -97,7 +98,7 @@ public function trainSkill(Character $character, int $skillId, float $xpPercenta ]); return $this->successResult([ - 'message' => 'You are now training '.$skill->name, + 'message' => 'You are now training ' . $skill->name, ]); } @@ -109,7 +110,8 @@ public function trainSkill(Character $character, int $skillId, float $xpPercenta * @return void * @throws Exception */ - public function assignXPToTrainingSkill(Character $character, int $xp): void { + public function assignXPToTrainingSkill(Character $character, int $xp): void + { $skillInTraining = $character->skills->where('currently_training', true)->first(); $event = ScheduledEvent::where('event_type', EventType::FEEDBACK_EVENT)->where('currently_running', true)->first(); @@ -189,6 +191,7 @@ public function getXpWithSkillTrainingReduction(Character $character, int $xp): public function assignXpToCraftingSkill(GameMap $gameMap, Skill $skill): void { if ($skill->level >= 400) { + $skill->update(['xp' => 0]); return; } @@ -197,10 +200,11 @@ public function assignXpToCraftingSkill(GameMap $gameMap, Skill $skill): void $newXp = $skill->xp + $xp; - $event = ScheduledEvent::where('event_type', EventType::FEEDBACK_EVENT)->where('currently_running', true)->first(); + $event = ScheduledEvent::where('event_type', EventType::FEEDBACK_EVENT) + ->where('currently_running', true) + ->first(); if (!is_null($event)) { - if ($skill->type()->isEnchanting() || $skill->type()->isCrafting() || $skill->type()->isAlchemy() || $skill->type()->isGemCrafting()) { $newXp += 175; } else { @@ -209,28 +213,23 @@ public function assignXpToCraftingSkill(GameMap $gameMap, Skill $skill): void } while ($newXp >= $skill->xp_max) { - - if ($skill->level >= 400) { - $newXp = 0; - break; - } - - $skill->update([ - 'xp' => $newXp, - ]); + $skill->update(['xp' => $skill->xp_max]); $newXp -= $skill->xp_max; - $skill = $skill->refresh(); $skill = $this->levelUpSkill($skill); - } - if ($newXp > 0) { - $skill->update(['xp' => $newXp]); + if ($skill->level >= 400) { + $newXp = 0; + break; + } } + + $skill->update(['xp' => $newXp]); } + /** * Level a skill. * diff --git a/database/factories/GlobalEventCraftingInventoryFactory.php b/database/factories/GlobalEventCraftingInventoryFactory.php new file mode 100644 index 000000000..f8cd05296 --- /dev/null +++ b/database/factories/GlobalEventCraftingInventoryFactory.php @@ -0,0 +1,29 @@ + null, + 'character_id' => null, + ]; + } +} diff --git a/database/factories/GlobalEventCraftingInventorySlotFactory.php b/database/factories/GlobalEventCraftingInventorySlotFactory.php new file mode 100644 index 000000000..a8b67aec4 --- /dev/null +++ b/database/factories/GlobalEventCraftingInventorySlotFactory.php @@ -0,0 +1,29 @@ + null, + 'item_id' => null, + ]; + } +} diff --git a/tests/Traits/CreateGlobalCraftingInventory.php b/tests/Traits/CreateGlobalCraftingInventory.php new file mode 100644 index 000000000..c7c320a5b --- /dev/null +++ b/tests/Traits/CreateGlobalCraftingInventory.php @@ -0,0 +1,14 @@ +create($options); + } +} diff --git a/tests/Traits/CreateGlobalCraftingInventorySlot.php b/tests/Traits/CreateGlobalCraftingInventorySlot.php new file mode 100644 index 000000000..aeed8452f --- /dev/null +++ b/tests/Traits/CreateGlobalCraftingInventorySlot.php @@ -0,0 +1,14 @@ +create($options); + } +} diff --git a/tests/Unit/Game/Skills/Services/CraftingServiceTest.php b/tests/Unit/Game/Skills/Services/CraftingServiceTest.php index ac6b71e05..07508fad0 100755 --- a/tests/Unit/Game/Skills/Services/CraftingServiceTest.php +++ b/tests/Unit/Game/Skills/Services/CraftingServiceTest.php @@ -2,6 +2,7 @@ namespace Tests\Unit\Game\Skills\Services; +use App\Flare\Builders\RandomAffixGenerator; use App\Flare\Models\GameSkill; use App\Flare\Models\GlobalEventCraftingInventory; use App\Flare\Models\GlobalEventCraftingInventorySlot; @@ -12,10 +13,14 @@ use App\Flare\Values\MaxCurrenciesValue; use App\Flare\Values\SpellTypes; use App\Flare\Values\WeaponTypes; +use App\Game\Events\Services\EventGoalsService; use App\Game\Events\Values\EventType; use App\Game\Events\Values\GlobalEventSteps; +use App\Game\Factions\FactionLoyalty\Services\FactionLoyaltyService; use App\Game\Messages\Builders\ServerMessageBuilder; use App\Game\Messages\Events\ServerMessageEvent; +use App\Game\Skills\Handlers\HandleUpdatingCraftingGlobalEventGoal; +use App\Game\Skills\Handlers\UpdateCraftingTasksForFactionLoyalty; use App\Game\Skills\Services\CraftingService; use App\Game\Skills\Services\SkillCheckService; use App\Game\Skills\Values\SkillTypeValue; @@ -750,11 +755,92 @@ public function testItemIsGivenToNpcWhenDoingFactionLoyaltyCrafting() $this->assertCount(0, $character->inventory->slots); - $this->assertEquals(1, $character->factionLoyalties->first() - ->factionLoyaltyNpcs - ->first() - ->factionLoyaltyNpcTasks - ->fame_tasks[0]['current_amount'] + $this->assertEquals( + 1, + $character->factionLoyalties->first() + ->factionLoyaltyNpcs + ->first() + ->factionLoyaltyNpcTasks + ->fame_tasks[0]['current_amount'] + ); + } + + public function testItemIsNotGivenToNpcWhenDoingFactionLoyaltyCrafting() + { + + $this->instance( + SkillCheckService::class, + Mockery::mock(SkillCheckService::class, function (MockInterface $mock) { + $mock->shouldReceive('getDCCheck')->once()->andReturn(1); + $mock->shouldReceive('characterRoll')->once()->andReturn(100); + }) + ); + + $character = (new CharacterFactory) + ->createBaseCharacter() + ->assignFactionSystem() + ->assignSkill($this->craftingSkill) + ->givePlayerLocation() + ->getCharacter(); + + $character->update([ + 'gold' => MaxCurrenciesValue::MAX_GOLD, + ]); + + $craftingService = $this->app->make(CraftingService::class); + + $character = $character->refresh(); + + $factionLoyalty = $this->createFactionLoyalty([ + 'character_id' => $character->id, + 'faction_id' => $character->factions->first(), + 'is_pledged' => false, + ]); + + $npc = $this->createNpc(); + + $factionLoyaltyNpc = $this->createFactionLoyaltyNpc([ + 'faction_loyalty_id' => $factionLoyalty->id, + 'npc_id' => $npc->id, + 'current_level' => 1, + 'max_level' => 25, + 'next_level_fame' => 1000, + 'currently_helping' => false, + 'kingdom_item_defence_bonus' => 0.002, + ]); + + $this->createFactionLoyaltyNpcTask([ + 'faction_loyalty_id' => $factionLoyalty->id, + 'faction_loyalty_npc_id' => $factionLoyaltyNpc->id, + 'fame_tasks' => [[ + 'type' => $this->craftingItem->crafting_type, + 'item_name' => $this->craftingItem->name, + 'item_id' => $this->craftingItem->id, + 'required_amount' => rand(10, 50), + 'current_amount' => 0, + ]], + ]); + + $character = $character->refresh(); + + $craftingService->craft($character, [ + 'item_to_craft' => $this->craftingItem->id, + 'type' => 'hammer', + 'craft_for_npc' => true, + 'craft_for_event' => false, + ]); + + $character = $character->refresh(); + + $this->assertCount(1, $character->inventory->slots); + + $this->assertEquals( + 0, + $character->factionLoyalties->first() + ->factionLoyaltyNpcs + ->first() + ->factionLoyaltyNpcTasks + ->fame_tasks[0]['current_amount'] ); } @@ -814,4 +900,55 @@ public function testCraftWhileParticipatingInEventGoal() $this->assertEquals($this->craftingItem->id, $globalEventCraftingInventorySlot->item_id); } + + public function testCraftWhileParticipatingInEventGoalWhenCurrentEventGoalIsNotCraft() + { + $this->instance( + SkillCheckService::class, + Mockery::mock(SkillCheckService::class, function (MockInterface $mock) { + $mock->shouldReceive('getDCCheck')->once()->andReturn(1); + $mock->shouldReceive('characterRoll')->once()->andReturn(100); + }) + ); + + $craftingService = $this->app->make(CraftingService::class); + + $this->createEvent([ + 'type' => EventType::DELUSIONAL_MEMORIES_EVENT, + 'current_event_goal_step' => GlobalEventSteps::BATTLE, + ]); + + $this->createGlobalEventGoal([ + 'event_type' => EventType::DELUSIONAL_MEMORIES_EVENT, + 'max_crafts' => 100, + 'reward_every' => 10, + 'next_reward_at' => 10, + 'item_specialty_type_reward' => ItemSpecialtyType::DELUSIONAL_SILVER, + 'should_be_unique' => false, + 'should_be_mythic' => true, + ]); + + $character = $this->character->getCharacter(); + + $character->update([ + 'gold' => MaxCurrenciesValue::MAX_GOLD, + ]); + + $character = $character->refresh(); + + $craftingService->craft($character, [ + 'item_to_craft' => $this->craftingItem->id, + 'type' => 'hammer', + 'craft_for_npc' => false, + 'craft_for_event' => true, + ]); + + $character = $character->refresh(); + + $this->assertCount(1, $character->inventory->slots); + + $globalEventCraftingInventory = GlobalEventCraftingInventory::where('character_id', $character->id)->first(); + + $this->assertNull($globalEventCraftingInventory); + } } diff --git a/tests/Unit/Game/Skills/Services/DisenchantServiceTest.php b/tests/Unit/Game/Skills/Services/DisenchantServiceTest.php index b286722b1..94a8ffd61 100755 --- a/tests/Unit/Game/Skills/Services/DisenchantServiceTest.php +++ b/tests/Unit/Game/Skills/Services/DisenchantServiceTest.php @@ -424,4 +424,77 @@ public function testCallDisenchantItemAndFail() return $event->message === resolve(ServerMessageBuilder::class)->build('failed_to_disenchant'); }); } + + public function testCannotDisentchantItemThatDoesNotExist() + { + $character = $this->character->getCharacter(); + + $disenchantingService = $this->app->make(DisenchantService::class); + + $item = $this->createItem(); + + $result = $disenchantingService->disenchantItem($character, $item); + + $this->assertEquals($item->affix_name . ' Cannot be disenchanted. Not found in inventory.', $result['message']); + $this->assertEquals(422, $result['status']); + } + + public function testCannotDisentchantItemThatIsNotEnchanted() + { + $item = $this->createItem(); + + $character = $this->character->inventoryManagement()->giveItem($item)->getCharacter(); + + $disenchantingService = $this->app->make(DisenchantService::class); + + $result = $disenchantingService->disenchantItem($character, $item); + + $this->assertEquals($item->affix_name . ' Cannot be disenchanted. Has no enchantments attached.', $result['message']); + $this->assertEquals(422, $result['status']); + } + + public function testCannotDisentchantItemIsAQuestItem() + { + $item = $this->createItem([ + 'item_prefix_id' => $this->createItemAffix([ + 'type' => 'prefix', + ]), + 'item_suffix_id' => $this->createItemAffix([ + 'type' => 'prefix', + ]), + 'type' => 'quest', + ]); + + $character = $this->character->inventoryManagement()->giveItem($item)->getCharacter(); + + $disenchantingService = $this->app->make(DisenchantService::class); + + $result = $disenchantingService->disenchantItem($character, $item); + + $this->assertEquals('Quest items cannot be disenchanted.', $result['message']); + $this->assertEquals(422, $result['status']); + } + + public function testDisenchantItemAndDoNotReturnResponse() + { + $character = $this->character->inventoryManagement()->giveItem($this->itemToDisenchant)->getCharacter(); + + $disenchantingService = $this->app->make(DisenchantService::class); + + $result = $disenchantingService->disenchantItem($character, $this->itemToDisenchant, true); + $this->assertEquals(200, $result['status']); + } + + public function testDisenchantItemAndReturnResponse() + { + $character = $this->character->inventoryManagement()->giveItem($this->itemToDisenchant)->getCharacter(); + + $disenchantingService = $this->app->make(DisenchantService::class); + + $result = $disenchantingService->disenchantItem($character, $this->itemToDisenchant); + + $this->assertEquals('Disenchanted item ' . $this->itemToDisenchant->affix_name . ' Check server message tab for Gold Dust output.', $result['message']); + $this->assertEmpty($result['inventory']['inventory']); + $this->assertEquals(200, $result['status']); + } } diff --git a/tests/Unit/Game/Skills/Services/EnchantItemServiceTest.php b/tests/Unit/Game/Skills/Services/EnchantItemServiceTest.php index cc424dd77..a0b6d7424 100755 --- a/tests/Unit/Game/Skills/Services/EnchantItemServiceTest.php +++ b/tests/Unit/Game/Skills/Services/EnchantItemServiceTest.php @@ -5,6 +5,7 @@ use App\Flare\Models\GameSkill; use App\Flare\Models\Item; use App\Flare\Models\ItemAffix; +use App\Flare\Values\RandomAffixDetails; use App\Game\Skills\Services\EnchantItemService; use App\Game\Skills\Services\SkillCheckService; use App\Game\Skills\Values\SkillTypeValue; @@ -15,12 +16,13 @@ use Tests\TestCase; use Tests\Traits\CreateClass; use Tests\Traits\CreateGameSkill; +use Tests\Traits\CreateGem; use Tests\Traits\CreateItem; use Tests\Traits\CreateItemAffix; class EnchantItemServiceTest extends TestCase { - use CreateClass, CreateGameSkill, CreateItem, CreateItemAffix, RefreshDatabase; + use CreateClass, CreateGameSkill, CreateItem, CreateItemAffix, CreateGem, RefreshDatabase; private ?CharacterFactory $character; @@ -105,6 +107,114 @@ public function testEnchantTheItemWithAPrefixWhenTooEasy() $this->assertNotNull($item->item_prefix_id); } + public function testEnchantTheItemWithAPrefixThatIsMythicAndExpectThePrefixToNotBeAttachedWhenTooEasy() + { + + $character = $this->character->getCharacter(); + + $skill = $character->skills->where('game_skill_id', $this->enchantingSkill->id)->first(); + + $this->itemToEnchant->update([ + 'item_prefix_id' => $this->createItemAffix([ + 'type' => 'prefix', + 'name' => 'Non Mythical' + ])->id + ]); + + $itemToEnchant = $this->itemToEnchant->refresh(); + + $this->enchantItemService->attachAffix($itemToEnchant, $this->createItemAffix([ + 'type' => 'prefix', + 'name' => 'Mythical', + 'cost' => RandomAffixDetails::MYTHIC, + ]), $skill, true); + + $item = $this->enchantItemService->getItem(); + + $this->assertNull($item->item_prefix_id); + } + + public function testEnchantTheItemWithAPrefixThatIsCosmicAndExpectThePrefixToNotBeAttachedWhenTooEasy() + { + + $character = $this->character->getCharacter(); + + $skill = $character->skills->where('game_skill_id', $this->enchantingSkill->id)->first(); + + $this->itemToEnchant->update([ + 'item_prefix_id' => $this->createItemAffix([ + 'type' => 'prefix', + 'name' => 'Non Cosmic' + ])->id + ]); + + $itemToEnchant = $this->itemToEnchant->refresh(); + + $this->enchantItemService->attachAffix($itemToEnchant, $this->createItemAffix([ + 'type' => 'prefix', + 'name' => 'Cosmic', + 'cost' => RandomAffixDetails::COSMIC, + ]), $skill, true); + + $item = $this->enchantItemService->getItem(); + + $this->assertNull($item->item_prefix_id); + } + + public function testEnchantTheItemWithASuffixThatIsMythicAndExpectThePrefixToNotBeAttachedWhenTooEasy() + { + + $character = $this->character->getCharacter(); + + $skill = $character->skills->where('game_skill_id', $this->enchantingSkill->id)->first(); + + $this->itemToEnchant->update([ + 'item_suffix_id' => $this->createItemAffix([ + 'type' => 'suffix', + 'name' => 'Non Mythical' + ])->id + ]); + + $itemToEnchant = $this->itemToEnchant->refresh(); + + $this->enchantItemService->attachAffix($itemToEnchant, $this->createItemAffix([ + 'type' => 'suffix', + 'name' => 'Mythical', + 'cost' => RandomAffixDetails::MYTHIC, + ]), $skill, true); + + $item = $this->enchantItemService->getItem(); + + $this->assertNull($item->item_suffix_id); + } + + public function testEnchantTheItemWithASuffixThatIsCosmicAndExpectThePrefixToNotBeAttachedWhenTooEasy() + { + + $character = $this->character->getCharacter(); + + $skill = $character->skills->where('game_skill_id', $this->enchantingSkill->id)->first(); + + $this->itemToEnchant->update([ + 'item_suffix_id' => $this->createItemAffix([ + 'type' => 'suffix', + 'name' => 'Non Mythical' + ])->id + ]); + + $itemToEnchant = $this->itemToEnchant->refresh(); + + $this->enchantItemService->attachAffix($itemToEnchant, $this->createItemAffix([ + 'type' => 'suffix', + 'name' => 'Mythical', + 'cost' => RandomAffixDetails::COSMIC, + ]), $skill, true); + + $item = $this->enchantItemService->getItem(); + + $this->assertNull($item->item_suffix_id); + } + public function testEnchantTheItemWithDcCheck() { $this->instance( @@ -170,6 +280,63 @@ public function testUpdateTheCharactersInventorySlot() $this->assertEquals($slot->refresh()->item_id, $item->id); } + public function testUpdateTheCharactersInventorySlotWhenThereAreAttachedHolyStacks() + { + + $this->itemToEnchant->appliedHolyStacks()->create([ + 'item_id' => $this->itemToEnchant->id, + 'devouring_darkness_bonus' => 0.10, + 'stat_increase_bonus' => 0.10, + ]); + + $itemToEnchant = $this->itemToEnchant->refresh(); + + $character = $this->character->inventoryManagement()->giveItem($itemToEnchant)->getCharacter(); + + $slot = $character->inventory->slots->first(); + + $skill = $character->skills->where('game_skill_id', $this->enchantingSkill->id)->first(); + + $this->enchantItemService->attachAffix($this->itemToEnchant, $this->suffix, $skill, true); + $this->enchantItemService->updateSlot($slot, false); + + $item = $this->enchantItemService->getItem(); + + $this->assertNotNull($item->item_suffix_id); + $this->assertEquals($slot->refresh()->item_id, $item->id); + $this->assertCount(1, $item->appliedHolyStacks); + } + + public function testUpdateTheCharactersInventorySlotWhenThereAreSocketsAttached() + { + + $this->itemToEnchant->sockets()->create([ + 'item_id' => $this->itemToEnchant->id, + 'gem_id' => $this->createGem()->id, + ]); + + $this->itemToEnchant->update([ + 'socket_count' => 1, + ]); + + $itemToEnchant = $this->itemToEnchant->refresh(); + + $character = $this->character->inventoryManagement()->giveItem($itemToEnchant)->getCharacter(); + + $slot = $character->inventory->slots->first(); + + $skill = $character->skills->where('game_skill_id', $this->enchantingSkill->id)->first(); + + $this->enchantItemService->attachAffix($this->itemToEnchant, $this->suffix, $skill, true); + $this->enchantItemService->updateSlot($slot, false); + + $item = $this->enchantItemService->getItem(); + + $this->assertNotNull($item->item_suffix_id); + $this->assertEquals($slot->refresh()->item_id, $item->id); + $this->assertCount(1, $item->sockets); + } + public function testUpdateTheCharactersInventorySlotWithMatchingItemWhenThereAreDuplicateItems() { diff --git a/tests/Unit/Game/Skills/Services/EnchantingServiceTest.php b/tests/Unit/Game/Skills/Services/EnchantingServiceTest.php index 93f7ba7cd..23c7006ab 100755 --- a/tests/Unit/Game/Skills/Services/EnchantingServiceTest.php +++ b/tests/Unit/Game/Skills/Services/EnchantingServiceTest.php @@ -24,14 +24,26 @@ use Tests\TestCase; use Tests\Traits\CreateClass; use Tests\Traits\CreateEvent; +use Tests\Traits\CreateGameMap; use Tests\Traits\CreateGameSkill; +use Tests\Traits\CreateGlobalCraftingInventory; +use Tests\Traits\CreateGlobalCraftingInventorySlot; use Tests\Traits\CreateGlobalEventGoal; use Tests\Traits\CreateItem; use Tests\Traits\CreateItemAffix; class EnchantingServiceTest extends TestCase { - use CreateClass, CreateEvent, CreateGameSkill, CreateGlobalEventGoal, CreateItem, CreateItemAffix, RefreshDatabase; + use CreateClass, + CreateEvent, + CreateGameSkill, + CreateGlobalEventGoal, + CreateItem, + CreateItemAffix, + CreateGlobalCraftingInventory, + CreateGlobalCraftingInventorySlot, + CreateGameMap, + RefreshDatabase; private ?CharacterFactory $character; @@ -108,6 +120,52 @@ public function testFetchAffixesAndItemsThatCanBeEnchanted() $this->assertNotEmpty($result['character_inventory']); } + public function testFetchAffixesAndItemsThatCanBeEnchantedForGlobalEvent() + { + $character = $this->character->inventoryManagement()->giveItem($this->itemToEnchant)->getCharacter(); + + $this->createEvent([ + 'type' => EventType::DELUSIONAL_MEMORIES_EVENT, + 'current_event_goal_step' => GlobalEventSteps::ENCHANT, + ]); + + $globalEventGoal = $this->createGlobalEventGoal([ + 'event_type' => EventType::DELUSIONAL_MEMORIES_EVENT, + 'max_enchants' => 100, + 'reward_every' => 10, + 'next_reward_at' => 10, + 'item_specialty_type_reward' => ItemSpecialtyType::DELUSIONAL_SILVER, + 'should_be_unique' => false, + 'should_be_mythic' => true, + ]); + + $character = $this->character->getCharacter(); + + $inventory = $this->createGlobalCraftingInventory([ + 'global_event_id' => $globalEventGoal->id, + 'character_id' => $character->id, + ]); + + $this->createGlobalCraftingInventorySlot([ + 'global_event_crafting_inventory_id' => $inventory->id, + 'item_id' => $this->createItem(), + ]); + + $gameMap = $this->createGameMap([ + 'only_during_event_type' => EventType::DELUSIONAL_MEMORIES_EVENT, + ]); + + $character->map()->update([ + 'game_map_id' => $gameMap->id + ]); + + $character = $character->refresh(); + + $result = $this->enchantingService->fetchAffixes($character, true); + + $this->assertNotEmpty($result['items_for_event']); + } + public function testFetchAffixesAsMerhcant() { Event::fake(); @@ -338,6 +396,7 @@ public function testEnchantWhenToEasy() }); } + public function testEnchantingSucceeds() { @@ -370,7 +429,7 @@ public function testEnchantingSucceeds() $this->assertEquals(0, $character->gold); Event::assertDispatched(function (ServerMessageEvent $event) use ($slot) { - return $event->message === 'Applied enchantment: '.$this->prefix->name.' to: '.$slot->item->refresh()->affix_name; + return $event->message === 'Applied enchantment: ' . $this->prefix->name . ' to: ' . $slot->item->refresh()->affix_name; }); } @@ -464,7 +523,7 @@ public function testEnchantingFails() $this->assertEquals(0, $character->gold); Event::assertDispatched(function (ServerMessageEvent $event) use ($itemName) { - return $event->message === 'You failed to apply '.$this->prefix->name.' to: '.$itemName.'. The item shatters before you. You lost the investment.'; + return $event->message === 'You failed to apply ' . $this->prefix->name . ' to: ' . $itemName . '. The item shatters before you. You lost the investment.'; }); } @@ -520,4 +579,34 @@ public function testFetchCharacterEnchantingXP() $this->assertEquals($weaponCraftingXpData['skill_name'], $enchantingSkill->baseSkill->name); } + + public function testGetItemForGlobalEvent() + { + + $globalEventGoal = $this->createGlobalEventGoal([ + 'event_type' => EventType::DELUSIONAL_MEMORIES_EVENT, + 'max_enchants' => 100, + 'reward_every' => 10, + 'next_reward_at' => 10, + 'item_specialty_type_reward' => ItemSpecialtyType::DELUSIONAL_SILVER, + 'should_be_unique' => false, + 'should_be_mythic' => true, + ]); + + $character = $this->character->getCharacter(); + + $inventory = $this->createGlobalCraftingInventory([ + 'global_event_id' => $globalEventGoal->id, + 'character_id' => $character->id, + ]); + + $slot = $this->createGlobalCraftingInventorySlot([ + 'global_event_crafting_inventory_id' => $inventory->id, + 'item_id' => $this->createItem(), + ]); + + $foundSlot = $this->enchantingService->getSlotFromInventory($character, $slot->id); + + $this->assertEquals($foundSlot->id, $slot->id); + } } diff --git a/tests/Unit/Game/Skills/Services/GemServiceTest.php b/tests/Unit/Game/Skills/Services/GemServiceTest.php index f325def95..665ee1908 100755 --- a/tests/Unit/Game/Skills/Services/GemServiceTest.php +++ b/tests/Unit/Game/Skills/Services/GemServiceTest.php @@ -187,6 +187,34 @@ public function testCraftTheGem() Event::assertDispatched(ServerMessageEvent::class); } + public function testCraftTheGemWhenSkillLevelIsMaxed() + { + Event::fake(); + + $character = $this->character->getCharacter(); + + $character->skills()->where('game_skill_id', GameSkill::where('name', 'Gem Crafting')->first()->id)->update([ + 'level' => 400 + ]); + + $character->update([ + 'gold_dust' => MaxCurrenciesValue::MAX_GOLD_DUST, + 'shards' => MaxCurrenciesValue::MAX_SHARDS, + 'copper_coins' => MaxCurrenciesValue::MAX_COPPER, + ]); + + $result = resolve(GemService::class)->generateGem($character, 1); + + $character = $character->refresh(); + + $this->assertEquals(1, $character->gemBag->gemSlots->first()->amount); + + $this->assertEquals(200, $result['status']); + + Event::assertDispatched(UpdateSkillEvent::class); + Event::assertDispatched(ServerMessageEvent::class); + } + public function testCraftTheGemButIncreaseTheAmount() { Event::fake(); diff --git a/tests/Unit/Game/Skills/Services/SkillServiceTest.php b/tests/Unit/Game/Skills/Services/SkillServiceTest.php index 24337376f..d60bf77fa 100755 --- a/tests/Unit/Game/Skills/Services/SkillServiceTest.php +++ b/tests/Unit/Game/Skills/Services/SkillServiceTest.php @@ -4,6 +4,7 @@ use App\Flare\Events\SkillLeveledUpServerMessageEvent; use App\Flare\Models\GameSkill; +use App\Game\Events\Values\EventType; use App\Game\Skills\Services\SkillService; use App\Game\Skills\Values\SkillTypeValue; use Illuminate\Foundation\Testing\RefreshDatabase; @@ -11,11 +12,13 @@ use Tests\Setup\Character\CharacterFactory; use Tests\TestCase; use Tests\Traits\CreateClass; +use Tests\Traits\CreateEvent; use Tests\Traits\CreateGameSkill; +use Tests\Traits\CreateScheduledEvent; class SkillServiceTest extends TestCase { - use CreateClass, CreateGameSkill, RefreshDatabase; + use CreateClass, CreateGameSkill, CreateEvent, CreateScheduledEvent, RefreshDatabase; private ?CharacterFactory $character; @@ -84,7 +87,7 @@ public function testTrainSkill() $this->assertTrue($skillToTrain->currently_training); $this->assertEquals(200, $result['status']); - $this->assertEquals('You are now training '.$skillToTrain->name, $result['message']); + $this->assertEquals('You are now training ' . $skillToTrain->name, $result['message']); } public function testSwitchTrainingSkills() @@ -115,7 +118,7 @@ public function testSwitchTrainingSkills() $this->assertFalse($secondarySkillTraining->currently_training); $this->assertEquals(200, $result['status']); - $this->assertEquals('You are now training '.$skillToTrain->name, $result['message']); + $this->assertEquals('You are now training ' . $skillToTrain->name, $result['message']); } public function testDoNotAssignXpToASkillThatDoesntExist() @@ -167,6 +170,32 @@ public function testAssignXpToSkill() $this->assertGreaterThan(10, $skill->xp); } + public function testAssignXpToSkillWhenEventIsRunning() + { + $this->createScheduledEvent([ + 'event_type' => EventType::FEEDBACK_EVENT, + 'start_date' => now()->addMinutes(5), + 'currently_running' => true, + ]); + + $character = $this->character->getCharacter(); + + $skill = $character->skills->first(); + + $skill->update([ + 'currently_training' => true, + 'xp_towards' => 0.10, + ]); + + $character = $character->refresh(); + + $this->skillService->assignXPToTrainingSkill($character, 10); + + $skill = $character->refresh()->skills->where('currently_training', true)->first(); + + $this->assertGreaterThan(10, $skill->xp); + } + public function testLevelSkill() { Event::fake(); @@ -230,4 +259,99 @@ public function testCraftSkillDoesNotGetXpBecauseItsMaxLevel() $this->assertEquals(0, $skill->refresh()->xp); } + + public function testAssignXpToCraftingSkillWhenFeedBackEventIsRunning() + { + $this->createScheduledEvent([ + 'event_type' => EventType::FEEDBACK_EVENT, + 'start_date' => now()->addMinutes(5), + 'currently_running' => true, + ]); + + $craftingSkill = $this->createGameSkill([ + 'type' => SkillTypeValue::CRAFTING, + 'name' => 'Weapon Crafting', + ]); + + $character = $this->character->assignSkill($craftingSkill, 1)->getCharacter(); + $skill = $character->skills->where('game_skill_id', $craftingSkill->id)->first(); + + $this->skillService->assignXpToCraftingSkill($character->map->gameMap, $skill); + + $this->assertGreaterThan(0, $skill->refresh()->xp); + } + + public function testAssignXpToRegularSkillWhenFeedBackEventIsRunning() + { + $this->createScheduledEvent([ + 'event_type' => EventType::FEEDBACK_EVENT, + 'start_date' => now()->addMinutes(5), + 'currently_running' => true, + ]); + + $regularSkill = $this->createGameSkill([ + 'type' => SkillTypeValue::TRAINING, + 'name' => 'Accuracy', + ]); + + $character = $this->character->assignSkill($regularSkill, 1)->getCharacter(); + $skill = $character->skills->where('game_skill_id', $regularSkill->id)->first(); + + $this->skillService->assignXpToCraftingSkill($character->map->gameMap, $skill); + + $this->assertGreaterThan(0, $skill->refresh()->xp); + } + + public function testAssignXpToRegularSkillAndLevelItUp() + { + $craftingSkill = $this->createGameSkill([ + 'type' => SkillTypeValue::TRAINING, + 'name' => 'Accuracy', + ]); + + $character = $this->character->assignSkill($craftingSkill, 1, false, [ + 'xp' => 999, + ])->getCharacter(); + $skill = $character->skills->where('game_skill_id', $craftingSkill->id)->first(); + + $this->skillService->assignXpToCraftingSkill($character->map->gameMap, $skill); + + $this->assertGreaterThan(1, $skill->refresh()->level); + } + + public function testAssignXpToRegularSkillAndDoNotLevelItUpWhenMaxed() + { + $craftingSkill = $this->createGameSkill([ + 'type' => SkillTypeValue::TRAINING, + 'name' => 'Accuracy', + ]); + + $character = $this->character->assignSkill($craftingSkill, 400, false, [ + 'xp' => 999, + ])->getCharacter(); + $skill = $character->skills->where('game_skill_id', $craftingSkill->id)->first(); + + $this->skillService->assignXpToCraftingSkill($character->map->gameMap, $skill); + + $this->assertEquals(400, $skill->refresh()->level); + $this->assertEquals(0, $skill->refresh()->xp); + } + + public function testAssignXpToRegularSkillAndDoNotLevelItBeyondLevel400() + { + $craftingSkill = $this->createGameSkill([ + 'type' => SkillTypeValue::TRAINING, + 'name' => 'Accuracy', + ]); + + $character = $this->character->assignSkill($craftingSkill, 399, false, [ + 'xp' => 999, + ])->getCharacter(); + $skill = $character->skills->where('game_skill_id', $craftingSkill->id)->first(); + + $this->skillService->assignXpToCraftingSkill($character->map->gameMap, $skill); + + $this->assertEquals(400, $skill->refresh()->level); + $this->assertEquals(0, $skill->refresh()->xp); + } }