diff --git a/app/Http/Controllers/Api/TradeController.php b/app/Http/Controllers/Api/TradeController.php index c1e3a47c..95aa2d79 100644 --- a/app/Http/Controllers/Api/TradeController.php +++ b/app/Http/Controllers/Api/TradeController.php @@ -56,7 +56,7 @@ public function sellItem(Request $request, SellItemCommandMapper $commandMapper) } catch (Exception $exception) { return response()->json([ - 'message' => 'Error buying item: ' . $exception->getMessage() + 'message' => 'Error selling item: ' . $exception->getMessage() ], 500); } diff --git a/app/Http/Controllers/LocationController.php b/app/Http/Controllers/LocationController.php index 6a8fe93b..38575f5b 100644 --- a/app/Http/Controllers/LocationController.php +++ b/app/Http/Controllers/LocationController.php @@ -16,7 +16,12 @@ public function __construct() public function show(string $locationId) { - $location = Location::query()->findOrFail($locationId); + /** @var Location $location */ + $location = Location::query() + ->with('characters.race') + ->with('characters.user') + ->with('adjacentLocations') + ->findOrFail($locationId); return view('location.show', compact('location')); } diff --git a/app/Models/Character.php b/app/Models/Character.php index 88d1ad93..d92cbcad 100644 --- a/app/Models/Character.php +++ b/app/Models/Character.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Modules\Character\Domain\CharacterType; use App\Modules\Equipment\Domain\ItemStatus; use App\Modules\Equipment\Domain\ItemType; use App\Traits\UsesStringId; @@ -27,6 +28,7 @@ * @property string location_id * @property Race race * @property string gender + * @property string type * @property int total_hit_points * @property int victor_xp_gained * @property Image profilePicture @@ -118,14 +120,29 @@ public function isYou(): bool return $this->isPlayerCharacter() && $this->user->isCurrentAuthenticatedUser(); } + public function isOwnMerchant(): bool + { + return $this->isMerchant() && $this->user->isCurrentAuthenticatedUser(); + } + public function isPlayerCharacter(): bool { - return $this->user !== null; + return $this->type === CharacterType::PLAYER; + } + + public function isMerchant(): bool + { + return $this->type === CharacterType::MERCHANT; + } + + public function isMonster(): bool + { + return $this->type === CharacterType::MONSTER; } public function isNPC(): bool { - return $this->user === null; + return !$this->isPlayerCharacter(); } public function hasProfilePicture(): bool @@ -258,6 +275,11 @@ public function getGender(): string return $this->gender; } + public function getType(): string + { + return $this->type; + } + public function getRaceId(): int { return $this->race->getId(); diff --git a/app/Models/Item.php b/app/Models/Item.php index b45b9e5d..d91246b4 100644 --- a/app/Models/Item.php +++ b/app/Models/Item.php @@ -5,6 +5,7 @@ use App\Modules\Equipment\Domain\ItemStatus; use App\Traits\UsesStringId; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; /** @@ -38,6 +39,11 @@ public function inventory(): BelongsToMany return $this->belongsToMany(Inventory::class); } + public function prototype(): BelongsTo + { + return $this->belongsTo(ItemPrototype::class); + } + public function getId(): string { return $this->id; diff --git a/app/Models/Location.php b/app/Models/Location.php index d95ac48c..4eb86d77 100644 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -4,6 +4,7 @@ use App\Traits\UsesStringId; use Carbon\Carbon; +use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -11,6 +12,7 @@ /** * @property string id * @property string name + * @property Collection adjacentLocations */ class Location extends Model { @@ -76,12 +78,14 @@ public function characters() */ public function adjacentLocations() { - return $this->belongsToMany(Location::class, 'adjacent_location', 'location_id', 'adjacent_location_id'); + return $this->belongsToMany(Location::class, 'adjacent_location', 'location_id', 'adjacent_location_id')->withPivot('direction'); } public function adjacent($type) { - return $this->adjacentLocations()->wherePivot('direction', $type)->first(); + return $this->adjacentLocations->filter(function (Location $value, $key) use ($type) { + return $value->getOriginal('pivot_direction') === $type; + })->first(); } public function addAdjacentLocation(Location $adjacent, $direction) diff --git a/app/Modules/Character/Application/Commands/CreateCharacterCommand.php b/app/Modules/Character/Application/Commands/CreateCharacterCommand.php index 42ef7216..289d02fc 100644 --- a/app/Modules/Character/Application/Commands/CreateCharacterCommand.php +++ b/app/Modules/Character/Application/Commands/CreateCharacterCommand.php @@ -15,6 +15,11 @@ class CreateCharacterCommand * @var string */ private $gender; + /** + * @var string + */ + private $type; + /** * @var int */ @@ -24,10 +29,11 @@ class CreateCharacterCommand */ private $userId; - public function __construct(string $name, string $gender, int $raceId, string $userId) + public function __construct(string $name, string $gender, string $type, int $raceId, string $userId) { $this->name = $name; $this->gender = $gender; + $this->type = $type; $this->raceId = $raceId; $this->userId = $userId; } @@ -42,6 +48,11 @@ public function getGender(): string return $this->gender; } + public function getCharacterType(): string + { + return $this->type; + } + public function getRaceId(): int { return $this->raceId; diff --git a/app/Modules/Character/Application/Factories/CharacterFactory.php b/app/Modules/Character/Application/Factories/CharacterFactory.php index 2cfb363a..24cd55b6 100644 --- a/app/Modules/Character/Application/Factories/CharacterFactory.php +++ b/app/Modules/Character/Application/Factories/CharacterFactory.php @@ -5,6 +5,7 @@ use App\Modules\Character\Application\Commands\CreateCharacterCommand; use App\Modules\Character\Domain\CharacterId; +use App\Modules\Character\Domain\CharacterType; use App\Modules\Character\Domain\Race; use App\Modules\Equipment\Domain\Inventory; use App\Modules\Character\Domain\Statistics; @@ -26,6 +27,7 @@ public function create(CharacterId $characterId, CreateCharacterCommand $command $race->getStartingLocationId(), $command->getName(), new Gender($command->getGender()), + new CharacterType($command->getCharacterType()), 0, new Reputation(0), new Attributes([ diff --git a/app/Modules/Character/Domain/Character.php b/app/Modules/Character/Domain/Character.php index 77e8a27a..54732613 100644 --- a/app/Modules/Character/Domain/Character.php +++ b/app/Modules/Character/Domain/Character.php @@ -22,6 +22,10 @@ class Character * @var Gender */ private $gender; + /** + * @var CharacterType + */ + private $type; /** * @var int */ @@ -78,6 +82,7 @@ public function __construct( string $locationId, string $name, Gender $gender, + CharacterType $type, int $xp, Reputation $reputation, Attributes $attributes, @@ -86,11 +91,11 @@ public function __construct( Inventory $inventory, int $userId = null, ImageId $profilePictureId = null - ) - { + ) { $this->id = $id; $this->name = $name; $this->gender = $gender; + $this->type = $type; $this->levelId = $levelId; $this->raceId = $raceId; $this->locationId = $locationId; @@ -239,6 +244,11 @@ public function getGender(): Gender return $this->gender; } + public function getType(): CharacterType + { + return $this->type; + } + public function getXp(): int { return $this->xp; @@ -347,4 +357,9 @@ public function getInventory(): Inventory { return $this->inventory; } + + public function isMerchant(): bool + { + return $this->type->isMerchant(); + } } diff --git a/app/Modules/Character/Domain/CharacterType.php b/app/Modules/Character/Domain/CharacterType.php new file mode 100644 index 00000000..a8fd9937 --- /dev/null +++ b/app/Modules/Character/Domain/CharacterType.php @@ -0,0 +1,42 @@ +value = $value; + } + + public function getValue(): string + { + return $this->value; + } + + public function isMerchant(): bool + { + return $this->value === self::MERCHANT; + } +} diff --git a/app/Modules/Character/Infrastructure/ReconstitutionFactories/CharacterReconstitutionFactory.php b/app/Modules/Character/Infrastructure/ReconstitutionFactories/CharacterReconstitutionFactory.php index e92d1ae0..08f8b1bd 100644 --- a/app/Modules/Character/Infrastructure/ReconstitutionFactories/CharacterReconstitutionFactory.php +++ b/app/Modules/Character/Infrastructure/ReconstitutionFactories/CharacterReconstitutionFactory.php @@ -4,6 +4,7 @@ namespace App\Modules\Character\Infrastructure\ReconstitutionFactories; use App\Modules\Character\Domain\CharacterId; +use App\Modules\Character\Domain\CharacterType; use App\Modules\Equipment\Infrastructure\ReconstitutionFactories\InventoryReconstitutionFactory; use App\Modules\Character\Domain\Attributes; use App\Modules\Character\Domain\Character; @@ -40,6 +41,7 @@ public function reconstitute(CharacterModel $characterModel): Character $characterModel->getLocationId(), $characterModel->getName(), new Gender($characterModel->getGender()), + new CharacterType($characterModel->getType()), $characterModel->getXp(), new Reputation(0), new Attributes([ diff --git a/app/Modules/Character/Infrastructure/Repositories/CharacterRepository.php b/app/Modules/Character/Infrastructure/Repositories/CharacterRepository.php index 584f47d4..2962ce0c 100644 --- a/app/Modules/Character/Infrastructure/Repositories/CharacterRepository.php +++ b/app/Modules/Character/Infrastructure/Repositories/CharacterRepository.php @@ -45,6 +45,7 @@ public function add(Character $character): void 'name' => $character->getName(), 'gender' => $character->getGender()->getValue(), + 'type' => $character->getType()->getValue(), 'xp' => $character->getXp(), 'level_id' => $character->getLevelNumber(), diff --git a/app/Modules/Character/UI/Http/CommandMappers/CreateCharacterCommandMapper.php b/app/Modules/Character/UI/Http/CommandMappers/CreateCharacterCommandMapper.php index 25dae010..cb1a9ec1 100644 --- a/app/Modules/Character/UI/Http/CommandMappers/CreateCharacterCommandMapper.php +++ b/app/Modules/Character/UI/Http/CommandMappers/CreateCharacterCommandMapper.php @@ -4,6 +4,7 @@ namespace App\Modules\Character\UI\Http\CommandMappers; use App\Modules\Character\Application\Commands\CreateCharacterCommand; +use App\Modules\Character\Domain\CharacterType; use Illuminate\Http\Request; use App\Models\User as UserModel; @@ -17,6 +18,7 @@ public function map(Request $request): CreateCharacterCommand return new CreateCharacterCommand( $request->input('name'), $request->input('gender'), + CharacterType::PLAYER, $request->input('race_id'), $userModel->getId() ); diff --git a/app/Modules/Equipment/Domain/InventoryItem.php b/app/Modules/Equipment/Domain/InventoryItem.php index 9c39a723..29791757 100644 --- a/app/Modules/Equipment/Domain/InventoryItem.php +++ b/app/Modules/Equipment/Domain/InventoryItem.php @@ -46,19 +46,4 @@ public function unEquip(): void { $this->status = ItemStatus::inBackpack(); } - - public function toBaseItem(): Item - { - return new Item( - $this->getId(), - $this->getName(), - $this->getDescription(), - $this->getImageFilePath(), - $this->getType(), - $this->getEffects(), - $this->getPrice(), - $this->getPrototypeId(), - $this->getCreatorCharacterId() - ); - } } diff --git a/app/Modules/Equipment/Domain/Item.php b/app/Modules/Equipment/Domain/Item.php index 0e3399c7..43f0c46a 100644 --- a/app/Modules/Equipment/Domain/Item.php +++ b/app/Modules/Equipment/Domain/Item.php @@ -138,8 +138,25 @@ public function getPrice(): ItemPrice return $this->price; } - public function changePrice(ItemPrice $price): void + public function changePrice(ItemPrice $price): self { $this->price = $price; + + return $this; + } + + public function toBaseItem(): Item + { + return new Item( + $this->getId(), + $this->getName(), + $this->getDescription(), + $this->getImageFilePath(), + $this->getType(), + $this->getEffects(), + $this->getPrice(), + $this->getPrototypeId(), + $this->getCreatorCharacterId() + ); } } diff --git a/app/Modules/Trade/Application/Services/TradeService.php b/app/Modules/Trade/Application/Services/TradeService.php index 67f5f071..d47c4e72 100644 --- a/app/Modules/Trade/Application/Services/TradeService.php +++ b/app/Modules/Trade/Application/Services/TradeService.php @@ -4,10 +4,14 @@ namespace App\Modules\Trade\Application\Services; use App\Modules\Equipment\Application\Contracts\InventoryRepositoryInterface; +use App\Modules\Equipment\Application\Contracts\ItemPrototypeRepositoryInterface; +use App\Modules\Equipment\Application\Contracts\ItemRepositoryInterface; +use App\Modules\Equipment\Domain\ItemPrice; use App\Modules\Equipment\Domain\Money; use App\Modules\Trade\Application\Commands\BuyItemCommand; use App\Modules\Trade\Application\Commands\SellItemCommand; use App\Modules\Trade\Application\Contracts\StoreRepositoryInterface; +use App\Modules\Trade\Domain\Exception\SellPriceIsTooHigh; class TradeService { @@ -19,14 +23,26 @@ class TradeService * @var InventoryRepositoryInterface */ private $inventoryRepository; + /** + * @var ItemPrototypeRepositoryInterface + */ + private $itemPrototypeRepository; + /** + * @var ItemRepositoryInterface + */ + private $itemRepository; public function __construct( StoreRepositoryInterface $storeRepository, - InventoryRepositoryInterface $inventoryRepository + InventoryRepositoryInterface $inventoryRepository, + ItemPrototypeRepositoryInterface $itemPrototypeRepository, + ItemRepositoryInterface $itemRepository ) { $this->storeRepository = $storeRepository; $this->inventoryRepository = $inventoryRepository; + $this->itemPrototypeRepository = $itemPrototypeRepository; + $this->itemRepository = $itemRepository; } public function buyItem(BuyItemCommand $command): void @@ -49,10 +65,26 @@ public function sellItem(SellItemCommand $command): void $store = $this->storeRepository->getOne($command->getStoreId()); $item = $inventory->takeOut($command->getItemId()); - $money = $store->takeMoneyOut(new Money($item->getPrice()->getAmount())); + + $itemPrototype = $this->itemPrototypeRepository->getOne($item->getPrototypeId()); + + $prototypePrice = $itemPrototype->getPrice()->getAmount(); + $traderBuyPrice = (int)floor($prototypePrice * 0.75); + $customerSellPrice = $item->getPrice()->getAmount(); + + if ($traderBuyPrice < $customerSellPrice) { + throw new SellPriceIsTooHigh( + "The store is willing to pay no more than {$traderBuyPrice} coins for {$itemPrototype->getName()}" + ); + } + + $money = $store->takeMoneyOut(new Money($customerSellPrice)); + + $item->changePrice(ItemPrice::ofAmount($prototypePrice)); $store->add($item); $inventory->putMoneyIn($money); + $this->itemRepository->update($item); $this->inventoryRepository->update($inventory); $this->storeRepository->update($store); } diff --git a/app/Modules/Trade/Domain/Exception/SellPriceIsTooHigh.php b/app/Modules/Trade/Domain/Exception/SellPriceIsTooHigh.php new file mode 100644 index 00000000..be4a9207 --- /dev/null +++ b/app/Modules/Trade/Domain/Exception/SellPriceIsTooHigh.php @@ -0,0 +1,10 @@ +id; } - public function addItemToSlot(int $slot, StoreItem $item): void + public function addItemToSlot(int $slot, Item $item): void { if ($slot >= self::NUMBER_OF_SLOTS) { throw new ContainerSlotOutOfRangeException("Store slot $slot is out of range."); @@ -79,8 +79,6 @@ public function addItemToSlot(int $slot, StoreItem $item): void public function add(Item $item): void { - $item = new StoreItem($item, $item->getPrice()); - $slot = $this->findFreeSlot(); $this->items->put($slot, $item); @@ -97,16 +95,16 @@ private function findFreeSlot(): int throw new ContainerIsFullException('Cannot add to full store'); } - public function findItem(ItemId $itemId): ?StoreItem + public function findItem(ItemId $itemId): ?Item { - return $this->items->first(static function (StoreItem $item) use ($itemId) { + return $this->items->first(static function (Item $item) use ($itemId) { return $item->getId()->equals($itemId); }); } public function findItemsOfType(ItemType $type): Collection { - return $this->items->filter(static function (StoreItem $item) use ($type) { + return $this->items->filter(static function (Item $item) use ($type) { return $item->isOfType($type); }); } @@ -123,7 +121,7 @@ public function getItems(): Collection public function takeOut(ItemId $itemId): Item { - $slot = $this->items->search(static function (StoreItem $item) use ($itemId) { + $slot = $this->items->search(static function (Item $item) use ($itemId) { return $item->getId()->equals($itemId); }); @@ -131,7 +129,7 @@ public function takeOut(ItemId $itemId): Item throw new ItemNotInContainer('Cannot take out item from empty slot'); } - /** @var StoreItem $item */ + /** @var Item $item */ $item = $this->items->get($slot); $this->items->forget($slot); diff --git a/app/Modules/Trade/Domain/StoreItem.php b/app/Modules/Trade/Domain/StoreItem.php deleted file mode 100644 index 995fb262..00000000 --- a/app/Modules/Trade/Domain/StoreItem.php +++ /dev/null @@ -1,57 +0,0 @@ -getId(), - $item->getName(), - $item->getDescription(), - $item->getImageFilePath(), - $item->getType(), - $item->getEffects(), - $item->getPrice(), - $item->getPrototypeId(), - $item->getCreatorCharacterId() - ); - - $this->price = $price; - } - - public function getPrice(): ItemPrice - { - return $this->price; - } - - public function changePrice(ItemPrice $price): void - { - $this->price = $price; - } - - public function toBaseItem(): Item - { - return new Item( - $this->getId(), - $this->getName(), - $this->getDescription(), - $this->getImageFilePath(), - $this->getType(), - $this->getEffects(), - $this->getPrice(), - $this->getPrototypeId(), - $this->getCreatorCharacterId() - ); - } -} diff --git a/app/Modules/Trade/Domain/StoreType.php b/app/Modules/Trade/Domain/StoreType.php index 7be23c9b..db2d6595 100644 --- a/app/Modules/Trade/Domain/StoreType.php +++ b/app/Modules/Trade/Domain/StoreType.php @@ -7,7 +7,7 @@ class StoreType { public const SELL_ONLY = 'sell_only'; - public const BUY_AND_SELL = 'by_and_sell'; + public const BUY_AND_SELL = 'buy_and_sell'; public const TYPES = [ self::SELL_ONLY, @@ -27,7 +27,7 @@ private function __construct(string $type) public static function ofType(string $type): self { if (!in_array($type, self::TYPES, true)) { - throw new InvalidArgumentException("$type is not a valid Item Type"); + throw new InvalidArgumentException("$type is not a valid Store Type"); } return new self($type); diff --git a/app/Modules/Trade/Infrastructure/ReconstitutionFactories/StoreItemReconstitutionFactory.php b/app/Modules/Trade/Infrastructure/ReconstitutionFactories/StoreItemReconstitutionFactory.php deleted file mode 100644 index 0c8cd5e3..00000000 --- a/app/Modules/Trade/Infrastructure/ReconstitutionFactories/StoreItemReconstitutionFactory.php +++ /dev/null @@ -1,31 +0,0 @@ -itemReconstitutionFactory = $itemReconstitutionFactory; - } - - public function reconstitute(ItemModel $model): StoreItem - { - return new StoreItem( - $this->itemReconstitutionFactory->reconstitute($model), - ItemPrice::ofAmount($model->getPrice()) - ); - } -} diff --git a/app/Modules/Trade/Infrastructure/ReconstitutionFactories/StoreReconstitutionFactory.php b/app/Modules/Trade/Infrastructure/ReconstitutionFactories/StoreReconstitutionFactory.php index e6297744..a274a303 100644 --- a/app/Modules/Trade/Infrastructure/ReconstitutionFactories/StoreReconstitutionFactory.php +++ b/app/Modules/Trade/Infrastructure/ReconstitutionFactories/StoreReconstitutionFactory.php @@ -5,6 +5,7 @@ use App\Models\Item as ItemModel; use App\Modules\Equipment\Domain\Money; +use App\Modules\Equipment\Infrastructure\ReconstitutionFactories\ItemReconstitutionFactory; use App\Modules\Trade\Domain\Store; use App\Modules\Trade\Domain\StoreId; use App\Modules\Trade\Domain\StoreType; @@ -14,13 +15,13 @@ class StoreReconstitutionFactory { /** - * @var StoreItemReconstitutionFactory + * @var ItemReconstitutionFactory */ - private $inventoryItemReconstitutionFactory; + private $itemReconstitutionFactory; - public function __construct(StoreItemReconstitutionFactory $inventoryItemReconstitutionFactory) + public function __construct(ItemReconstitutionFactory $itemReconstitutionFactory) { - $this->inventoryItemReconstitutionFactory = $inventoryItemReconstitutionFactory; + $this->itemReconstitutionFactory = $itemReconstitutionFactory; } public function reconstitute(StoreModel $storeModel): Store @@ -28,7 +29,7 @@ public function reconstitute(StoreModel $storeModel): Store $items = $storeModel->items->mapWithKeys(function (ItemModel $itemModel) { $key = $itemModel->getInventorySlotNumber(); - $inventoryItem = $this->inventoryItemReconstitutionFactory->reconstitute($itemModel); + $inventoryItem = $this->itemReconstitutionFactory->reconstitute($itemModel); return [$key => $inventoryItem]; }); diff --git a/app/Modules/Trade/Infrastructure/Repositories/StoreRepository.php b/app/Modules/Trade/Infrastructure/Repositories/StoreRepository.php index f095d290..933dcda8 100644 --- a/app/Modules/Trade/Infrastructure/Repositories/StoreRepository.php +++ b/app/Modules/Trade/Infrastructure/Repositories/StoreRepository.php @@ -2,7 +2,7 @@ namespace App\Modules\Trade\Infrastructure\Repositories; -use App\Modules\Trade\Domain\StoreItem; +use App\Modules\Equipment\Domain\Item; use App\Modules\Trade\Infrastructure\ReconstitutionFactories\StoreReconstitutionFactory; use App\Models\Store as StoreModel; use App\Modules\Character\Domain\CharacterId; @@ -66,7 +66,7 @@ public function update(Store $store): void /** @var StoreModel $storeModel */ $storeModel = StoreModel::query()->findOrFail($store->getId()->toString()); - $storeItems = $store->getItems()->mapWithKeys(static function (StoreItem $item, int $slot) { + $storeItems = $store->getItems()->mapWithKeys(static function (Item $item, int $slot) { $itemId = $item->getId()->toString(); diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index c36f7fc5..9455e559 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -8,6 +8,7 @@ use App\Models\ItemPrototype; use App\Models\Location; use App\Modules\Character\Application\Contracts\CharacterRepositoryInterface; +use App\Modules\Character\Domain\CharacterType; use App\Modules\Character\Domain\HitPoints; use App\Modules\Character\Infrastructure\Repositories\RaceRepository; use App\Modules\Equipment\Application\Contracts\InventoryRepositoryInterface; @@ -17,6 +18,7 @@ use App\Models\Race; use App\Models\Store; use App\Models\User; +use App\Modules\Trade\Domain\StoreType; use Illuminate\Database\Eloquent\Factory; use Illuminate\Support\Str; use Faker\Generator; @@ -48,6 +50,7 @@ $hitPoints = HitPoints::byRace($race); $genders = ['male', 'female']; + $types = CharacterType::TYPES; $characterId = $characterRepository->nextIdentity()->toString(); @@ -62,6 +65,7 @@ 'name' => $faker->name, 'gender' => $genders[array_rand($genders)], + 'type' => $characterType = $types[array_rand($types)], 'xp' => 0, 'reputation' => 0, @@ -76,8 +80,8 @@ 'hit_points' => $hitPoints->getCurrentHitPoints(), 'total_hit_points' => $hitPoints->getMaximumHitPoints(), - 'user_id' => static function () { - return random_int(0, 3) + 'user_id' => static function () use ($characterType) { + return $characterType === CharacterType::PLAYER ? factory(User::class)->create()->id : null; }, @@ -102,7 +106,7 @@ 'id' => $storeRepository->nextIdentity()->toString(), 'character_id' => $character->getId(), 'money' => random_int(0, 5000), - 'type' => 'sell_only', + 'type' => $character->isMerchant() ? StoreType::BUY_AND_SELL : StoreType::SELL_ONLY, ]); }); diff --git a/database/migrations/2017_05_14_055844_create_characters_table.php b/database/migrations/2017_05_14_055844_create_characters_table.php index 6eed6708..3e9a64dc 100644 --- a/database/migrations/2017_05_14_055844_create_characters_table.php +++ b/database/migrations/2017_05_14_055844_create_characters_table.php @@ -19,6 +19,7 @@ public function up() $table->string('name')->unique(); $table->enum('gender', ['male', 'female']); + $table->enum('type', ['player', 'merchant', 'civilian', 'monster']); $table->unsignedInteger('xp')->default(0); $table->unsignedInteger('available_attribute_points')->default(0); diff --git a/database/seeders/CharacterSeeder.php b/database/seeders/CharacterSeeder.php index b4640a6d..1ca76b6a 100644 --- a/database/seeders/CharacterSeeder.php +++ b/database/seeders/CharacterSeeder.php @@ -8,6 +8,7 @@ use App\Models\ItemPrototype; use App\Models\Location; use App\Modules\Character\Application\Contracts\CharacterRepositoryInterface; +use App\Modules\Character\Domain\CharacterType; use App\Modules\Equipment\Application\Contracts\InventoryRepositoryInterface; use App\Modules\Equipment\Application\Contracts\ItemRepositoryInterface; use App\Modules\Equipment\Domain\ItemStatus; @@ -55,6 +56,7 @@ public function run() 'id' => $characterRepository->nextIdentity()->toString(), 'name' => 'Someone', 'gender' => 'male', + 'type' => CharacterType::PLAYER, 'xp' => 0, 'reputation' => 0, diff --git a/resources/js/components/StoreTrade.vue b/resources/js/components/StoreTrade.vue index 8d5caea9..5a1e65a7 100644 --- a/resources/js/components/StoreTrade.vue +++ b/resources/js/components/StoreTrade.vue @@ -46,6 +46,12 @@ {{ itemToDisplay.price }} + + Store buy price + + {{ toStoreBuyPrice(itemToDisplay) }} + + Type {{ itemToDisplay.type | underscoreToWhitespace | capitalize }} @@ -186,6 +192,9 @@ export default { effects: { quantity: 0, type: '' + }, + prototype: { + price: 0 } }, showModal: false, @@ -211,6 +220,9 @@ export default { effects: { quantity: 0, type: '' + }, + prototype: { + price: 0 } } ], @@ -234,6 +246,9 @@ export default { effects: { quantity: 0, type: '' + }, + prototype: { + price: 0 } } ], @@ -272,7 +287,7 @@ export default { this.logSuccess('Bought: ' + item.name + ' for ' + item.price + ' coins'); }).catch(error => { this.exchangeItemForMoney(item); - this.logError('Buying failed: ' + error.response.data.message); + this.logError(error.response.data.message); }); }, @@ -294,15 +309,21 @@ export default { return; } + if (item.prototype.price < item.price) { + this.logError('The store is willing to pay no more than ' + item.prototype.price + ' coins for ' + item.name); + + return; + } this.exchangeItemForMoney(item); axios.post('/api/store/' + this.trader.store.id + '/item/' + item.id + '/sell') .then(() => { this.logSuccess('Sold: ' + item.name + ' for ' + item.price + ' coins'); + item.price = item.prototype.price; }).catch(error => { this.exchangeMoneyForItem(item); - this.logError('Selling failed: ' + error.response.data.message); + this.logError(error.response.data.message); }); }, @@ -412,6 +433,10 @@ export default { return this.getInventoryItem(index) && this.getInventoryItem(index).pivot.status === 'equipped'; }, + toStoreBuyPrice(item) { + return Math.floor(item.prototype.price * 0.75); + }, + startDrag(evt, itemIndex, container) { evt.dataTransfer.dropEffect = 'move'; evt.dataTransfer.effectAllowed = 'move'; diff --git a/resources/views/character/partials/actions.blade.php b/resources/views/character/partials/actions.blade.php index 62848f55..031cce90 100644 --- a/resources/views/character/partials/actions.blade.php +++ b/resources/views/character/partials/actions.blade.php @@ -3,16 +3,16 @@
@if($character->isYou()) - Manage Inventory - + Inventory + - Manage Store - + Store + @else
- @if(!$character->isNPC()) + @if($character->isPlayerCharacter()) message @@ -23,6 +23,11 @@ class="btn btn-sm btn-success"> class="btn btn-sm btn-danger"> attack + + + trade +
@endif
diff --git a/resources/views/components/short_character_description.blade.php b/resources/views/components/short_character_description.blade.php index edcb5e2a..ccd552c8 100644 --- a/resources/views/components/short_character_description.blade.php +++ b/resources/views/components/short_character_description.blade.php @@ -1,2 +1,2 @@ {{ $character->name }} -({{ $character->getLevelNumber() }}) +({{ $character->getRaceName() }}) diff --git a/resources/views/location/partials/list-character.blade.php b/resources/views/location/partials/list-character.blade.php index 9f41b2ec..313a51a8 100644 --- a/resources/views/location/partials/list-character.blade.php +++ b/resources/views/location/partials/list-character.blade.php @@ -45,15 +45,18 @@ class="btn btn-xxs btn-success"> @endif + @if($character->isMerchant()) + + trade + + @endif + - - trade - @endif diff --git a/resources/views/trade/store/index.blade.php b/resources/views/trade/store/index.blade.php index 22fd4534..68af1fec 100644 --- a/resources/views/trade/store/index.blade.php +++ b/resources/views/trade/store/index.blade.php @@ -7,7 +7,7 @@ @section('body') - +