1
0
Fork 0

Added damage evasion

This commit is contained in:
Michaël Lemaire 2018-03-26 17:30:43 +02:00
parent 11c38fb657
commit 37bb85e773
37 changed files with 217 additions and 3121 deletions

View File

@ -55,7 +55,7 @@ Battle
Ships models and actions
------------------------
* Replace maneuvrability and precision, with evasion (damage avoidance) and movement (for main engine action, km/power)
* Add movement attribute (for main engine action, km/power)
* Add vigilance system, to watch if another ship enters a given radius, to be able to interrupt its turn
* Remove safety margin for move actions (vigilance system should replace it)
* Add damage over time effect (tricky to make intuitive)

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

17
docs/balancing.md Normal file
View File

@ -0,0 +1,17 @@
# Balancing notes
## Constant
* Initiative = 0-3
## Level 1
* Mean HP = 5
* Mean damage = 3
* Power = move half arena + one action
## Level 10
* Mean HP = 15
* Mean damage = 6
* Power = move across arena + two actions (or one action and move again)

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 376 KiB

After

Width:  |  Height:  |  Size: 248 KiB

View File

@ -5,15 +5,15 @@ module TK.SpaceTac {
var fleet2 = new Fleet();
var ship1 = new Ship(fleet1, "F1S1");
TestTools.setAttribute(ship1, "maneuvrability", 2);
TestTools.setAttribute(ship1, "initiative", 2);
var ship2 = new Ship(fleet1, "F1S2");
TestTools.setAttribute(ship2, "maneuvrability", 4);
TestTools.setAttribute(ship2, "initiative", 4);
var ship3 = new Ship(fleet1, "F1S3");
TestTools.setAttribute(ship3, "maneuvrability", 1);
TestTools.setAttribute(ship3, "initiative", 1);
var ship4 = new Ship(fleet2, "F2S1");
TestTools.setAttribute(ship4, "maneuvrability", 8);
TestTools.setAttribute(ship4, "initiative", 8);
var ship5 = new Ship(fleet2, "F2S2");
TestTools.setAttribute(ship5, "maneuvrability", 2);
TestTools.setAttribute(ship5, "initiative", 2);
var battle = new Battle(fleet1, fleet2);
check.equals(battle.play_order.length, 0);
@ -76,7 +76,7 @@ module TK.SpaceTac {
check.equals(battle.playing_ship, null);
// Force play order
iforeach(battle.iships(), ship => TestTools.setAttribute(ship, "maneuvrability", 1));
iforeach(battle.iships(), ship => TestTools.setAttribute(ship, "initiative", 1));
var gen = new SkewedRandomGenerator([0.1, 0.2, 0.0]);
battle.throwInitiative(gen);
check.equals(battle.playing_ship, null);
@ -298,13 +298,13 @@ module TK.SpaceTac {
check.equals(imaterialize(battle.iAreaEffects(100, 50)), [drone1.effects[0]], "drone effects");
let eq1 = new ToggleAction("eq1", { power: 0, radius: 500, effects: [new AttributeEffect("maneuvrability", 1)] });
let eq1 = new ToggleAction("eq1", { power: 0, radius: 500, effects: [new AttributeEffect("initiative", 1)] });
ship.actions.addCustom(eq1);
ship.actions.toggle(eq1, true);
let eq2 = new ToggleAction("eq2", { power: 0, radius: 500, effects: [new AttributeEffect("maneuvrability", 2)] });
let eq2 = new ToggleAction("eq2", { power: 0, radius: 500, effects: [new AttributeEffect("initiative", 2)] });
ship.actions.addCustom(eq2);
ship.actions.toggle(eq2, false);
let eq3 = new ToggleAction("eq3", { power: 0, radius: 100, effects: [new AttributeEffect("maneuvrability", 3)] });
let eq3 = new ToggleAction("eq3", { power: 0, radius: 100, effects: [new AttributeEffect("initiative", 3)] });
ship.actions.addCustom(eq3);
ship.actions.toggle(eq3, true);

View File

@ -6,7 +6,7 @@ module TK.SpaceTac {
let battle = TestTools.createBattle();
let ship = nn(battle.playing_ship);
TestTools.setShipModel(ship, 100, 0, 10);
let weapon = new DeployDroneAction("testdrone", { power: 2 }, { deploy_distance: 300, drone_radius: 30, drone_effects: [new AttributeEffect("precision", 15)] });
let weapon = new DeployDroneAction("testdrone", { power: 2 }, { deploy_distance: 300, drone_radius: 30, drone_effects: [new AttributeEffect("evasion", 15)] });
ship.actions.addCustom(weapon);
let engine = TestTools.addEngine(ship, 1000);
@ -56,9 +56,9 @@ module TK.SpaceTac {
drone.effects = [
new DamageEffect(5),
new AttributeEffect("precision", 1)
new AttributeEffect("evasion", 1)
]
check.equals(drone.getDescription(), "While deployed:\n• do 5 damage\n• precision +1");
check.equals(drone.getDescription(), "While deployed:\n• do 5 damage\n• evasion +1");
});
});
}

View File

@ -138,32 +138,32 @@ module TK.SpaceTac.Specs {
let ship = new Ship();
check.equals(imaterialize(ship.ieffects()), []);
let effect1 = new AttributeEffect("precision", 4);
let effect1 = new AttributeEffect("evasion", 4);
check.patch(ship.model, "getEffects", () => [effect1]);
check.equals(imaterialize(ship.ieffects()), [effect1]);
let effect2 = new AttributeLimitEffect("precision", 2);
let effect2 = new AttributeLimitEffect("evasion", 2);
ship.active_effects.add(new StickyEffect(effect2, 4));
check.equals(imaterialize(ship.ieffects()), [effect1, effect2]);
});
test.case("gets a textual description of an attribute", check => {
let ship = new Ship();
check.equals(ship.getAttributeDescription("maneuvrability"), "Ability to move first, fast and to evade weapons");
check.equals(ship.getAttributeDescription("evasion"), "Damage points that may be evaded by maneuvering");
check.patch(ship, "getUpgrades", () => [
{ code: "Base", effects: [new AttributeEffect("maneuvrability", 3)] },
{ code: "Up1", effects: [new AttributeEffect("precision", 1)] },
{ code: "Up2", effects: [new AttributeEffect("precision", 1), new AttributeEffect("maneuvrability", 1)] }
{ code: "Base", effects: [new AttributeEffect("evasion", 3)] },
{ code: "Up1", effects: [new AttributeEffect("shield_capacity", 1)] },
{ code: "Up2", effects: [new AttributeEffect("shield_capacity", 1), new AttributeEffect("evasion", 1)] }
]);
check.equals(ship.getAttributeDescription("maneuvrability"), "Ability to move first, fast and to evade weapons\n\nBase: +3\nUp2: +1");
check.equals(ship.getAttributeDescription("evasion"), "Damage points that may be evaded by maneuvering\n\nBase: +3\nUp2: +1");
ship.active_effects.add(new StickyEffect(new AttributeLimitEffect("maneuvrability", 3)));
check.equals(ship.getAttributeDescription("maneuvrability"), "Ability to move first, fast and to evade weapons\n\nBase: +3\nUp2: +1\nSticky effect: limit to 3");
ship.active_effects.add(new StickyEffect(new AttributeLimitEffect("evasion", 3)));
check.equals(ship.getAttributeDescription("evasion"), "Damage points that may be evaded by maneuvering\n\nBase: +3\nUp2: +1\nSticky effect: limit to 3");
ship.active_effects.remove(ship.active_effects.list()[0]);
ship.active_effects.add(new AttributeEffect("maneuvrability", -1));
check.equals(ship.getAttributeDescription("maneuvrability"), "Ability to move first, fast and to evade weapons\n\nBase: +3\nUp2: +1\nActive effect: -1");
ship.active_effects.add(new AttributeEffect("evasion", -1));
check.equals(ship.getAttributeDescription("evasion"), "Damage points that may be evaded by maneuvering\n\nBase: +3\nUp2: +1\nActive effect: -1");
});
test.case("produces death diffs", check => {
@ -175,17 +175,17 @@ module TK.SpaceTac.Specs {
new ShipDeathDiff(battle, ship),
]);
let effect1 = ship.active_effects.add(new AttributeEffect("precision", 2));
let effect2 = ship.active_effects.add(new StickyEffect(new AttributeLimitEffect("maneuvrability", 1)));
let effect1 = ship.active_effects.add(new AttributeEffect("shield_capacity", 2));
let effect2 = ship.active_effects.add(new StickyEffect(new AttributeLimitEffect("evasion", 1)));
let action1 = ship.actions.addCustom(new ToggleAction("weapon1", { power: 3 }));
let action2 = ship.actions.addCustom(new ToggleAction("weapon2", { power: 3 }));
ship.actions.toggle(action2, true);
check.equals(ship.getDeathDiffs(battle), [
new ShipEffectRemovedDiff(ship, effect1),
new ShipAttributeDiff(ship, "precision", {}, { cumulative: 2 }),
new ShipAttributeDiff(ship, "shield_capacity", {}, { cumulative: 2 }),
new ShipEffectRemovedDiff(ship, effect2),
new ShipAttributeDiff(ship, "maneuvrability", {}, { limit: 1 }),
new ShipAttributeDiff(ship, "evasion", {}, { limit: 1 }),
new ShipActionToggleDiff(ship, action2, false),
new ShipValueDiff(ship, "hull", -1),
new ShipDeathDiff(battle, ship),

View File

@ -112,7 +112,7 @@ module TK.SpaceTac {
// Make an initiative throw, to resolve play order in a battle
throwInitiative(gen: RandomGenerator): void {
this.play_priority = gen.random() * this.attributes.maneuvrability.get();
this.play_priority = gen.random() * this.attributes.initiative.get();
}
/**

View File

@ -15,21 +15,21 @@ module TK.SpaceTac.Specs {
check.equals(level.checkLevelUp(), true);
check.equals(level.get(), 2);
check.equals(level.getNextGoal(), 300);
check.equals(level.getUpgradePoints(), 6);
check.equals(level.getUpgradePoints(), 3);
level.addExperience(200); // 330
check.equals(level.get(), 2);
check.equals(level.checkLevelUp(), true);
check.equals(level.get(), 3);
check.equals(level.getNextGoal(), 600);
check.equals(level.getUpgradePoints(), 9);
check.equals(level.getUpgradePoints(), 5);
level.addExperience(320); // 650
check.equals(level.get(), 3);
check.equals(level.checkLevelUp(), true);
check.equals(level.get(), 4);
check.equals(level.getNextGoal(), 1000);
check.equals(level.getUpgradePoints(), 12);
check.equals(level.getUpgradePoints(), 7);
});
test.case("forces a given level", check => {

View File

@ -86,7 +86,7 @@ module TK.SpaceTac {
* This does not deduce activated upgrades usage
*/
getUpgradePoints(): number {
return this.level > 1 ? (3 * this.level) : 0;
return this.level > 1 ? (1 + 2 * (this.level - 1)) : 0;
}
/**

View File

@ -4,25 +4,25 @@ module TK.SpaceTac {
}
export const SHIP_VALUES_DESCRIPTIONS: ShipValuesMapping = {
"initiative": "Capacity to play before others in a battle",
"hull": "Physical structure of the ship",
"shield": "Shield around the ship that may absorb damage",
"power": "Power available to supply the equipments",
"hull_capacity": "Maximal Hull value before the ship risks collapsing",
"shield_capacity": "Maximal Shield value to protect the hull from damage",
"power_capacity": "Maximal Power value to use equipment",
"maneuvrability": "Ability to move first, fast and to evade weapons",
"precision": "Ability to target far and aim good",
"evasion": "Damage points that may be evaded by maneuvering",
}
export const SHIP_VALUES_NAMES: ShipValuesMapping = {
"initiative": "initiative",
"hull": "hull",
"shield": "shield",
"power": "power",
"hull_capacity": "hull capacity",
"shield_capacity": "shield capacity",
"power_capacity": "power capacity",
"maneuvrability": "maneuvrability",
"precision": "precision",
"evasion": "evasion",
}
/**
@ -116,16 +116,16 @@ module TK.SpaceTac {
* Set of ShipAttribute for a ship
*/
export class ShipAttributes {
// Initiative (capacity to play first)
initiative = new ShipAttribute()
// Maximal hull value
hull_capacity = new ShipAttribute()
// Maximal shield value
shield_capacity = new ShipAttribute()
// Maximal power value
power_capacity = new ShipAttribute()
// Ability to move first and fast
maneuvrability = new ShipAttribute()
// Ability to fire far and good
precision = new ShipAttribute()
// Damage evation
evasion = new ShipAttribute()
}
/**

View File

@ -159,7 +159,7 @@ module TK.SpaceTac.Specs {
let ship = battle.play_order[0];
let effect1 = new BaseEffect("e1");
let effect2 = new StickyEffect(new AttributeLimitEffect("precision", 7), 2);
let effect2 = new StickyEffect(new AttributeLimitEffect("evasion", 7), 2);
ship.active_effects.add(effect1);
ship.active_effects.add(effect2);
@ -175,23 +175,23 @@ module TK.SpaceTac.Specs {
check.equals(ship.active_effects.count(), 2, "effect count");
check.contains(ship.active_effects.ids(), effect2.id, "sticky effect active");
check.equals((<StickyEffect>nn(ship.active_effects.get(effect2.id))).duration, 2, "duration sticky effect");
check.equals(ship.attributes.precision.getMaximal(), 7, "max precision");
check.equals(ship.attributes.evasion.getMaximal(), 7, "max evasion");
},
check => {
check.equals(ship.active_effects.count(), 2, "effect count");
check.contains(ship.active_effects.ids(), effect2.id, "sticky effect active");
check.equals((<StickyEffect>nn(ship.active_effects.get(effect2.id))).duration, 1, "duration sticky effect");
check.equals(ship.attributes.precision.getMaximal(), 7, "max precision");
check.equals(ship.attributes.evasion.getMaximal(), 7, "max evasion");
},
check => {
check.equals(ship.active_effects.count(), 1, "effect count");
check.notcontains(ship.active_effects.ids(), effect2.id, "sticky effect removed");
check.equals(ship.attributes.precision.getMaximal(), Infinity, "max precision");
check.equals(ship.attributes.evasion.getMaximal(), Infinity, "max evasion");
},
check => {
check.equals(ship.active_effects.count(), 1, "effect count");
check.notcontains(ship.active_effects.ids(), effect2.id, "sticky effect removed");
check.equals(ship.attributes.precision.getMaximal(), Infinity, "max precision");
check.equals(ship.attributes.evasion.getMaximal(), Infinity, "max evasion");
}
]);
});

View File

@ -120,21 +120,21 @@ module TK.SpaceTac.Specs {
let action = new TriggerAction();
check.equals(action.getEffectsDescription(), "");
let effects: BaseEffect[] = [new AttributeMultiplyEffect("precision", 20)];
let effects: BaseEffect[] = [new AttributeMultiplyEffect("evasion", 20)];
action.configureTrigger({ effects: effects, power: 0 });
check.equals(action.getEffectsDescription(), "Trigger:\n• precision +20% on self");
check.equals(action.getEffectsDescription(), "Trigger:\n• evasion +20% on self");
action.configureTrigger({ effects: effects, power: 2 });
check.equals(action.getEffectsDescription(), "Trigger (power 2):\n• precision +20% on self");
check.equals(action.getEffectsDescription(), "Trigger (power 2):\n• evasion +20% on self");
action.configureTrigger({ effects: effects, power: 2, range: 120 });
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km):\n• precision +20% on target");
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km):\n• evasion +20% on target");
action.configureTrigger({ effects: effects, power: 2, range: 120, angle: 80 });
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km):\n• precision +20% in 80° arc");
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km):\n• evasion +20% in 80° arc");
action.configureTrigger({ effects: effects, power: 2, range: 120, blast: 100, angle: 80 });
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km):\n• precision +20% in 100km radius");
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km):\n• evasion +20% in 100km radius");
})
});
}

View File

@ -28,8 +28,8 @@ module TK.SpaceTac.Specs {
check.contains(maneuver.effects, new ShipValueDiff(ship2, "shield", -50), "ship2 shield value");
check.contains(maneuver.effects, new ShipValueDiff(ship3, "shield", -30), "ship3 shield value");
check.contains(maneuver.effects, new ShipValueDiff(ship3, "hull", -20), "ship3 hull value");
check.contains(maneuver.effects, new ShipDamageDiff(ship2, 0, 50, 50), "ship2 damage");
check.contains(maneuver.effects, new ShipDamageDiff(ship3, 20, 30, 50), "ship3 damage");
check.contains(maneuver.effects, new ShipDamageDiff(ship2, 0, 50, 0, 50), "ship2 damage");
check.contains(maneuver.effects, new ShipDamageDiff(ship3, 20, 30, 0, 50), "ship3 damage");
});
});
}

View File

@ -7,45 +7,45 @@ module TK.SpaceTac.Specs {
let ship = battle.fleets[0].addShip();
TestTools.diffChain(check, battle, [
new ShipAttributeDiff(ship, "precision", { cumulative: 5 }, {}),
new ShipAttributeDiff(ship, "maneuvrability", { cumulative: 8 }, {}),
new ShipAttributeDiff(ship, "precision", { cumulative: 2 }, {}),
new ShipAttributeDiff(ship, "precision", { cumulative: 4 }, { cumulative: 5 }),
new ShipAttributeDiff(ship, "maneuvrability", { multiplier: 50 }, {}),
new ShipAttributeDiff(ship, "maneuvrability", { limit: 2 }, {}),
new ShipAttributeDiff(ship, "maneuvrability", {}, { multiplier: 50, limit: 2 }),
new ShipAttributeDiff(ship, "power_capacity", { cumulative: 5 }, {}),
new ShipAttributeDiff(ship, "evasion", { cumulative: 8 }, {}),
new ShipAttributeDiff(ship, "power_capacity", { cumulative: 2 }, {}),
new ShipAttributeDiff(ship, "power_capacity", { cumulative: 4 }, { cumulative: 5 }),
new ShipAttributeDiff(ship, "evasion", { multiplier: 50 }, {}),
new ShipAttributeDiff(ship, "evasion", { limit: 2 }, {}),
new ShipAttributeDiff(ship, "evasion", {}, { multiplier: 50, limit: 2 }),
], [
check => {
check.equals(ship.getAttribute("precision"), 0, "precision value");
check.equals(ship.getAttribute("maneuvrability"), 0, "maneuvrability value");
check.equals(ship.getAttribute("power_capacity"), 0, "power capacity value");
check.equals(ship.getAttribute("evasion"), 0, "evasion value");
},
check => {
check.equals(ship.getAttribute("precision"), 5, "precision value");
check.equals(ship.getAttribute("maneuvrability"), 0, "maneuvrability value");
check.equals(ship.getAttribute("power_capacity"), 5, "power capacity value");
check.equals(ship.getAttribute("evasion"), 0, "evasion value");
},
check => {
check.equals(ship.getAttribute("precision"), 5, "precision value");
check.equals(ship.getAttribute("maneuvrability"), 8, "maneuvrability value");
check.equals(ship.getAttribute("power_capacity"), 5, "power capacity value");
check.equals(ship.getAttribute("evasion"), 8, "evasion value");
},
check => {
check.equals(ship.getAttribute("precision"), 7, "precision value");
check.equals(ship.getAttribute("maneuvrability"), 8, "maneuvrability value");
check.equals(ship.getAttribute("power_capacity"), 7, "power capacity value");
check.equals(ship.getAttribute("evasion"), 8, "evasion value");
},
check => {
check.equals(ship.getAttribute("precision"), 6, "precision value");
check.equals(ship.getAttribute("maneuvrability"), 8, "maneuvrability value");
check.equals(ship.getAttribute("power_capacity"), 6, "power capacity value");
check.equals(ship.getAttribute("evasion"), 8, "evasion value");
},
check => {
check.equals(ship.getAttribute("precision"), 6, "precision value");
check.equals(ship.getAttribute("maneuvrability"), 12, "maneuvrability value");
check.equals(ship.getAttribute("power_capacity"), 6, "power capacity value");
check.equals(ship.getAttribute("evasion"), 12, "evasion value");
},
check => {
check.equals(ship.getAttribute("precision"), 6, "precision value");
check.equals(ship.getAttribute("maneuvrability"), 2, "maneuvrability value");
check.equals(ship.getAttribute("power_capacity"), 6, "power capacity value");
check.equals(ship.getAttribute("evasion"), 2, "evasion value");
},
check => {
check.equals(ship.getAttribute("precision"), 6, "precision value");
check.equals(ship.getAttribute("maneuvrability"), 8, "maneuvrability value");
check.equals(ship.getAttribute("power_capacity"), 6, "power capacity value");
check.equals(ship.getAttribute("evasion"), 8, "evasion value");
},
])
});

View File

@ -13,14 +13,18 @@ module TK.SpaceTac {
// Damage to shield
shield: number
// Evaded damage
evaded: number
// Theoretical damage value
theoretical: number
constructor(ship: Ship, hull: number, shield: number, theoretical = hull + shield) {
constructor(ship: Ship, hull: number, shield: number, evaded = 0, theoretical = hull + shield + evaded) {
super(ship);
this.hull = hull;
this.shield = shield;
this.evaded = evaded;
this.theoretical = theoretical;
}
}

View File

@ -3,26 +3,26 @@ module TK.SpaceTac {
test.case("applies cumulatively on attribute", check => {
let battle = new Battle();
let ship = battle.fleets[0].addShip();
check.equals(ship.getAttribute("maneuvrability"), 0, "initial");
check.equals(ship.getAttribute("evasion"), 0, "initial");
let effect1 = new AttributeEffect("maneuvrability", 20);
let effect1 = new AttributeEffect("evasion", 20);
battle.applyDiffs(effect1.getOnDiffs(ship, ship));
check.equals(ship.getAttribute("maneuvrability"), 20, "applied 1");
check.equals(ship.getAttribute("evasion"), 20, "applied 1");
let effect2 = new AttributeEffect("maneuvrability", 10);
let effect2 = new AttributeEffect("evasion", 10);
battle.applyDiffs(effect2.getOnDiffs(ship, ship));
check.equals(ship.getAttribute("maneuvrability"), 30, "applied 2");
check.equals(ship.getAttribute("evasion"), 30, "applied 2");
battle.applyDiffs(effect1.getOffDiffs(ship));
check.equals(ship.getAttribute("maneuvrability"), 10, "reverted 1");
check.equals(ship.getAttribute("evasion"), 10, "reverted 1");
battle.applyDiffs(effect2.getOffDiffs(ship));
check.equals(ship.getAttribute("maneuvrability"), 0, "reverted 2");
check.equals(ship.getAttribute("evasion"), 0, "reverted 2");
});
test.case("has a description", check => {
let effect = new AttributeEffect("maneuvrability", 12);
check.equals(effect.getDescription(), "maneuvrability +12");
let effect = new AttributeEffect("evasion", 12);
check.equals(effect.getDescription(), "evasion +12");
effect = new AttributeEffect("shield_capacity", -4);
check.equals(effect.getDescription(), "shield capacity -4");

View File

@ -3,22 +3,22 @@ module TK.SpaceTac {
test.case("applies cumulatively on attribute", check => {
let battle = new Battle();
let ship = battle.fleets[0].addShip();
ship.attributes.precision.addModifier(12);
check.equals(ship.getAttribute("precision"), 12, "initial");
ship.attributes.evasion.addModifier(12);
check.equals(ship.getAttribute("evasion"), 12, "initial");
let effect1 = new AttributeLimitEffect("precision", 5);
let effect1 = new AttributeLimitEffect("evasion", 5);
battle.applyDiffs(effect1.getOnDiffs(ship, ship));
check.equals(ship.getAttribute("precision"), 5, "applied 1");
check.equals(ship.getAttribute("evasion"), 5, "applied 1");
let effect2 = new AttributeLimitEffect("precision", 3);
let effect2 = new AttributeLimitEffect("evasion", 3);
battle.applyDiffs(effect2.getOnDiffs(ship, ship));
check.equals(ship.getAttribute("precision"), 3, "applied 2");
check.equals(ship.getAttribute("evasion"), 3, "applied 2");
battle.applyDiffs(effect1.getOffDiffs(ship));
check.equals(ship.getAttribute("precision"), 3, "reverted 1");
check.equals(ship.getAttribute("evasion"), 3, "reverted 1");
battle.applyDiffs(effect2.getOffDiffs(ship));
check.equals(ship.getAttribute("precision"), 12, "reverted 2");
check.equals(ship.getAttribute("evasion"), 12, "reverted 2");
});
test.case("has a description", check => {

View File

@ -4,21 +4,25 @@ module TK.SpaceTac.Specs {
let ship = new Ship();
TestTools.setShipModel(ship, 2, 3);
check.equals(new DamageEffect(1, DamageEffectMode.HULL_ONLY).getEffectiveDamage(ship), new ShipDamageDiff(ship, 1, 0, 1), "hull 1");
check.equals(new DamageEffect(3, DamageEffectMode.HULL_ONLY).getEffectiveDamage(ship), new ShipDamageDiff(ship, 2, 0, 3), "hull 3");
check.equals(new DamageEffect(1, DamageEffectMode.HULL_ONLY).getEffectiveDamage(ship), new ShipDamageDiff(ship, 1, 0, 0, 1), "hull 1");
check.equals(new DamageEffect(3, DamageEffectMode.HULL_ONLY).getEffectiveDamage(ship), new ShipDamageDiff(ship, 2, 0, 0, 3), "hull 3");
check.equals(new DamageEffect(1, DamageEffectMode.SHIELD_ONLY).getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 1, 1), "shield 1");
check.equals(new DamageEffect(4, DamageEffectMode.SHIELD_ONLY).getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 3, 4), "shield 4");
check.equals(new DamageEffect(1, DamageEffectMode.SHIELD_ONLY).getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 1, 0, 1), "shield 1");
check.equals(new DamageEffect(4, DamageEffectMode.SHIELD_ONLY).getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 3, 0, 4), "shield 4");
check.equals(new DamageEffect(1, DamageEffectMode.SHIELD_THEN_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 1, 1), "piercing 1");
check.equals(new DamageEffect(4, DamageEffectMode.SHIELD_THEN_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 1, 3, 4), "piercing 4");
check.equals(new DamageEffect(8, DamageEffectMode.SHIELD_THEN_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 2, 3, 8), "piercing 8");
check.equals(new DamageEffect(1, DamageEffectMode.SHIELD_THEN_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 1, 0, 1), "piercing 1");
check.equals(new DamageEffect(4, DamageEffectMode.SHIELD_THEN_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 1, 3, 0, 4), "piercing 4");
check.equals(new DamageEffect(8, DamageEffectMode.SHIELD_THEN_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 2, 3, 0, 8), "piercing 8");
check.equals(new DamageEffect(1, DamageEffectMode.SHIELD_OR_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 1, 1), "normal 1");
check.equals(new DamageEffect(4, DamageEffectMode.SHIELD_OR_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 3, 4), "normal 4");
check.equals(new DamageEffect(1, DamageEffectMode.SHIELD_OR_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 1, 0, 1), "normal 1");
check.equals(new DamageEffect(4, DamageEffectMode.SHIELD_OR_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 3, 0, 4), "normal 4");
ship.setValue("shield", 0);
check.equals(new DamageEffect(1, DamageEffectMode.SHIELD_OR_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 1, 0, 1), "normal no shield 1");
check.equals(new DamageEffect(4, DamageEffectMode.SHIELD_OR_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 2, 0, 4), "normal no shield 4");
check.equals(new DamageEffect(1, DamageEffectMode.SHIELD_OR_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 1, 0, 0, 1), "normal no shield 1");
check.equals(new DamageEffect(4, DamageEffectMode.SHIELD_OR_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 2, 0, 0, 4), "normal no shield 4");
ship.setValue("shield", 3);
TestTools.setAttribute(ship, "evasion", 1);
check.equals(new DamageEffect(5, DamageEffectMode.SHIELD_THEN_HULL).getEffectiveDamage(ship), new ShipDamageDiff(ship, 1, 3, 1, 5), "piercing 5 evade 1");
});
test.case("applies damage", check => {
@ -54,31 +58,5 @@ module TK.SpaceTac.Specs {
check.equals(new DamageEffect(10, DamageEffectMode.SHIELD_ONLY).getDescription(), "do 10 shield damage");
check.equals(new DamageEffect(10, DamageEffectMode.SHIELD_THEN_HULL).getDescription(), "do 10 piercing damage");
});
test.case("applies damage modifiers", check => {
let ship = new Ship();
TestTools.setShipModel(ship, 1000, 1000);
let damage = new DamageEffect(200);
check.equals(damage.getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 200));
check.patch(ship, "ieffects", iterator([
isingle(new DamageModifierEffect(-15)),
isingle(new DamageModifierEffect(20)),
isingle(new DamageModifierEffect(-150)),
isingle(new DamageModifierEffect(180)),
iarray([new DamageModifierEffect(10), new DamageModifierEffect(-15)]),
isingle(new DamageModifierEffect(3))
]));
check.equals(damage.getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 170));
check.equals(damage.getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 240));
check.equals(damage.getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 0));
check.equals(damage.getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 400));
check.equals(damage.getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 190));
damage = new DamageEffect(40);
check.equals(damage.getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 41));
});
});
}

View File

@ -25,24 +25,15 @@ module TK.SpaceTac {
// Damage mode
mode: DamageEffectMode
constructor(value: number, mode = DamageEffectMode.SHIELD_OR_HULL) {
// Evadable damage (applies evasion)
evadable: boolean
constructor(value: number, mode = DamageEffectMode.SHIELD_OR_HULL, evadable = true) {
super("damage");
this.value = value;
this.mode = mode;
}
/**
* Apply damage modifiers to get the final damage factor
*/
getFactor(ship: Ship): number {
let percent = 0;
iforeach(ship.ieffects(), effect => {
if (effect instanceof DamageModifierEffect) {
percent += effect.factor;
}
});
return (clamp(percent, -100, 100) + 100) / 100;
this.evadable = true;
}
/**
@ -54,8 +45,9 @@ module TK.SpaceTac {
let dhull = 0;
let dshield = 0;
// Apply modifiers
let damage = Math.round(this.value * this.getFactor(ship));
// Apply evasion
let evaded = this.evadable ? Math.min(this.value, ship.getAttribute("evasion")) : 0;
let damage = this.value - evaded;
// Split in shield/hull damage
if (this.mode == DamageEffectMode.HULL_ONLY) {
@ -73,7 +65,7 @@ module TK.SpaceTac {
dhull = Math.min(damage - dshield, hull);
}
return new ShipDamageDiff(ship, dhull, dshield, damage);
return new ShipDamageDiff(ship, dhull, dshield, evaded, this.value);
}
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {

View File

@ -1,25 +0,0 @@
/// <reference path="BaseEffect.ts"/>
module TK.SpaceTac {
/**
* Modify damage on ships.
*/
export class DamageModifierEffect extends BaseEffect {
// Percent factor (ex: -15 for -15%)
factor: number
constructor(factor = 0) {
super("damagemod");
this.factor = factor;
}
getDescription(): string {
return `damage ${this.factor}%`;
}
isBeneficial(): boolean {
return this.factor <= 0;
}
}
}

View File

@ -6,10 +6,10 @@ module TK.SpaceTac.Specs {
check.in("before", check => {
check.equals(ship.active_effects.count(), 0, "no sticky effect");
check.equals(ship.getAttribute("precision"), 0, "precision");
check.equals(ship.getAttribute("evasion"), 0, "evasion");
})
let effect = new StickyEffect(new AttributeEffect("precision", 1), 2);
let effect = new StickyEffect(new AttributeEffect("evasion", 1), 2);
battle.applyDiffs(effect.getOnDiffs(ship, ship));
check.in("after", check => {
@ -18,7 +18,7 @@ module TK.SpaceTac.Specs {
if (sticked instanceof StickyEffect) {
check.equals(sticked.base, effect.base, "sticked effect");
check.equals(sticked.duration, 2, "sticked duration");
check.equals(ship.getAttribute("precision"), 1, "precision");
check.equals(ship.getAttribute("evasion"), 1, "evasion");
sticked.duration = 1;
} else {
check.fail("Not a sticky effect");
@ -33,7 +33,7 @@ module TK.SpaceTac.Specs {
if (sticked instanceof StickyEffect) {
check.equals(sticked.base, effect.base, "sticked effect");
check.equals(sticked.duration, 2, "sticked duration");
check.equals(ship.getAttribute("precision"), 1, "precision");
check.equals(ship.getAttribute("evasion"), 1, "evasion");
} else {
check.fail("Not a sticky effect");
}

View File

@ -38,8 +38,6 @@ module TK.SpaceTac {
{
code: "Avenger Base",
effects: [
new AttributeEffect("precision", 8),
new AttributeEffect("maneuvrability", 0),
new AttributeEffect("hull_capacity", 2),
new AttributeEffect("shield_capacity", 1),
new AttributeEffect("power_capacity", 8),
@ -58,64 +56,6 @@ module TK.SpaceTac {
actions: [long_range_missile]
},
];
} else if (level == 2) {
return [
{
code: "Laser Targetting",
description: "Improved targetting, using fine-grained laser sensors",
cost: 1,
effects: [new AttributeEffect("precision", 2)],
},
{
code: "Basic Countermeasures",
description: "Chaffs and lures to divert enemy fire",
cost: 1,
effects: [new AttributeEffect("maneuvrability", 2)],
},
{
code: "Targetting Assist",
description: "Share your targetting subnetwork with nearby ships",
cost: 3,
actions: [new ToggleAction("Targetting Assist", {
power: 3,
radius: 300,
effects: [new AttributeEffect("precision", 2)]
}, "precisionboost")],
},
];
} else if (level == 3) {
let shield_booster = new TriggerAction("Shield Booster", {
effects: [
new StickyEffect(new AttributeEffect("shield_capacity", 2), 2),
new ValueEffect("shield", 3),
],
power: 2
}, "forcefield");
shield_booster.configureCooldown(1, 4);
return [
{
code: "Gyroscopic Stabilizers",
description: "Heavy mercury gyroscopes, used to stabilize the whole ship while firing",
cost: 1,
effects: [
new AttributeEffect("precision", 3),
new AttributeEffect("maneuvrability", -2)
]
},
{
code: "Shield Booster",
description: "Temporary power surge directed toward the shield mainframe, to boost its output",
cost: 3,
actions: [shield_booster]
},
{
code: "Hard Coated Hull",
description: "Improved metal coating of outer hull layers, making them more damage resistant",
cost: 3,
effects: [new AttributeEffect("hull_capacity", 1)]
},
];
} else {
return this.getStandardUpgrades(level);
}

View File

@ -36,10 +36,10 @@ module TK.SpaceTac {
{
code: "Breeze Base",
effects: [
new AttributeEffect("precision", 3),
new AttributeEffect("maneuvrability", 12),
new AttributeEffect("initiative", 3),
new AttributeEffect("evasion", 1),
new AttributeEffect("hull_capacity", 1),
new AttributeEffect("shield_capacity", 2),
new AttributeEffect("shield_capacity", 1),
new AttributeEffect("power_capacity", 7),
]
},

View File

@ -34,8 +34,7 @@ module TK.SpaceTac {
{
code: "Commodore Base",
effects: [
new AttributeEffect("precision", 5),
new AttributeEffect("maneuvrability", 6),
new AttributeEffect("initiative", 2),
new AttributeEffect("hull_capacity", 2),
new AttributeEffect("shield_capacity", 1),
new AttributeEffect("power_capacity", 8),

View File

@ -42,8 +42,7 @@ module TK.SpaceTac {
{
code: "Creeper Base",
effects: [
new AttributeEffect("precision", 3),
new AttributeEffect("maneuvrability", 12),
new AttributeEffect("initiative", 3),
new AttributeEffect("hull_capacity", 1),
new AttributeEffect("shield_capacity", 2),
new AttributeEffect("power_capacity", 7),

View File

@ -34,8 +34,6 @@ module TK.SpaceTac {
{
code: "Falcon Base",
effects: [
new AttributeEffect("precision", 8),
new AttributeEffect("maneuvrability", 4),
new AttributeEffect("hull_capacity", 2),
new AttributeEffect("shield_capacity", 2),
new AttributeEffect("power_capacity", 9),

View File

@ -34,8 +34,8 @@ module TK.SpaceTac {
{
code: "Flea Base",
effects: [
new AttributeEffect("precision", 0),
new AttributeEffect("maneuvrability", 15),
new AttributeEffect("initiative", 2),
new AttributeEffect("evasion", 1),
new AttributeEffect("hull_capacity", 1),
new AttributeEffect("shield_capacity", 2),
new AttributeEffect("power_capacity", 8),

View File

@ -24,7 +24,7 @@ module TK.SpaceTac {
}, "submunitionmissile");
let protector = new TriggerAction("Damage Reductor", {
effects: [new StickyEffect(new DamageModifierEffect(-20), 2)],
effects: [new StickyEffect(new AttributeEffect("evasion", 1), 2)],
power: 3,
range: 300, blast: 150
}, "damageprotector");
@ -39,8 +39,7 @@ module TK.SpaceTac {
{
code: "Jumper Base",
effects: [
new AttributeEffect("precision", 9),
new AttributeEffect("maneuvrability", 3),
new AttributeEffect("initiative", 1),
new AttributeEffect("hull_capacity", 2),
new AttributeEffect("shield_capacity", 2),
new AttributeEffect("power_capacity", 6),

View File

@ -33,8 +33,7 @@ module TK.SpaceTac {
{
code: "Rhino Base",
effects: [
new AttributeEffect("precision", 4),
new AttributeEffect("maneuvrability", 3),
new AttributeEffect("initiative", 1),
new AttributeEffect("hull_capacity", 3),
new AttributeEffect("shield_capacity", 1),
new AttributeEffect("power_capacity", 9),

View File

@ -51,8 +51,7 @@ module TK.SpaceTac {
{
code: "Tomahawk Base",
effects: [
new AttributeEffect("precision", 8),
new AttributeEffect("maneuvrability", 3),
new AttributeEffect("initiative", 2),
new AttributeEffect("hull_capacity", 2),
new AttributeEffect("shield_capacity", 1),
new AttributeEffect("power_capacity", 11),

View File

@ -20,7 +20,7 @@ module TK.SpaceTac {
let protector = new ToggleAction("Damage Protector", {
power: 4,
radius: 300,
effects: [new DamageModifierEffect(-35)]
effects: [new AttributeEffect("evasion", 1)]
});
let depleter = new TriggerAction("Power Depleter", {
@ -40,8 +40,7 @@ module TK.SpaceTac {
{
code: "Trapper Base",
effects: [
new AttributeEffect("precision", 3),
new AttributeEffect("maneuvrability", 2),
new AttributeEffect("evasion", 1),
new AttributeEffect("hull_capacity", 1),
new AttributeEffect("shield_capacity", 2),
new AttributeEffect("power_capacity", 8),

View File

@ -38,8 +38,8 @@ module TK.SpaceTac {
{
code: "Xander Base",
effects: [
new AttributeEffect("precision", 8),
new AttributeEffect("maneuvrability", 5),
new AttributeEffect("initiative", 1),
new AttributeEffect("evasion", 1),
new AttributeEffect("hull_capacity", 2),
new AttributeEffect("shield_capacity", 1),
new AttributeEffect("power_capacity", 7),

View File

@ -10,14 +10,12 @@ module TK.SpaceTac.UI.Specs {
ship.model = new ShipModel("fake", "Fury");
check.patch(ship.model, "getDescription", () => "Super ship model !");
TestTools.addWeapon(ship, 50);
TestTools.setAttribute(ship, "precision", 7);
TestTools.setAttribute(ship, "maneuvrability", 3);
TestTools.setAttribute(ship, "evasion", 7);
ship.setValue("hull", 57);
ship.setValue("shield", 100);
ship.setValue("power", 9);
ship.active_effects.add(new AttributeEffect("hull_capacity", 50));
ship.active_effects.add(new StickyEffect(new DamageModifierEffect(-15), 3));
ship.active_effects.add(new AttributeLimitEffect("precision", 10));
ship.active_effects.add(new StickyEffect(new AttributeLimitEffect("shield_capacity", 2), 3));
tooltip.setShip(ship);
let images = collectImages((<any>tooltip).container);
@ -26,8 +24,8 @@ module TK.SpaceTac.UI.Specs {
check.contains(images, "action-weapon");
check.equals(texts, [
"Level 1 Fury", "Plays in 2 turns",
"7", "3", "9", "max", "12", "57", "max", "58", "100", "max", "140",
"Weapon", "• hull capacity +50", "• damage -15% for 3 turns", "• limit precision to 10",
"57", "max", "58", "100", "max", "140", "7", "9", "max", "12",
"Weapon", "• hull capacity +50", "• limit shield capacity to 2 for 3 turns",
"Super ship model !"
]);
});

View File

@ -36,11 +36,10 @@ module TK.SpaceTac.UI {
let turns = this.battleview.battle.getPlayOrder(ship);
builder.text((turns == 0) ? "Playing" : ((turns == 1) ? "Plays next" : `Plays in ${turns} turns`), 230, 36, { color: "#cccccc", size: 18 });
ShipTooltip.addValue(builder, 0, "#aa6f33", "attribute-precision", ship.getAttribute("precision"));
ShipTooltip.addValue(builder, 1, "#c1f06b", "attribute-maneuvrability", ship.getAttribute("maneuvrability"));
ShipTooltip.addValue(builder, 2, "#ffdd4b", "attribute-power_capacity", ship.getValue("power"), ship.getAttribute("power_capacity"));
ShipTooltip.addValue(builder, 3, "#eb4e4a", "attribute-hull_capacity", ship.getValue("hull"), ship.getAttribute("hull_capacity"));
ShipTooltip.addValue(builder, 4, "#2ad8dc", "attribute-shield_capacity", ship.getValue("shield"), ship.getAttribute("shield_capacity"));
ShipTooltip.addValue(builder, 0, "#eb4e4a", "attribute-hull_capacity", ship.getValue("hull"), ship.getAttribute("hull_capacity"));
ShipTooltip.addValue(builder, 1, "#2ad8dc", "attribute-shield_capacity", ship.getValue("shield"), ship.getAttribute("shield_capacity"));
ShipTooltip.addValue(builder, 2, "#c1f06b", "attribute-evasion", ship.getAttribute("evasion"));
ShipTooltip.addValue(builder, 3, "#ffdd4b", "attribute-power_capacity", ship.getValue("power"), ship.getAttribute("power_capacity"));
let iy = 210;

View File

@ -67,9 +67,9 @@ module TK.SpaceTac.UI.Specs {
upgrade.effects = [
new DamageEffect(10),
new AttributeMultiplyEffect("precision", 2)
new AttributeMultiplyEffect("evasion", 2)
];
check.equals(display.getIcon(), "attribute-precision");
check.equals(display.getIcon(), "attribute-evasion");
})
})
}