• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[Typescript] Need help with my logic

Status
Not open for further replies.
TypeScript:
export interface Deck<T = any> {
    cards: Card<T>[];
}
export interface Card<T> {
    name: string,
    giveBonus: (param: T) => void;
    param: T;
}
function giveHealth({ amount, heal }: { amount: number, heal: boolean }) {
    const unit = Unit.fromHandle(GetTriggerUnit());
    if(!unit) return;
    unit.maxLife += amount;
    if(heal) unit.life += amount;
}
function increaseSpellPower(by: number){
    Players[0].setTechResearched(FourCC("SSSS"), by);
}
const exampleDeck:Deck = {
    cards: [
        {
            name: "Big Flesh",
            giveBonus: giveHealth,
            param: {amount: 50, heal: true}
        },
        {
            name: "Huge Spell Powerer",
            giveBonus: increaseSpellPower,
            param: 3
        }
    ]
}
function PickFromDeck(){
    const card = exampleDeck.cards[0];
    card.giveBonus(card.param);
}
An example code logic
I will have many cards that will do certain stuff (hp mana heal unit aoe stun). With this logic I don't need any if statements when picking the card like
TypeScript:
if(type === "life") do stuff
else if(type === "unit") do stuff

  1. I want params type to be defined by the giveBonus callback's parameter type. Is it possible?
  2. Does this code make sense?
  3. Rate this logic on 1-10
    :Pepehands:
    If there is a better way please halp.
 
Last edited:
With the reading I have done, the traits/mixing kind of allows multiple inheritance. Composition instead of using multiple inheritance, has the functionalities separate class and contains in in the main class.
I don't want bark() or drink() when I pick a card. I want doSomething() and have the card do its specified thing without the card drawer knowing what it is.
My readings have not helped me in the logic above. My mind clearly could not put them together, could you help me learn what you have in mind regarding this logic?
With your statement, I believe your answer to my second question is that it doesn't make sense.
 
I'm on Mobile so excuse my brevity

You have done a good job capturing out doSomething instead of many conditional branches

At this point though your challenge is one of interface design

On one extreme, doSomething is a complex function with many arguments and possibly a return type

On the other extreme, your doSomething wants to be split into a more specific, concrete interface focused on your API (addHealth, increaseSpellPower)

I'd also say that your use of anonymous interfaces and functions here might be causing you some extra confusion, typical in typescript

Ultimately I don't know what API you're trying to achieve, but I think something like this would be an improvement:

const coolCard = {
name: "Golem",
stats: { ... },
effects: [
spellPowerEffect, healthEffect
]
}
 
With your code I came up something like this:

TypeScript:
interface Deck {
    cards: Card[];
}
interface Card {
    name: string,
    cost: number,
    effects: CardEffect<any>[]
}
abstract class CardEffect<T>{
    protected stats: T;
    set Stats(value: T) { this.stats = value; }
    constructor(stats: T) { this.stats = stats; }
    abstract effect(): void;
    abstract getDescription(): string;
}
class AddHealthEffect extends CardEffect<{ amount: number, heal: boolean }>{
    effect() {
        const unit = Unit.fromHandle(GetTriggerUnit());
        if (!unit) return;
        unit.maxLife += this.stats.amount;
        if (this.stats.heal) unit.life += this.stats.amount;
    };
    getDescription(): string {
        return "Increases max health by " + this.stats.amount;
    }
}
class AddSpellPowerEffect extends CardEffect<{ amount: number }>{
    effect() {
        Players[0].setTechResearched(FourCC("SSSS"), this.stats.amount);
    };
    getDescription(): string {
        return "Increases spell power by " + this.stats.amount + "%";
    }
}
const exampleDeck: Deck = {
    cards: [
        {
            name: "Big Flesh",
            cost: 60,
            effects: [new AddHealthEffect({ amount: 25, heal: true })],
        },
        {
            name: "Wisdom of Cokemonkey",
            cost: 120,
            effects: [new AddSpellPowerEffect({ amount: 10 })],
        }
    ]
}
function PickFromDeck() {
    //Player picks the card
    const card = exampleDeck.cards[0];
    //Card does its effects
    for (const effect of card.effects) {
        effect.effect();
    }
}

Now cards can have multiple effects, and with the class you get autocomplete for the stats as well as description for the cards. Also the picker function doesn't even need to handle the arguments. It will just call the effect.
How is this looking? 👀
 
Status
Not open for further replies.
Top