1
0
Fork 0

Removed randomness factors in battle actions

This commit is contained in:
Michaël Lemaire 2018-03-21 00:23:00 +01:00
parent 28e2f889bd
commit 3d6bc192d0
39 changed files with 91 additions and 306 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 B

View file

@ -10,8 +10,6 @@ module TK.SpaceTac.Specs {
var action = new MoveAction("Engine", { distance_per_power: 10 });
ship.actions.addCustom(action);
check.equals(action.getDistanceByPower(ship), 10);
var result = action.checkTarget(ship, Target.newFromLocation(0, 20));
check.equals(result, Target.newFromLocation(0, 20));
@ -120,35 +118,12 @@ module TK.SpaceTac.Specs {
check.equals(result, Target.newFromLocation(0, 1400));
});
test.case("applies ship maneuvrability to determine distance per power point", check => {
let ship = new Ship();
let action = new MoveAction("Engine", { distance_per_power: 100, maneuvrability_factor: 60 });
TestTools.setAttribute(ship, "maneuvrability", 0);
check.nears(action.getDistanceByPower(ship), 40);
TestTools.setAttribute(ship, "maneuvrability", 1);
check.nears(action.getDistanceByPower(ship), 60);
TestTools.setAttribute(ship, "maneuvrability", 2);
check.nears(action.getDistanceByPower(ship), 70);
TestTools.setAttribute(ship, "maneuvrability", 10);
check.nears(action.getDistanceByPower(ship), 90);
action = new MoveAction("Engine", { distance_per_power: 100, maneuvrability_factor: 0 });
TestTools.setAttribute(ship, "maneuvrability", 0);
check.nears(action.getDistanceByPower(ship), 100);
TestTools.setAttribute(ship, "maneuvrability", 10);
check.nears(action.getDistanceByPower(ship), 100);
});
test.case("builds a textual description", check => {
let action = new MoveAction("Engine", { distance_per_power: 58, safety_distance: 0 });
check.equals(action.getEffectsDescription(), "Move: 58km per power point");
action = new MoveAction("Engine", { distance_per_power: 58, safety_distance: 12 });
check.equals(action.getEffectsDescription(), "Move: 58km per power point (safety: 12km)");
action = new MoveAction("Engine", { distance_per_power: 58, safety_distance: 12, maneuvrability_factor: 80 });
check.equals(action.getEffectsDescription(), "Move: 12-58km per power point (safety: 12km)");
});
});
}

View file

@ -7,8 +7,6 @@ module TK.SpaceTac {
distance_per_power: number
// Safety distance from other ships
safety_distance: number
// Impact of maneuvrability (in % of distance)
maneuvrability_factor: number
}
/**
@ -68,9 +66,11 @@ module TK.SpaceTac {
}
getPowerUsage(ship: Ship, target: Target | null): number {
if (target) {
if (this.distance_per_power == 0) {
return Infinity;
} else if (target) {
let distance = Target.newFromShip(ship).getDistanceTo(target);
return Math.ceil(distance / this.getDistanceByPower(ship));
return Math.ceil(distance / this.distance_per_power);
} else {
return 0;
}
@ -84,27 +84,7 @@ module TK.SpaceTac {
* Get the distance reachable with a given power
*/
getRangeRadiusForPower(ship: Ship, power = ship.getValue("power")): number {
return power * this.getDistanceByPower(ship);
}
/**
* Get the distance range that may be traveled with 1 power point
*
* The actual range will then depend on the ship maneuvrability
*/
getDistanceRangeByPower(): IntegerRange {
let min_distance = Math.ceil(this.distance_per_power * (1 - this.maneuvrability_factor * 0.01));
return new IntegerRange(min_distance, this.distance_per_power);
}
/**
* Get the distance that may be traveled with 1 power point
*/
getDistanceByPower(ship: Ship): number {
let maneuvrability = Math.max(ship.getAttribute("maneuvrability"), 0);
let factor = maneuvrability / (maneuvrability + 2);
let range = this.getDistanceRangeByPower();
return range.getProportional(factor);
return power * this.distance_per_power;
}
/**
@ -147,9 +127,7 @@ module TK.SpaceTac {
}
getEffectsDescription(): string {
let range = this.getDistanceRangeByPower();
let rangeinfo = (range.max == range.min) ? `${range.min}` : `${range.min}-${range.max}`;
let result = `Move: ${rangeinfo}km per power point`;
let result = `Move: ${this.distance_per_power}km per power point`;
if (this.safety_distance) {
result += ` (safety: ${this.safety_distance}km)`;

View file

@ -34,7 +34,7 @@ module TK.SpaceTac.Specs {
action.apply(battle, ship, Target.newFromLocation(50, 50));
check.called(mock_apply, [
[ship2, ship, 1]
[ship2, ship]
]);
})
@ -82,82 +82,6 @@ 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("testaction", { aim: precision_factor, 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("testaction", { 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 action = new TriggerAction("testaction");
@ -206,20 +130,11 @@ module TK.SpaceTac.Specs {
action.configureTrigger({ effects: effects, power: 2, range: 120 });
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km):\n• precision +20% on target");
action.configureTrigger({ effects: effects, power: 2, range: 120, aim: 10 });
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km, aim +10%):\n• precision +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");
action.configureTrigger({ effects: effects, power: 2, range: 120, aim: 10, evasion: 35 });
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km, aim +10%, evasion -35%):\n• precision +20% on target");
action.configureTrigger({ effects: effects, power: 2, range: 120, aim: 10, evasion: 35, angle: 80 });
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km, aim +10%, evasion -35%):\n• precision +20% in 80° arc");
action.configureTrigger({ effects: effects, power: 2, range: 120, aim: 10, evasion: 35, blast: 100, angle: 80 });
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km, aim +10%, evasion -35%):\n• precision +20% in 100km radius");
action.configureTrigger({ effects: effects, power: 2, range: 120, aim: 10, evasion: 35, blast: 100, angle: 80, luck: 15 });
check.equals(action.getEffectsDescription(), "Fire (power 2, range 120km, aim +10%, evasion -35%, luck ±15%):\n• precision +20% in 100km radius");
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");
})
});
}

View file

@ -15,12 +15,6 @@ module TK.SpaceTac {
blast: number
// 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 (0..100)
luck: number
}
/**
@ -34,9 +28,6 @@ module TK.SpaceTac {
range = 0
blast = 0
angle = 0
aim = 0
evasion = 0
luck = 0
constructor(name?: string, config?: Partial<TriggerActionConfig>, code?: string) {
super(name, code);
@ -99,42 +90,6 @@ 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);
@ -181,15 +136,12 @@ 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, luck?: RandomGenerator): [Ship, BaseEffect, number][] {
let result: [Ship, BaseEffect, number][] = [];
getEffects(ship: Ship, target: Target, source = ship.location): [Ship, BaseEffect][] {
let result: [Ship, BaseEffect][] = [];
let ships = this.getImpactedShips(ship, target, source);
ships.forEach(iship => {
let success = luck ? this.getEffectiveSuccess(ship, iship, luck) : this.getSuccessFactor(ship, iship);
this.effects.forEach(effect => result.push([iship, effect, success]));
this.effects.forEach(effect => result.push([iship, effect]));
});
return result;
}
@ -213,9 +165,9 @@ module TK.SpaceTac {
}
// Apply effects
let effects = this.getEffects(ship, target, undefined, RandomGenerator.global);
effects.forEach(([ship_target, effect, success]) => {
let diffs = effect.getOnDiffs(ship_target, ship, success);
let effects = this.getEffects(ship, target);
effects.forEach(([ship_target, effect]) => {
let diffs = effect.getOnDiffs(ship_target, ship);
result = result.concat(diffs);
});
@ -234,15 +186,6 @@ module TK.SpaceTac {
if (this.range) {
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 = (info.length) ? `${this.getVerb()} (${info.join(", ")})` : this.getVerb();
let effects = this.effects.map(effect => {

View file

@ -150,8 +150,7 @@ module TK.SpaceTac.Specs {
test.case("evaluates damage to enemies", check => {
let battle = new Battle();
let ship = battle.fleets[0].addShip();
let weapon = TestTools.addWeapon(ship, 50, 5, 500, 100);
let action = weapon;
let action = TestTools.addWeapon(ship, 50, 5, 500, 100);
let enemy1 = battle.fleets[1].addShip();
enemy1.setArenaPosition(250, 0);
@ -162,6 +161,7 @@ module TK.SpaceTac.Specs {
// no enemies hurt
let maneuver = new Maneuver(ship, action, Target.newFromLocation(100, 0));
console.log(maneuver)
check.nears(TacticalAIHelpers.evaluateEnemyHealth(ship, battle, maneuver), 0, 8);
// one enemy loses half-life

View file

@ -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, 1));
battle.applyDiffs(effect1.getOnDiffs(ship, ship));
check.equals(ship.getAttribute("maneuvrability"), 20, "applied 1");
let effect2 = new AttributeEffect("maneuvrability", 10);
battle.applyDiffs(effect2.getOnDiffs(ship, ship, 1));
battle.applyDiffs(effect2.getOnDiffs(ship, ship));
check.equals(ship.getAttribute("maneuvrability"), 30, "applied 2");
battle.applyDiffs(effect1.getOffDiffs(ship));

View file

@ -20,7 +20,7 @@ module TK.SpaceTac {
this.value = value;
}
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
return [
new ShipAttributeDiff(ship, this.attrcode, { cumulative: this.value }, {}),
];

View file

@ -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, 1));
battle.applyDiffs(effect1.getOnDiffs(ship, ship));
check.equals(ship.getAttribute("precision"), 5, "applied 1");
let effect2 = new AttributeLimitEffect("precision", 3);
battle.applyDiffs(effect2.getOnDiffs(ship, ship, 1));
battle.applyDiffs(effect2.getOnDiffs(ship, ship));
check.equals(ship.getAttribute("precision"), 3, "applied 2");
battle.applyDiffs(effect1.getOffDiffs(ship));

View file

@ -20,7 +20,7 @@ module TK.SpaceTac {
this.value = value;
}
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
return [
new ShipAttributeDiff(ship, this.attrcode, { limit: this.value }, {}),
];

View file

@ -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, 1));
battle.applyDiffs(effect1.getOnDiffs(ship, ship));
check.equals(ship.getAttribute("hull_capacity"), 130, "applied 1");
let effect2 = new AttributeMultiplyEffect("hull_capacity", -10);
battle.applyDiffs(effect2.getOnDiffs(ship, ship, 1));
battle.applyDiffs(effect2.getOnDiffs(ship, ship));
check.equals(ship.getAttribute("hull_capacity"), 120, "applied 2");
battle.applyDiffs(effect1.getOffDiffs(ship));

View file

@ -21,7 +21,7 @@ module TK.SpaceTac {
this.value = value;
}
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
return [
new ShipAttributeDiff(ship, this.attrcode, { multiplier: this.value }, {}),
];

View file

@ -19,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, success = 1): BaseBattleDiff[] {
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
return [];
}

View file

@ -8,24 +8,24 @@ module TK.SpaceTac {
check.equals(weapons.map(weapon => ship.actions.getCooldown(weapon).heat), [0, 0, 0]);
let effect = new CooldownEffect(0, 0);
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
battle.applyDiffs(effect.getOnDiffs(ship, ship));
check.equals(weapons.map(weapon => ship.actions.getCooldown(weapon).heat), [0, 0, 0]);
weapons.forEach(weapon => ship.actions.storeUsage(weapon));
check.equals(weapons.map(weapon => ship.actions.getCooldown(weapon).heat), [3, 3, 3]);
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
battle.applyDiffs(effect.getOnDiffs(ship, ship));
check.equals(weapons.map(weapon => ship.actions.getCooldown(weapon).heat), [0, 0, 0]);
weapons.forEach(weapon => ship.actions.storeUsage(weapon));
check.equals(weapons.map(weapon => ship.actions.getCooldown(weapon).heat), [3, 3, 3]);
effect = new CooldownEffect(1, 0);
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
battle.applyDiffs(effect.getOnDiffs(ship, ship));
check.equals(weapons.map(weapon => ship.actions.getCooldown(weapon).heat), [2, 2, 2]);
effect = new CooldownEffect(1, 2);
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
battle.applyDiffs(effect.getOnDiffs(ship, ship));
check.equals(weapons.map(weapon => ship.actions.getCooldown(weapon).heat).sort(), [1, 1, 2]);
})

View file

@ -18,7 +18,7 @@ module TK.SpaceTac {
this.maxcount = maxcount;
}
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
let actions = ship.actions.listOverheated();
if (this.maxcount && actions.length > this.maxcount) {

View file

@ -14,22 +14,21 @@ module TK.SpaceTac.Specs {
checkValues("initial", 150, 400);
battle.applyDiffs(new DamageEffect(50).getOnDiffs(ship, ship, 1));
battle.applyDiffs(new DamageEffect(50).getOnDiffs(ship, ship));
checkValues("after 50 damage", 150, 350);
battle.applyDiffs(new DamageEffect(250).getOnDiffs(ship, ship, 1));
battle.applyDiffs(new DamageEffect(250).getOnDiffs(ship, ship));
checkValues("after 250 damage", 150, 100);
battle.applyDiffs(new DamageEffect(201).getOnDiffs(ship, ship, 1));
battle.applyDiffs(new DamageEffect(201).getOnDiffs(ship, ship));
checkValues("after 201 damage", 49, 0);
battle.applyDiffs(new DamageEffect(8000).getOnDiffs(ship, ship, 1));
battle.applyDiffs(new DamageEffect(8000).getOnDiffs(ship, ship));
checkValues("after 8000 damage", 0, 0);
});
test.case("gets a textual description", check => {
check.equals(new DamageEffect(10).getDescription(), "do 10 damage");
check.equals(new DamageEffect(10, 5).getDescription(), "do 10-15 damage");
});
test.case("applies damage modifiers", check => {
@ -37,7 +36,7 @@ module TK.SpaceTac.Specs {
TestTools.setShipModel(ship, 1000, 1000);
let damage = new DamageEffect(200);
check.equals(damage.getEffectiveDamage(ship, 1), new ShipDamageDiff(ship, 0, 200));
check.equals(damage.getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 200));
check.patch(ship, "ieffects", iterator([
isingle(new DamageModifierEffect(-15)),
@ -48,14 +47,14 @@ module TK.SpaceTac.Specs {
isingle(new DamageModifierEffect(3))
]));
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));
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, 1), new ShipDamageDiff(ship, 0, 41));
check.equals(damage.getEffectiveDamage(ship), new ShipDamageDiff(ship, 0, 41));
});
});
}

View file

@ -8,16 +8,12 @@ module TK.SpaceTac {
*/
export class DamageEffect extends BaseEffect {
// Base damage points
base: number
value: number
// Range of randomness (effective damage will be between *value* and *value+range*)
span: number
constructor(value = 0, span = 0) {
constructor(value = 0) {
super("damage");
this.base = value;
this.span = span;
this.value = value;
}
/**
@ -36,9 +32,9 @@ module TK.SpaceTac {
/**
* Get the effective damage done to both shield and hull (in this order)
*/
getEffectiveDamage(ship: Ship, success: number): ShipDamageDiff {
getEffectiveDamage(ship: Ship): ShipDamageDiff {
// Apply modifiers
let theoritical = Math.round((this.base + this.span * success) * this.getFactor(ship));
let theoritical = Math.round(this.value * this.getFactor(ship));
let damage = theoritical;
// Apply on shields
@ -51,10 +47,10 @@ module TK.SpaceTac {
return new ShipDamageDiff(ship, hull, shield, theoritical);
}
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
let result: BaseBattleDiff[] = [];
let damage = this.getEffectiveDamage(ship, success);
let damage = this.getEffectiveDamage(ship);
if (damage.shield || damage.hull) {
result.push(damage);
@ -72,11 +68,7 @@ module TK.SpaceTac {
}
getDescription(): string {
if (this.span > 0) {
return `do ${this.base}-${this.base + this.span} damage`;
} else {
return `do ${this.base} damage`;
}
return `do ${this.value} damage`;
}
}
}

View file

@ -14,9 +14,9 @@ module TK.SpaceTac.Specs {
ship2a.setArenaPosition(100, 280);
let effect = new RepelEffect(12);
battle.applyDiffs(effect.getOnDiffs(ship1a, ship1a, 1));
battle.applyDiffs(effect.getOnDiffs(ship1b, ship1a, 1));
battle.applyDiffs(effect.getOnDiffs(ship2a, ship1a, 1));
battle.applyDiffs(effect.getOnDiffs(ship1a, ship1a));
battle.applyDiffs(effect.getOnDiffs(ship1b, ship1a));
battle.applyDiffs(effect.getOnDiffs(ship2a, ship1a));
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, 1));
battle.applyDiffs(effect.getOnDiffs(ship2a, ship1a));
check.equals(ship2a.location, new ArenaLocationAngle(100, 250));
})
})

View file

@ -13,7 +13,7 @@ module TK.SpaceTac {
this.value = value;
}
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
getOnDiffs(ship: Ship, source: Ship | Drone): 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);

View file

@ -10,7 +10,7 @@ module TK.SpaceTac.Specs {
})
let effect = new StickyEffect(new AttributeEffect("precision", 1), 2);
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
battle.applyDiffs(effect.getOnDiffs(ship, ship));
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, 1));
battle.applyDiffs(effect.getOnDiffs(ship, ship));
check.in("after second apply", check => {
check.equals(ship.active_effects.count(), 1, "one sticky effect");

View file

@ -21,7 +21,7 @@ module TK.SpaceTac {
this.duration = duration;
}
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
let result: BaseBattleDiff[] = [];
let previous = ship.active_effects.get(this.id);

View file

@ -8,10 +8,10 @@ module TK.SpaceTac {
ship.setValue("shield", 55);
check.equals(ship.getValue("shield"), 55);
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
battle.applyDiffs(effect.getOnDiffs(ship, ship));
check.equals(ship.getValue("shield"), 75);
battle.applyDiffs(effect.getOnDiffs(ship, ship, 1));
battle.applyDiffs(effect.getOnDiffs(ship, ship));
check.equals(ship.getValue("shield"), 95);
});

View file

@ -36,7 +36,7 @@ module TK.SpaceTac {
this.value_end = value_end;
}
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
if (this.value_on) {
return ship.getValueDiffs(this.valuetype, this.value_on, true);
} else {

View file

@ -9,12 +9,12 @@ module TK.SpaceTac.Specs {
TestTools.setShipModel(ship2, 100, 50);
let effect = new ValueTransferEffect("hull", -30);
battle.applyDiffs(effect.getOnDiffs(ship2, ship1, 1));
battle.applyDiffs(effect.getOnDiffs(ship2, ship1));
check.equals(ship1.getValue("hull"), 40);
check.equals(ship2.getValue("hull"), 70);
effect = new ValueTransferEffect("hull", 1000);
battle.applyDiffs(effect.getOnDiffs(ship2, ship1, 1));
battle.applyDiffs(effect.getOnDiffs(ship2, ship1));
check.equals(ship1.getValue("hull"), 0);
check.equals(ship2.getValue("hull"), 110); // over limit but will be fixed later
})

View file

@ -18,10 +18,10 @@ module TK.SpaceTac {
this.amount = amount;
}
getOnDiffs(ship: Ship, source: Ship | Drone, success: number): BaseBattleDiff[] {
getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] {
if (source instanceof Ship) {
if (this.amount < 0) {
return new ValueTransferEffect(this.valuetype, -this.amount).getOnDiffs(source, ship, success);
return new ValueTransferEffect(this.valuetype, -this.amount).getOnDiffs(source, ship);
} else {
let amount = Math.min(source.getValue(this.valuetype), this.amount);
if (amount) {

View file

@ -20,18 +20,16 @@ module TK.SpaceTac {
// TODO Weapons should be less efficient in short range
let charged_shot = new TriggerAction("Charged Shot", {
effects: [new DamageEffect(30, 20)],
effects: [new DamageEffect(40)],
power: 3,
range: 900,
aim: 90, evasion: 40, luck: 20
}, "gatlinggun");
charged_shot.configureCooldown(2, 2);
let long_range_missile = new TriggerAction("Long Range Missile", {
effects: [new DamageEffect(15, 25)],
effects: [new DamageEffect(27)],
power: 4,
range: 700, blast: 120,
aim: 70, evasion: 20, luck: 50
}, "submunitionmissile");
long_range_missile.configureCooldown(1, 2);

View file

@ -14,16 +14,14 @@ module TK.SpaceTac {
if (level == 1) {
let engine = new MoveAction("Engine", {
distance_per_power: 300,
safety_distance: 100,
maneuvrability_factor: 60
safety_distance: 100
});
engine.configureCooldown(2, 1);
let gatling = new TriggerAction("Gatling Gun", {
effects: [new DamageEffect(35, 20)],
effects: [new DamageEffect(45)],
power: 2,
range: 200,
aim: 30, evasion: 10, luck: 20
}, "gatlinggun");
gatling.configureCooldown(3, 1);

View file

@ -17,10 +17,9 @@ module TK.SpaceTac {
});
let laser = new TriggerAction("Wingspan Laser", {
effects: [new DamageEffect(25, 25)],
effects: [new DamageEffect(25)],
power: 4,
range: 250, angle: 140,
aim: 30, evasion: 45, luck: 30,
}, "prokhorovlaser");
laser.configureCooldown(3, 1);

View file

@ -17,7 +17,7 @@ module TK.SpaceTac {
});
let gatling = new TriggerAction("Gatling Gun", {
effects: [new DamageEffect(15, 10)],
effects: [new DamageEffect(20)],
power: 2,
range: 200,
}, "gatlinggun");

View file

@ -17,14 +17,14 @@ module TK.SpaceTac {
});
let missile = new TriggerAction("SubMunition Missile", {
effects: [new DamageEffect(10, 10)],
effects: [new DamageEffect(15)],
power: 2,
range: 250, blast: 150,
}, "submunitionmissile");
missile.configureCooldown(2, 2);
let gatling = new TriggerAction("Gatling Gun", {
effects: [new DamageEffect(10, 10)],
effects: [new DamageEffect(15)],
power: 1,
range: 350,
}, "gatlinggun");

View file

@ -24,7 +24,7 @@ module TK.SpaceTac {
depleter.configureCooldown(1, 1);
let gatling = new TriggerAction("Gatling Gun", {
effects: [new DamageEffect(5, 30)],
effects: [new DamageEffect(20)],
power: 3,
range: 300,
}, "gatlinggun");

View file

@ -18,10 +18,9 @@ module TK.SpaceTac {
});
let missile = new TriggerAction("SubMunition Missile", {
effects: [new DamageEffect(30, 30)],
effects: [new DamageEffect(30)],
power: 3,
range: 400, blast: 120,
aim: 70, evasion: 30, luck: 10,
}, "submunitionmissile");
let protector = new TriggerAction("Damage Reductor", {

View file

@ -17,17 +17,16 @@ module TK.SpaceTac {
});
let gatling = new TriggerAction("Gatling Gun", {
effects: [new DamageEffect(30, 20)],
effects: [new DamageEffect(40)],
power: 3,
range: 400,
}, "gatlinggun");
gatling.configureCooldown(2, 2);
let laser = new TriggerAction("Prokhorov Laser", {
effects: [new DamageEffect(25, 25)],
effects: [new DamageEffect(35)],
power: 4,
range: 250, angle: 60,
aim: 30, evasion: 45, luck: 30,
}, "prokhorovlaser");
return [

View file

@ -17,26 +17,26 @@ module TK.SpaceTac {
});
let gatling1 = new TriggerAction("Primary Gatling", {
effects: [new DamageEffect(15, 15)],
effects: [new DamageEffect(22)],
power: 2, range: 400
}, "gatlinggun");
gatling1.configureCooldown(1, 1);
let gatling2 = new TriggerAction("Secondary Gatling", {
effects: [new DamageEffect(20, 15)],
effects: [new DamageEffect(28)],
power: 1, range: 200
}, "gatlinggun");
gatling2.configureCooldown(1, 1);
let missile = new TriggerAction("Diffuse Missiles", {
effects: [new DamageEffect(10, 18)],
effects: [new DamageEffect(19)],
power: 2,
range: 200, blast: 100,
}, "submunitionmissile");
missile.configureCooldown(1, 1);
let laser = new TriggerAction("Low-power Laser", {
effects: [new DamageEffect(20, 20)],
effects: [new DamageEffect(26)],
power: 2,
range: 200, angle: 30
}, "prokhorovlaser");

View file

@ -31,7 +31,7 @@ module TK.SpaceTac {
depleter.configureCooldown(1, 1);
let missile = new TriggerAction("Defense Missiles", {
effects: [new DamageEffect(25, 30)],
effects: [new DamageEffect(40)],
power: 3,
range: 200, blast: 180,
}, "submunitionmissile");

View file

@ -17,10 +17,9 @@ module TK.SpaceTac {
});
let laser = new TriggerAction("Prokhorov Laser", {
effects: [new DamageEffect(20, 40)],
effects: [new DamageEffect(35)],
power: 3,
range: 250, angle: 80,
aim: 30, evasion: 45, luck: 30,
});
let hull = new TriggerAction("Hull Shedding", {

View file

@ -19,7 +19,7 @@ module TK.SpaceTac.UI {
if (ship.getValue("power") == 0) {
cost = "Not enough power";
} else {
cost = `Cost: 1 power per ${action.getDistanceByPower(ship)}km`;
cost = `Cost: 1 power per ${action.distance_per_power}km`;
}
} else {
let power_usage = action.getPowerUsage(ship, null);

View file

@ -112,7 +112,7 @@ module TK.SpaceTac.UI {
let move = part.action instanceof MoveAction;
let color = (enabled && part.possible) ? (move ? 0xe09c47 : 0xdc6441) : 0x8e8e8e;
let src = previous ? previous.target : this.ship.location;
let gradation = (part.action instanceof MoveAction) ? part.action.getDistanceByPower(this.ship) : 0;
let gradation = (part.action instanceof MoveAction) ? part.action.distance_per_power : 0;
this.drawVector(color, src.x, src.y, part.target.x, part.target.y, gradation);
}
@ -123,19 +123,10 @@ module TK.SpaceTac.UI {
let ships = action.getImpactedShips(ship, target, source);
if (ships.length) {
// TODO differential
impacts.removeAll(true);
let builder = new UIBuilder(this.view).in(impacts);
builder.clear();
ships.forEach(iship => {
let builder = new UIBuilder(this.view, impacts);
let indicator = builder.image("battle-hud-ship-impacted", iship.arena_x, iship.arena_y, true);
if (action instanceof TriggerAction) {
let success = action.getSuccessFactor(ship, iship);
builder.in(indicator, builder => {
builder.image("battle-hud-ship-success-back", -29, -50);
builder.valuebar("battle-hud-ship-success-fill", -28, -49).setValue(success, 1);
});
}
builder.image("battle-hud-ship-impacted", iship.arena_x, iship.arena_y, true);
});
impacts.visible = true;
} else {