Skip to content

Commit

Permalink
Poison drips that affect player, enemies
Browse files Browse the repository at this point in the history
  • Loading branch information
hubol committed Aug 10, 2024
1 parent 293e661 commit 56b08e7
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 18 deletions.
8 changes: 6 additions & 2 deletions src/igua/mixins/mxn-enemy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import { RpgEnemy } from "../rpg/rpg-enemy";
import { objLootDrop } from "../objects/obj-loot-drop";
import { layers } from "../globals";

export function mxnEnemy(obj: DisplayObject) {
interface MxnEnemyArgs {
hurtboxes: DisplayObject[];
}

export function mxnEnemy(obj: DisplayObject, args: MxnEnemyArgs) {
// TODO config probably comes from args!!
const status: RpgStatus.Model = {
health: 30,
Expand Down Expand Up @@ -40,7 +44,7 @@ export function mxnEnemy(obj: DisplayObject) {

// TODO maybe exposes a way to create projectiles associated with this enemy?

const enemyObj = obj.mixin(mxnRpgStatus, status, effects)
const enemyObj = obj.mixin(mxnRpgStatus, { status, effects, hurtboxes: args.hurtboxes })
// TODO needs more
// Particle effects
// Might need to be overrideable too, actually
Expand Down
26 changes: 17 additions & 9 deletions src/igua/mixins/mxn-rpg-status.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
import { DisplayObject } from "pixi.js";
import { RpgStatus } from "../rpg/rpg-status";

export function mxnRpgStatus(obj: DisplayObject, status: RpgStatus.Model, effects: RpgStatus.Effects) {
interface MxnRpgStatusArgs {
status: RpgStatus.Model;
effects: RpgStatus.Effects;
hurtboxes: DisplayObject[];
}

export function mxnRpgStatus(obj: DisplayObject, args: MxnRpgStatusArgs) {
let tickCount = 0;

const rpgStatusObj = obj.merge({
status,
const rpgStatusObj = obj
.track(mxnRpgStatus)
.merge({ hurtboxes: args.hurtboxes })
.merge({
damage(amount: number) {
RpgStatus.Methods.damage(status, effects, amount);
RpgStatus.Methods.damage(args.status, args.effects, amount);
// TODO feels weird, should maybe be part of return value of damage?
if (status.health === 0)
if (args.status.health === 0)
rpgStatusObj.dispatch('rpgStatus.died');
},
heal(amount: number) {
RpgStatus.Methods.heal(status, effects, amount);
RpgStatus.Methods.heal(args.status, args.effects, amount);
},
poison(amount: number) {
RpgStatus.Methods.poison(status, effects, amount);
RpgStatus.Methods.poison(args.status, args.effects, amount);
}
})
.dispatches<'rpgStatus.died'>()
.step(() => {
RpgStatus.Methods.tick(status, effects, tickCount = (tickCount + 1) % 120);
obj.visible = status.invulnerable > 0 ? !obj.visible : true;
RpgStatus.Methods.tick(args.status, args.effects, tickCount = (tickCount + 1) % 120);
obj.visible = args.status.invulnerable > 0 ? !obj.visible : true;
})

return rpgStatusObj;
Expand Down
2 changes: 1 addition & 1 deletion src/igua/objects/enemies/obj-angel-bouncing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function objAngelBouncing() {

let appliedOpaqueTint = false;
const obj = container(graphics, spikeBall, hatSprite, sprite, mask)
.mixin(mxnEnemy)
.mixin(mxnEnemy, { hurtboxes: [ mask ] })
.mixin(mxnPhysics, { gravity: 0.25, physicsRadius: 8, physicsOffset: vnew(), onMove(event) {
// TODO in igua 1, some wouldn't bounce
if (event.hitWall)
Expand Down
6 changes: 4 additions & 2 deletions src/igua/objects/obj-player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ const PlayerConsts = {
}

function objPlayer(looks: IguanaLooks.Serializable) {
const puppet = objIguanaLocomotive(looks)
.mixin(mxnRpgStatus, RpgPlayer.Model, layers.overlay.hud.healthBarObj.effects)
const iguanaLocomotiveObj = objIguanaLocomotive(looks);

const puppet = iguanaLocomotiveObj
.mixin(mxnRpgStatus, { status: RpgPlayer.Model, effects: layers.overlay.hud.healthBarObj.effects, hurtboxes: [ iguanaLocomotiveObj ] })
.merge({ get hasControl() { return !Cutscene.isPlaying; }, get walkingTopSpeed() { return RpgPlayer.WalkingTopSpeed; } })
.step(() => {
if (puppet.isBeingPiloted)
Expand Down
20 changes: 17 additions & 3 deletions src/igua/objects/obj-water-drip-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Tx } from "../../assets/textures";
import { mxnPhysics } from "../mixins/mxn-physics";
import { sleep } from "../../lib/game-engine/promise/sleep";
import { Rng } from "../../lib/math/rng";
import { Instances } from "../../lib/game-engine/instances";
import { mxnRpgStatus } from "../mixins/mxn-rpg-status";

interface ObjWaterDripSourceArgs {
delayMin: number;
Expand All @@ -12,17 +14,29 @@ interface ObjWaterDripSourceArgs {

export function objWaterDripSource({ delayMin, delayMax }: ObjWaterDripSourceArgs) {
return container()
.track(objWaterDripSource)
.merge({ poison: false })
.async(async self => {
while (true) {
await sleep(Rng.intc(delayMin, delayMax));
objWaterDrip().at(self).show(self.parent);
objWaterDrip(self.poison).at(self).show(self.parent);
}
})
}

function objWaterDrip() {
const obj = Sprite.from(Tx.Effects.WaterDripSmall)
function objWaterDrip(poison: boolean) {
const obj = Sprite.from(poison ? Tx.Effects.PoisonDripSmall : Tx.Effects.WaterDripSmall)
.mixin(mxnPhysics, { gravity: 0.05, physicsRadius: 4, physicsOffset: [0, -2], onMove: (ev) => {
if (poison) {
// TODO should be a more terse way to accomplish this!
for (const instance of Instances(mxnRpgStatus)) {
if (obj.collidesOne(instance.hurtboxes)) {
instance.poison(5);
// TODO sfx
return obj.destroy();
}
}
}
if (ev.hitGround) {
obj.destroy();
// TODO drip sfx
Expand Down
11 changes: 10 additions & 1 deletion src/igua/scenes/player-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,22 @@ import { sleep } from "../../lib/game-engine/promise/sleep";
import { objStatusBar } from "../objects/obj-status-bar";
import { RpgProgress } from "../rpg/rpg-progress";
import { objAngelBouncing } from "../objects/enemies/obj-angel-bouncing";
import { Instances } from "../../lib/game-engine/instances";
import { objWaterDripSource } from "../objects/obj-water-drip-source";

export function PlayerTest() {
Sprite.from(Tx.Placeholder).at(128, 128 - 14).mixin(mxnCutscene, async () => {
await show('Hello!');
}).show();

const { LockedDoor } = Lvl.Test();
const level = Lvl.Test();

for (const dripSource of Instances(objWaterDripSource)) {
dripSource.poison = true;
}

const { LockedDoor } = level;

LockedDoor.async(async () => {
while (true) {
LockedDoor.add(Rng.vunit().scale(4));
Expand Down

0 comments on commit 56b08e7

Please sign in to comment.