Skip to content

Commit

Permalink
Merge branch 'main' into feature/set4-bunch11
Browse files Browse the repository at this point in the history
  • Loading branch information
AMMayberry1 authored Mar 5, 2025
2 parents b80f1e1 + abca051 commit e8cc0ec
Show file tree
Hide file tree
Showing 34 changed files with 1,028 additions and 32 deletions.
2 changes: 1 addition & 1 deletion server/game/cards/02_SHD/events/EvidenceOfTheCrime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default class EvidenceOfTheCrime extends EventCard {
dependsOn: 'upgrade',
activePromptTitle: 'Choose a unit to attach the upgrade to',
controller: WildcardRelativePlayer.Any,
cardCondition: (card, context) => context.targets.upgrade.isUpgrade() && context.targets.upgrade.canAttach(card, context.player),
cardCondition: (card, context) => context.targets.upgrade.isUpgrade() && context.targets.upgrade.canAttach(card, context, context.player),
immediateEffect: AbilityHelper.immediateEffects.attachUpgrade((context) => ({
newController: RelativePlayer.Self,
upgrade: context.targets.upgrade,
Expand Down
4 changes: 2 additions & 2 deletions server/game/cards/02_SHD/units/PreVizslaPowerHungry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ export default class PreVizslaPowerHungry extends NonLeaderUnitCard {
}))
},
ifYouDo: (ifYouDoContext) => ({
title: ifYouDoContext.target.canAttach(ifYouDoContext.source, ifYouDoContext.player)
title: ifYouDoContext.target.canAttach(ifYouDoContext.source, ifYouDoContext, ifYouDoContext.player)
? `Take control of ${ifYouDoContext.target.title} and attach it to this unit`
: `Defeat ${ifYouDoContext.target.title}`,
immediateEffect: AbilityHelper.immediateEffects.conditional({
condition: () => ifYouDoContext.target.canAttach(ifYouDoContext.source, ifYouDoContext.player),
condition: () => ifYouDoContext.target.canAttach(ifYouDoContext.source, ifYouDoContext, ifYouDoContext.player),
onTrue: AbilityHelper.immediateEffects.attachUpgrade({
newController: RelativePlayer.Self,
upgrade: ifYouDoContext.target,
Expand Down
2 changes: 1 addition & 1 deletion server/game/cards/02_SHD/units/SurvivorsGauntlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default class SurvivorsGauntlet extends NonLeaderUnitCard {
cardCondition: (card, context) =>
context.targets.chooseUpgrade.isUpgrade() &&
context.targets.chooseUpgrade.parentCard !== card &&
context.targets.chooseUpgrade.canAttach(card, context.targets.chooseUpgrade.parentCard.controller),
context.targets.chooseUpgrade.canAttach(card, context, context.targets.chooseUpgrade.parentCard.controller),
immediateEffect: AbilityHelper.immediateEffects.attachUpgrade((context) => ({
upgrade: context.targets.chooseUpgrade,
target: context.targets.chooseUnit,
Expand Down
3 changes: 2 additions & 1 deletion server/game/cards/02_SHD/upgrades/LegalAuthority.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { UpgradeCard } from '../../../core/card/UpgradeCard';
import { RelativePlayer } from '../../../core/Constants';
import type { Card } from '../../../core/card/Card';
import type Player from '../../../core/Player';
import type { AbilityContext } from '../../../core/ability/AbilityContext';

export default class LegalAuthority extends UpgradeCard {
protected override getImplementationId() {
Expand All @@ -12,7 +13,7 @@ export default class LegalAuthority extends UpgradeCard {
};
}

public override canAttach(targetCard: Card, controller: Player): boolean {
public override canAttach(targetCard: Card, _context: AbilityContext, controller: Player): boolean {
return targetCard.isUnit() && targetCard.controller === controller;
}

Expand Down
3 changes: 2 additions & 1 deletion server/game/cards/02_SHD/upgrades/TheMandaloriansRifle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { UpgradeCard } from '../../../core/card/UpgradeCard';
import { RelativePlayer, Trait } from '../../../core/Constants';
import type { Card } from '../../../core/card/Card';
import type Player from '../../../core/Player';
import type { AbilityContext } from '../../../core/ability/AbilityContext';

export default class TheMandaloriansRifle extends UpgradeCard {
protected override getImplementationId() {
Expand All @@ -12,7 +13,7 @@ export default class TheMandaloriansRifle extends UpgradeCard {
};
}

public override canAttach(targetCard: Card, controller: Player): boolean {
public override canAttach(targetCard: Card, _context: AbilityContext, controller: Player): boolean {
return targetCard.isUnit() && !targetCard.hasSomeTrait(Trait.Vehicle) && targetCard.controller === controller;
}

Expand Down
38 changes: 38 additions & 0 deletions server/game/cards/04_JTL/events/CoordinatedFront.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { EventCard } from '../../../core/card/EventCard';
import AbilityHelper from '../../../AbilityHelper';
import { WildcardCardType, ZoneName } from '../../../core/Constants';

export default class CoordinatedFront extends EventCard {
protected override getImplementationId() {
return {
id: '9595202461',
internalName: 'coordinated-front',
};
}

public override setupCardAbilities() {
this.setEventAbility({
title: 'Give a ground unit and a space unit +2/+2 for this phase',
targetResolvers: {
groundUnit: {
activePromptTitle: 'Give a ground unit +2/+2 for this phase',
optional: true,
cardTypeFilter: WildcardCardType.Unit,
zoneFilter: ZoneName.GroundArena,
immediateEffect: AbilityHelper.immediateEffects.forThisPhaseCardEffect({
effect: AbilityHelper.ongoingEffects.modifyStats({ power: 2, hp: 2 })
})
},
spaceUnit: {
activePromptTitle: 'Give a space unit +2/+2 for this phase',
optional: true,
cardTypeFilter: WildcardCardType.Unit,
zoneFilter: ZoneName.SpaceArena,
immediateEffect: AbilityHelper.immediateEffects.forThisPhaseCardEffect({
effect: AbilityHelper.ongoingEffects.modifyStats({ power: 2, hp: 2 })
})
},
},
});
}
}
33 changes: 33 additions & 0 deletions server/game/cards/04_JTL/events/ShootDown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { EventCard } from '../../../core/card/EventCard';
import { CardType, WildcardCardType, ZoneName } from '../../../core/Constants';
import AbilityHelper from '../../../AbilityHelper';

export default class ShootDown extends EventCard {
protected override getImplementationId() {
return {
id: '7730475388',
internalName: 'shoot-down',
};
}

public override setupCardAbilities() {
this.setEventAbility({
title: 'Deal 3 damage to space unit.',
targetResolver: {
zoneFilter: ZoneName.SpaceArena,
cardTypeFilter: WildcardCardType.Unit,
immediateEffect: AbilityHelper.immediateEffects.damage({ amount: 3 })
},
ifYouDo: {
title: 'Deal 2 damage to a base',
optional: true,
ifYouDoCondition: (ifYouDoContext) => ifYouDoContext.events[0].willDefeat,
immediateEffect: AbilityHelper.immediateEffects.selectCard({
activePromptTitle: 'Deal 2 damage to a base',
cardTypeFilter: CardType.Base,
innerSystem: AbilityHelper.immediateEffects.damage({ amount: 2 })
})
}
});
}
}
42 changes: 42 additions & 0 deletions server/game/cards/04_JTL/units/ChewbaccaFaithfulFirstMate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import AbilityHelper from '../../../../../server/game/AbilityHelper';
import { NonLeaderUnitCard } from '../../../../../server/game/core/card/NonLeaderUnitCard';
import { AbilityRestriction } from '../../../../../server/game/core/Constants';

export default class ChewbaccaFaithfulFirstMate extends NonLeaderUnitCard {
protected override getImplementationId() {
return {
id: '7208848194',
internalName: 'chewbacca#faithful-first-mate',
};
}

public override setupCardAbilities() {
this.addConstantAbility({
title: 'This unit can\'t be defeated or returned to hand by enemy card abilities',
ongoingEffect: [
AbilityHelper.ongoingEffects.cardCannot({
cannot: AbilityRestriction.ReturnToHand,
restrictedActionCondition: (context) => context.player !== this.controller,
}),
AbilityHelper.ongoingEffects.cardCannot({
cannot: AbilityRestriction.BeDefeated,
restrictedActionCondition: (context) => context.player !== this.controller,
})
]
});

this.addPilotingConstantAbilityTargetingAttached({
title: 'This unit can\'t be captured or damaged by enemy card abilities',
ongoingEffect: [
AbilityHelper.ongoingEffects.cardCannot({
cannot: AbilityRestriction.ReturnToHand,
restrictedActionCondition: (context) => context.player !== this.controller,
}),
AbilityHelper.ongoingEffects.cardCannot({
cannot: AbilityRestriction.BeDefeated,
restrictedActionCondition: (context) => context.player !== this.controller,
})
]
});
}
}
18 changes: 18 additions & 0 deletions server/game/cards/04_JTL/units/CorporateDefenseShuttle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NonLeaderUnitCard } from '../../../core/card/NonLeaderUnitCard';
import AbilityHelper from '../../../AbilityHelper';

export default class CorporateDefenseShuttle extends NonLeaderUnitCard {
protected override getImplementationId() {
return {
id: '4332645242',
internalName: 'corporate-defense-shuttle',
};
}

public override setupCardAbilities() {
this.addConstantAbility({
title: 'This unit can\'t attack',
ongoingEffect: AbilityHelper.ongoingEffects.cannotAttack()
});
}
}
20 changes: 20 additions & 0 deletions server/game/cards/04_JTL/units/FlankingFangFighter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import AbilityHelper from '../../../AbilityHelper';
import { NonLeaderUnitCard } from '../../../core/card/NonLeaderUnitCard';
import { KeywordName, Trait } from '../../../core/Constants';

export default class FlankingFangFighter extends NonLeaderUnitCard {
protected override getImplementationId () {
return {
id: '0626954301',
internalName: 'flanking-fang-fighter',
};
}

public override setupCardAbilities () {
this.addConstantAbility({
title: 'While you control another Fighter unit, this unit gains Raid 2',
condition: (context) => context.player.isTraitInPlay(Trait.Fighter, context.source),
ongoingEffect: AbilityHelper.ongoingEffects.gainKeyword({ keyword: KeywordName.Raid, amount: 2 })
});
}
}
39 changes: 39 additions & 0 deletions server/game/cards/04_JTL/units/KimogilaHeavyFighter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import AbilityHelper from '../../../AbilityHelper';
import { NonLeaderUnitCard } from '../../../core/card/NonLeaderUnitCard';
import { EventName, TargetMode } from '../../../core/Constants';

export default class KimogilaHeavyFighter extends NonLeaderUnitCard {
protected override getImplementationId () {
return {
id: '6757031085',
internalName: 'kimogila-heavy-fighter',
};
}

private filterUnitsDamagedThatCanBeExhausted(events) {
return events
.filter((event) => event.name === EventName.OnDamageDealt)
.filter((event) => event.card.canBeExhausted())
.map((event) => event.card);
}

public override setupCardAbilities () {
this.addTriggeredAbility({
title: 'Deal 3 indirect damage to a player',
when: {
onCardPlayed: (event, context) => event.card === context.source,
},
targetResolver: {
mode: TargetMode.Player,
immediateEffect: AbilityHelper.immediateEffects.indirectDamageToPlayer({ amount: 3 })
},
then: (thenContext) => ({
title: 'Exhaust each unit damaged this way.',
thenCondition: () => this.filterUnitsDamagedThatCanBeExhausted(thenContext.events).length > 0,
immediateEffect: AbilityHelper.immediateEffects.exhaust({
target: this.filterUnitsDamagedThatCanBeExhausted(thenContext.events),
})
})
});
}
}
28 changes: 28 additions & 0 deletions server/game/cards/04_JTL/units/MillenniumFalconGetOutAndPush.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import AbilityHelper from '../../../AbilityHelper';
import type { Card } from '../../../core/card/Card';
import { NonLeaderUnitCard } from '../../../core/card/NonLeaderUnitCard';
import { Trait } from '../../../core/Constants';

export default class MillenniumFalconGetOutAndPush extends NonLeaderUnitCard {
protected override getImplementationId () {
return {
id: '8845408332',
internalName: 'millennium-falcon#get-out-and-push',
};
}

public override setupCardAbilities () {
this.addConstantAbility({
title: 'You may play or deploy 1 additional Pilot on this unit',
ongoingEffect: AbilityHelper.ongoingEffects.modifyPilotingLimit({ amount: 1 })
});

this.addConstantAbility({
title: 'This unit gets +1/+0 for each Pilot on it',
ongoingEffect: AbilityHelper.ongoingEffects.modifyStats((target) => ({
power: target.upgrades.reduce((count: number, upgrade: Card) => count + (upgrade.hasSomeTrait(Trait.Pilot) ? 1 : 0), 0),
hp: 0
})),
});
}
}
25 changes: 25 additions & 0 deletions server/game/cards/04_JTL/units/R2D2Artooooooooo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import AbilityHelper from '../../../AbilityHelper';
import { NonLeaderUnitCard } from '../../../core/card/NonLeaderUnitCard';
import { WildcardZoneName } from '../../../core/Constants';

export default class R2D2Artooooooooo extends NonLeaderUnitCard {
protected override getImplementationId () {
return {
id: '5375722883',
internalName: 'r2d2#artooooooooo',
};
}

public override setupCardAbilities () {
this.addPilotingConstantAbilityTargetingAttached({
title: 'You may play or deploy 1 additional Pilot on this unit',
ongoingEffect: AbilityHelper.ongoingEffects.modifyPilotingLimit({ amount: 1 })
});

this.addConstantAbility({
title: 'This upgrade can be played on a friendly Vehicle unit with a Pilot on it.',
sourceZoneFilter: WildcardZoneName.Any,
ongoingEffect: AbilityHelper.ongoingEffects.ignorePilotingPilotLimit(),
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default class ShuttleST149UnderKrennicsAuthority extends NonLeaderUnitCar
controller: WildcardRelativePlayer.Any,
cardCondition: (card, context) =>
context.targets.chooseUpgrade.parentCard !== card &&
context.targets.chooseUpgrade.canAttach(card, context.targets.chooseUpgrade.parentCard.controller),
context.targets.chooseUpgrade.canAttach(card, context, context.targets.chooseUpgrade.parentCard.controller),
immediateEffect: AbilityHelper.immediateEffects.attachUpgrade((context) => ({
upgrade: context.targets.chooseUpgrade,
target: context.targets.chooseUnit,
Expand Down
3 changes: 3 additions & 0 deletions server/game/core/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export enum EffectName {
CanAttackGroundArenaFromSpaceArena = 'canAttackGroundArenaFromSpaceArena',
CanAttackSpaceArenaFromGroundArena = 'canAttackSpaceArenaFromGroundArena',
CanBeTriggeredByOpponent = 'canBeTriggeredByOpponent',
CanBePlayedWithPilotingIgnoringPilotLimit = 'canBePlayedWithPilotingIgnoringPilotLimit',
CannotBeDefeatedByDamage = 'cannotBeDefeatedByDamage',
CanPlayFromDiscard = 'canPlayFromDiscard',
ChangeType = 'changeType',
Expand All @@ -87,6 +88,7 @@ export enum EffectName {
LoseKeyword = 'loseKeyword',
LoseTrait = 'loseTrait',
ModifyHp = 'modifyHp',
ModifyPilotLimit = 'modifyPilotLimit',
ModifyPower = 'modifyPower',
ModifyStats = 'modifyStats',
MustBeChosen = 'mustBeChosen',
Expand All @@ -101,6 +103,7 @@ export enum EffectName {
// "cannot" effects
CannotApplyLastingEffects = 'cannotApplyLastingEffects',
CannotAttackBase = 'cannotAttackBase',
CannotAttack = 'cannotAttack',
}

export enum Duration {
Expand Down
2 changes: 1 addition & 1 deletion server/game/core/Player.js
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ class Player extends GameObject {
if (context.stage === Stage.Cost && !context.target && context.source.isUpgrade()) {
const upgrade = context.source;
return context.game.getArenaUnits()
.filter((unit) => upgrade.canAttach(unit))
.filter((unit) => upgrade.canAttach(unit, context))
.some((unit) => adjuster.canAdjust(context.playType, upgrade, context, unit, penaltyAspect));
}
return adjuster.canAdjust(context.playType, context.source, context, context.target, penaltyAspect);
Expand Down
7 changes: 3 additions & 4 deletions server/game/core/card/EventCard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ export class EventCard extends EventCardParent {

/** Ability of event card when played. Will be a "blank" ability with no effect if this card is disabled by an effect. */
public getEventAbility(): EventAbility {
return this.isBlank()
? new EventAbility(this._eventAbility.game, this._eventAbility.card, {
title: 'No effect',
return this.isBlank() || !this.hasImplementationFile
? new EventAbility(this.game, this, {
title: this.hasImplementationFile ? 'Unimplemented event card ability' : 'No effect',
printedAbility: false,
immediateEffect: new NoActionSystem({ hasLegalTarget: true })
})
Expand All @@ -81,7 +81,6 @@ export class EventCard extends EventCardParent {
this._eventAbility = new EventAbility(this.game, this, properties);
}


/** Add a constant ability on the card that decreases its cost under the given condition */
protected addDecreaseCostAbility(properties: IDecreaseCostAbilityProps<this>): void {
this.constantAbilities.push(this.createConstantAbility(this.generateDecreaseCostAbilityProps(properties)));
Expand Down
4 changes: 2 additions & 2 deletions server/game/core/card/LeaderUnitCard.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type Player from '../Player';
import type { ZoneFilter } from '../Constants';
import { CardType, DeployType, RelativePlayer, Trait, WildcardCardType } from '../Constants';
import { CardType, DeployType, PlayType, RelativePlayer, Trait, WildcardCardType } from '../Constants';
import { AbilityType, ZoneName } from '../Constants';
import type { IUnitCard } from './propertyMixins/UnitProperties';
import { WithUnitProperties } from './propertyMixins/UnitProperties';
Expand Down Expand Up @@ -145,7 +145,7 @@ export class LeaderUnitCard extends LeaderUnitCardParent implements IDeployableL
targetResolver: {
cardTypeFilter: WildcardCardType.Unit,
controller: RelativePlayer.Self,
cardCondition: (card) => card.isUnit() && card.hasSomeTrait(Trait.Vehicle) && card.canAttachPilot(),
cardCondition: (card, context) => card.isUnit() && card.hasSomeTrait(Trait.Vehicle) && card.canAttachPilot(context.source, PlayType.Piloting),
immediateEffect: AbilityHelper.immediateEffects.deployAndAttachPilotLeader((context) => ({
leaderPilotCard: context.source
}))
Expand Down
Loading

0 comments on commit e8cc0ec

Please sign in to comment.