Skip to content

Commit

Permalink
[SYNC] Adjusting logics of the game, GOAP planner and logics updates (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Neloreck authored Aug 23, 2023
2 parents 6b17682 + e266ba4 commit eb61dd3
Show file tree
Hide file tree
Showing 98 changed files with 1,078 additions and 765 deletions.
19 changes: 18 additions & 1 deletion src/engine/core/database/objects.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { describe, expect, it } from "@jest/globals";

import { registerObject, resetObject, unregisterObject } from "@/engine/core/database/objects";
import {
registerObject,
registerWoundedObject,
resetObject,
unregisterObject,
unRegisterWoundedObject,
} from "@/engine/core/database/objects";
import { registry } from "@/engine/core/database/registry";
import { IRegistryObjectState } from "@/engine/core/database/types";
import { ClientObject } from "@/engine/lib/types";
Expand All @@ -22,4 +28,15 @@ describe("database objects utilities", () => {
unregisterObject(object);
expect(registry.objects.get(object.id())).toBeNull();
});

it("should correctly register and unregister wounded objects", () => {
const object: ClientObject = mockClientGameObject();
const state: IRegistryObjectState = registerObject(object);

registerWoundedObject(object);
expect(registry.objectsWounded.get(object.id())).toBe(state);

unRegisterWoundedObject(object);
expect(registry.objectsWounded.get(object.id())).toBeNull();
});
});
25 changes: 24 additions & 1 deletion src/engine/core/database/objects.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { setPortableStoreValue } from "@/engine/core/database/portable_store";
import { registry } from "@/engine/core/database/registry";
import { IRegistryObjectState } from "@/engine/core/database/types";
import { ClientObject, Optional } from "@/engine/lib/types";
import { HELPING_WOUNDED_OBJECT_KEY } from "@/engine/lib/constants/portable_store_keys";
import { ClientObject, Optional, TNumberId } from "@/engine/lib/types";

/**
* Register client object in RAM registry.
Expand Down Expand Up @@ -47,3 +49,24 @@ export function resetObject(object: ClientObject, state: Partial<IRegistryObject

return state as IRegistryObjectState;
}

/**
* Register object as wounded so others can detect it for searching and helping.
*
* @param object - client object to register as wounded
*/
export function registerWoundedObject(object: ClientObject): void {
const objectId: TNumberId = object.id();

registry.objectsWounded.set(objectId, registry.objects.get(objectId));
}

/**
* Unregister object as wounded so others will not detect it for helping.
*
* @param object - client object to unregister
*/
export function unRegisterWoundedObject(object: ClientObject): void {
setPortableStoreValue(object.id(), HELPING_WOUNDED_OBJECT_KEY, null);
registry.objectsWounded.delete(object.id());
}
3 changes: 2 additions & 1 deletion src/engine/core/database/registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { registry } from "@/engine/core/database/registry";

describe("registry storage", () => {
it("storage to contain all fields", () => {
expect(Object.keys(registry)).toHaveLength(38);
expect(Object.keys(registry)).toHaveLength(39);
});

it("storage to initialize with correct data", () => {
Expand All @@ -16,6 +16,7 @@ describe("registry storage", () => {
expect(registry.cache.conditionLists instanceof LuaTable).toBeTruthy();
expect(registry.actorCombat instanceof LuaTable).toBeTruthy();
expect(registry.objects instanceof LuaTable).toBeTruthy();
expect(registry.objectsWounded instanceof LuaTable).toBeTruthy();
expect(registry.offlineObjects instanceof LuaTable).toBeTruthy();
expect(registry.simulationObjects instanceof LuaTable).toBeTruthy();
expect(registry.storyLink.sidById instanceof LuaTable).toBeTruthy();
Expand Down
4 changes: 4 additions & 0 deletions src/engine/core/database/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ export const registry = {
* List of offline objects.
*/
offlineObjects: new LuaTable<TNumberId, IStoredOfflineObject>(),
/**
* List of wounded objects.
*/
objectsWounded: new LuaTable<TNumberId, IRegistryObjectState>(),
/**
* List of objects participating in alife simulation.
*/
Expand Down
4 changes: 2 additions & 2 deletions src/engine/core/database/stalker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ describe("'stalker' module of the database", () => {
callback: callbackPlaceholder,
},
1000,
{ lookObject: null, lookPosition: createEmptyVector() },
{ lookObjectId: null, lookPosition: createEmptyVector() },
{ isForced: true }
);

Expand All @@ -83,7 +83,7 @@ describe("'stalker' module of the database", () => {
turnEndCallback: callbackPlaceholder,
},
1000,
{ lookObject: null, lookPosition: { x: 0, y: 0, z: 0 } },
{ lookObjectId: null, lookPosition: { x: 0, y: 0, z: 0 } },
{ isForced: true }
);

Expand Down
11 changes: 0 additions & 11 deletions src/engine/core/database/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,17 +126,6 @@ export interface IRegistryObjectState extends Record<EScheme, Optional<IBaseSche
* todo;
*/
mute: Optional<boolean>;
/**
* ID of object currently looting object.
* Used to prevent looting of same object by multiple objects at once.
*
* todo: Move to loot scheme state, not store it in global. Probaly pstore is correct place.
*/
lootedByObject: Optional<TNumberId>;
/**
* todo;
*/
wounded_already_selected: Optional<TNumberId>;
/**
* todo;
*/
Expand Down
34 changes: 30 additions & 4 deletions src/engine/core/managers/debug/DebugManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { alife, relation_registry } from "xray16";
import { alife, cast_planner, relation_registry, stalker_ids } from "xray16";

import { IRegistryObjectState, registry } from "@/engine/core/database";
import { AbstractCoreManager } from "@/engine/core/managers/base/AbstractCoreManager";
Expand All @@ -7,11 +7,12 @@ import { StalkerStateManager } from "@/engine/core/objects/state/StalkerStateMan
import { EActionId } from "@/engine/core/schemes";
import { gameTimeToString } from "@/engine/core/utils/game/game_time";
import { LuaLogger } from "@/engine/core/utils/logging";
import { getObjectActiveWeaponSlot } from "@/engine/core/utils/object";
import { getNumberRelationBetweenCommunities } from "@/engine/core/utils/relation";
import { toJSON } from "@/engine/core/utils/transform/json";
import { stalkerCommunities, TCommunity } from "@/engine/lib/constants/communities";
import { NIL } from "@/engine/lib/constants/words";
import { ActionBase, ActionPlanner, ClientObject, ESchemeType, Optional, TLabel, TNumberId } from "@/engine/lib/types";
import { ActionPlanner, ClientObject, ESchemeType, Optional, TLabel, TName, TNumberId } from "@/engine/lib/types";

const logger: LuaLogger = new LuaLogger($filename);

Expand Down Expand Up @@ -55,7 +56,21 @@ export class DebugManager extends AbstractCoreManager {
logger.info("Current best enemy:", object.best_enemy()?.name() || NIL);
logger.info("Current best danger:", object.best_danger()?.object()?.name() || NIL);
logger.info("Current planner initialized:", actionPlanner.initialized());
logger.info("Current action id:", currentActionId);
logger.info("Current planner action id:", currentActionId, EActionId[currentActionId]);

// Detect specifically which action is played.
if (
currentActionId === stalker_ids.action_alife_planner ||
currentActionId === stalker_ids.action_combat_planner ||
currentActionId === stalker_ids.action_danger_planner
) {
logger.info(
"Current action id:",
currentActionId,
"->",
cast_planner(actionPlanner.action(currentActionId)).current_action_id()
);
}

if (actionPlanner.show !== null) {
actionPlanner.show(plannerShowPrefix);
Expand All @@ -74,7 +89,7 @@ export class DebugManager extends AbstractCoreManager {
const currentActionId: Optional<TNumberId> = actionPlanner.current_action_id();

logger.info("Current state planner initialized:", actionPlanner.initialized());
logger.info("Current state action id:", currentActionId);
logger.info("Current state action id:", currentActionId, EStateActionId[currentActionId]);

if (actionPlanner.show !== null) {
actionPlanner.show(plannerShowPrefix + "[planner] ");
Expand All @@ -96,16 +111,27 @@ export class DebugManager extends AbstractCoreManager {
if (registry.objects.get(object.id())?.stateManager) {
const stateManager: StalkerStateManager = registry.objects.get(object.id()).stateManager!;

logger.info("State controller:", stateManager.controller);
logger.info("Target state:", stateManager.targetState);
logger.info(
"Look object:",
stateManager.lookObjectId ? alife().object(stateManager.lookObjectId)?.name() || NIL : NIL
);
logger.info("Look type:", stateManager.getObjectLookPositionType());
logger.info("Current animation slot:", getObjectActiveWeaponSlot(object));
logger.info("Callback object:", toJSON(stateManager.callback));
logger.info("Is combat:", stateManager.isCombat);
logger.info("Is alife:", stateManager.isAlife);
logger.info("Animation states:", toJSON(stateManager.animation.state));
logger.info(
"Animation controller animation:",
toJSON(stateManager.animation.animations.get(stateManager.animation.state.currentState as TName))
);
logger.info("Animstate states:", toJSON(stateManager.animstate.state));
logger.info(
"Animstate controller animation:",
toJSON(stateManager.animation.animations.get(stateManager.animation.state.currentState as TName))
);
} else {
logger.info("No state manager declared for object");
}
Expand Down
3 changes: 2 additions & 1 deletion src/engine/core/objects/animation/animations/base.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { mockFromLuaTable } from "@/fixtures/lua";

describe("base animations list", () => {
it("should list all needed animations", () => {
expect(baseAnimations.length()).toBe(46);
expect(baseAnimations.length()).toBe(47);

assertArraysIntersecting(mockFromLuaTable(baseAnimations).getKeysArray(), [
EStalkerState.IDLE,
Expand Down Expand Up @@ -56,6 +56,7 @@ describe("base animations list", () => {
EStalkerState.LAY_ON_BED,
EStalkerState.SEARCH_CORPSE,
EStalkerState.HELP_WOUNDED,
EStalkerState.HELP_WOUNDED_WITH_MEDKIT,
]);
});
});
29 changes: 27 additions & 2 deletions src/engine/core/objects/animation/animations/base.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { IAnimationDescriptor } from "@/engine/core/objects/animation/animation_types";
import { EStalkerState } from "@/engine/core/objects/animation/state_types";
import { finishCorpseLooting } from "@/engine/core/schemes/corpse_detection/utils";
import { finishHelpWounded } from "@/engine/core/schemes/help_wounded/utils";
import { finishObjectHelpWounded } from "@/engine/core/schemes/help_wounded/utils";
import { createSequence } from "@/engine/core/utils/animation";
import { getExtern } from "@/engine/core/utils/binding";
import { startPlayingGuitar, startPlayingHarmonica } from "@/engine/core/utils/camp";
import { clearObjectAbuse, objectPunchActor } from "@/engine/core/utils/object";
import { misc } from "@/engine/lib/constants/items/misc";
import { AnyCallablesModule, ClientObject, TName } from "@/engine/lib/types";

/**
Expand Down Expand Up @@ -1017,13 +1018,37 @@ export const baseAnimations: LuaTable<TName, IAnimationDescriptor> = $fromObject
"dinamit_1",
{
// When animation ends, finish help wounded and heal up.
// todo: Probably just handle as callback in action object? Why setting globally?
f: (object: ClientObject) => {
finishHelpWounded(object);
finishObjectHelpWounded(object);
},
},
]),
out: null,
rnd: null,
idle: null,
},
[EStalkerState.HELP_WOUNDED_WITH_MEDKIT]: {
prop: {
maxidle: 1,
sumidle: 1,
rnd: 100,
moving: null,
},
into: createSequence([
"cr_raciya_0_draw_0",
{ a: misc.medkit_script },
"dinamit_1",
{
// When animation ends, finish help wounded and heal up.
// todo: Probably just handle as callback in action object? Why setting globally?
f: (object: ClientObject) => {
finishObjectHelpWounded(object);
},
},
]),
out: createSequence(["cr_raciya_0_hide_0", { d: misc.medkit_script }, "cr_raciya_0_hide_1"]),
rnd: null,
idle: null,
},
});
7 changes: 4 additions & 3 deletions src/engine/core/objects/animation/state_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import type {
AnyCallable,
AnyContextualCallable,
AnyObject,
ClientObject,
Optional,
TAnimationType,
TDuration,
TIndex,
TLookType,
TMoveType,
TName,
TNumberId,
TSightType,
TTimestamp,
Vector,
Expand Down Expand Up @@ -237,6 +237,7 @@ export enum EStalkerState {
HELLO = "hello",
HELLO_WPN = "hello_wpn",
HELP_WOUNDED = "help_wounded",
HELP_WOUNDED_WITH_MEDKIT = "help_wounded_with_medkit",
HIDE = "hide",
HIDE_FIRE = "hide_fire",
HIDE_NA = "hide_na",
Expand Down Expand Up @@ -344,10 +345,10 @@ export interface IStateDescriptor {
}

/**
* todo;
* Descriptor of loop position for state animation.
*/
export interface ILookTargetDescriptor {
lookObject: Optional<ClientObject>;
lookObjectId: Optional<TNumberId>;
lookPosition: Optional<Vector>;
}

Expand Down
3 changes: 2 additions & 1 deletion src/engine/core/objects/animation/states/base.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { mockFromLuaTable } from "@/fixtures/lua";

describe("base states list", () => {
it("should list all needed animations", () => {
expect(baseStates.length()).toBe(102);
expect(baseStates.length()).toBe(103);

assertArraysIntersecting(mockFromLuaTable(baseStates).getKeysArray(), [
EStalkerState.IDLE,
Expand Down Expand Up @@ -79,6 +79,7 @@ describe("base states list", () => {
EStalkerState.PUNCH,
EStalkerState.SEARCH_CORPSE,
EStalkerState.HELP_WOUNDED,
EStalkerState.HELP_WOUNDED_WITH_MEDKIT,
EStalkerState.DYNAMITE,
EStalkerState.BINOCULAR,
EStalkerState.HIDE_RAC,
Expand Down
8 changes: 8 additions & 0 deletions src/engine/core/objects/animation/states/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,14 @@ export const baseStates: LuaTable<TName, IStateDescriptor> = $fromObject<TName,
animstate: null,
animation: EStalkerState.HELP_WOUNDED,
},
[EStalkerState.HELP_WOUNDED_WITH_MEDKIT]: {
weapon: EWeaponAnimation.STRAPPED,
movement: move.stand,
mental: anim.danger,
bodystate: move.crouch,
animstate: null,
animation: EStalkerState.HELP_WOUNDED_WITH_MEDKIT,
},
[EStalkerState.DYNAMITE]: {
weapon: EWeaponAnimation.STRAPPED,
movement: move.stand,
Expand Down
4 changes: 2 additions & 2 deletions src/engine/core/objects/binders/camp/CampBinder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class CampBinder extends object_binder {
return false;
}

logger.info("Spawn camp:", this.object.name());
// logger.info("Spawn camp:", this.object.name());

const ini: IniFile = this.object.spawn_ini();

Expand All @@ -62,7 +62,7 @@ export class CampBinder extends object_binder {
* Handle net destroy event.
*/
public override net_destroy(): void {
logger.info("Destroy camp:", this.object.name());
// logger.info("Destroy camp:", this.object.name());

unregisterCamp(this.object);
super.net_destroy();
Expand Down
Loading

0 comments on commit eb61dd3

Please sign in to comment.