Skip to content

Commit 32f5696

Browse files
strideraclaude
andcommitted
feat: Flag reorganization schema and GraphQL fixes
Schema changes: - Rename TWO_HAND to TWOHAND (matches MAINHAND/OFFHAND pattern) - Add decorative field to MobResetEquipment/MobCarrying (decorative = visual only, can't be looted) (different from TEMPORARY object flag which IS lootable) - Add new mob fields: traits, behaviors, aggressionFormula, activityRestrictions, resistances GraphQL fixes for composite keys: - Update trigger operations to use (zoneId, id) parameters - Fix TriggerFields fragment (remove legacyVnum/legacyScript) - Add mobZoneId/objectZoneId to trigger queries - Update scripts page and TriggerManager components API fixes: - Update mob.dto.ts with new enum registrations - Update mob.mapper.ts with new field mappings - Fix test files for WearFlag and ExitState changes - Fix characters.service.ts stamina field names 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ae451b7 commit 32f5696

12 files changed

Lines changed: 2933 additions & 24470 deletions

File tree

apps/api/src/characters/characters.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,9 @@ export class CharactersService {
165165
...data,
166166
users: { connect: { id: userId } },
167167
hitPointsMax: Math.max(50, data.constitution * 5 + data.level * 10),
168-
movementMax: Math.max(100, data.constitution * 8 + data.level * 5),
169168
hitPoints: Math.max(50, data.constitution * 5 + data.level * 10),
170-
movement: Math.max(100, data.constitution * 8 + data.level * 5),
169+
staminaMax: Math.max(100, data.constitution * 8 + data.level * 5),
170+
stamina: Math.max(100, data.constitution * 8 + data.level * 5),
171171
};
172172
return this.db.characters.create({
173173
data: createData,

apps/api/src/common/mappers/__tests__/object.mapper.spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ function base(): ObjectMapperSource {
3535
deletedAt: null,
3636
createdBy: null,
3737
updatedBy: null,
38+
// New restriction fields
39+
restrictedClassIds: [],
40+
restrictedAlignments: [],
41+
minSize: null,
42+
maxSize: null,
43+
allowedRaces: [],
44+
passengerCapacity: null,
3845
};
3946
}
4047

apps/api/src/common/mappers/__tests__/room.mapper.spec.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { Direction, ExitFlag, RoomFlag, Sector } from '@prisma/client';
1+
import {
2+
Direction,
3+
ExitFlag,
4+
ExitState,
5+
RoomFlag,
6+
Sector,
7+
} from '@prisma/client';
28
import { mapRoom } from '../room.mapper';
39
import { RoomMapperSource } from '../types';
410

@@ -14,7 +20,9 @@ describe('mapRoom', () => {
1420
{
1521
id: 100,
1622
direction: Direction.NORTH,
17-
flags: [ExitFlag.CLOSED],
23+
flags: [ExitFlag.IS_DOOR],
24+
defaultState: ExitState.CLOSED,
25+
hitPoints: null,
1826
roomZoneId: 9,
1927
roomId: 55,
2028
keywords: ['door'],
@@ -27,6 +35,8 @@ describe('mapRoom', () => {
2735
id: 101,
2836
direction: Direction.SOUTH,
2937
flags: [],
38+
defaultState: ExitState.OPEN,
39+
hitPoints: null,
3040
roomZoneId: 9,
3141
roomId: 55,
3242
keywords: [],

apps/api/src/common/mappers/mob.mapper.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,17 @@ export function mapMob(db: MobMapperSource): MobDto {
7272
composition: db.composition,
7373
mobFlags: db.mobFlags,
7474
effectFlags: db.effectFlags,
75+
traits: db.traits ?? [],
76+
behaviors: db.behaviors ?? [],
77+
...(db.aggressionFormula !== null &&
78+
db.aggressionFormula !== undefined && {
79+
aggressionFormula: db.aggressionFormula,
80+
}),
81+
...(db.activityRestrictions !== null &&
82+
db.activityRestrictions !== undefined && {
83+
activityRestrictions: db.activityRestrictions,
84+
}),
85+
resistances: (resistances as Record<string, number>) ?? {},
7586
position: db.position,
7687
stance: db.stance,
7788
...(db.classId !== null &&

apps/api/src/mobs/mob-reset.service.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ describe('MobResetService mapping', () => {
117117
id: 100,
118118
objectZoneId: 5,
119119
objectId: 201,
120-
wearLocation: WearFlag.WIELD,
120+
wearLocation: WearFlag.MAINHAND,
121121
maxInstances: 1,
122122
probability: 1.0,
123123
objects: { id: 201, zoneId: 5, name: 'Short Bow', type: 'WEAPON' },
@@ -129,6 +129,6 @@ describe('MobResetService mapping', () => {
129129
(db.mobResets.findMany as jest.Mock).mockResolvedValue([mockReset]);
130130

131131
const result = await service.findByMob(5, 23);
132-
expect(result[0]!.equipment[0]!.wearLocation).toBe(WearFlag.WIELD);
132+
expect(result[0]!.equipment[0]!.wearLocation).toBe(WearFlag.MAINHAND);
133133
});
134134
});

apps/api/src/mobs/mob.dto.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ import {
1111
EffectFlag,
1212
Gender,
1313
LifeForce,
14+
MobBehavior,
1415
MobFlag,
1516
MobRole,
17+
MobTrait,
1618
Position,
1719
Race,
1820
Size,
1921
Stance,
2022
} from '@prisma/client';
23+
import GraphQLJSON from 'graphql-type-json';
2124
import {
2225
IsArray,
2326
IsEnum,
@@ -38,6 +41,8 @@ registerEnumType(Composition, { name: 'Composition' });
3841
registerEnumType(Stance, { name: 'Stance' });
3942
registerEnumType(Size, { name: 'Size' });
4043
registerEnumType(MobRole, { name: 'MobRole' });
44+
registerEnumType(MobTrait, { name: 'MobTrait' });
45+
registerEnumType(MobBehavior, { name: 'MobBehavior' });
4146

4247
// This DTO matches the actual Prisma Mob model
4348
@ObjectType()
@@ -189,6 +194,21 @@ export class MobDto {
189194
@Field(() => [EffectFlag])
190195
effectFlags: EffectFlag[];
191196

197+
@Field(() => [MobTrait])
198+
traits: MobTrait[];
199+
200+
@Field(() => [MobBehavior])
201+
behaviors: MobBehavior[];
202+
203+
@Field({ nullable: true, description: 'Lua formula for aggression targeting' })
204+
aggressionFormula?: string;
205+
206+
@Field({ nullable: true, description: 'Lua formula for activity restrictions' })
207+
activityRestrictions?: string;
208+
209+
@Field(() => GraphQLJSON, { description: 'JSON resistances map: {"FIRE": 0, "charm": 50}' })
210+
resistances: Record<string, number>;
211+
192212
@Field(() => Position)
193213
position: Position;
194214

@@ -441,6 +461,36 @@ export class CreateMobInput {
441461
@IsEnum(EffectFlag, { each: true })
442462
effectFlags?: EffectFlag[];
443463

464+
@Field(() => [MobTrait], { defaultValue: [] })
465+
@IsOptional()
466+
@IsArray()
467+
@IsEnum(MobTrait, { each: true })
468+
traits?: MobTrait[];
469+
470+
@Field(() => [MobBehavior], { defaultValue: [] })
471+
@IsOptional()
472+
@IsArray()
473+
@IsEnum(MobBehavior, { each: true })
474+
behaviors?: MobBehavior[];
475+
476+
@Field({ nullable: true, description: 'Lua formula for aggression targeting' })
477+
@IsOptional()
478+
@IsString()
479+
aggressionFormula?: string;
480+
481+
@Field({ nullable: true, description: 'Lua formula for activity restrictions' })
482+
@IsOptional()
483+
@IsString()
484+
activityRestrictions?: string;
485+
486+
@Field(() => GraphQLJSON, {
487+
nullable: true,
488+
defaultValue: {},
489+
description: 'JSON resistances map: {"FIRE": 0, "charm": 50}',
490+
})
491+
@IsOptional()
492+
resistances?: Record<string, number>;
493+
444494
@Field(() => Position, { defaultValue: Position.STANDING })
445495
@IsOptional()
446496
@IsEnum(Position)
@@ -708,6 +758,32 @@ export class UpdateMobInput {
708758
@IsEnum(EffectFlag, { each: true })
709759
effectFlags?: EffectFlag[];
710760

761+
@Field(() => [MobTrait], { nullable: true })
762+
@IsOptional()
763+
@IsArray()
764+
@IsEnum(MobTrait, { each: true })
765+
traits?: MobTrait[];
766+
767+
@Field(() => [MobBehavior], { nullable: true })
768+
@IsOptional()
769+
@IsArray()
770+
@IsEnum(MobBehavior, { each: true })
771+
behaviors?: MobBehavior[];
772+
773+
@Field({ nullable: true, description: 'Lua formula for aggression targeting' })
774+
@IsOptional()
775+
@IsString()
776+
aggressionFormula?: string;
777+
778+
@Field({ nullable: true, description: 'Lua formula for activity restrictions' })
779+
@IsOptional()
780+
@IsString()
781+
activityRestrictions?: string;
782+
783+
@Field(() => GraphQLJSON, { nullable: true, description: 'JSON resistances map' })
784+
@IsOptional()
785+
resistances?: Record<string, number>;
786+
711787
@Field(() => Position, { nullable: true })
712788
@IsOptional()
713789
@IsEnum(Position)

0 commit comments

Comments
 (0)