diff --git a/css/aa.css b/css/aa.css index f5819ea1..40d57b15 100755 --- a/css/aa.css +++ b/css/aa.css @@ -2974,6 +2974,14 @@ body.is_safari .cornholio .sub-sprite { color: #666; } +.sprite.flame { + /* background-image: url(../image/tank_flame.png); */ + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAASCAMAAAANFixgAAAAD1BMVEUAAAC1BwD/xQAAAAD////xz7/wAAAAAXRSTlMAQObYZgAAAJBJREFUeNplkQsOhDAQQgW5/5k3wnx0S1KtPoYSvT66R3k+GUp/lhcjCEBvy0CS4WRSmtecJIjmsVQVY7NHGK4OAUlJhmMTaJ4EgquatyuO20fkLZIj7xVHSiY8bWs/LR5HUthSptNiPgRB+eKlOSHqTwUwqxKKT4q2re9j2BQT82qw2i4IP3/6dtnp09Ea/gMASwNU7KO2mwAAAABJRU5ErkJggg==); + background-size: contain; + width: 32px; + height: 18px; +} + .sprite.missile-launcher.building { margin-top: 18px; } diff --git a/image/tank_flame.png b/image/tank_flame.png new file mode 100644 index 00000000..422bd6cb Binary files /dev/null and b/image/tank_flame.png differ diff --git a/script/buildings/SuperBunker.js b/script/buildings/SuperBunker.js index 3f7409d8..f7234d96 100755 --- a/script/buildings/SuperBunker.js +++ b/script/buildings/SuperBunker.js @@ -85,8 +85,8 @@ const SuperBunker = (options = {}) => { } function hit(points, target) { - // only tank gunfire counts against super bunkers. - if (target && target.data.type === 'gunfire' && target.data?.parentType === TYPES.tank) { + // only tank flamethrowers - or, gunfire - counts against super bunkers. + if (target && (target.data.type === TYPES.flame || target.data.type === TYPES.gunfire) && target.data.parentType === TYPES.tank) { data.energy = Math.max(0, data.energy - points); updateFireModulus(); sprites.updateEnergy(exports); diff --git a/script/core/Game.js b/script/core/Game.js index f0a3a42b..cc9f4197 100755 --- a/script/core/Game.js +++ b/script/core/Game.js @@ -869,6 +869,7 @@ const game = (() => { ephemeralExplosion: [], 'end-bunker': [], engineer: [], + flame: [], gunfire: [], infantry: [], 'parachute-infantry': [], @@ -910,6 +911,7 @@ const game = (() => { 'end-bunker': EndBunker, engineer: Engineer, // flyingAce: FlyingAce, + flame: Flame, gunfire: GunFire, helicopter: Helicopter, infantry: Infantry, diff --git a/script/core/global.js b/script/core/global.js index 78246bac..c2754793 100755 --- a/script/core/global.js +++ b/script/core/global.js @@ -97,7 +97,7 @@ const bananaMode = 'banana-mode'; const TYPES = (() => { // assign 1:1 key / value strings in a DRY fashion - const types = 'base, bomb, balloon, bunker, chain, cloud, cornholio, engineer, gunfire, helicopter, infantry, end-bunker, landing-pad, missile-launcher, parachute-infantry, smart-missile, smoke, shrapnel, super-bunker, tank, turret, terrain-item, van'; + const types = 'base, bomb, balloon, bunker, chain, cloud, cornholio, engineer, flame, gunfire, helicopter, infantry, end-bunker, landing-pad, missile-launcher, parachute-infantry, smart-missile, smoke, shrapnel, super-bunker, tank, turret, terrain-item, van'; const result = {}; types.split(', ').forEach((type) => { diff --git a/script/munitions/Flame.js b/script/munitions/Flame.js new file mode 100644 index 00000000..32348570 --- /dev/null +++ b/script/munitions/Flame.js @@ -0,0 +1,119 @@ +import { common } from '../core/common.js'; +import { collisionTest } from '../core/logic.js'; +import { TYPES, getTypes } from '../core/global.js'; +import { sprites } from '../core/sprites.js'; + +const Flame = (options = {}) => { + + let css, data, dom, collision, exports; + + function die(force) { + + // aieee! + + if (data.dead && !force) return; + + data.dead = true; + + sprites.removeNodesAndUnlink(exports); + + common.onDie(exports); + + } + + function animate() { + + sprites.moveWithScrollOffset(exports); + + if (data.dead) return true; + + if (!data.expired && data.frameCount > data.expireFrameCount) { + die(); + } + + data.frameCount++; + + if (!data.isInert) { + collisionTest(collision, exports); + } + + // notify caller if now dead and can be removed. + return (data.dead && !dom.o); + + } + + function initDOM() { + + dom.o = sprites.create({ + className: css.className + }); + + } + + function initFlame() { + + initDOM(); + + sprites.setTransformXY(exports, dom.o, `${data.x}px`, `${data.y}px`, data.extraTransforms); + + } + + css = common.inheritCSS({ + className: 'flame' + }); + + data = common.inheritData({ + type: 'flame', + parent: options.parent || null, + parentType: options.parentType || null, + isEnemy: options.isEnemy, + frameCount: 0, + extraTransforms: (options.isEnemy ? 'scaleX(-1)' : ''), + expireFrameCount: options.expireFrameCount || 2, + width: 32, + height: 18, + damagePoints: options.damagePoints || 1, + target: null, + }, options); + + // offset left 100% if parent tank is an enemy, so we line up with the tank + if (options.isEnemy) { + data.x -= data.width; + } + + dom = { + o: null + }; + + exports = { + animate, + data, + dom, + die, + init: initFlame + }; + + collision = { + options: { + source: exports, + targets: undefined, + hit(target) { + if (data.damagePoints) { + // hit once, then remain until the object animation has completed. + common.hit(target, data.damagePoints, exports); + // nullify this object unless infantry / engineers, so we don't hit e.g., a super-bunker repeatedly. + if (target.data.type !== TYPES.infantry) { + data.damagePoints = 0; + } + } + } + }, + // if unspecified, use default list of items which flames can hit. + items: options.collisionItems || getTypes('infantry, parachuteInfantry, engineer, helicopter, endBunker, superBunker, turret', { exports }) + }; + + return exports; + + }; + + export { Flame } \ No newline at end of file