Further progress with Entity Manager

~ Made some changes to try to make it compile (doesn't compile yet)
This commit is contained in:
loplkc loplkc 2022-05-27 18:57:52 -04:00
parent 052a37b36f
commit 894def692c
4 changed files with 965 additions and 209 deletions

View file

@ -8,8 +8,11 @@
"$className": "DataModel",
"ServerScriptService": {
"$className": "ServerScriptService",
"TS": {
"Server": {
"$path": "out/server"
},
"Game": {
"$path": "out/game"
}
},
"StarterPlayer": {

861
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -21,5 +21,8 @@
"eslint-plugin-roblox-ts": "^0.0.31",
"prettier": "^2.3.2",
"typescript": "^4.4.2"
},
"dependencies": {
"roblox-ts": "^1.3.3"
}
}

View file

@ -3,9 +3,9 @@
import { makePuppet, puppet, puppetEntry } from "./Puppetmaster";
// import { ability } from "./AbilityManager";
// I spent a lot of time thinking about the names for these types and they still suck
type modifiers = readonly [[maxHealth: number, defense: number], [power: number, speed: number, resistance: number]]; // values used for calculation, only modified by buffs and debuffs (the first group is additive, the second multiplicative)
type modifiers = readonly [power: number, speed: number, defense: number, resistance: number]; // values used for calculation, only modified by buffs and debuffs (the first group is additive, the second multiplicative)
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, (entity: entity) => entity];
type statusEffect = readonly [string, modifiers, entityTransformTemplate, number];
export interface entityController {
setPosition: (location: Vector3) => void;
@ -32,27 +32,27 @@ export interface entityModifier {}
return resultOfFirstAbilityPart = ableToUse ? useAbilityPart(ability.firstPart, setOfAllEntities, thisEntity) : [ableToUse]
*/
interface entityStats {
statuses: statuses // Health and stuff that change constantly
baseModifiers: modifiers // Base modifiers that change only when the player switches weapons or something
immunities: {
[statusEffectName: string]: boolean | undefined
}
statusEffects: statusEffect[] // Burn, poison, etc.
statuses: statuses; // Health and stuff that change constantly
/* immunities: {
[statusEffectName: string]: boolean | undefined;
};*/
statusEffects: statusEffect[]; // Burn, poison, etc.
}
interface entityId {
readonly name: string
readonly team: "players" | "enemies",
readonly isMinion: boolean
readonly name: string;
readonly team: "players" | "enemies";
readonly isMinion: boolean;
}
export interface entity {
readonly id: entityId
stats: entityStats
puppet: puppet
readonly id: entityId;
stats: entityStats;
baseModifiers: modifiers; // Base modifiers that change only when the player switches weapons or something
maxStatuses: statuses;
puppet: puppet;
}
type entityTransform = (entity: entity) => entity
// type entityTransform = (entity: entity) => entity;
// interface entityTransformTemplate {
type abuiloga = (entityPerformingId: entityId, entityReceivingId: entityId) => entityTransformTemplate | false
/*
allies: {
minions: {
@ -64,15 +64,23 @@ type abuiloga = (entityPerformingId: entityId, entityReceivingId: entityId) => e
affectsMinions: boolean,
excludesSelf: boolean,
affectsSameTeam: boolean,
*///}
type entityTransformType = "heal" | "attack"
*/ //}
type entityTransformType = "heal" | "attack";
interface entityTransformTemplate {
extraFunction: (entityPerformingTransform: entity, entityReceivingTransform: entity) => boolean
thingus: entityTransformType
magnitude: number, // Positive for heal, negative for damage
affectsHealth: boolean
affectsBarrier: boolean
statusEffectsGranted: placeholder[], // Stuff like burn, slow, stun, etc.*/
thingus: entityTransformType;
magnitude: number;
affectsHealth: boolean;
affectsBarrier: boolean;
statusEffectsGranted?: placeholder[]; // TBA (Stuff like burn, slow, stun, etc.)
}
type entityTransformDeterminer = (
entityPerformingId: entityId,
entityReceivingId: entityId,
entityPerformingPuppet: puppet,
entityReceivingPuppet: puppet,
) => entityTransformTemplate | false;
interface ability {
placeholder: entityTransformDeterminer; // TBA (Most abilities will not be a single instant of damage/heal)
}
// type entityTransformTemplate = [entityTransformEligibilityTemplate, entityTransformApplicationTemplate]
/*function isEligibleForTransform(entityPerformingTransform: entity, entityReceivingTransform: entity, eligibilityTemplate: entityTransformEligibilityTemplate): false | [boolean] { // This function sucks
@ -92,31 +100,82 @@ interface entityTransformTemplate {
}
return [onSameTeam]
}*/
function applyEntityToAttack(entityModifiers: modifiers, entityStatusEffects: statusEffect[], magnitude: number): number {
function applyEntityToAttack(
entityModifiers: modifiers,
entityStatusEffects: statusEffect[],
magnitude: number,
): number {
const attack = applyModifiersToAttack(magnitude, entityModifiers);
// + Apply status effects of performing entity to attack (e.g. weaken)
return attack
return attack;
}
function applyAttackToEntityStatuses(entityStatuses: statuses, entityModifiers: modifiers, entityStatusEffects: statusEffect[], attack: number, affectsHealth: boolean, affectsBarrier: boolean): statuses { // Not sure if this should return a whole entity
function applyAttackToEntityStatuses(
entityStatuses: statuses,
entityModifiers: modifiers,
entityStatusEffects: statusEffect[],
attack: number,
affectsHealth: boolean,
affectsBarrier: boolean,
): statuses {
// Not sure if this should return a whole entity
// + Apply status effects of receiving entity to damage (e.g. armor break)
const damage = applyModifiersToAttack(attack, entityModifiers);
const newStatuses = applyDamageToStatuses(entityStatuses, damage, affectsHealth, affectsBarrier);
return entityStatuses
return entityStatuses;
}
function makeEntityTransform(entityPerformingTransformId: entityId, abuiloga: abuiloga): (entityReceivingTransform: entity) => entityStats {
return function(entityReceivingTransform: entity): entityStats {
const entityTransformTemplate = abuiloga(entityPerformingTransformId, entityReceivingTransform.id);
const newStats = transformEntityStatuses( // All of this stuff should be packed into one object, maybe a new entityTransformTemplate
entityReceivingTransform.stats.statuses,
finalCalculatedMaxHealth,
finalCalculatedMaxBarrier,
entityTransformTemplate.thingus,
finalCalculatedMagnitude,
finalCalculatedAffectsHealth,
finalCalculatedAffectsBarrier) // L
// const newEntity = entityTransformTemplate ? applyEntityTransform(entityPerformingTransform, entityReceivingTransform, onSameTeam, template[1]) : entityReceivingTransform;
return newStats
// ? Are you meant to pipe determineEntityTransform into the resulting function?
/*function determineEntityTransform(
entityPerformingTransformId: entityId,
entityReceivingTransform: entityId,
): entityTransformTemplate | false {
return false; // Placeholder
}
*/
function transformEntityStats(
entityPerformingTransform: entity,
entityStats: entityStats,
entityTransformTemplate: entityTransformTemplate,
baseModifiers: modifiers,
maxStatuses: statuses,
): entityStats {
const transformType = entityTransformTemplate.thingus;
if (transformType === "attack") {
const outgoingAttack = applyModifiersToAttack(
entityTransformTemplate.magnitude,
entityPerformingTransform.baseModifiers,
);
// Apply user's status effects to outgoing attack
// Apply receiver's status effects to incoming damage
const incomingDamage = applyModifiersToDamage(outgoingAttack, baseModifiers);
const newEntityStatuses = applyDamageToStatuses(
entityStats.statuses,
incomingDamage,
entityTransformTemplate.affectsHealth,
entityTransformTemplate.affectsBarrier,
);
// Add or remove status effects
return {
statuses: newEntityStatuses,
statusEffects: entityStats.statusEffects, // Placeholder
};
} else if (transformType === "heal") {
const outgoingHeal = entityTransformTemplate.magnitude; // There could be a heal modifier later
// Apply user's status effects to outgoing heal
// Apply receiver's status effects to incoming heal
const newEntityStatuses = applyHealToStatuses(
entityStats.statuses, // DRY alert
outgoingHeal,
entityTransformTemplate.affectsHealth,
entityTransformTemplate.affectsBarrier,
maxStatuses,
);
// Add or remove status effects
return {
statuses: newEntityStatuses,
statusEffects: entityStats.statusEffects, // Placeholder
};
} else {
throw "Unknown entity transform type " + transformType; // Should be never
}
}
/*interface entityTransform extends entityTransformTemplate {
@ -124,8 +183,8 @@ function makeEntityTransform(entityPerformingTransformId: entityId, abuiloga: ab
team: "players" | "enemies",
}*/
type abilityTemplate = [
[entityTransformTemplate[], number] // I guess the number is a delay until the next part or something
]
[entityTransformTemplate[], number], // I guess the number is a delay until the next part or something
];
/*type ability = [
[entityTransform[], number]
]*/
@ -133,95 +192,135 @@ type abilityTemplate = [
// const ability = getAbility
// const entities = applyAbilityToScene(scene, ability)
function applyDamageToHealth(health: number, damage: number): [newHealth: number, excessDamage: number] { // Needs testing
const newHealth = health - damage
function applyDamageToHealth(health: number, damage: number): [newHealth: number, excessDamage: number] {
// Needs testing
const newHealth = health - damage;
if (newHealth < 0) {
return [0, -newHealth]
return [0, -newHealth];
} else {
return [newHealth, 0]
return [newHealth, 0];
}
}
const applyDamageToBarrier = applyDamageToHealth
function applyDamageToStatuses(statuses: statuses, damage: number, affectsHealth: boolean, affectsBarrier: boolean): statuses {
const applyDamageToBarrier = applyDamageToHealth;
function applyDamageToStatuses(
statuses: statuses,
damage: number,
affectsHealth: boolean,
affectsBarrier: boolean,
): statuses {
if (affectsBarrier) {
const [newBarrier, excessBarrierDamage] = applyDamageToBarrier(statuses[1], damage)
const [newHealth, excessHealthDamage] = applyDamageToHealth(statuses[0], affectsHealth? excessBarrierDamage : 0)
return [newHealth, newBarrier]
const [newBarrier, excessBarrierDamage] = applyDamageToBarrier(statuses[1], damage);
const [newHealth, excessHealthDamage] = applyDamageToHealth(
statuses[0],
affectsHealth ? excessBarrierDamage : 0,
);
return [newHealth, newBarrier];
} else if (affectsHealth) {
const [newHealth, excessHealthDamage] = applyDamageToHealth(statuses[0], damage)
return [newHealth, statuses[1]]
const [newHealth, excessHealthDamage] = applyDamageToHealth(statuses[0], damage);
return [newHealth, statuses[1]];
} else {
return statuses
return statuses;
}
}
function applyHealToHealth(currentHealth: number, heal: number, maxHealth: number): [newHealth: number, excessHeal: number] {
const newHealth = currentHealth + heal
function applyHealToHealth(
currentHealth: number,
heal: number,
maxHealth: number,
): [newHealth: number, excessHeal: number] {
const newHealth = currentHealth + heal;
if (newHealth > maxHealth) {
return [maxHealth, newHealth - maxHealth]
return [maxHealth, newHealth - maxHealth];
} else {
return [newHealth, 0]
return [newHealth, 0];
}
}
const applyHealToBarrier = applyHealToHealth
function applyHealToStatuses(statuses: statuses, heal: number, maxHealth: number, maxBarrier: number, affectsHealth: boolean, affectsBarrier: boolean): statuses {
const applyHealToBarrier = applyHealToHealth;
function applyHealToStatuses(
statuses: statuses,
heal: number,
affectsHealth: boolean,
affectsBarrier: boolean,
maxStatuses: statuses,
): statuses {
if (affectsHealth) {
const [newHealth, excessHealth] = applyHealToHealth(statuses[0], heal, maxHealth)
const [newBarrier, excessBarrier] = applyHealToBarrier(statuses[1], affectsBarrier ? excessHealth : 0, maxBarrier)
return [newHealth, newBarrier]
} else if (affectsBarrier) { // Using a branch isn't optimal, but as of writing I can't think of a better solution
const [newBarrier, excessBarrier] = applyHealToBarrier(statuses[1], heal, maxBarrier)
return [statuses[0], newBarrier]
const [newHealth, excessHealth] = applyHealToHealth(statuses[0], heal, maxStatuses[0]);
const [newBarrier, excessBarrier] = applyHealToBarrier(
statuses[1],
affectsBarrier ? excessHealth : 0,
maxStatuses[1],
);
return [newHealth, newBarrier];
} else if (affectsBarrier) {
// Using a branch isn't optimal, but as of writing I can't think of a better solution
const [newBarrier, excessBarrier] = applyHealToBarrier(statuses[1], heal, maxStatuses[1]);
return [statuses[0], newBarrier];
} else {
return statuses
return statuses;
}
}
function transformEntityStatuses(entityStatuses: statuses, maxHealth: number, maxBarrier: number, transformType: string, magnitude: number, affectsHealth: boolean, affectsBarrier: boolean): statuses {
if (transformType == "heal") {
const newStatuses = applyHealToStatuses(entityStatuses, magnitude, maxHealth, maxBarrier, affectsHealth, affectsBarrier) // More chaining method calls...
return newStatuses
} else if (transformType == "attack") {
const newStatuses = applyDamageToStatuses(entityStatuses, magnitude, affectsHealth, affectsBarrier)
return newStatuses
} else {
throw "Unimplemented transformType " + transformType
}
}// Damage should come before status effects are applied
function applyPowerToAttack(attack: number, power: number) {
return attack*power
return attack * power;
}
function applyModifiersToAttack(attack: number, modifiers: modifiers): number { // Get arguments they use (a bit sketchy)
return applyPowerToAttack(attack, modifiers[1][0])
function applyModifiersToAttack(attack: number, modifiers: modifiers): number {
// Get arguments they use (a bit sketchy)
return applyPowerToAttack(attack, modifiers[0]);
}
function applyResistanceToDamage(damage: number, resistance: number): number {
return damage*(1 - resistance)
return damage * (1 - resistance);
}
function applyDefenseToDamage(damage: number, defense: number): number {
return damage - defense
return damage - defense;
}
function applyModifiersToDamage(damage: number, modifiers: modifiers): number {
return applyResistanceToDamage(applyDefenseToDamage(damage, modifiers[0][1]), modifiers[1][2])
return applyResistanceToDamage(applyDefenseToDamage(damage, modifiers[2]), modifiers[3]);
}
function modifiersArrayFunction(applyModifiersToNumber: (number: number, modifiers: modifiers) => number): (number: number, modifiers: modifiers[]) => number {
return function(number: number, modifiersArray: modifiers[]) {
let newNumber = number
modifiersArray.forEach(function(modifiers: modifiers) {
newNumber = applyModifiersToNumber(newNumber, modifiers)
})
return newNumber
}
function modifiersArrayFunction(
applyModifiersToNumber: (number: number, modifiers: modifiers) => number,
): (number: number, modifiers: modifiers[]) => number {
return function (number: number, modifiersArray: modifiers[]) {
let newNumber = number;
modifiersArray.forEach(function (modifiers: modifiers) {
newNumber = applyModifiersToNumber(newNumber, modifiers);
});
return newNumber;
};
}
const applyModifiersArrayToAttack = modifiersArrayFunction(applyModifiersToAttack);
const applyModifiersArrayToDamage = modifiersArrayFunction(applyModifiersToDamage);
function getEntityByName(entityList: entity[], entityName: string): success<entity> {
entityList.forEach(function(entity: entity) {
if (entity.id.name == entityName) { // Chained method calls are cringe
return [true, entity]
entityList.forEach(function (entity: entity) {
if (entity.id.name === entityName) {
// Chained method calls are cringe
return [true, entity];
}
})
return [false, "Entity not found"]
});
return [false, "Entity not found"];
}
function getAbility() {}
function useAbility(entityList: entity[], entityUsing: entity, aim: Vector3): [entity[], placeholder[]] {
function applyEntityTransformToEntityList(
entityList: entity[],
entityTransformDeterminer: entityTransformDeterminer,
entityPerformingTransform: entity,
aim: Vector3,
): [entity[], placeholder[]?] {
const newEntityList = entityList.map(function (entityReceivingTransform: entity): entity {
const entityTransformTemplate = entityTransformDeterminer(
entityPerformingTransform.id,
entityReceivingTransform.id,
entityPerformingTransform.puppet,
entityReceivingTransform.puppet,
);
const newEntityStats = entityTransformTemplate
? transformEntityStats(
entityPerformingTransform,
entityReceivingTransform.stats,
entityTransformTemplate,
entityReceivingTransform.baseModifiers,
entityReceivingTransform.maxStatuses,
)
: entityReceivingTransform.stats;
});
return [newEntityList];
}
/*class entityHandler implements entityController {
constructor(baseStats: stats, baseAmounts: amounts, puppetEntry: puppetEntry) {