New weapon effectiveness system, based on precision, maneuvrability and luck
This commit is contained in:
parent
56a85333f5
commit
231484f7a8
4
TODO.md
4
TODO.md
|
@ -36,6 +36,7 @@ Character sheet
|
|||
Battle
|
||||
------
|
||||
|
||||
* Display precision and maneuvrability in ship tooltip
|
||||
* Add a voluntary retreat option
|
||||
* Add scroll buttons when there are too many actions
|
||||
* Toggle bar/text display in power section of action bar
|
||||
|
@ -60,9 +61,8 @@ Ships models and equipments
|
|||
---------------------------
|
||||
|
||||
* Add permanent effects and actions to ship models
|
||||
* Add critical hit/miss
|
||||
* Add critical hit/miss (or indicate lucky/unlucky throws)
|
||||
* Add damage over time effect (tricky to make intuitive)
|
||||
* Chance to hit should increase with precision
|
||||
* Add actions with cost dependent of distance (like current move actions)
|
||||
* Add disc targetting (for some jump move actions)
|
||||
* Add "chain" effects
|
||||
|
|
|
@ -49,14 +49,14 @@ module TK.SpaceTac.Specs {
|
|||
|
||||
let action = new TriggerAction(equipment, [new DamageEffect(50)], 1, 200, 0);
|
||||
equipment.action = action;
|
||||
check.equals(equipment.getEffectsDescription(), "Fire (power usage 1, max range 200km):\n• do 50 damage on target");
|
||||
check.equals(equipment.getEffectsDescription(), "Fire (power 1, range 200km):\n• do 50 damage on target");
|
||||
|
||||
action.blast = 20;
|
||||
check.equals(equipment.getEffectsDescription(), "Fire (power usage 1, max range 200km):\n• do 50 damage in 20km radius");
|
||||
check.equals(equipment.getEffectsDescription(), "Fire (power 1, range 200km):\n• do 50 damage in 20km radius");
|
||||
|
||||
action.blast = 0;
|
||||
action.effects.push(new StickyEffect(new AttributeLimitEffect("shield_capacity", 200), 3));
|
||||
check.equals(equipment.getEffectsDescription(), "Fire (power usage 1, max range 200km):\n• do 50 damage on target\n• limit shield capacity to 200 for 3 turns on target");
|
||||
check.equals(equipment.getEffectsDescription(), "Fire (power 1, range 200km):\n• do 50 damage on target\n• limit shield capacity to 200 for 3 turns on target");
|
||||
});
|
||||
|
||||
test.case("gets a minimal level, based on skills requirements", check => {
|
||||
|
|
|
@ -206,10 +206,10 @@ module TK.SpaceTac {
|
|||
/**
|
||||
* Add a trigger action.
|
||||
*/
|
||||
addTriggerAction(power: LeveledValue, effects: EffectTemplate<any>[], range: LeveledValue = irepeat(0), blast: LeveledValue = irepeat(0), angle: LeveledValue = irepeat(0)): void {
|
||||
addTriggerAction(power: LeveledValue, effects: EffectTemplate<any>[], range: LeveledValue = irepeat(0), blast: LeveledValue = irepeat(0), angle: LeveledValue = irepeat(0), aim: LeveledValue = irepeat(0), evasion: LeveledValue = irepeat(0), luck: LeveledValue = irepeat(0)): void {
|
||||
this.base_modifiers.push((equipment, level) => {
|
||||
let reffects = effects.map(effect => effect.generate(level));
|
||||
equipment.action = new TriggerAction(equipment, reffects, resolveForLevel(power, level), resolveForLevel(range, level), resolveForLevel(blast, level), resolveForLevel(angle, level));
|
||||
equipment.action = new TriggerAction(equipment, reffects, resolveForLevel(power, level), resolveForLevel(range, level), resolveForLevel(blast, level), resolveForLevel(angle, level), resolveForLevel(aim, level), resolveForLevel(evasion, level), resolveForLevel(luck, level));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@ module TK.SpaceTac {
|
|||
"shield_capacity": "Maximal Shield value to protect the hull from damage",
|
||||
"power_capacity": "Maximal Power value to use equipment",
|
||||
"power_generation": "Power generated at the end of the ship's turn",
|
||||
"maneuvrability": "Ability to move first and fast",
|
||||
"precision": "Ability to target far and good",
|
||||
"maneuvrability": "Ability to move first, fast and to evade weapons",
|
||||
"precision": "Ability to target far and aim good",
|
||||
}
|
||||
|
||||
export const SHIP_VALUES_NAMES: ShipValuesMapping = {
|
||||
|
|
|
@ -120,7 +120,9 @@ module TK.SpaceTac {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Get the range of this action
|
||||
/**
|
||||
* Get the range of this action, for targetting purpose
|
||||
*/
|
||||
getRangeRadius(ship: Ship): number {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ module TK.SpaceTac.Specs {
|
|||
|
||||
action.apply(battle, ship, Target.newFromLocation(50, 50));
|
||||
check.called(mock_apply, [
|
||||
[ship2, ship]
|
||||
[ship2, ship, 1]
|
||||
]);
|
||||
})
|
||||
|
||||
|
@ -85,6 +85,85 @@ module TK.SpaceTac.Specs {
|
|||
check.equals(action.filterImpactedShips({ x: 0, y: 51 }, Target.newFromLocation(30, 50), ships), [ship1, ship2]);
|
||||
})
|
||||
|
||||
test.case("computes a success factor, from precision and maneuvrability", check => {
|
||||
function verify(precision: number, precision_factor: number, maneuvrability: number, maneuvrability_factor: number, result: number) {
|
||||
let ship1 = new Ship();
|
||||
let ship2 = new Ship();
|
||||
|
||||
TestTools.setAttribute(ship1, "precision", precision);
|
||||
TestTools.setAttribute(ship2, "maneuvrability", maneuvrability);
|
||||
|
||||
let action = new TriggerAction(new Equipment());
|
||||
action.aim = precision_factor;
|
||||
action.evasion = maneuvrability_factor;
|
||||
check.nears(action.getSuccessFactor(ship1, ship2), result, 3,
|
||||
`precision ${precision} (weight ${precision_factor}), maneuvrability ${maneuvrability} (weight ${maneuvrability_factor})`);
|
||||
}
|
||||
|
||||
// no weight => always 100%
|
||||
verify(0, 0, 0, 0, 1);
|
||||
verify(10, 0, 20, 0, 1);
|
||||
verify(40, 0, -5, 0, 1);
|
||||
|
||||
// precision only
|
||||
verify(0, 100, 0, 0, 0);
|
||||
verify(1, 100, 1, 0, 0.5);
|
||||
verify(2, 100, 2, 0, 0.8);
|
||||
verify(10, 100, 10, 0, 0.99);
|
||||
verify(1, 50, 1, 0, 0.75);
|
||||
|
||||
// maneuvrability only
|
||||
verify(0, 0, 0, 100, 1);
|
||||
verify(1, 0, 1, 100, 0.5);
|
||||
verify(2, 0, 2, 100, 0.2);
|
||||
verify(10, 0, 10, 100, 0.01);
|
||||
verify(1, 0, 1, 50, 0.75);
|
||||
|
||||
// precision vs maneuvrability
|
||||
verify(0, 100, 0, 100, 0);
|
||||
verify(4, 50, 4, 50, 0.5);
|
||||
verify(4, 50, 8, 50, 0.283);
|
||||
verify(4, 50, 20, 50, 0.016);
|
||||
verify(4, 50, 4, 50, 0.5);
|
||||
verify(8, 50, 4, 50, 0.717);
|
||||
verify(20, 50, 4, 50, 0.984);
|
||||
|
||||
// complex example
|
||||
verify(7, 20, 5, 40, 0.639);
|
||||
})
|
||||
|
||||
test.case("computes an effective success value, with random element", check => {
|
||||
function verify(success_base: number, luck: number, random: number, expected: number) {
|
||||
let ship1 = new Ship();
|
||||
let ship2 = new Ship();
|
||||
let action = new TriggerAction(new Equipment());
|
||||
action.luck = luck;
|
||||
check.patch(action, "getSuccessFactor", () => success_base);
|
||||
check.nears(action.getEffectiveSuccess(ship1, ship2, new SkewedRandomGenerator([random])), expected, 5,
|
||||
`success ${success_base}, luck ${luck}, random ${random}`);
|
||||
}
|
||||
|
||||
// no luck influence
|
||||
verify(0.3, 0, 0.4, 0.3);
|
||||
verify(0.51, 0, 0.7, 0.51);
|
||||
|
||||
// small luck influence
|
||||
verify(0.5, 5, 0.0, 0);
|
||||
verify(0.5, 5, 0.1, 0.47979);
|
||||
verify(0.5, 5, 0.4, 0.49715);
|
||||
verify(0.5, 5, 0.8, 0.51161);
|
||||
verify(0.5, 5, 1.0, 1.0);
|
||||
verify(0.7, 5, 0.5, 0.69399);
|
||||
|
||||
// large luck influence
|
||||
verify(0.5, 45, 0.0, 0);
|
||||
verify(0.5, 45, 0.1, 0.31336);
|
||||
verify(0.5, 45, 0.4, 0.46864);
|
||||
verify(0.5, 45, 0.8, 0.61679);
|
||||
verify(0.5, 45, 1.0, 1);
|
||||
verify(0.7, 45, 0.5, 0.63485);
|
||||
})
|
||||
|
||||
test.case("guesses targetting mode", check => {
|
||||
let ship = new Ship();
|
||||
let equ = new Equipment();
|
||||
|
@ -120,5 +199,35 @@ module TK.SpaceTac.Specs {
|
|||
check.equals(result, true);
|
||||
check.nears(ship.arena_angle, 1.107, 3);
|
||||
})
|
||||
|
||||
test.case("builds a textual description", check => {
|
||||
let action = new TriggerAction(new Equipment());
|
||||
action.power = 0;
|
||||
check.equals(action.getEffectsDescription(), "");
|
||||
|
||||
action.effects.push(new AttributeMultiplyEffect("precision", 20));
|
||||
check.equals(action.getEffectsDescription(), "Trigger:\n• precision +20% on self");
|
||||
|
||||
action.power = 2;
|
||||
check.equals(action.getEffectsDescription(), "Trigger (power 2):\n• precision +20% on self");
|
||||
|
||||
action.range = 120;
|
||||
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km):\n• precision +20% on target");
|
||||
|
||||
action.aim = 10;
|
||||
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km, aim +10%):\n• precision +20% on target");
|
||||
|
||||
action.evasion = 35;
|
||||
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km, aim +10%, evasion -35%):\n• precision +20% on target");
|
||||
|
||||
action.angle = 80;
|
||||
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km, aim +10%, evasion -35%):\n• precision +20% in 80° arc");
|
||||
|
||||
action.blast = 100;
|
||||
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km, aim +10%, evasion -35%):\n• precision +20% in 100km radius");
|
||||
|
||||
action.luck = 15;
|
||||
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km, aim +10%, evasion -35%, luck ±15%):\n• precision +20% in 100km radius");
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19,13 +19,22 @@ module TK.SpaceTac {
|
|||
// Angle of the area between the source and the target that will be impacted
|
||||
angle: number
|
||||
|
||||
// Influence of "precision" of firing ship (0..100)
|
||||
aim: number
|
||||
|
||||
// Influence of "maneuvrability" of impacted ship (0..100)
|
||||
evasion: number
|
||||
|
||||
// Influence of luck
|
||||
luck: number
|
||||
|
||||
// Effects applied on target
|
||||
effects: BaseEffect[]
|
||||
|
||||
// Equipment cannot be null
|
||||
equipment: Equipment
|
||||
|
||||
constructor(equipment: Equipment, effects: BaseEffect[] = [], power = 1, range = 0, blast = 0, angle = 0, code = `fire-${equipment.code}`) {
|
||||
constructor(equipment: Equipment, effects: BaseEffect[] = [], power = 1, range = 0, blast = 0, angle = 0, aim = 0, evasion = 0, luck = 0, code = `fire-${equipment.code}`) {
|
||||
super(code, equipment);
|
||||
|
||||
this.power = power;
|
||||
|
@ -33,6 +42,9 @@ module TK.SpaceTac {
|
|||
this.effects = effects;
|
||||
this.blast = blast;
|
||||
this.angle = angle;
|
||||
this.aim = aim;
|
||||
this.evasion = evasion;
|
||||
this.luck = luck;
|
||||
}
|
||||
|
||||
getVerb(): string {
|
||||
|
@ -82,6 +94,42 @@ module TK.SpaceTac {
|
|||
return this.range;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the success factor [0-1] for this action applied from a ship to another
|
||||
*
|
||||
* This is a predictible formula, not including random elements.
|
||||
*/
|
||||
getSuccessFactor(from: Ship, to: Ship): number {
|
||||
let aim = this.aim * 0.01;
|
||||
let evasion = this.evasion * 0.01;
|
||||
let f1 = (x: number) => (x < 0 ? -1 : 1) * (1 - 1 / (x * x + 1));
|
||||
let prec = from.getAttribute("precision");
|
||||
let man = to.getAttribute("maneuvrability");
|
||||
let delta = Math.min(aim, evasion) * f1(0.2 * (prec - man));
|
||||
return clamp(1 - aim * (1 - f1(prec)) - evasion * f1(man) + delta, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the effective success of the action [0-1].
|
||||
*
|
||||
* Result has more chance to be near the success factor, but may be in the whole [0-1] range.
|
||||
*/
|
||||
getEffectiveSuccess(from: Ship, to: Ship, random = RandomGenerator.global): number {
|
||||
let p = this.getSuccessFactor(from, to);
|
||||
let s = this.luck * 0.01;
|
||||
if (s) {
|
||||
let c = (2 / (2 - s)) - 1;
|
||||
let x = random.random();
|
||||
if (x <= p) {
|
||||
return Math.pow(x, c) / Math.pow(p, c - 1);
|
||||
} else {
|
||||
return 1 - Math.pow(1 - x, c) / Math.pow(1 - p, c - 1);
|
||||
}
|
||||
} else {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
filterImpactedShips(source: ArenaLocation, target: Target, ships: Ship[]): Ship[] {
|
||||
if (this.blast) {
|
||||
return ships.filter(ship => arenaDistance(ship.location, target) <= this.blast);
|
||||
|
@ -128,12 +176,15 @@ module TK.SpaceTac {
|
|||
|
||||
/**
|
||||
* Collect the effects applied by this action
|
||||
*
|
||||
* If *luck* is specified, an effective success factor is used, instead of an estimated one
|
||||
*/
|
||||
getEffects(ship: Ship, target: Target, source = ship.location): [Ship, BaseEffect][] {
|
||||
let result: [Ship, BaseEffect][] = [];
|
||||
getEffects(ship: Ship, target: Target, source = ship.location, luck?: RandomGenerator): [Ship, BaseEffect, number][] {
|
||||
let result: [Ship, BaseEffect, number][] = [];
|
||||
let ships = this.getImpactedShips(ship, target, source);
|
||||
ships.forEach(ship => {
|
||||
this.effects.forEach(effect => result.push([ship, effect]));
|
||||
ships.forEach(iship => {
|
||||
let success = luck ? this.getEffectiveSuccess(ship, iship, luck) : this.getSuccessFactor(ship, iship);
|
||||
this.effects.forEach(effect => result.push([iship, effect, success]));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
@ -157,9 +208,9 @@ module TK.SpaceTac {
|
|||
}
|
||||
|
||||
// Apply effects
|
||||
let effects = this.getEffects(ship, target);
|
||||
effects.forEach(([ship_target, effect]) => {
|
||||
let diffs = effect.getOnDiffs(ship_target, ship);
|
||||
let effects = this.getEffects(ship, target, undefined, RandomGenerator.global);
|
||||
effects.forEach(([ship_target, effect, success]) => {
|
||||
let diffs = effect.getOnDiffs(ship_target, ship, success);
|
||||
result = result.concat(diffs);
|
||||
});
|
||||
|
||||
|
@ -173,13 +224,22 @@ module TK.SpaceTac {
|
|||
|
||||
let info: string[] = [];
|
||||
if (this.power) {
|
||||
info.push(`power usage ${this.power}`);
|
||||
info.push(`power ${this.power}`);
|
||||
}
|
||||
if (this.range) {
|
||||
info.push(`max range ${this.range}km`);
|
||||
info.push(`range ${this.range}km`);
|
||||
}
|
||||
if (this.aim) {
|
||||
info.push(`aim +${this.aim}%`);
|
||||
}
|
||||
if (this.evasion) {
|
||||
info.push(`evasion -${this.evasion}%`);
|
||||
}
|
||||
if (this.luck) {
|
||||
info.push(`luck ±${this.luck}%`);
|
||||
}
|
||||
|
||||
let desc = `${this.getVerb()} (${info.join(", ")})`;
|
||||
let desc = (info.length) ? `${this.getVerb()} (${info.join(", ")})` : this.getVerb();
|
||||
let effects = this.effects.map(effect => {
|
||||
let suffix: string;
|
||||
if (this.blast) {
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
module TK.SpaceTac.Specs {
|
||||
testing("Maneuver", test => {
|
||||
function compare_maneuver_effects(check: TestContext, meff1: [Ship, BaseEffect][], meff2: [Ship, BaseEffect][]): void {
|
||||
let [ships1, effects1] = unzip(meff1);
|
||||
let [ships2, effects2] = unzip(meff2);
|
||||
check.equals(ships1, ships2, "impacted ships");
|
||||
compare_effects(check, effects1, effects2);
|
||||
function compare_maneuver_effects(check: TestContext, meff1: ManeuverEffect[], meff2: ManeuverEffect[]): void {
|
||||
check.equals(meff1.map(ef => ef.ship), meff2.map(ef => ef.ship), "impacted ships");
|
||||
compare_effects(check, meff1.map(ef => ef.effect), meff2.map(ef => ef.effect));
|
||||
check.equals(meff1.map(ef => ef.success), meff2.map(ef => ef.success), "success factor");
|
||||
}
|
||||
|
||||
test.case("guesses weapon effects", check => {
|
||||
|
@ -21,8 +20,8 @@ module TK.SpaceTac.Specs {
|
|||
TestTools.setShipHP(ship3, 30, 30);
|
||||
let maneuver = new Maneuver(ship1, nn(weapon.action), Target.newFromLocation(0, 0));
|
||||
compare_maneuver_effects(check, maneuver.effects, [
|
||||
[ship1, new DamageEffect(50)],
|
||||
[ship2, new DamageEffect(50)]
|
||||
{ ship: ship1, effect: new DamageEffect(50), success: 1 },
|
||||
{ ship: ship2, effect: new DamageEffect(50), success: 1 },
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -41,8 +40,8 @@ module TK.SpaceTac.Specs {
|
|||
TestTools.setShipHP(ship3, 30, 30);
|
||||
let maneuver = new Maneuver(ship1, weapon.action, Target.newFromLocation(0, 0));
|
||||
compare_maneuver_effects(check, maneuver.effects, [
|
||||
[ship1, new ValueEffect("shield", 10)],
|
||||
[ship2, new ValueEffect("shield", 10)]
|
||||
{ ship: ship1, effect: new ValueEffect("shield", 10), success: 1 },
|
||||
{ ship: ship2, effect: new ValueEffect("shield", 10), success: 1 },
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -66,7 +65,7 @@ module TK.SpaceTac.Specs {
|
|||
maneuver = new Maneuver(ship, move, Target.newFromLocation(100, 30));
|
||||
check.containing(maneuver.getFinalLocation(), { x: 100, y: 30 });
|
||||
compare_maneuver_effects(check, maneuver.effects, [
|
||||
[ship, new AttributeEffect("maneuvrability", 1)]
|
||||
{ ship: ship, effect: new AttributeEffect("maneuvrability", 1), success: 1 },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
module TK.SpaceTac {
|
||||
// Single effect of a maneuver
|
||||
export type ManeuverEffect = {
|
||||
ship: Ship
|
||||
effect: BaseEffect
|
||||
success: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Ship maneuver for an artifical intelligence
|
||||
*
|
||||
|
@ -21,7 +28,7 @@ module TK.SpaceTac {
|
|||
simulation: MoveFireResult
|
||||
|
||||
// List of guessed effects of this maneuver
|
||||
effects: [Ship, BaseEffect][]
|
||||
effects: ManeuverEffect[]
|
||||
|
||||
constructor(ship: Ship, action: BaseAction, target: Target, move_margin = 1) {
|
||||
this.ship = ship;
|
||||
|
@ -74,16 +81,18 @@ module TK.SpaceTac {
|
|||
/**
|
||||
* Guess what will be the effects applied on any ship by this maneuver
|
||||
*/
|
||||
guessEffects(): [Ship, BaseEffect][] {
|
||||
let result: [Ship, BaseEffect][] = [];
|
||||
guessEffects(): ManeuverEffect[] {
|
||||
let result: ManeuverEffect[] = [];
|
||||
|
||||
// Effects of weapon
|
||||
if (this.action instanceof TriggerAction) {
|
||||
result = result.concat(this.action.getEffects(this.ship, this.target));
|
||||
this.action.getEffects(this.ship, this.target).forEach(([ship, effect, success]) => {
|
||||
result.push({ ship: ship, effect: effect, success: success });
|
||||
})
|
||||
} else if (this.action instanceof DeployDroneAction) {
|
||||
let ships = this.battle.collectShipsInCircle(this.target, this.action.drone_radius, true);
|
||||
this.action.drone_effects.forEach(effect => {
|
||||
result = result.concat(ships.map(ship => <[Ship, BaseEffect]>[ship, effect]));
|
||||
result = result.concat(ships.map(ship => ({ ship: ship, effect: effect, success: 1 })));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -91,7 +100,9 @@ module TK.SpaceTac {
|
|||
let location = this.getFinalLocation();
|
||||
let effects = this.battle.drones.list().forEach(drone => {
|
||||
if (Target.newFromLocation(location.x, location.y).isInRange(drone.x, drone.y, drone.radius)) {
|
||||
result = result.concat(drone.effects.map(effect => <[Ship, BaseEffect]>[this.ship, effect]));
|
||||
result = result.concat(drone.effects.map(effect => (
|
||||
{ ship: this.ship, effect: effect, success: 1 }
|
||||
)));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -29,17 +29,17 @@ module TK.SpaceTac {
|
|||
let dhull = 0;
|
||||
let dshield = 0;
|
||||
|
||||
maneuver.effects.forEach(([iship, effect]) => {
|
||||
if (iship === ship) {
|
||||
if (effect instanceof DamageEffect) {
|
||||
let [ds, dh] = effect.getEffectiveDamage(ship);
|
||||
dhull -= dh;
|
||||
dshield -= ds;
|
||||
} else if (effect instanceof ValueEffect) {
|
||||
if (effect.valuetype == "hull") {
|
||||
dhull = clamp(hull + effect.value_on, 0, chull) - hull;
|
||||
} else if (effect.valuetype == "shield") {
|
||||
dshield += clamp(shield + effect.value_on, 0, cshield) - shield;
|
||||
maneuver.effects.forEach(result => {
|
||||
if (result.ship === ship) {
|
||||
if (result.effect instanceof DamageEffect) {
|
||||
let damage = result.effect.getEffectiveDamage(ship, result.success);
|
||||
dhull -= damage.hull;
|
||||
dshield -= damage.shield;
|
||||
} else if (result.effect instanceof ValueEffect) {
|
||||
if (result.effect.valuetype == "hull") {
|
||||
dhull = clamp(hull + result.effect.value_on, 0, chull) - hull;
|
||||
} else if (result.effect.valuetype == "shield") {
|
||||
dshield += clamp(shield + result.effect.value_on, 0, cshield) - shield;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,11 +13,15 @@ module TK.SpaceTac {
|
|||
// Damage to shield
|
||||
shield: number
|
||||
|
||||
constructor(ship: Ship, hull: number, shield: number) {
|
||||
// Theoretical damage value
|
||||
theoretical: number
|
||||
|
||||
constructor(ship: Ship, hull: number, shield: number, theoretical = hull + shield) {
|
||||
super(ship);
|
||||
|
||||
this.hull = hull;
|
||||
this.shield = shield;
|
||||
this.theoretical = theoretical;
|
||||
}
|
||||
|
||||
protected applyOnShip(ship: Ship, battle: Battle): void {
|
||||
|
|
|
@ -6,11 +6,11 @@ module TK.SpaceTac {
|
|||
check.equals(ship.getAttribute("maneuvrability"), 0, "initial");
|
||||
|
||||
let effect1 = new AttributeEffect("maneuvrability", 20);
|
||||
battle.applyDiffs(effect1.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect1.getOnDiffs(ship, ship, 1));
|
||||
check.equals(ship.getAttribute("maneuvrability"), 20, "applied 1");
|
||||
|
||||
let effect2 = new AttributeEffect("maneuvrability", 10);
|
||||
battle.applyDiffs(effect2.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect2.getOnDiffs(ship, ship, 1));
|
||||
check.equals(ship.getAttribute("maneuvrability"), 30, "applied 2");
|
||||
|
||||
battle.applyDiffs(effect1.getOffDiffs(ship));
|
||||
|
|
|
@ -20,7 +20,7 @@ module TK.SpaceTac {
|
|||
this.value = value;
|
||||
}
|
||||
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
|
||||
return [
|
||||
new ShipAttributeDiff(ship, this.attrcode, { cumulative: this.value }, {}),
|
||||
];
|
||||
|
|
|
@ -7,11 +7,11 @@ module TK.SpaceTac {
|
|||
check.equals(ship.getAttribute("precision"), 12, "initial");
|
||||
|
||||
let effect1 = new AttributeLimitEffect("precision", 5);
|
||||
battle.applyDiffs(effect1.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect1.getOnDiffs(ship, ship, 1));
|
||||
check.equals(ship.getAttribute("precision"), 5, "applied 1");
|
||||
|
||||
let effect2 = new AttributeLimitEffect("precision", 3);
|
||||
battle.applyDiffs(effect2.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect2.getOnDiffs(ship, ship, 1));
|
||||
check.equals(ship.getAttribute("precision"), 3, "applied 2");
|
||||
|
||||
battle.applyDiffs(effect1.getOffDiffs(ship));
|
||||
|
|
|
@ -20,7 +20,7 @@ module TK.SpaceTac {
|
|||
this.value = value;
|
||||
}
|
||||
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
|
||||
return [
|
||||
new ShipAttributeDiff(ship, this.attrcode, { limit: this.value }, {}),
|
||||
];
|
||||
|
|
|
@ -7,11 +7,11 @@ module TK.SpaceTac {
|
|||
check.equals(ship.getAttribute("hull_capacity"), 100, "initial");
|
||||
|
||||
let effect1 = new AttributeMultiplyEffect("hull_capacity", 30);
|
||||
battle.applyDiffs(effect1.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect1.getOnDiffs(ship, ship, 1));
|
||||
check.equals(ship.getAttribute("hull_capacity"), 130, "applied 1");
|
||||
|
||||
let effect2 = new AttributeMultiplyEffect("hull_capacity", -10);
|
||||
battle.applyDiffs(effect2.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect2.getOnDiffs(ship, ship, 1));
|
||||
check.equals(ship.getAttribute("hull_capacity"), 120, "applied 2");
|
||||
|
||||
battle.applyDiffs(effect1.getOffDiffs(ship));
|
||||
|
|
|
@ -21,7 +21,7 @@ module TK.SpaceTac {
|
|||
this.value = value;
|
||||
}
|
||||
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
|
||||
return [
|
||||
new ShipAttributeDiff(ship, this.attrcode, { multiplier: this.value }, {}),
|
||||
];
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
module TK.SpaceTac.Specs {
|
||||
testing("BaseEffect", test => {
|
||||
test.case("gets a fixed or variable amount", check => {
|
||||
let effect = new BaseEffect("test");
|
||||
|
||||
check.equals(effect.resolveAmount(50), 50);
|
||||
check.equals(effect.resolveAmount({ base: 20, span: 10 }, new SkewedRandomGenerator([0.3])), 23);
|
||||
check.equals(effect.resolveAmount({ base: 20, span: 0 }, new SkewedRandomGenerator([0.3])), 20);
|
||||
})
|
||||
})
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
/// <reference path="../diffs/BaseBattleDiff.ts" />
|
||||
|
||||
module TK.SpaceTac {
|
||||
export type EffectAmount = number | { base: number, span: number };
|
||||
|
||||
/**
|
||||
* Base class for effects of actions that can be applied on ships
|
||||
*
|
||||
|
@ -21,7 +19,7 @@ module TK.SpaceTac {
|
|||
/**
|
||||
* Get the list of diffs needed to activate this effect on a ship
|
||||
*/
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone, success = 1): BaseBattleDiff[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
@ -60,18 +58,5 @@ module TK.SpaceTac {
|
|||
getDescription(): string {
|
||||
return "unknown effect";
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve an effect amount
|
||||
*/
|
||||
resolveAmount(val: EffectAmount, random = RandomGenerator.global): number {
|
||||
if (typeof val == "number") {
|
||||
return val;
|
||||
} else if (val.span) {
|
||||
return random.randInt(val.base, val.base + val.span);
|
||||
} else {
|
||||
return val.base;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,24 +8,24 @@ module TK.SpaceTac {
|
|||
check.equals(weapons.map(weapon => weapon.cooldown.heat), [0, 0, 0]);
|
||||
|
||||
let effect = new CooldownEffect(0, 0);
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
|
||||
check.equals(weapons.map(weapon => weapon.cooldown.heat), [0, 0, 0]);
|
||||
|
||||
weapons.forEach(weapon => weapon.cooldown.use());
|
||||
check.equals(weapons.map(weapon => weapon.cooldown.heat), [3, 3, 3]);
|
||||
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
|
||||
check.equals(weapons.map(weapon => weapon.cooldown.heat), [0, 0, 0]);
|
||||
|
||||
weapons.forEach(weapon => weapon.cooldown.use());
|
||||
check.equals(weapons.map(weapon => weapon.cooldown.heat), [3, 3, 3]);
|
||||
|
||||
effect = new CooldownEffect(1, 0);
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
|
||||
check.equals(weapons.map(weapon => weapon.cooldown.heat), [2, 2, 2]);
|
||||
|
||||
effect = new CooldownEffect(1, 2);
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
|
||||
check.equals(weapons.map(weapon => weapon.cooldown.heat).sort(), [1, 1, 2]);
|
||||
})
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ module TK.SpaceTac {
|
|||
this.maxcount = maxcount;
|
||||
}
|
||||
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
|
||||
let equipments = ship.listEquipment().filter(equ => equ.cooldown.heat > 0);
|
||||
|
||||
if (this.maxcount && equipments.length > this.maxcount) {
|
||||
|
|
|
@ -20,16 +20,16 @@ module TK.SpaceTac.Specs {
|
|||
|
||||
checkValues("initial", 150, 400, 0, 0);
|
||||
|
||||
battle.applyDiffs(new DamageEffect(50).getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(new DamageEffect(50).getOnDiffs(ship, ship, 1));
|
||||
checkValues("after 50 damage", 150, 350, 0, 5);
|
||||
|
||||
battle.applyDiffs(new DamageEffect(250).getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(new DamageEffect(250).getOnDiffs(ship, ship, 1));
|
||||
checkValues("after 250 damage", 150, 100, 0, 30);
|
||||
|
||||
battle.applyDiffs(new DamageEffect(201).getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(new DamageEffect(201).getOnDiffs(ship, ship, 1));
|
||||
checkValues("after 201 damage", 49, 0, 11, 40);
|
||||
|
||||
battle.applyDiffs(new DamageEffect(8000).getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(new DamageEffect(8000).getOnDiffs(ship, ship, 1));
|
||||
checkValues("after 8000 damage", 0, 0, 16, 40);
|
||||
});
|
||||
|
||||
|
@ -43,7 +43,7 @@ module TK.SpaceTac.Specs {
|
|||
TestTools.setShipHP(ship, 1000, 1000);
|
||||
let damage = new DamageEffect(200);
|
||||
|
||||
check.equals(damage.getEffectiveDamage(ship), [200, 0]);
|
||||
check.equals(damage.getEffectiveDamage(ship, 1), new ShipDamageDiff(ship, 0, 200));
|
||||
|
||||
check.patch(ship, "ieffects", iterator([
|
||||
isingle(new DamageModifierEffect(-15)),
|
||||
|
@ -54,14 +54,14 @@ module TK.SpaceTac.Specs {
|
|||
isingle(new DamageModifierEffect(3))
|
||||
]));
|
||||
|
||||
check.equals(damage.getEffectiveDamage(ship), [170, 0]);
|
||||
check.equals(damage.getEffectiveDamage(ship), [240, 0]);
|
||||
check.equals(damage.getEffectiveDamage(ship), [0, 0]);
|
||||
check.equals(damage.getEffectiveDamage(ship), [400, 0]);
|
||||
check.equals(damage.getEffectiveDamage(ship), [190, 0]);
|
||||
check.equals(damage.getEffectiveDamage(ship, 1), new ShipDamageDiff(ship, 0, 170));
|
||||
check.equals(damage.getEffectiveDamage(ship, 1), new ShipDamageDiff(ship, 0, 240));
|
||||
check.equals(damage.getEffectiveDamage(ship, 1), new ShipDamageDiff(ship, 0, 0));
|
||||
check.equals(damage.getEffectiveDamage(ship, 1), new ShipDamageDiff(ship, 0, 400));
|
||||
check.equals(damage.getEffectiveDamage(ship, 1), new ShipDamageDiff(ship, 0, 190));
|
||||
|
||||
damage = new DamageEffect(40);
|
||||
check.equals(damage.getEffectiveDamage(ship), [41, 0]);
|
||||
check.equals(damage.getEffectiveDamage(ship, 1), new ShipDamageDiff(ship, 0, 41));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,10 +8,10 @@ module TK.SpaceTac {
|
|||
*/
|
||||
export class DamageEffect extends BaseEffect {
|
||||
// Base damage points
|
||||
base: number;
|
||||
base: number
|
||||
|
||||
// Range of randomness (effective damage will be between *value* and *value+range*)
|
||||
span: number;
|
||||
span: number
|
||||
|
||||
constructor(value = 0, span = 0) {
|
||||
super("damage");
|
||||
|
@ -36,47 +36,36 @@ module TK.SpaceTac {
|
|||
/**
|
||||
* Get the effective damage done to both shield and hull (in this order)
|
||||
*/
|
||||
getEffectiveDamage(ship: Ship): [number, number] {
|
||||
var damage = (this.span > 0) ? RandomGenerator.global.randInt(this.base, this.base + this.span) : this.base;
|
||||
var hull: number;
|
||||
var shield: number;
|
||||
|
||||
getEffectiveDamage(ship: Ship, success: number): ShipDamageDiff {
|
||||
// Apply modifiers
|
||||
damage = Math.round(damage * this.getFactor(ship));
|
||||
let theoritical = Math.round((this.base + this.span * success) * this.getFactor(ship));
|
||||
let damage = theoritical;
|
||||
|
||||
// Apply on shields
|
||||
if (damage >= ship.getValue("shield")) {
|
||||
shield = ship.getValue("shield");
|
||||
} else {
|
||||
shield = damage;
|
||||
}
|
||||
let shield = (damage >= ship.getValue("shield")) ? ship.getValue("shield") : damage;
|
||||
damage -= shield;
|
||||
|
||||
// Apply on hull
|
||||
if (damage >= ship.getValue("hull")) {
|
||||
hull = ship.getValue("hull");
|
||||
} else {
|
||||
hull = damage;
|
||||
}
|
||||
let hull = (damage >= ship.getValue("hull")) ? ship.getValue("hull") : damage;
|
||||
|
||||
return [shield, hull];
|
||||
return new ShipDamageDiff(ship, hull, shield, theoritical);
|
||||
}
|
||||
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
|
||||
let [shield, hull] = this.getEffectiveDamage(ship);
|
||||
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
|
||||
let result: BaseBattleDiff[] = [];
|
||||
|
||||
if (shield || hull) {
|
||||
result.push(new ShipDamageDiff(ship, hull, shield));
|
||||
let damage = this.getEffectiveDamage(ship, success);
|
||||
|
||||
if (damage.shield || damage.hull) {
|
||||
result.push(damage);
|
||||
}
|
||||
|
||||
if (shield) {
|
||||
result.push(new ShipValueDiff(ship, "shield", -shield));
|
||||
if (damage.shield) {
|
||||
result.push(new ShipValueDiff(ship, "shield", -damage.shield));
|
||||
}
|
||||
|
||||
if (hull) {
|
||||
result.push(new ShipValueDiff(ship, "hull", -hull));
|
||||
if (damage.hull) {
|
||||
result.push(new ShipValueDiff(ship, "hull", -damage.hull));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -14,9 +14,9 @@ module TK.SpaceTac.Specs {
|
|||
ship2a.setArenaPosition(100, 280);
|
||||
|
||||
let effect = new RepelEffect(12);
|
||||
battle.applyDiffs(effect.getOnDiffs(ship1a, ship1a));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship1b, ship1a));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship2a, ship1a));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship1a, ship1a, 1));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship1b, ship1a, 1));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship2a, ship1a, 1));
|
||||
|
||||
check.equals(ship1a.location, new ArenaLocationAngle(100, 100));
|
||||
check.equals(ship1b.location, new ArenaLocationAngle(262, 100));
|
||||
|
@ -33,7 +33,7 @@ module TK.SpaceTac.Specs {
|
|||
ship2b.setArenaPosition(100, 350);
|
||||
|
||||
let effect = new RepelEffect(85);
|
||||
battle.applyDiffs(effect.getOnDiffs(ship2a, ship1a));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship2a, ship1a, 1));
|
||||
check.equals(ship2a.location, new ArenaLocationAngle(100, 250));
|
||||
})
|
||||
})
|
||||
|
|
|
@ -13,7 +13,7 @@ module TK.SpaceTac {
|
|||
this.value = value;
|
||||
}
|
||||
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
|
||||
if (ship != source) {
|
||||
let angle = arenaAngle(source.location, ship.location);
|
||||
let destination = new ArenaLocation(ship.arena_x + Math.cos(angle) * this.value, ship.arena_y + Math.sin(angle) * this.value);
|
||||
|
|
|
@ -10,7 +10,7 @@ module TK.SpaceTac.Specs {
|
|||
})
|
||||
|
||||
let effect = new StickyEffect(new AttributeEffect("precision", 1), 2);
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
|
||||
|
||||
check.in("after", check => {
|
||||
check.equals(ship.active_effects.count(), 1, "one sticky effect");
|
||||
|
@ -25,7 +25,7 @@ module TK.SpaceTac.Specs {
|
|||
}
|
||||
})
|
||||
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
|
||||
|
||||
check.in("after second apply", check => {
|
||||
check.equals(ship.active_effects.count(), 1, "one sticky effect");
|
||||
|
|
|
@ -21,7 +21,7 @@ module TK.SpaceTac {
|
|||
this.duration = duration;
|
||||
}
|
||||
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
|
||||
let result: BaseBattleDiff[] = [];
|
||||
|
||||
let previous = ship.active_effects.get(this.id);
|
||||
|
|
|
@ -8,10 +8,10 @@ module TK.SpaceTac {
|
|||
ship.setValue("shield", 55);
|
||||
check.equals(ship.getValue("shield"), 55);
|
||||
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
|
||||
check.equals(ship.getValue("shield"), 75);
|
||||
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
|
||||
check.equals(ship.getValue("shield"), 95);
|
||||
});
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ module TK.SpaceTac {
|
|||
this.value_end = value_end;
|
||||
}
|
||||
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
|
||||
if (this.value_on) {
|
||||
return ship.getValueDiffs(this.valuetype, this.value_on, true);
|
||||
} else {
|
||||
|
|
|
@ -9,12 +9,12 @@ module TK.SpaceTac.Specs {
|
|||
TestTools.setShipHP(ship2, 100, 50);
|
||||
|
||||
let effect = new ValueTransferEffect("hull", -30);
|
||||
battle.applyDiffs(effect.getOnDiffs(ship2, ship1));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship2, ship1, 1));
|
||||
check.equals(ship1.getValue("hull"), 40);
|
||||
check.equals(ship2.getValue("hull"), 70);
|
||||
|
||||
effect = new ValueTransferEffect("hull", 1000);
|
||||
battle.applyDiffs(effect.getOnDiffs(ship2, ship1));
|
||||
battle.applyDiffs(effect.getOnDiffs(ship2, ship1, 1));
|
||||
check.equals(ship1.getValue("hull"), 0);
|
||||
check.equals(ship2.getValue("hull"), 110); // over limit but will be fixed later
|
||||
})
|
||||
|
|
|
@ -18,10 +18,10 @@ module TK.SpaceTac {
|
|||
this.amount = amount;
|
||||
}
|
||||
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
|
||||
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
|
||||
if (source instanceof Ship) {
|
||||
if (this.amount < 0) {
|
||||
return new ValueTransferEffect(this.valuetype, -this.amount).getOnDiffs(source, ship);
|
||||
return new ValueTransferEffect(this.valuetype, -this.amount).getOnDiffs(source, ship, success);
|
||||
} else {
|
||||
let amount = Math.min(source.getValue(this.valuetype), this.amount);
|
||||
if (amount) {
|
||||
|
|
|
@ -5,25 +5,25 @@ module TK.SpaceTac.Specs {
|
|||
|
||||
let equipment = template.generate(1);
|
||||
check.equals(equipment.requirements, { "skill_materials": 1 });
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(30, 20)], 3, 400, 0));
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(30, 20)], 3, 400, 0, 0, 60, 20, 15));
|
||||
check.equals(equipment.price, 100);
|
||||
check.equals(equipment.cooldown, new Cooldown(2, 2));
|
||||
|
||||
equipment = template.generate(2);
|
||||
check.equals(equipment.requirements, { "skill_materials": 2 });
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(42, 28)], 3, 412, 0));
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(42, 28)], 3, 412, 0, 0, 60, 20, 15));
|
||||
check.equals(equipment.price, 350);
|
||||
check.equals(equipment.cooldown, new Cooldown(2, 2));
|
||||
|
||||
equipment = template.generate(3);
|
||||
check.equals(equipment.requirements, { "skill_materials": 4 });
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(56, 37)], 3, 426, 0));
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(56, 37)], 3, 426, 0, 0, 60, 20, 15));
|
||||
check.equals(equipment.price, 850);
|
||||
check.equals(equipment.cooldown, new Cooldown(2, 2));
|
||||
|
||||
equipment = template.generate(10);
|
||||
check.equals(equipment.requirements, { "skill_materials": 23 });
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(224, 149)], 3, 594, 0));
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(224, 149)], 3, 594, 0, 0, 60, 20, 15));
|
||||
check.equals(equipment.price, 11350);
|
||||
check.equals(equipment.cooldown, new Cooldown(2, 2));
|
||||
});
|
||||
|
@ -33,25 +33,25 @@ module TK.SpaceTac.Specs {
|
|||
|
||||
let equipment = template.generate(1);
|
||||
check.equals(equipment.requirements, { "skill_materials": 1, "skill_photons": 1 });
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(26, 4)], 4, 500, 150));
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(26, 4)], 4, 500, 150, 0, 30, 40, 10));
|
||||
check.equals(equipment.cooldown, new Cooldown(1, 0));
|
||||
check.equals(equipment.price, 163);
|
||||
|
||||
equipment = template.generate(2);
|
||||
check.equals(equipment.requirements, { "skill_materials": 2, "skill_photons": 1 });
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(28, 5)], 4, 520, 155));
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(28, 5)], 4, 520, 155, 0, 30, 40, 10));
|
||||
check.equals(equipment.cooldown, new Cooldown(1, 0));
|
||||
check.equals(equipment.price, 570);
|
||||
|
||||
equipment = template.generate(3);
|
||||
check.equals(equipment.requirements, { "skill_materials": 3, "skill_photons": 2 });
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(30, 6)], 4, 544, 161));
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(30, 6)], 4, 544, 161, 0, 30, 40, 10));
|
||||
check.equals(equipment.cooldown, new Cooldown(1, 0));
|
||||
check.equals(equipment.price, 1385);
|
||||
|
||||
equipment = template.generate(10);
|
||||
check.equals(equipment.requirements, { "skill_materials": 20, "skill_photons": 13 });
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(58, 20)], 4, 824, 231));
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(58, 20)], 4, 824, 231, 0, 30, 40, 10));
|
||||
check.equals(equipment.cooldown, new Cooldown(1, 0));
|
||||
check.equals(equipment.price, 18500);
|
||||
});
|
||||
|
@ -61,25 +61,25 @@ module TK.SpaceTac.Specs {
|
|||
|
||||
let equipment = template.generate(1);
|
||||
check.equals(equipment.requirements, { "skill_photons": 1, "skill_quantum": 1 });
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(20, 25)], 5, 300, 0, 40));
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(20, 25)], 5, 300, 0, 40, 45, 60, 20));
|
||||
check.equals(equipment.cooldown, new Cooldown(1, 1));
|
||||
check.equals(equipment.price, 152);
|
||||
|
||||
equipment = template.generate(2);
|
||||
check.equals(equipment.requirements, { "skill_antimatter": 1, "skill_photons": 2, "skill_quantum": 2 });
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(28, 35)], 5, 310, 0, 42));
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(28, 35)], 5, 310, 0, 42, 45, 60, 20));
|
||||
check.equals(equipment.cooldown, new Cooldown(1, 1));
|
||||
check.equals(equipment.price, 532);
|
||||
|
||||
equipment = template.generate(3);
|
||||
check.equals(equipment.requirements, { "skill_antimatter": 1, "skill_photons": 4, "skill_quantum": 3 });
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(37, 47)], 5, 322, 0, 44));
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(37, 47)], 5, 322, 0, 44, 45, 60, 20));
|
||||
check.equals(equipment.cooldown, new Cooldown(1, 1));
|
||||
check.equals(equipment.price, 1292);
|
||||
|
||||
equipment = template.generate(10);
|
||||
check.equals(equipment.requirements, { "skill_antimatter": 11, "skill_photons": 23, "skill_quantum": 20 });
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(149, 187)], 5, 462, 0, 72));
|
||||
compare_trigger_action(check, equipment.action, new TriggerAction(equipment, [new DamageEffect(149, 187)], 5, 462, 0, 72, 45, 60, 20));
|
||||
check.equals(equipment.cooldown, new Cooldown(1, 1));
|
||||
check.equals(equipment.price, 17252);
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ module TK.SpaceTac.Equipments {
|
|||
this.setCooldown(irepeat(2), irepeat(2));
|
||||
this.addTriggerAction(irepeat(3), [
|
||||
new EffectTemplate(new DamageEffect(), { base: leveled(30), span: leveled(20) })
|
||||
], leveled(400, 12));
|
||||
], leveled(400, 12), undefined, undefined, irepeat(60), irepeat(20), irepeat(15));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ module TK.SpaceTac.Equipments {
|
|||
this.setCooldown(irepeat(1), irepeat(0));
|
||||
this.addTriggerAction(irepeat(4), [
|
||||
new EffectTemplate(new DamageEffect(), { base: leveled(26, 2), span: leveled(4, 1) })
|
||||
], leveled(500, 20), leveled(150, 5));
|
||||
], leveled(500, 20), leveled(150, 5), undefined, irepeat(30), irepeat(40), irepeat(10));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ module TK.SpaceTac.Equipments {
|
|||
this.setCooldown(irepeat(1), irepeat(1));
|
||||
this.addTriggerAction(irepeat(5), [
|
||||
new EffectTemplate(new DamageEffect(), { base: leveled(20), span: leveled(25) })
|
||||
], leveled(300, 10), irepeat(0), leveled(40, 2));
|
||||
], leveled(300, 10), irepeat(0), leveled(40, 2), irepeat(45), irepeat(60), irepeat(20));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ module TK.SpaceTac.UI.Specs {
|
|||
ActionTooltip.fill(tooltip.getFiller(), ship, action2, 1);
|
||||
checkText(check, (<any>tooltip).container.content.children[1], "Weapon");
|
||||
checkText(check, (<any>tooltip).container.content.children[2], "Cost: 2 power");
|
||||
checkText(check, (<any>tooltip).container.content.children[3], "Fire (power usage 2, max range 50km):\n• do 12 damage on target");
|
||||
checkText(check, (<any>tooltip).container.content.children[3], "Fire (power 2, range 50km):\n• do 12 damage on target");
|
||||
checkText(check, (<any>tooltip).container.content.children[4], "[ 2 ]");
|
||||
|
||||
tooltip.hide();
|
||||
|
|
|
@ -68,7 +68,8 @@ module TK.SpaceTac.UI {
|
|||
// Add stasis effect
|
||||
this.stasis = this.battleview.newImage("battle-hud-ship-stasis");
|
||||
this.stasis.anchor.set(0.5, 0.5);
|
||||
this.stasis.visible = false;
|
||||
this.stasis.alpha = 0.9;
|
||||
this.stasis.visible = !ship.alive;
|
||||
this.add(this.stasis);
|
||||
|
||||
// HSP display
|
||||
|
@ -202,7 +203,7 @@ module TK.SpaceTac.UI {
|
|||
return {
|
||||
background: async (animate, timer) => {
|
||||
if (animate) {
|
||||
await this.displayEffect(`${diff.hull + diff.shield} damage`, false);
|
||||
await this.displayEffect(`${diff.theoretical} damage`, false);
|
||||
await timer.sleep(1000);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,11 +55,11 @@ module TK.SpaceTac.UI {
|
|||
this.impact_area = new Phaser.Graphics(view.game);
|
||||
this.impact_area.visible = false;
|
||||
|
||||
this.container.add(this.impact_indicators);
|
||||
this.container.add(this.impact_area);
|
||||
this.container.add(this.drawn_info);
|
||||
this.container.add(this.move_ghost);
|
||||
this.container.add(this.fire_arrow);
|
||||
this.container.add(this.impact_indicators);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,7 +117,7 @@ module TK.SpaceTac.UI {
|
|||
}
|
||||
|
||||
/**
|
||||
* Update impact indicators (highlighting impacted ships)
|
||||
* Update impact indicators (highlighting impacted ships, with success factor)
|
||||
*/
|
||||
updateImpactIndicators(impacts: Phaser.Group, ship: Ship, action: BaseAction, target: Target, source: IArenaLocation = ship.location): void {
|
||||
let ships = action.getImpactedShips(ship, target, source);
|
||||
|
@ -125,9 +125,18 @@ module TK.SpaceTac.UI {
|
|||
// TODO differential
|
||||
impacts.removeAll(true);
|
||||
ships.forEach(iship => {
|
||||
let indicator = this.view.newImage("battle-hud-ship-impacted", iship.arena_x, iship.arena_y);
|
||||
indicator.anchor.set(0.5);
|
||||
impacts.add(indicator);
|
||||
let builder = new UIBuilder(this.view, impacts);
|
||||
|
||||
let indicator = builder.image("battle-hud-ship-impacted", iship.arena_x, iship.arena_y);
|
||||
indicator.anchor.set(0.5, 0.5);
|
||||
|
||||
if (action instanceof TriggerAction) {
|
||||
let success = action.getSuccessFactor(ship, iship);
|
||||
builder.in(indicator, builder => {
|
||||
builder.text(`${Math.round(success * 100)}%`, 0, -32,
|
||||
{ center: true, color: "#c69b70", size: 14, shadow: true });
|
||||
});
|
||||
}
|
||||
});
|
||||
impacts.visible = true;
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue