diff --git a/src/empire/empire.controller.ts b/src/empire/empire.controller.ts index 3025ba1..dbee13e 100644 --- a/src/empire/empire.controller.ts +++ b/src/empire/empire.controller.ts @@ -1,5 +1,5 @@ -import {Body, Controller, ForbiddenException, Get, Param, Patch} from '@nestjs/common'; -import {ApiForbiddenResponse, ApiOkResponse, ApiOperation, ApiTags, refs} from '@nestjs/swagger'; +import {Body, Controller, ForbiddenException, Get, Param, ParseBoolPipe, Patch, Query} from '@nestjs/common'; +import {ApiForbiddenResponse, ApiOkResponse, ApiOperation, ApiQuery, ApiTags, refs} from '@nestjs/swagger'; import {Auth, AuthUser} from '../auth/auth.decorator'; import {User} from '../user/user.schema'; import {Throttled} from '../util/throttled.decorator'; @@ -48,6 +48,12 @@ export class EmpireController { @Patch(':empire') @ApiOperation({description: 'Update empire details.'}) + @ApiQuery({ + name: 'free', + description: 'Change the resources directly without spending or receiving credits. ' + + 'Useful for events, testing or debugging. ' + + 'Note that it is not possible to change the population directly.', + }) @ApiOkResponse({type: Empire}) @ApiForbiddenResponse({description: 'Cannot modify another user\'s empire.'}) @NotFound('Game or empire not found.') @@ -56,12 +62,13 @@ export class EmpireController { @Param('game', ObjectIdPipe) game: Types.ObjectId, @Param('empire', ObjectIdPipe) id: Types.ObjectId, @Body() dto: UpdateEmpireDto, + @Query('free', new ParseBoolPipe({optional: true})) free = false, ): Promise { const empire = await this.empireService.find(id) ?? notFound(id); if (!currentUser._id.equals(empire.user)) { throw new ForbiddenException('Cannot modify another user\'s empire.'); } - this.empireService.updateEmpire(empire, dto); + this.empireService.updateEmpire(empire, dto, free); await this.empireService.saveAll([empire]); // emits update event return empire; } diff --git a/src/empire/empire.dto.ts b/src/empire/empire.dto.ts index 31a4c09..25591ae 100644 --- a/src/empire/empire.dto.ts +++ b/src/empire/empire.dto.ts @@ -5,6 +5,7 @@ import {SYSTEM_TYPES, SystemTypeName} from '../game-logic/system-types'; import {IsIn, IsOptional} from 'class-validator'; import {PartialType} from '../util/partial-type'; import {RESOURCES_SCHEMA_PROPERTIES} from '../game-logic/types'; +import {ResourceName} from '../game-logic/resources'; export class ReadEmpireDto extends OmitType(Empire, [ 'resources', @@ -43,7 +44,9 @@ export class UpdateEmpireDto extends PartialType(PickType(Empire, [ ] as const)) { @ApiPropertyOptional({ ...RESOURCES_SCHEMA_PROPERTIES, - description: 'Update resources for market trades. The credits are automatically updated as well.', + description: 'Update (delta) resources for market trades. ' + + 'The credits are automatically updated as well (unless the `free` query parameter is true). ' + + 'Use negative values to sell resources, positive values to buy resources.', }) - resources?: Record; + resources?: Record; } diff --git a/src/empire/empire.service.ts b/src/empire/empire.service.ts index 1a29f75..2770441 100644 --- a/src/empire/empire.service.ts +++ b/src/empire/empire.service.ts @@ -1,4 +1,4 @@ -import {Injectable} from '@nestjs/common'; +import {BadRequestException, Injectable} from '@nestjs/common'; import {InjectModel} from '@nestjs/mongoose'; import {Document, Model} from 'mongoose'; import {EventRepository, EventService, MongooseRepository} from '@mean-stream/nestx'; @@ -9,6 +9,7 @@ import {COLOR_PALETTE, EMPIRE_PREFIX_PALETTE, EMPIRE_SUFFIX_PALETTE, MIN_EMPIRES import {generateTraits} from '../game-logic/traits'; import {Member} from '../member/member.schema'; import {EmpireLogicService} from './empire-logic.service'; +import {ResourceName} from '../game-logic/resources'; @Injectable() @EventRepository() @@ -40,11 +41,20 @@ export class EmpireService extends MongooseRepository { return rest; } - updateEmpire(empire: EmpireDocument, dto: UpdateEmpireDto) { + updateEmpire(empire: EmpireDocument, dto: UpdateEmpireDto, free: boolean) { const {resources, ...rest} = dto; empire.set(rest); if (resources) { - this.empireLogicService.tradeResources(empire, resources); + if (free) { + for (const resource of Object.keys(resources) as ResourceName[]) { + if (resource === 'population') { + throw new BadRequestException('Cannot directly change empire population.'); + } + empire.resources[resource] += resources[resource]; + } + } else { + this.empireLogicService.tradeResources(empire, resources); + } } }