diff --git a/src/workshop/Characters.tsx b/src/workshop/Characters.tsx index 16ba4f4..3c0523b 100644 --- a/src/workshop/Characters.tsx +++ b/src/workshop/Characters.tsx @@ -1,6 +1,5 @@ import { ICharacter, CharacterClassName, equip, ICharacterActionDecision } from '../off-limits/ICharacter'; -import { IWeapon, IItem, isMeleeWeapon } from '../off-limits/IWeapons'; -import { Character } from './BaseCharacter'; +import { IWeapon, IItem, isConsumable, isMeleeWeapon } from "../off-limits/IWeapons"; import { ClericStartItem, MageStartItem, @@ -8,116 +7,95 @@ import { WarriorStartItem, } from './Weapons'; -//todo: too many duplicate classes in this file! -//todo: customize the chooseAction() to better fight the dragon -//todo: update the `getASCIIStatus` function(s) to return X when dead and a unique character per class - -export class Warrior implements ICharacter { - health: number = 5; - position: number = 10; +const STARTING_HEALTH = 5; +const STARTING_POSITION = 10; +class DragonWarrior implements ICharacter { + health: number = STARTING_HEALTH; + position: number = STARTING_POSITION; weapons: IWeapon[] = []; item?: IItem; - feet = new Feet(this); + + constructor(public name: string, public key: number) { + } classname(): CharacterClassName { - return 'Warrior'; + throw new Error("Method not implemented."); } move(){ - this.feet.move(); + if (this.weapons.some(x => isMeleeWeapon(x))){ + this.position = Math.max(this.position - 10, 1); + } } - constructor(public name: string, public key: number) { - equip(WarriorStartItem, this); + getASCIIStatus(): string { + return this.health > 0 ? "@" : "X"; } chooseAction(): ICharacterActionDecision { + let healthPercentage = (this.health / STARTING_HEALTH) * 100; + if (healthPercentage > 20) { + return { + attack: this.weapons[0] + }; + } else { + if (this.item && isConsumable(this.item)) { + return { + use: this.item + }; + } + } + + // fallback return { attack: this.weapons[0] - } + }; } - getASCIIStatus(): string { - return "@"; +} + +export class Warrior extends DragonWarrior { + classname(): CharacterClassName { + return 'Warrior'; + } + constructor(public name: string, public key: number) { + super(name, key); + equip(WarriorStartItem, this); } } -export class Cleric implements ICharacter{ - health: number = 5; - position: number = 10; - weapons: IWeapon[] = []; - item?: IItem; - feet = new Feet(this); +export class Cleric extends DragonWarrior{ classname(): CharacterClassName { return 'Cleric'; } - move(){ - this.feet.move(); - } constructor(public name: string, public key: number) { + super(name, key); equip(ClericStartItem, this); } chooseAction(): ICharacterActionDecision { + if (this.item) { + return { + use: this.item + } + } + return { attack: this.weapons[0] } } - getASCIIStatus(): string { - return "@"; - } } -export class Mage implements ICharacter { - health: number = 5; - position: number = 10; - weapons: IWeapon[] = []; - item?: IItem; - feet = new Feet(this); +export class Mage extends DragonWarrior { classname(): CharacterClassName { return 'Mage'; } constructor(public name: string, public key: number) { + super(name, key); equip(MageStartItem, this); } - move(){ - this.feet.move(); - } - chooseAction(): ICharacterActionDecision { - return { - attack: this.weapons[0] - } - } - getASCIIStatus(): string { - return "@"; - } } -export class Thief implements ICharacter { - health: number = 5; - position: number = 10; - weapons: IWeapon[] = []; - item?: IItem; - feet = new Feet(this); - move(){ - this.feet.move(); - } +export class Thief extends DragonWarrior { classname(): CharacterClassName { return 'Thief'; } constructor(public name: string, public key: number) { + super(name, key); equip(ThiefStartItem, this); } - chooseAction(): ICharacterActionDecision { - return { - attack: this.weapons[0] - } - } - getASCIIStatus(): string { - return "@"; - } -} - -//todo: something about this class is code smell... -export class Feet{ - constructor(private character: ICharacter){} - move(){ - if (this.character.weapons.some(x => isMeleeWeapon(x))){ - this.character.position = Math.max(this.character.position - 5, 1); - } - } } diff --git a/src/workshop/Weapons.tsx b/src/workshop/Weapons.tsx index 05e4f63..6830709 100644 --- a/src/workshop/Weapons.tsx +++ b/src/workshop/Weapons.tsx @@ -1,56 +1,80 @@ import { IWeapon, IItem, IMeleeWeapon, IRangedWeapon, IConsumableItem, IEnchantedItem } from "../off-limits/IWeapons"; -// INTERFACE QUICK REFERENCE -// export interface IItem { -// name: string; -// } -// export interface IWeapon extends IItem { -// damage: number; -// } -// export interface IMeleeWeapon extends IWeapon { -// meleeRange: number; -// } -// export interface IRangedWeapon { -// damage: 0; -// projectiles: T[]; -// } -// export interface IEnchantedItem extends IItem { -// fireDamage?: number; -// partyHealthBonus?: number; -// } -// export interface IConsumableItem extends IItem { -// healthBonus: number; -// } - // WEAPON ARMORY -// todo: add more and better weapons! -export class Club implements IMeleeWeapon { - name = 'Club'; - damage = 1; +export class Sword implements IMeleeWeapon { + name = 'Sword'; + damage = 9; + meleeRange = 2; +} + +export class EnchantedSword extends Sword implements IEnchantedItem { + name = 'Enchanted Sword'; + fireDamage = 3; +} + +export class Knife implements IMeleeWeapon { + name = 'Knife'; + damage = 9; meleeRange = 1; } +export class EnchantedKnife extends Knife implements IEnchantedItem { + name = 'Enchanted Knife'; + fireDamage = 3; +} + +export class Staff implements IRangedWeapon { + name = 'Staff'; + damage: any; + projectiles:StaffCharge[] = []; + constructor() { + for (let i = 0; i <= 100; i++) { + this.projectiles.push(new StaffCharge()); + } + } +} + +// dragonDamage: dmg + fireDmg + boltDmg, +export class EnchantedStaff extends Staff implements IEnchantedItem { + name = 'Fire bolt Staff'; + fireDamage = 3; + damage = 9; +} + +export class StaffCharge implements IWeapon { + name = 'Fire bolt'; + damage = 3; +} + // ITEM VAULT -// todo: add more and better items! -export class UselessAmulet implements IItem { - name = 'Useless Amulet'; +export class UnstablePotion implements IEnchantedItem { + name = 'Unstable Potion'; + fireDamage = 3; + partyHealthBonus = 4; } +export class Stimpack implements IConsumableItem { + name = 'Stimpack'; + healthBonus = 4; +} // ITEM ASSIGNMENTS -// todo: assign starting items -export const WarriorStartItem: IItem|undefined = new Club(); -export const ClericStartItem: IItem|undefined = new Club(); -export const MageStartItem: IItem|undefined = undefined; -export const ThiefStartItem: IItem|undefined = new Club(); +// NOTES: EnchantedStaff is too OP +export const WarriorStartItem: IItem|undefined = new EnchantedSword(); +export const ClericStartItem: IItem|undefined = new EnchantedSword(); +export const MageStartItem: IItem|undefined = new EnchantedStaff(); +export const ThiefStartItem: IItem|undefined = new EnchantedKnife(); +// export const WarriorStartItem: IItem|undefined = new EnchantedStaff(); +// export const ClericStartItem: IItem|undefined = new EnchantedSword(); +// export const MageStartItem: IItem|undefined = new EnchantedStaff(); +// export const ThiefStartItem: IItem|undefined = new EnchantedStaff(); // TREASURE ASSIGNMENTS -// todo: assign treasure from chests export function GetItemsInTreasureChests(): IItem[]{ return [ - new UselessAmulet(), //this will be found by the warrior - new UselessAmulet(), //this will be found by the cleric - new UselessAmulet(), //this will be found by the mage - new UselessAmulet(), //this will be found by the thief + new Stimpack(), //this will be found by the warrior + new UnstablePotion(), //this will be found by the cleric + new UnstablePotion(), //this will be found by the mage + new Stimpack(), //this will be found by the thief ]; }