1
0
Fork 0

Added Damage Protector (visual feedback still missing)

This commit is contained in:
Michaël Lemaire 2017-06-13 00:28:54 +02:00
parent 7275288f13
commit f62f2236f8
20 changed files with 663 additions and 33 deletions

View file

@ -16,12 +16,28 @@
version="1.1"
inkscape:version="0.92.1 r15371"
sodipodi:docname="actions.svg"
inkscape:export-filename="/home/michael/workspace/perso/spacetac/out/assets/images/equipment/shieldtransfer.png"
inkscape:export-filename="/home/michael/workspace/perso/spacetac/out/assets/images/equipment/damageprotector.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
viewBox="0 0 256 256">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4953">
<stop
style="stop-color:#4191ac;stop-opacity:1"
offset="0"
id="stop4949" />
<stop
id="stop4973"
offset="0.6337238"
style="stop-color:#6d8688;stop-opacity:0.96470588" />
<stop
style="stop-color:#2e584f;stop-opacity:0.94901961"
offset="1"
id="stop4951" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4958">
@ -575,6 +591,42 @@
y1="108.47467"
x2="279.88568"
y2="110.07293" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4953"
id="radialGradient4955"
cx="128"
cy="128"
fx="128"
fy="128"
r="110.79634"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter5465"
x="-0.2172"
width="1.4344"
y="-0.2172"
height="1.4344">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="1.6296207"
id="feGaussianBlur5467" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter5535"
x="-0.4452"
width="1.8904"
y="-0.4452"
height="1.8904">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.52701551"
id="feGaussianBlur5537" />
</filter>
</defs>
<sodipodi:namedview
id="base"
@ -583,11 +635,11 @@
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="3.8613642"
inkscape:cy="88.185766"
inkscape:zoom="2.8"
inkscape:cx="138.46109"
inkscape:cy="124.35486"
inkscape:document-units="px"
inkscape:current-layer="layer10"
inkscape:current-layer="layer11"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1030"
@ -599,7 +651,8 @@
inkscape:snap-nodes="true"
inkscape:snap-bbox-midpoints="false"
units="px"
inkscape:snap-object-midpoints="true">
inkscape:snap-object-midpoints="true"
showguides="false">
<inkscape:grid
type="xygrid"
id="grid3004"
@ -1268,7 +1321,7 @@
inkscape:groupmode="layer"
id="layer10"
inkscape:label="ShieldTransfer"
style="display:inline">
style="display:none">
<g
id="g4936"
transform="matrix(0.86849352,0,0,0.86849352,21.648667,33.463089)">
@ -1346,4 +1399,222 @@
transform="matrix(-0.92576699,0.28645103,-0.28645103,-0.92576699,308.06375,180.7838)"
sodipodi:nodetypes="ccccccccc" />
</g>
<g
inkscape:groupmode="layer"
id="layer11"
inkscape:label="DamageProtector"
style="display:inline">
<circle
style="fill:url(#radialGradient4955);fill-opacity:1;fill-rule:evenodd;stroke:#6c6c6c;stroke-width:7.49999961;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.57234043;stroke-miterlimit:4;stroke-dasharray:1.8749999,1.8749999;stroke-dashoffset:0"
id="path4921"
cx="128"
cy="128"
r="110.32759" />
<path
style="fill:none;fill-rule:evenodd;stroke:#d2ead7;stroke-width:7.49999952;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 128.79443,128.62609 74.10416,3.31455"
id="path5363"
inkscape:connector-curvature="0" />
<use
x="0"
y="0"
xlink:href="#g4943"
id="use4947"
width="100%"
height="100%"
transform="rotate(144.83146,129.4117,131.17457)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#d2ead7;stroke-width:7.49999952;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 70.552838,87.430802 127.84742,128.15258"
id="path5365"
inkscape:connector-curvature="0" />
<g
id="g4943"
transform="translate(-2.6042991,-2.6042994)">
<circle
r="20.341978"
cy="91.692383"
cx="73.867401"
id="path4927"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:12.08983517;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.41489366" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="use4939"
d="M 44.634009,103.02611 C 46.255886,82.288564 62.977551,63.514951 81.20414,60.845617"
style="fill:none;fill-rule:evenodd;stroke:#d2ead7;stroke-width:7.24609804;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#c0e6c8;stroke-width:6.38581514;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 47.991422,101.47181 C 49.420744,83.1963 64.157153,66.651557 80.219816,64.299136"
id="path5469"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<circle
style="fill:#b7d7c8;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.93749994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter5535)"
id="path5473"
cx="53.033005"
cy="95.835587"
r="1.420527"
transform="matrix(1.7878646,1.3264786,-0.30857423,0.41590488,-10.61234,-8.0960556)" />
<circle
transform="matrix(1.7878646,1.3264786,-0.30857423,0.41590488,-10.61234,-8.0960556)"
r="1.420527"
cy="95.835587"
cx="53.033005"
id="circle5539"
style="fill:#b7d7c8;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.93749994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter5535)" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5541"
width="100%"
height="100%"
transform="translate(3.3145629,-2.6042994)" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5549"
width="100%"
height="100%"
transform="translate(1.4205269,-7.5761437)" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5551"
width="100%"
height="100%"
transform="translate(6.6291258,-7.694521)" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5553"
width="100%"
height="100%"
transform="translate(1.1837725,-14.323647)" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5555"
width="100%"
height="100%"
transform="translate(7.5761437,-14.797156)" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5559"
width="100%"
height="100%"
transform="translate(14.442024,-16.691192)" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5561"
width="100%"
height="100%"
transform="translate(7.5761437,-21.189527)" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5563"
width="100%"
height="100%"
transform="translate(14.323647,-20.716018)" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5565"
width="100%"
height="100%"
transform="translate(13.258252,-27.108389)" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5567"
width="100%"
height="100%"
transform="translate(21.89979,-27.108389)" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5569"
width="100%"
height="100%"
transform="translate(28.173784,-30.422952)" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5573"
width="100%"
height="100%"
transform="translate(21.544659,-30.541329)" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5575"
width="100%"
height="100%"
transform="translate(27.93703,-18.821982)"
style="opacity:0.64800002" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5577"
width="100%"
height="100%"
transform="translate(18.940359,-3.9064491)"
style="opacity:0.43399999" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5579"
width="100%"
height="100%"
transform="translate(13.850138,-10.535575)"
style="opacity:0.28000004" />
<use
x="0"
y="0"
xlink:href="#circle5539"
id="use5581"
width="100%"
height="100%"
transform="translate(6.5107485,2.3675449)"
style="opacity:0.329" />
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#d2ead7;stroke-width:9.37499905;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 99.910392,155.37934 128.32093,128.15258"
id="path5367"
inkscape:connector-curvature="0" />
<circle
style="fill:#d3f8e9;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.6806401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter5465)"
id="path5361"
cx="128"
cy="128"
r="9.0034294"
transform="matrix(2.2706815,0,0,2.2706815,-162.64723,-162.64723)" />
<use
x="0"
y="0"
xlink:href="#g4943"
id="use4945"
width="100%"
height="100%"
transform="rotate(-80.838515,124.57679,104.88647)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View file

@ -329,5 +329,43 @@ module TS.SpaceTac {
expect(battle.getTurnsBefore(battle.play_order[1])).toBe(1);
expect(battle.getTurnsBefore(battle.play_order[2])).toBe(2);
});
it("lists area effects", function () {
let battle = new Battle();
let ship = battle.fleets[0].addShip();
expect(imaterialize(battle.iAreaEffects(100, 50))).toEqual([]);
let drone1 = new Drone(ship);
drone1.x = 120;
drone1.y = 60;
drone1.radius = 40;
drone1.effects = [new DamageEffect(12)];
battle.addDrone(drone1);
let drone2 = new Drone(ship);
drone2.x = 130;
drone2.y = 70;
drone2.radius = 20;
drone2.effects = [new DamageEffect(14)];
battle.addDrone(drone2);
expect(imaterialize(battle.iAreaEffects(100, 50))).toEqual([
new DamageEffect(12)
]);
let eq1 = ship.addSlot(SlotType.Weapon).attach(new Equipment(SlotType.Weapon));
eq1.action = new ToggleAction(eq1, 0, 500, [new AttributeEffect("maneuvrability", 1)]);
(<ToggleAction>eq1.action).activated = true;
let eq2 = ship.addSlot(SlotType.Weapon).attach(new Equipment(SlotType.Weapon));
eq2.action = new ToggleAction(eq2, 0, 500, [new AttributeEffect("maneuvrability", 2)]);
(<ToggleAction>eq2.action).activated = false;
let eq3 = ship.addSlot(SlotType.Weapon).attach(new Equipment(SlotType.Weapon));
eq3.action = new ToggleAction(eq3, 0, 100, [new AttributeEffect("maneuvrability", 3)]);
(<ToggleAction>eq3.action).activated = true;
expect(imaterialize(battle.iAreaEffects(100, 50))).toEqual([
new DamageEffect(12), new AttributeEffect("maneuvrability", 1)
]);
});
});
}

View file

@ -366,5 +366,17 @@ module TS.SpaceTac {
}
}
}
/**
* Get the list of area effects at a given location
*/
iAreaEffects(x: number, y: number): Iterator<BaseEffect> {
let drones_in_range = ifilter(iarray(this.drones), drone => drone.isInRange(x, y));
return ichain(
ichainit(imap(drones_in_range, drone => iarray(drone.effects))),
ichainit(imap(this.iships(), ship => ship.iAreaEffects(x, y)))
);
}
}
}

View file

@ -41,6 +41,13 @@ module TS.SpaceTac {
return `For ${this.duration} activation${this.duration > 1 ? "s" : ""}:\n${effects}`;
}
/**
* Check if a location is in range
*/
isInRange(x: number, y: number): boolean {
return Target.newFromLocation(x, y).getDistanceTo(this) <= this.radius;
}
/**
* Get the list of affected ships.
*/

View file

@ -303,6 +303,16 @@ module TS.SpaceTac {
});
}
/**
* Add a toggle action.
*/
addToggleAction(power: LeveledValue, radius: LeveledValue, effects: EffectTemplate<BaseEffect>[]): void {
this.base_modifiers.push((equipment, level) => {
let reffects = effects.map(effect => effect.generate(level));
equipment.action = new ToggleAction(equipment, resolveForLevel(power, level), resolveForLevel(radius, level), reffects);
});
}
/**
* Check if the template has any damage effect (to know if is an offensive weapon)
*/

View file

@ -482,5 +482,24 @@ module TS.SpaceTac.Specs {
expect(ship.sticky_effects.length).toEqual(0);
expect(ship.getAttribute("power_capacity")).toEqual(5);
});
it("lists active effects", function () {
let ship = new Ship();
expect(imaterialize(ship.ieffects())).toEqual([]);
let equipment = ship.addSlot(SlotType.Engine).attach(new Equipment(SlotType.Engine));
expect(imaterialize(ship.ieffects())).toEqual([]);
equipment.effects.push(new AttributeEffect("precision", 4));
expect(imaterialize(ship.ieffects())).toEqual([
new AttributeEffect("precision", 4)
]);
ship.addStickyEffect(new StickyEffect(new AttributeLimitEffect("precision", 2), 4));
expect(imaterialize(ship.ieffects())).toEqual([
new AttributeEffect("precision", 4),
new AttributeLimitEffect("precision", 2)
]);
});
});
}

View file

@ -678,27 +678,41 @@ module TS.SpaceTac {
}
}
/**
* Iterator over all effects active for this ship.
*
* This includes:
* - Permanent equipment effects
* - Sticky effects
* - Area effects at current location
*/
ieffects(): Iterator<BaseEffect> {
let battle = this.getBattle();
let area_effects = battle ? battle.iAreaEffects(this.arena_x, this.arena_y) : IEMPTY;
return ichain(
ichainit(imap(iarray(this.slots), slot => slot.attached ? iarray(slot.attached.effects) : IEMPTY)),
imap(iarray(this.sticky_effects), effect => effect.base),
area_effects
);
}
/**
* Iterator over area effects from this ship impacting a location
*/
iAreaEffects(x: number, y: number): Iterator<BaseEffect> {
let distance = Target.newFromShip(this).getDistanceTo({ x: x, y: y });
return ichainit(imap(iarray(this.getAvailableActions()), action => {
if (action instanceof ToggleAction && action.activated && distance <= action.radius) {
return iarray(action.effects);
} else {
return IEMPTY;
}
}));
}
// Collect all effects to apply for updateAttributes
private collectEffects(code: string): BaseEffect[] {
var result: BaseEffect[] = [];
this.slots.forEach(slot => {
if (slot.attached) {
slot.attached.effects.forEach(effect => {
if (effect.code == code) {
result.push(effect);
}
});
}
});
this.sticky_effects.forEach(effect => {
if (effect.base.code == code) {
result.push(effect.base);
}
});
return result;
return imaterialize(ifilter(this.ieffects(), effect => effect.code == code));
}
}
}

View file

View file

@ -0,0 +1,77 @@
/// <reference path="BaseAction.ts"/>
module TS.SpaceTac {
/**
* Action to toggle some effects on the ship or around it, until next turn start
*/
export class ToggleAction extends BaseAction {
// Power consumption (activation only)
power: number
// Effect radius
radius: number
// Effects applied
effects: BaseEffect[]
// Equipment cannot be null
equipment: Equipment
// Current activation status
activated = false
constructor(equipment: Equipment, power = 1, radius = 0, effects: BaseEffect[] = [], name = "(De)activate") {
super("toggle-" + equipment.code, name, false, equipment);
this.power = power;
this.radius = radius;
this.effects = effects;
}
getActionPointsUsage(ship: Ship, target: Target | null): number {
return this.activated ? 0 : this.power;
}
getRangeRadius(ship: Ship): number {
return 0;
}
getBlastRadius(ship: Ship): number {
return this.radius;
}
/**
* Collect the effects applied by this action
*/
getEffects(ship: Ship): [Ship, BaseEffect][] {
let target = Target.newFromShip(ship);
let result: [Ship, BaseEffect][] = [];
let radius = this.getBlastRadius(ship);
let battle = ship.getBattle();
let ships = (radius && battle) ? battle.collectShipsInCircle(target, radius, true) : ((target.ship && target.ship.alive) ? [target.ship] : []);
ships.forEach(ship => {
this.effects.forEach(effect => result.push([ship, effect]));
});
return result;
}
protected customApply(ship: Ship, target: Target) {
this.activated = !this.activated;
ship.addBattleEvent(new ToggleEvent(ship, this, this.activated));
// TODO Refresh area effects
}
getEffectsDescription(): string {
if (this.effects.length == 0) {
return "";
}
let desc = `When active (power usage ${this.power})`;
let effects = this.effects.map(effect => {
let suffix = this.radius ? `in ${this.radius}km radius` : "on owner ship";
return "• " + effect.getDescription() + " " + suffix;
});
return `${desc}:\n${effects.join("\n")}`;
}
}
}

View file

@ -44,5 +44,31 @@ module TS.SpaceTac.Specs {
expect(new DamageEffect(10).getDescription()).toEqual("do 10 damage");
expect(new DamageEffect(10, 5).getDescription()).toEqual("do 10-15 damage");
});
it("applies damage modifiers", function () {
let ship = new Ship();
TestTools.setShipHP(ship, 1000, 1000);
let damage = new DamageEffect(200);
expect(damage.getEffectiveDamage(ship)).toEqual([200, 0]);
spyOn(ship, "ieffects").and.returnValues(
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))
);
expect(damage.getEffectiveDamage(ship)).toEqual([170, 0]);
expect(damage.getEffectiveDamage(ship)).toEqual([240, 0]);
expect(damage.getEffectiveDamage(ship)).toEqual([0, 0]);
expect(damage.getEffectiveDamage(ship)).toEqual([400, 0]);
expect(damage.getEffectiveDamage(ship)).toEqual([190, 0]);
damage = new DamageEffect(40);
expect(damage.getEffectiveDamage(ship)).toEqual([41, 0]);
});
});
}

View file

@ -20,6 +20,19 @@ module TS.SpaceTac {
this.span = span;
}
/**
* 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;
}
/**
* Get the effective damage done to both shield and hull (in this order)
*/
@ -28,6 +41,9 @@ module TS.SpaceTac {
var hull: number;
var shield: number;
// Apply modifiers
damage = Math.round(damage * this.getFactor(ship));
// Apply on shields
if (damage >= ship.values.shield.get()) {
shield = ship.values.shield.get();

View file

@ -0,0 +1,21 @@
/// <reference path="BaseEffect.ts"/>
module TS.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}%`;
}
}
}

View file

@ -0,0 +1,83 @@
module TS.SpaceTac.Equipments {
describe("DamageProtector", function () {
it("generates equipment based on level", function () {
let template = new DamageProtector();
let equipment = template.generate(1);
expect(equipment.requirements).toEqual({ "skill_time": 1 });
expect(equipment.action).toEqual(new ToggleAction(equipment, 2, 300, [
new DamageModifierEffect(-30)
]));
equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_time": 3 });
expect(equipment.action).toEqual(new ToggleAction(equipment, 2, 310, [
new DamageModifierEffect(-31)
]));
equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_time": 5 });
expect(equipment.action).toEqual(new ToggleAction(equipment, 2, 320, [
new DamageModifierEffect(-32)
]));
equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_time": 19 });
expect(equipment.action).toEqual(new ToggleAction(equipment, 3, 390, [
new DamageModifierEffect(-39)
]));
});
it("reduces damage around the ship", function () {
let battle = new Battle();
let ship1 = battle.fleets[0].addShip();
ship1.upgradeSkill("skill_time");
let protector = ship1.addSlot(SlotType.Weapon).attach(new DamageProtector().generate(1));
TestTools.setShipAP(ship1, 10);
let ship2 = battle.fleets[0].addShip();
let ship3 = battle.fleets[0].addShip();
ship1.setArenaPosition(0, 0);
ship2.setArenaPosition(100, 0);
ship3.setArenaPosition(800, 0);
battle.playing_ship = ship1;
ship1.playing = true;
expect(ship1.getAvailableActions()).toEqual([
protector.action,
new EndTurnAction()
]);
TestTools.setShipHP(ship1, 100, 0);
TestTools.setShipHP(ship2, 100, 0);
TestTools.setShipHP(ship3, 100, 0);
iforeach(battle.iships(), ship => new DamageEffect(10).applyOnShip(ship, ship1));
expect(ship1.getValue("power")).toEqual(10);
expect(ship1.getValue("hull")).toEqual(90);
expect(ship2.getValue("hull")).toEqual(90);
expect(ship3.getValue("hull")).toEqual(90);
let result = protector.action.apply(ship1, null);
expect(result).toBe(true);
expect((<ToggleAction>protector.action).activated).toBe(true);
iforeach(battle.iships(), ship => new DamageEffect(10).applyOnShip(ship, ship1));
expect(ship1.getValue("power")).toEqual(8);
expect(ship1.getValue("hull")).toEqual(83);
expect(ship2.getValue("hull")).toEqual(83);
expect(ship3.getValue("hull")).toEqual(80);
result = protector.action.apply(ship1, null);
expect(result).toBe(true);
expect((<ToggleAction>protector.action).activated).toBe(false);
iforeach(battle.iships(), ship => new DamageEffect(10).applyOnShip(ship, ship1));
expect(ship1.getValue("power")).toEqual(8);
expect(ship1.getValue("hull")).toEqual(73);
expect(ship2.getValue("hull")).toEqual(73);
expect(ship3.getValue("hull")).toEqual(70);
});
});
}

View file

@ -0,0 +1,14 @@
/// <reference path="../LootTemplate.ts"/>
module TS.SpaceTac.Equipments {
export class DamageProtector extends LootTemplate {
constructor() {
super(SlotType.Weapon, "Damage Protector", "Extend a time-displacement subfield, to reduce damage taken by ships around");
this.setSkillsRequirements({ "skill_time": istep(1, irepeat(2)) });
this.addToggleAction(istep(2, irepeat(0.2)), istep(300, irepeat(10)), [
new EffectTemplate(new DamageModifierEffect(), { factor: istep(-30, irepeat(-1)) })
]);
}
}
}

View file

@ -4,19 +4,19 @@ module TS.SpaceTac.Equipments {
let template = new PowerDepleter();
let equipment = template.generate(1);
expect(equipment.requirements).toEqual({ "skill_photons": 1 });
expect(equipment.requirements).toEqual({ "skill_antimatter": 1 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 500, 0, [new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)]));
equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_photons": 2 });
expect(equipment.requirements).toEqual({ "skill_antimatter": 2 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 520, 0, [new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)]));
equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_photons": 3 });
expect(equipment.requirements).toEqual({ "skill_antimatter": 3 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 540, 0, [new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)]));
equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_photons": 10 });
expect(equipment.requirements).toEqual({ "skill_antimatter": 10 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 680, 0, [new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)]));
});

View file

@ -3,9 +3,9 @@
module TS.SpaceTac.Equipments {
export class PowerDepleter extends LootTemplate {
constructor() {
super(SlotType.Weapon, "Power Depleter", "Direct-hit weapon that creates an energy well near the target, sucking its power surplus");
super(SlotType.Weapon, "Power Depleter", "Direct-hit weapon that creates an antimatter well near the target, sucking its power surplus");
this.setSkillsRequirements({ "skill_photons": 1 });
this.setSkillsRequirements({ "skill_antimatter": 1 });
this.setCooldown(irepeat(2), irepeat(3));
this.addFireAction(irepeat(4), istep(500, irepeat(20)), 0, [
new StickyEffectTemplate(new AttributeLimitEffect("power_capacity"), { "value": irepeat(3) }, irepeat(2))

View file

@ -6,7 +6,7 @@ module TS.SpaceTac.Equipments {
*/
export class RepairDrone extends LootTemplate {
constructor() {
super(SlotType.Weapon, "Repair Drone", "Drone able to repair small hull breaches, remotely controlled by human pilots");
super(SlotType.Weapon, "Repair Drone", "Drone able to repair small hull breaches, using quantum patches");
this.setSkillsRequirements({ "skill_quantum": 1 });
this.setCooldown(irepeat(1), istep(3, irepeat(0.2)));

View file

@ -0,0 +1,21 @@
/// <reference path="BaseBattleEvent.ts"/>
module TS.SpaceTac {
/**
* Event logged when a toggle action is activated or deactivated
*/
export class ToggleEvent extends BaseLogShipEvent {
// Pointer to the action
action: BaseAction
// true for activation, false for deactivation
activated: boolean
constructor(ship: Ship, action: BaseAction, activated: boolean) {
super("toggle", ship);
this.action = action;
this.activated = activated;
}
}
}

View file

@ -103,6 +103,7 @@ module TS.SpaceTac.UI {
this.loadImage("equipment/submunitionmissile.png");
this.loadImage("equipment/repairdrone.png");
this.loadImage("equipment/shieldtransfer.png");
this.loadImage("equipment/damageprotector.png");
// Load ships
this.loadShip("avenger");