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
43 changes: 27 additions & 16 deletions src/workshop/BaseCharacter.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
import { CharacterClassName, ICharacter, ICharacterActionDecision } from "../off-limits/ICharacter";
import { IWeapon, IItem } from "../off-limits/IWeapons";
import { CharacterClassName, equip, ICharacter, ICharacterActionDecision } from "../off-limits/ICharacter";
import { IWeapon, IItem, isMeleeWeapon, isRangedWeapon } from "../off-limits/IWeapons";


//todo: use this base class somehow in Characters.tsx
export class Character implements ICharacter {
export abstract class Character implements ICharacter {
name: string = '';
health: number = 5;
position: number = 10;
weapons: IWeapon[] = [];
item?: IItem;
item?: IItem;

classname(): CharacterClassName {
throw new Error("Method not implemented.");
}
move(){
throw new Error("Method not implemented.");
}
chooseAction(): ICharacterActionDecision{
throw new Error("Method not implemented.");
}
getASCIIStatus(): string {
throw new Error("Method not implemented.");
}
constructor(protected avatar:string,
protected characterClass: CharacterClassName,
protected equipment: IItem|undefined,
public key: number) { equip(equipment, this); }

classname: () => CharacterClassName = () => this.characterClass;
move: () => void = () => this.position = Math.max(this.position - 5, 1);
chooseAction: () => ICharacterActionDecision = () => {
let canAttack:boolean = false;
let weapon = this.weapons[0];
if(this.health < 2 && this.item) return { use: this.item };
if(weapon) {
if(isMeleeWeapon(weapon) && this.position <= weapon.meleeRange)
canAttack = true;
if(isRangedWeapon(weapon) && weapon.projectiles.length > 0)
canAttack = true;
return canAttack ? { attack: weapon } : { use: this.item } as ICharacterActionDecision;
} else {
return { use: this.item } as ICharacterActionDecision;
}
};
getASCIIStatus:() => string = () => this.health <= 0 ? "X" : this.avatar;
}
114 changes: 13 additions & 101 deletions src/workshop/Characters.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ICharacter, CharacterClassName, equip, ICharacterActionDecision } from '../off-limits/ICharacter';
import { IWeapon, IItem, isMeleeWeapon } from '../off-limits/IWeapons';

import { Character } from './BaseCharacter';
import {
ClericStartItem,
Expand All @@ -11,113 +10,26 @@ import {
//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;
weapons: IWeapon[] = [];
item?: IItem;
feet = new Feet(this);
classname(): CharacterClassName {
return 'Warrior';
}
move(){
this.feet.move();
}
constructor(public name: string, public key: number) {
equip(WarriorStartItem, this);
}
chooseAction(): ICharacterActionDecision {
return {
attack: this.weapons[0]
}
}
getASCIIStatus(): string {
return "@";
}
export class Warrior extends Character {
constructor(public name: string, public key: number) {
super('W', 'Warrior', WarriorStartItem, key);
}
}

export class Cleric implements ICharacter{
health: number = 5;
position: number = 10;
weapons: IWeapon[] = [];
item?: IItem;
feet = new Feet(this);
classname(): CharacterClassName {
return 'Cleric';
}
move(){
this.feet.move();
}
export class Cleric extends Character{
constructor(public name: string, public key: number) {
equip(ClericStartItem, this);
}
chooseAction(): ICharacterActionDecision {
return {
attack: this.weapons[0]
}
}
getASCIIStatus(): string {
return "@";
}
super('C', 'Cleric', ClericStartItem, key)
}
}

export class Mage implements ICharacter {
health: number = 5;
position: number = 10;
weapons: IWeapon[] = [];
item?: IItem;
feet = new Feet(this);
classname(): CharacterClassName {
return 'Mage';
}
export class Mage extends Character{
constructor(public name: string, public key: number) {
equip(MageStartItem, this);
}
move(){
this.feet.move();
}
chooseAction(): ICharacterActionDecision {
return {
attack: this.weapons[0]
}
}
getASCIIStatus(): string {
return "@";
super('M', 'Mage', MageStartItem, key)
}
}

export class Thief implements ICharacter {
health: number = 5;
position: number = 10;
weapons: IWeapon[] = [];
item?: IItem;
feet = new Feet(this);
move(){
this.feet.move();
}
classname(): CharacterClassName {
return 'Thief';
}
export class Thief extends Character{
constructor(public name: string, public key: number) {
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);
}
}
super('T', 'Thief', ThiefStartItem, key)
}
}
59 changes: 50 additions & 9 deletions src/workshop/Weapons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,53 @@ import { IWeapon, IItem, IMeleeWeapon, IRangedWeapon, IConsumableItem, IEnchante

// WEAPON ARMORY
// todo: add more and better weapons!

export class Redhorse implements IConsumableItem {
healthBonus = 4;
name = 'Redhorse';

}

export class Club implements IMeleeWeapon {
name = 'Club';
damage = 1;
meleeRange = 1;
damage = 2;
meleeRange = 2;
}

export class Grenade implements IMeleeWeapon {
name = 'Grenade';
damage = 2;
meleeRange = 2;
}

export class GrenadeLauncher implements IRangedWeapon<Grenade> {
name = 'GrenadeLauncher';
damage:0 = 0;
projectiles: Grenade[] = [
new Grenade(), new Grenade()
];

}

export class BattleFury implements IMeleeWeapon {
name = 'Battle Fury';
damage = 2;
meleeRange = 2;
}

export class BloodThorn implements IMeleeWeapon {
name = 'Blood Thorn';
damage = 2;
meleeRange = 2;
}

export class AghanimsBlessing implements IEnchantedItem {
name = 'Aghanims Blessing';
fireDamage = 3;
partyHealthBonus = 4;
}


// ITEM VAULT
// todo: add more and better items!
export class UselessAmulet implements IItem {
Expand All @@ -39,18 +80,18 @@ export class UselessAmulet implements IItem {

// ITEM ASSIGNMENTS
// todo: assign starting items
export const WarriorStartItem: IItem|undefined = new Club();
export const ClericStartItem: IItem|undefined = new Club();
export const WarriorStartItem: IItem|undefined = new Redhorse();
export const ClericStartItem: IItem|undefined = new Redhorse();
export const MageStartItem: IItem|undefined = undefined;
export const ThiefStartItem: IItem|undefined = new Club();
export const ThiefStartItem: IItem|undefined = new Redhorse();

// 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 GrenadeLauncher(), //this will be found by the warrior
new BattleFury(), //this will be found by the cleric
new AghanimsBlessing(), //this will be found by the mage
new BloodThorn(), //this will be found by the thief
];
}