• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Typescript] Need help with my logic

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.
 

Cokemonkey11

Spell Reviewer
Level 30
Joined
May 9, 2006
Messages
3,537
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? 👀
 
Top