After further reading, re-combined the interfaces
= There wasn't really any point in trying to split the interfaces all the way up to the top level - this is a game; it is inevitable that some object data will change and some will stay the same
This commit is contained in:
parent
8a9d5414f8
commit
88129a87ba
3 changed files with 106 additions and 70 deletions
|
@ -1,3 +1,4 @@
|
|||
--An attempt to profile the speed of TweenService:GetValue
|
||||
local TweenService = game:GetService("TweenService")
|
||||
local clock = os.clock
|
||||
local first = clock()
|
|
@ -1,12 +1,19 @@
|
|||
// "EntityManager": Create entity objects and apply transformations to them.
|
||||
// A bold attempt at functional programming in a videogame entity system
|
||||
// A bold (or just foolish) attempt at functional programming in a videogame entity system
|
||||
import { makePuppet, puppet, puppetEntry } from "./Puppetmaster";
|
||||
// import { ability } from "./AbilityManager";
|
||||
const entityTags = ["minion"] as const
|
||||
const entityTags = ["minion"] as const;
|
||||
type modifiers = readonly [power: number, speed: number, defense: number, resistance: number]; // values used for calculation, only modified by buffs and debuffs
|
||||
type statuses = readonly [health: number, barrier: number]; // values used to store an entity's current status (more existential than stats)
|
||||
type statusEffect = readonly [string, modifiers, entityTransformTemplate, number];
|
||||
type entityTag = typeof entityTags[number]
|
||||
type statusEffect = readonly [
|
||||
name: string,
|
||||
type: string,
|
||||
strength: number,
|
||||
modifiers?: modifiers,
|
||||
effect?: entityTransformTemplate,
|
||||
]; // Should also be able to cause a visual effect somehow - maybe rather than having an entityTransformTemplate, it should broadcast a message back to the top
|
||||
// ...that can affect other entities or communicate with the client
|
||||
type entityTag = typeof entityTags[number];
|
||||
export interface entityId {
|
||||
readonly name: string;
|
||||
readonly team: "players" | "enemies";
|
||||
|
@ -15,20 +22,21 @@ export interface entityId {
|
|||
};
|
||||
}
|
||||
export interface entityProperties {
|
||||
readonly id: entityId,
|
||||
readonly baseModifiers: modifiers,
|
||||
readonly maxStatuses: statuses,
|
||||
readonly baseStatusEffects: statusEffect[],// Permanent immunities/status effects
|
||||
readonly id: entityId;
|
||||
readonly maxStatuses: statuses;
|
||||
readonly baseModifiers: modifiers;
|
||||
readonly baseStatusEffects: statusEffect[]; // Permanent immunities/status effects
|
||||
}
|
||||
export interface entityStatuses {
|
||||
readonly statuses: statuses; // Health and stuff that change constantly
|
||||
readonly statusEffects: statusEffect[]; // Burn, poison, etc.
|
||||
export interface entity {
|
||||
statuses: statuses;
|
||||
statusEffects: statusEffect[];
|
||||
readonly properties: entityProperties;
|
||||
}
|
||||
|
||||
|
||||
type entityTransformType = "support" | "attack";
|
||||
type healthTransformValue = [magnitude: number, affectsHealth: boolean, affectsBarrier: boolean]
|
||||
type healthTransformValue = [magnitude: number, affectsHealth: boolean, affectsBarrier: boolean];
|
||||
interface entityTransformTemplate {
|
||||
healthTransformValue: healthTransformValue,
|
||||
healthTransformValue: healthTransformValue;
|
||||
statusEffectsGranted?: placeholder[]; // TBA (Stuff like burn, slow, stun, etc.)
|
||||
}
|
||||
type entityTransformDeterminer = (
|
||||
|
@ -43,12 +51,13 @@ interface ability {
|
|||
// Immunities are just status effects that take the place of a damaging status effect (so ones of that type can't be added) but don't do anything
|
||||
// Status effects have a strength value that determines whether they can override another status effect of the same type (holy inferno can replace burn but burn can't replace holy inferno)
|
||||
|
||||
export interface entityController {//Deprecated
|
||||
export interface entityController {
|
||||
//Deprecated
|
||||
setPosition: (location: Vector3) => void;
|
||||
useAbility: (abilityName: string, activating: boolean) => void;
|
||||
}
|
||||
|
||||
export interface entityModifier {}// Deprecated
|
||||
export interface entityModifier {} // Deprecated
|
||||
/* Prototype
|
||||
entityTransform(setOfAllEntities: entity[], actingEntity: entity, ability destructured to {hitBoxList, modificationList})
|
||||
const entitiesEligible = getAffectedEntities(setOfAllEntities, actingEntity)
|
||||
|
@ -101,7 +110,7 @@ export interface entityModifier {}// Deprecated
|
|||
return [onSameTeam]
|
||||
}*/
|
||||
|
||||
/*function applyAttackToEntityStats() {//else if (transformType === "heal") {
|
||||
/*function applyAttackToEntityStats() {//else if (transformType === "heal") {
|
||||
// Apply receiver's status effects to incoming heal
|
||||
const newEntityStatuses = applyHealToStatuses(
|
||||
entityStats.statuses, // DRY alert
|
||||
|
@ -124,10 +133,15 @@ function applyAttackToEntityStatuses(
|
|||
): statuses {
|
||||
// + Apply status effects of receiving entity to damage (e.g. armor break)
|
||||
const modifiedDamage = applyModifiersToDamage(entityTransformTemplate.magnitude, entityModifiers);
|
||||
const newStatuses = applyDamageToStatuses(entityStatuses, modifiedDamage, entityTransformTemplate.affectsHealth, entityTransformTemplate.affectsBarrier);
|
||||
const newStatuses = applyDamageToStatuses(
|
||||
entityStatuses,
|
||||
modifiedDamage,
|
||||
entityTransformTemplate.affectsHealth,
|
||||
entityTransformTemplate.affectsBarrier,
|
||||
);
|
||||
return entityStatuses;
|
||||
}
|
||||
/*function applyHealToEntityStats() {//if (transformType === "attack") {
|
||||
/*function applyHealToEntityStats() {//if (transformType === "attack") {
|
||||
// Apply receiver's status effects to incoming damage
|
||||
const incomingDamage = applyModifiersToDamage(magnitude, baseModifiers);
|
||||
const newEntityStatuses = applyDamageToStatuses(
|
||||
|
@ -150,7 +164,13 @@ function applyHealToEntityStatuses(
|
|||
entityStatusEffects: statusEffect[],
|
||||
): statuses {
|
||||
// + Apply status effects of receiving entity to damage (e.g. heal up)
|
||||
const newStatuses = applyHealToStatuses(entityStatuses, entityTransformTemplate.magnitude, entityTransformTemplate.affectsHealth, entityTransformTemplate.affectsBarrier, entityMaxStatuses);
|
||||
const newStatuses = applyHealToStatuses(
|
||||
entityStatuses,
|
||||
entityTransformTemplate.magnitude,
|
||||
entityTransformTemplate.affectsHealth,
|
||||
entityTransformTemplate.affectsBarrier,
|
||||
entityMaxStatuses,
|
||||
);
|
||||
return entityStatuses;
|
||||
}
|
||||
// ? Are you meant to pipe determineEntityTransform into the resulting function?
|
||||
|
@ -178,7 +198,7 @@ function applyEntityToHeal(
|
|||
entityTransformTemplate: entityTransformTemplate,
|
||||
): entityTransformTemplate {
|
||||
// + Apply user's status effects to outgoing heal
|
||||
return entityTransformTemplate // There could be a heal modifier later
|
||||
return entityTransformTemplate; // There could be a heal modifier later
|
||||
}
|
||||
/*function transformEntityStats(
|
||||
entityStats: entityStats,
|
||||
|
@ -307,17 +327,19 @@ function getEntityByName(entityList: entity[], entityName: string): success<enti
|
|||
return [false, "Entity not found"];
|
||||
}
|
||||
function getAbility() {}
|
||||
function applyEntityTransformToEntityStatuses(entityTransform: entityTransformTemplate, statuses: statuses, maxStatuses: statuses) {
|
||||
|
||||
}
|
||||
function applyEntityTransformToEntityStatuses(
|
||||
entityTransform: entityTransformTemplate,
|
||||
statuses: statuses,
|
||||
maxStatuses: statuses,
|
||||
) {}
|
||||
function applyEntityTransformToEntityList(
|
||||
entityList: entity[],
|
||||
entityTransformDeterminer: entityTransformDeterminer,
|
||||
entityPerformingTransform: entity,
|
||||
aim: Vector3,
|
||||
): [entity[], placeholder[]?] {
|
||||
const entityPerformingTransformModifiers = entityPerformingTransform.baseModifiers
|
||||
const entityPerformingTransformStatusEffects = entityPerformingTransform.stats.statusEffects // Not good
|
||||
const entityPerformingTransformModifiers = entityPerformingTransform.baseModifiers;
|
||||
const entityPerformingTransformStatusEffects = entityPerformingTransform.stats.statusEffects; // Not good
|
||||
const newEntityList = entityList.map(function (entityReceivingTransform: entity): entity {
|
||||
const entityTransform = entityTransformDeterminer(
|
||||
entityPerformingTransform.id,
|
||||
|
@ -326,13 +348,13 @@ function applyEntityTransformToEntityList(
|
|||
entityReceivingTransform.puppet,
|
||||
);
|
||||
if (entityTransform) {
|
||||
const entityStatuses = entityPerformingTransform.stats.statuses
|
||||
const [entityTransformType, entityTransformTemplate] = entityTransform
|
||||
const entityStatuses = entityPerformingTransform.stats.statuses;
|
||||
const [entityTransformType, entityTransformTemplate] = entityTransform;
|
||||
if (entityTransformType === "attack") {
|
||||
const outgoingTransformTemplate = applyEntityToAttack(
|
||||
entityPerformingTransformModifiers,
|
||||
entityPerformingTransformStatusEffects,
|
||||
entityTransformTemplate
|
||||
entityPerformingTransformModifiers,
|
||||
entityPerformingTransformStatusEffects,
|
||||
entityTransformTemplate,
|
||||
);
|
||||
const newEntityStatuses = outgoingTransformTemplate
|
||||
? applyAttackToEntityStatuses(
|
||||
|
@ -343,11 +365,12 @@ function applyEntityTransformToEntityList(
|
|||
)
|
||||
: entityStatuses; // Also cringe
|
||||
} else {
|
||||
assert(entityTransformType === "heal")
|
||||
const outgoingTransformTemplate = applyEntityToHeal( // Lots of DRY violations here
|
||||
entityPerformingTransformModifiers,
|
||||
entityPerformingTransformStatusEffects,
|
||||
entityTransformTemplate
|
||||
assert(entityTransformType === "heal");
|
||||
const outgoingTransformTemplate = applyEntityToHeal(
|
||||
// Lots of DRY violations here
|
||||
entityPerformingTransformModifiers,
|
||||
entityPerformingTransformStatusEffects,
|
||||
entityTransformTemplate,
|
||||
);
|
||||
const newEntityStatuses = outgoingTransformTemplate
|
||||
? applyHealToEntityStatuses(
|
||||
|
@ -357,7 +380,7 @@ function applyEntityTransformToEntityList(
|
|||
entityReceivingTransform.maxStatuses,
|
||||
entityReceivingTransform.stats.statusEffects, // So much cringe
|
||||
)
|
||||
: entityStatuses;
|
||||
: entityStatuses;
|
||||
}
|
||||
} else {
|
||||
return entityReceivingTransform;
|
||||
|
@ -429,4 +452,4 @@ class entityManager extends actorClass<entityManagerRequest> {
|
|||
export function initEntityManager() {
|
||||
return new entityManager();
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
|
|
@ -1,28 +1,37 @@
|
|||
// "The": Handle events.
|
||||
import { entityId, entityProperties, entityStatuses/*entityManagerRequest /*makeEntity, entityController*/ } from "./EntityManager";
|
||||
import { applyRequestsToPlayerStorage, playerManagerRequest } from "./PlayerManager"
|
||||
export type sceneManagerRequest = [Player, "useAbility", Vector3] | [Player, "foo", "bar"]
|
||||
type endConditionFunction = (containedScenes: scene[], containedEntities: entity[], timeElapsed: number) => boolean
|
||||
import { entity } from "./EntityManager";
|
||||
import { applyRequestsToPlayerStorage, playerManagerRequest } from "./PlayerManager";
|
||||
export type sceneManagerRequest = [Player, "useAbility", Vector3] | [Player, "foo", "bar"];
|
||||
type endConditionFunction = (containedEntities: entity[], timeElapsed: number) => boolean;
|
||||
export interface sceneTemplate {
|
||||
readonly sceneComplete: endConditionFunction // Checks conditions that need to pass for the scene to end (e.g. entityX.Alive == false || timeSpent > 1000)
|
||||
readonly onCompletion: readonly playerManagerRequest[] // Requests to get sent out when the scene ends
|
||||
readonly sceneComplete: endConditionFunction; // Checks conditions that need to pass for the scene to end (e.g. entityX.Alive == false || timeSpent > 1000)
|
||||
readonly onCompletion: readonly playerManagerRequest[]; // Requests to get sent out when the scene ends
|
||||
}
|
||||
export interface scene extends sceneTemplate {
|
||||
/*containedScenes?: {
|
||||
export interface scene {
|
||||
entities: entity[];
|
||||
}
|
||||
/*export interface sceneBackstage {
|
||||
readonly entityProperties: {
|
||||
[glumph: string]: entityProperties;
|
||||
}
|
||||
}*/
|
||||
|
||||
// export interface scene extends sceneTemplate {
|
||||
/*containedScenes?: {
|
||||
[sceneName: string]: scene | undefined
|
||||
}; // Scenes within this scene that are isolated from each other and can be run in parallel
|
||||
// Not necessarily "A list of events that need to return true (in sequence) to complete this event", but such events would go there
|
||||
*///Scene nesting is currently cancelled
|
||||
containedEntities: string[]; // "A list of entities that need to die to complete the event" (not really but kinda)
|
||||
containedEntityProperties: {
|
||||
[entityName: string]: entityProperties
|
||||
}
|
||||
containedEntityStatuses
|
||||
players: {
|
||||
[userId: number]: [inThisScene: true] | [inThisScene: false, subScene: string] | undefined
|
||||
}
|
||||
//timeout?: number; // A timeout for the event; passes a lose condition if there are other completion requirements that have not been satisfied
|
||||
}
|
||||
*/ //Scene nesting is currently cancelled
|
||||
// containedEntities: string[]; // "A list of entities that need to die to complete the event" (not really but kinda)
|
||||
// containedEntityProperties: {
|
||||
// [entityName: string]: entityProperties
|
||||
// }
|
||||
// containedEntityStatuses
|
||||
// players: {
|
||||
// [userId: number]: [inThisScene: true] | [inThisScene: false, subScene: string] | undefined
|
||||
// }
|
||||
//timeout?: number; // A timeout for the event; passes a lose condition if there are other completion requirements that have not been satisfied
|
||||
// }
|
||||
export function runScene(scene: scene, now: number): success<[scene, playerManagerRequest[]]> {
|
||||
return [true, [scene, []]];
|
||||
}
|
||||
|
@ -60,19 +69,22 @@ function applyRequestToScene(scene: scene, now: number, request: sceneManagerReq
|
|||
return [scene, sceneRequestResult[1]]
|
||||
}*/
|
||||
}
|
||||
export function applyRequestsToScene(scene: scene, now: number, requests: sceneManagerRequest[]): success<[scene, playerManagerRequest[]]> {
|
||||
export function applyRequestsToScene(
|
||||
scene: scene,
|
||||
now: number,
|
||||
requests: sceneManagerRequest[],
|
||||
): success<[scene, playerManagerRequest[]]> {
|
||||
try {
|
||||
let newScene: scene = scene
|
||||
let outgoingRequests: playerManagerRequest[] = []
|
||||
requests.forEach(function(request: sceneManagerRequest) {
|
||||
let newScene: scene = scene;
|
||||
let outgoingRequests: playerManagerRequest[] = [];
|
||||
requests.forEach(function (request: sceneManagerRequest) {
|
||||
const sceneRequestResult = applyRequestToScene(newScene, now, request);
|
||||
newScene = sceneRequestResult[0]
|
||||
outgoingRequests = [...outgoingRequests, ...sceneRequestResult[1]]
|
||||
})
|
||||
newScene = sceneRequestResult[0];
|
||||
outgoingRequests = [...outgoingRequests, ...sceneRequestResult[1]];
|
||||
});
|
||||
return [true, [newScene, outgoingRequests]];
|
||||
}
|
||||
catch(error) {
|
||||
return [false, error]
|
||||
} catch (error) {
|
||||
return [false, error];
|
||||
}
|
||||
}
|
||||
export function initScene(sceneTemplate: sceneTemplate): scene {
|
||||
|
@ -80,8 +92,8 @@ export function initScene(sceneTemplate: sceneTemplate): scene {
|
|||
const newScene: scene = {
|
||||
containedEntities: [],
|
||||
players: [],
|
||||
sceneComplete: sceneTemplate.sceneComplete,
|
||||
sceneComplete: sceneTemplate.sceneComplete,
|
||||
onCompletion: sceneTemplate.onCompletion,
|
||||
}
|
||||
};
|
||||
return newScene;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue