Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 51 additions & 73 deletions src/workshop/Characters.tsx
Original file line number Diff line number Diff line change
@@ -1,123 +1,101 @@
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,
ThiefStartItem,
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);
}
}
}
102 changes: 63 additions & 39 deletions src/workshop/Weapons.tsx
Original file line number Diff line number Diff line change
@@ -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<T extends IWeapon> {
// 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<StaffCharge> {
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
];
}