From 0d648cc873fcb4bcb26e4f56a22db7ab27fe97be Mon Sep 17 00:00:00 2001 From: Thaum Date: Mon, 17 Nov 2014 13:48:46 +0000 Subject: [PATCH] Changed how effects are applied and removed to enable effects expiring after a set duration. --- rpg-docs/Model/Character/Characters.js | 97 ++++++++----------- .../Model/Character/SubSchemas/Attributes.js | 2 +- .../Model/Character/SubSchemas/Effect/Buff.js | 7 +- .../Character/SubSchemas/Effect/Effect.js | 14 +-- .../Model/Character/SubSchemas/Expiration.js | 12 +++ .../Model/Character/SubSchemas/Features.js | 3 +- .../Character/SubSchemas/Vulnerabilities.js | 4 +- rpg-docs/client/views/home/home.html | 1 - rpg-docs/lib/functions/buffsToCharacter.js | 39 +++++++- rpg-docs/lib/functions/characterUtility.js | 7 ++ rpg-docs/lib/functions/pop.js | 2 +- 11 files changed, 103 insertions(+), 85 deletions(-) create mode 100644 rpg-docs/Model/Character/SubSchemas/Expiration.js create mode 100644 rpg-docs/lib/functions/characterUtility.js diff --git a/rpg-docs/Model/Character/Characters.js b/rpg-docs/Model/Character/Characters.js index df8272ce..b10e2c0e 100644 --- a/rpg-docs/Model/Character/Characters.js +++ b/rpg-docs/Model/Character/Characters.js @@ -9,31 +9,26 @@ Schemas.Character = new SimpleSchema({ proficiencies: { type: Schemas.Proficiencies }, features: { type: [Schemas.Feature]}, time: { type: Number, min: 0, decimal: true}, - initiativeOrder:{ type: Number, min: 0, max: 1, decimal: true} + initiativeOrder:{ type: Number, min: 0, max: 1, decimal: true}, + expirations: { type: [Schemas.Expiration]} //TODO add permission stuff for owner, readers and writers //TODO hit dice + //TODO spells }); Characters.attachSchema(Schemas.Character); -//react to time changing -Characters.find({fields: {time: 1}}).observeChanges({ - changed: function(id, fields){ - var currentTime = fields.time; - console.log(id + "time changed to " + currentTime) - var features = Characters.findOne(id, { fields: {features: 1} }).features; - _.each(features, function(feature){ - //expired features, if no expiry time is set, this is always false - if(feature.expires >= currentTime){ - //remove buffs - pullBuffs(id, feature.buffs); - //disable feature - Characters.update( - {_id: id, "features._id": feature.id}, - {$set: {"features.$.enabled": false}} - ); +//reactively remove expired effects +//this can be optimised a lot once clients can do projections +Characters.find({},{fields: {time: 1, expirations: 1}}).observe({ + changed: function(character, oldCharacter){ + var currentTime = character.time; + _.each(character.expirations, function(expiration){ + if(expiration.expiry <= currentTime){ + pullEffect(character._id, expiration.stat, expiration.effectId); + pullExpiry(character._id, expiration._id); } - }); + }) } }); @@ -45,28 +40,26 @@ Characters.helpers({ var value = attribute.base; //add all values in add array - for(var i = 0, l = attribute.add.length; i < l; i++){ - var add = pop(attribute.add[i].value, this); - value += add ; - } + _.each(attribute.add, function(effect){ + value += pop(effect.value, this) + }); //multiply all values in mul array - for(var i = 0, l = attribute.mul.length; i < l; i++){ - var mul = pop(attribute.mul[i], this); - value *= mul; - } + _.each(attribute.mul, function(effect){ + value *= pop(effect.value, this) + }); //largest min - for(var i = 0, l = attribute.min.length; i < l; i++){ - var min = pop(attribute.min[i], this); + _.each(attribute.min, function(effect){ + var min = pop(effect.value, this); value = value > min? value : min; - } + }); //smallest max - for(var i = 0, l = attribute.max.length; i < l; i++){ - var max = pop(attribute.max[i], this); + _.each(attribute.max, function(effect){ + var max = pop(effect.value, this); value = value < max? value : max; - } + }); return value; }, @@ -101,26 +94,26 @@ Characters.helpers({ mod += prof * this.attributeValue(this.attributes.proficiencyBonus); //add all values in add array - for(var i = 0, l = skill.add.length; i < l; i++){ - mod += pop(skill.add[i].value, this); - } + _.each(skill.add, function(effect){ + mod += pop(effect.value, this) + }); //multiply all values in mul array - for(var i = 0, l = skill.mul.length; i < l; i++){ - mod *= pop(skill.mul[i].value, this); - } + _.each(skill.mul, function(effect){ + mod *= pop(effect.value, this) + }); //largest min - for(var i = 0, l = skill.min.length; i < l; i++){ - var min = pop(skill.min[i], this); + _.each(skill.min, function(effect){ + var min = pop(effect.value, this); mod = mod > min? mod : min; - } + }); //smallest max - for(var i = 0, l = skill.max.length; i < l; i++){ - var max = pop(skill.max[i], this); + _.each(skill.max, function(effect){ + var max = pop(effect.value, this); mod = mod < max? mod : max; - } + }); return signedString(mod); }, @@ -128,9 +121,9 @@ Characters.helpers({ passiveSkill: function(skill){ var mod = +this.skillMod(skill); var value = 10 + mod; - for(var i = 0, l = skill.passiveAdd.length; i < l; i++){ - value += pop(skill.passiveAdd[i].value, this); - } + _.each(skill.passiveAdd, function(effect){ + value += pop(effect.value, this); + }); return value; //TODO decide whether (dis)advantage gives (-)+5 to passive checks }, @@ -156,12 +149,4 @@ Characters.helpers({ }); return 20; } -}); - -getMod = function(score){ - return Math.floor((score-10)/2); -} - -signedString = function(number){ - return number > 0? "+" + number : "" + number; -} \ No newline at end of file +}); \ No newline at end of file diff --git a/rpg-docs/Model/Character/SubSchemas/Attributes.js b/rpg-docs/Model/Character/SubSchemas/Attributes.js index d2c59b53..d5cd6ecd 100644 --- a/rpg-docs/Model/Character/SubSchemas/Attributes.js +++ b/rpg-docs/Model/Character/SubSchemas/Attributes.js @@ -44,7 +44,7 @@ Schemas.Attributes = new SimpleSchema({ "armor.add": { type: [Schemas.Effect], defaultValue: [ - new Effect("Dexterity Modifier", "skillMod skills.dexterityArmor") + {name: "Dexterity Modifier", value: "skillMod skills.dexterityArmor"} ] } }); \ No newline at end of file diff --git a/rpg-docs/Model/Character/SubSchemas/Effect/Buff.js b/rpg-docs/Model/Character/SubSchemas/Effect/Buff.js index 75c9eb6c..cbe993d0 100644 --- a/rpg-docs/Model/Character/SubSchemas/Effect/Buff.js +++ b/rpg-docs/Model/Character/SubSchemas/Effect/Buff.js @@ -9,9 +9,4 @@ Schemas.Buff = new SimpleSchema({ effect: { type: Schemas.Effect } -}); - -Buff = function(name, stat, value){ - this.stat = stat; - this.effect = new Effect(name, value); -}; \ No newline at end of file +}); \ No newline at end of file diff --git a/rpg-docs/Model/Character/SubSchemas/Effect/Effect.js b/rpg-docs/Model/Character/SubSchemas/Effect/Effect.js index 698a9650..9f68f379 100644 --- a/rpg-docs/Model/Character/SubSchemas/Effect/Effect.js +++ b/rpg-docs/Model/Character/SubSchemas/Effect/Effect.js @@ -7,7 +7,7 @@ Schemas.Effect = new SimpleSchema({ type: String, regEx: SimpleSchema.RegEx.Id, autoValue: function(){ - if(!isSet) return Random.id(); + if(!this.isSet) return Random.id(); } }, name: { @@ -22,14 +22,4 @@ Schemas.Effect = new SimpleSchema({ type: String, optional: true } -}); - -Effect = function(name, value){ - this._id = Random.id(); - this.name = name; - if (typeof value === "string"){ - this.calculation = value; - } else if (typeof valye === "number"){ - this.value = value; - } -}; \ No newline at end of file +}); \ No newline at end of file diff --git a/rpg-docs/Model/Character/SubSchemas/Expiration.js b/rpg-docs/Model/Character/SubSchemas/Expiration.js new file mode 100644 index 00000000..c70714b5 --- /dev/null +++ b/rpg-docs/Model/Character/SubSchemas/Expiration.js @@ -0,0 +1,12 @@ +//schema to store all effects which expire and their expiry dates +Schemas.Expiration = new SimpleSchema({ + _id: { + type: String, + regEx: SimpleSchema.RegEx.Id, + autoValue: function(){ + if(!this.isSet) return Random.id(); + }}, + stat: { type: String }, + effectId: { type: String, regEx: SimpleSchema.RegEx.Id }, + expiry: { type: Number } +}); \ No newline at end of file diff --git a/rpg-docs/Model/Character/SubSchemas/Features.js b/rpg-docs/Model/Character/SubSchemas/Features.js index e6f059d4..8014ff3b 100644 --- a/rpg-docs/Model/Character/SubSchemas/Features.js +++ b/rpg-docs/Model/Character/SubSchemas/Features.js @@ -1,6 +1,5 @@ Schemas.Feature = new SimpleSchema({ _id: {type: String, regEx: SimpleSchema.RegEx.Id}, - character: {type: String, regEx: SimpleSchema.RegEx.Id}, name: {type: String}, description:{type: String}, buffs: {type: [Schemas.Buff], optional: true}, @@ -8,4 +7,4 @@ Schemas.Feature = new SimpleSchema({ expires: {type: Number, optional: true}, duration: {type: Number, optional: true}, uses: {type: Number, min: 0, optional: true}, -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/rpg-docs/Model/Character/SubSchemas/Vulnerabilities.js b/rpg-docs/Model/Character/SubSchemas/Vulnerabilities.js index a4d2f34b..8da04688 100644 --- a/rpg-docs/Model/Character/SubSchemas/Vulnerabilities.js +++ b/rpg-docs/Model/Character/SubSchemas/Vulnerabilities.js @@ -1,9 +1,9 @@ Schemas.Vulnerability = _.extend({ "min.defaultValue": [ - new Effect("Resistance doesn't stack", 0.5) + {name: "Resistance doesn't stack", value: 0.5} ], "max.defaultValue": [ - new Effect("Vulnerability doesn't stack", 2) + {name: "Vulnerability doesn't stack", value: 2} ] }, Schemas.Attribute); diff --git a/rpg-docs/client/views/home/home.html b/rpg-docs/client/views/home/home.html index 5ff2521c..d49b039b 100644 --- a/rpg-docs/client/views/home/home.html +++ b/rpg-docs/client/views/home/home.html @@ -6,5 +6,4 @@ {{/each}} - {{> quickForm collection="Characters" id="insertCharacterForm" type="insert"}} \ No newline at end of file diff --git a/rpg-docs/lib/functions/buffsToCharacter.js b/rpg-docs/lib/functions/buffsToCharacter.js index f3bc785d..0d7ecd0c 100644 --- a/rpg-docs/lib/functions/buffsToCharacter.js +++ b/rpg-docs/lib/functions/buffsToCharacter.js @@ -1,11 +1,42 @@ -pushBuffs = function(id, buffArray){ +//give a character a set of buffs that expire after [duration] +pushBuffs = function(id, buffArray, duration){ _.each(buffArray, function(buff){ - Characters.update(id, {$push: {"buff.stat": buff.effect}}); + var pushObject = {}; + if(duration > 0){ + //expiry time is now plus duration + var expiry = Characters.findOne(id, {fields: {time: 1}}).time + duration; + //ensure the effect has an id + buff.effect._id = buff.effect._id || Random.id(); + //build the expiration object + var expiration = { + stat: buff.stat, + effectId: buff.effect._id, + expiry: expiry + }; + //push expiration object to character + Characters.update(id, {$push: {expirations: expiration } }); + } + //push the effect to the character + pushObject[buff.stat] = buff.effect; + Characters.update(id, {$push: pushObject}); }); }; +//pull all the buffs listed in the buffArray pullBuffs = function(id, buffArray){ _.each(buffArray, function(buff){ - Characters.update(id, {$pull: {"buff.stat": {_id: buff.effect._id} } }); + pullEffect(id, buff.effect._id); }); -}; \ No newline at end of file +}; + +//pull a single effect by stat and id +pullEffect = function(id, stat, effectId){ + var pullObject = {}; + pullObject[stat] = {_id: effectId}; + Characters.update(id, {$pull: pullObject }); +} + +//pull an expiry by id +pullExpiry = function(id, expiryId){ + Characters.update(id, {$pull: {expirations: {_id: expiryId} } }); +} \ No newline at end of file diff --git a/rpg-docs/lib/functions/characterUtility.js b/rpg-docs/lib/functions/characterUtility.js new file mode 100644 index 00000000..093c38f3 --- /dev/null +++ b/rpg-docs/lib/functions/characterUtility.js @@ -0,0 +1,7 @@ +getMod = function(score){ + return Math.floor((score-10)/2); +} + +signedString = function(number){ + return number > 0? "+" + number : "" + number; +} \ No newline at end of file diff --git a/rpg-docs/lib/functions/pop.js b/rpg-docs/lib/functions/pop.js index be35f736..3bd145fb 100644 --- a/rpg-docs/lib/functions/pop.js +++ b/rpg-docs/lib/functions/pop.js @@ -1,6 +1,6 @@ // turns dot notation strings into keys of root // argument formats: -// 157, anything -> 157 +// 157, object -> 157 // "some.number", object -> object.some.number // "some.function", object -> object.some.function() // "some.function arg1 arg2", object -> object.some.function(arg1, arg2)