programming-game
Version:
The client for programming game, an mmorpg that you interact with entirely through code.
923 lines (922 loc) • 23.9 kB
TypeScript
import { Amulets, Boots, Chests, Equipments, Gloves, Helms, ItemDefinition, Items, Legs, OffhandEquipment, OneHandedWeapons, Rings, UsableItems, Weapons, WeaponType } from "./items";
import { recipes } from "./recipes";
import { CastIntent, Spells } from "./spells";
import { WeaponSkill, WeaponSkillSpecifics } from "./weapon-skills";
import { Monsters } from "./monsters";
export declare enum RACE {
human = "human",
orc = "orc",
imp = "imp",
goblin = "goblin",
wolf = "wolf",
snake = "snake",
rat = "rat",
troll = "troll",
chicken = "chicken",
slime = "slime"
}
export declare enum ROLES {
new_arrival = "new_arrival",
healer = "healer",
guard = "guard",
mage = "mage",
warrior = "warrior",
ranger = "ranger",
merchant = "merchant",
scout = "scout"
}
type BaseGameObject = {
position: Position;
label: string;
id: string;
radius: number;
};
export type Portal = BaseGameObject & {
type: "portal";
};
export type Hazard = BaseGameObject & {
type: "hazard";
};
export type TreeType = "pine" | "oak";
export type Tree = BaseGameObject & {
type: "tree";
treeType: TreeType;
};
export type OreType = "copper" | "tin";
export type MiningNode = BaseGameObject & {
type: "miningNode";
oreType: OreType;
};
export type GameObject = {
id: string;
type: string;
} & (Portal | Hazard | Tree | MiningNode);
export type Parties = Record<string, {
lootIndex: number;
members: Record<string, boolean>;
}>;
export type PlayersSeekingParty = Pick<ClientSidePlayer, "name" | "role" | "id">[];
export type ClientSidePartyInvites = Pick<ClientSidePlayer, "name" | "role" | "id">[];
export type InstanceName = "overworld" | "1v1Arena";
export type NPCQuestStep = {
type: "gather";
targets: Partial<Record<Items, number>>;
} | {
type: "kill";
targets: Partial<Record<Monsters, number>>;
} | {
type: "goto";
position: Position;
} | {
type: "turn_in";
/**
* The id of the NPC to turn the quest in to.
*/
target: string;
requiredItems?: Partial<Record<Items, number>>;
position: {
x?: number;
y?: number;
};
};
export type ClientSidePlayerKillStep = {
type: "kill";
targets: Partial<Record<Monsters, {
required: number;
killed: number;
}>>;
};
export type PlayerQuestStep = ClientSidePlayerKillStep | {
type: "goto";
position: Position;
completed: boolean;
} | {
type: "turn_in";
/**
* The id of the NPC to turn the quest in to.
*/
target: string;
requiredItems?: Partial<Record<Items, number>>;
position: {
x?: number;
y?: number;
};
};
export type ActiveQuest = {
id: string;
start_npc: string;
end_npc: string;
name: string;
steps: PlayerQuestStep[];
};
export type ActiveQuests = Record<string, ActiveQuest>;
export type CombatSkills = Record<WeaponType, number>;
export interface ClientSidePlayer extends BaseUnit {
type: UnitTypes.player;
bounty: number;
name: string;
id: string;
calories: number;
equipment: PlayerEquipment;
partyLeader: boolean;
role: ROLES;
partyInvites: ClientSidePartyInvites;
threat: Record<string, true>;
demo?: boolean;
completedQuests?: Set<string>;
party: Record<string, true>;
quests: ActiveQuests;
storage: Inventory;
combatSkills: CombatSkills;
}
export type ClientSideUnit = ClientSideMonster | ClientSideNPC | ClientSidePlayer;
export type ClientSideMonster = Omit<Monster, "partyInvites" | "party"> & {
partyInvites: ClientSidePartyInvites;
party: Record<string, true>;
};
export type ClientSideNPC = Omit<NPC, "partyInvites" | "party"> & {
partyInvites: ClientSidePartyInvites;
party: Record<string, true>;
availableQuests: Record<string, {
repeatable: boolean;
id: string;
name: string;
steps: NPCQuestStep[];
rewards: {
items: Partial<Record<Items, number>>;
};
}>;
};
export type Boundary = {
xMin: number;
xMax: number;
yMin: number;
yMax: number;
};
export type Constants = {
/**
* The maximum size of a party.
*/
maxPartySize: 5;
/**
* Length of the global cooldown in seconds.
*/
globalCooldown: 0.5;
/**
* The max carry weight before you're movement is reduced to 0, in grams.
*/
maxCarryWeight: 70000;
/**
* The % of carry weight at which your movement begins to slow.
*/
encumbranceThreshold: 0.7;
/**
* The maximum amount of calories a unit can have.
*/
maxCalories: 3000;
/**
* The maximum number of active quests a unit can have.
*/
maxActiveQuests: 5;
/**
* The maximum number of spells that can be set to the spellbook.
*/
spellbookSize: 15;
/**
* The time it takes to equip a spell into your spellbook.
*/
spellEquipMS: 5000;
};
/**
* Events coming from the server telling the client what has happened.
*/
export type RawEvents = {
acceptedPartyInvite: {
inviteeId: string;
inviterId: string;
};
updatedPartyInvites: {
invites: ClientSidePartyInvites;
unitId: string;
};
focus: {
monsterId: string;
focus: string | null;
};
boundary: Boundary;
connectionEvent: {
player: ClientSidePlayer;
party: Record<string, true>;
units: Record<string, ClientSideUnit>;
gameObjects: Record<string, GameObject>;
playersSeekingParty: PlayersSeekingParty;
time: number;
partyInvites: ClientSidePartyInvites;
items?: Record<Items, ItemDefinition>;
constants?: Constants;
recipes?: typeof recipes;
};
updatedRole: {
unitId: string;
role: ROLES;
};
/**
* @deprecated Use updatedPartyV2 instead.
*/
updatedParty: {
party: Record<string, true>;
};
/**
* Updated party information for a party. Identical to v1, but sent to all units in vision of the party members.
* The client should be smarter here and update all the visible units rather than assuming the event is for themselves.
*/
updatedPartyV2: {
party: Record<string, true>;
playerId: string;
};
invited: {
inviter: {
id: string;
role: ROLES;
name: string;
};
invitee: string;
};
seekParty: {
playersSeeking: PlayersSeekingParty[0];
};
unitAppeared: {
unit: ClientSideUnit;
};
unitDisappeared: {
unitId: string;
};
objectAppeared: {
object: GameObject;
};
objectDisappeared: {
objectId: string;
};
objectUpdated: {
objectId: string;
properties: Partial<GameObject>;
};
moved: {
id: string;
} & Position;
attacked: {
attacker: string;
attacked: string;
damage: number;
hp: number;
attackerTp: number;
};
combatSkillIncreased: {
unitId: string;
amount: number;
skill: WeaponType;
};
hazardDamaged: {
hazardId: string;
unitId: string;
damage: number;
hp: number;
};
used: {
item: Items;
unitId: string;
target: string;
};
updatedTrade: {
unitId: string;
trades: Trades & NewTrades;
};
dropped: {
unitId: string;
item: Items;
amount: number;
};
loot: {
unitId: string;
items: Partial<Record<Items, number>>;
};
beganEquippingSpell: {
unitId: string;
spell: Spells;
duration: number;
};
beganCasting: {
unitId: string;
spell: Spells;
target?: string;
duration?: number;
};
beganHarvesting: {
unitId: string;
objectId: string;
duration: number;
};
harvested: {
unitId: string;
objectId: string;
};
castSpell: {
unitId: string;
spell: Spells;
};
gainedStatus: {
unitId: string;
effect: StatusEffectName;
duration: number;
source: string;
stacks: number;
target?: string;
effects: AppliesMechanics;
};
arena: {
duration: number;
};
lostStatus: {
unitId: string;
effect: StatusEffectName;
};
hp: {
unitId: string;
hp: number;
};
mp: {
unitId: string;
mp: number;
};
tp: {
unitId: string;
tp: number;
};
calories: {
unitId: string;
calories: number;
};
ate: {
unitId: string;
item: Items;
calories: number;
remaining: number;
};
equipped: {
unitId: string;
item: Equipments;
slot: keyof PlayerEquipment;
};
usedWeaponSkill: {
unitId: string;
targetId: string;
skill: WeaponSkill;
tp: number;
};
unequipped: {
unitId: string;
item: Equipments;
slot: keyof PlayerEquipment;
};
beganCrafting: {
unitId: string;
item: Items;
duration: number;
};
finishedCrafting: {
unitId: string;
items: Partial<Record<keyof typeof recipes, number>>;
spent: Partial<Record<Items, number>>;
};
setIntent: {
unitId: string;
intent: Intent | null;
};
despawn: {
unitId: string;
};
died: {
unitId: string;
};
traded: {
actingUnitId: string;
targetUnitId: string;
gave: Partial<Record<Items, number>>;
got: Partial<Record<Items, number>>;
};
stats: {
unitId: string;
stats: UnitStats;
};
acceptedQuest: {
unitId: string;
quest: ClientSidePlayer["quests"][string];
};
abandonedQuest: {
unitId: string;
questId: string;
questName: string;
};
completedQuest: {
unitId: string;
questId: string;
questName: string;
};
questAvailable: {
npcId: string;
quest: ClientSideNPC["availableQuests"][string];
};
questUpdate: {
unitId: string;
quest: ClientSidePlayer["quests"][string];
};
inventory: {
unitId: string;
inventory: Inventory;
};
storageEmptied: undefined;
storageCharged: {
coinsLeft: number;
charged: number;
};
deposited: {
items: Inventory;
};
withdrew: {
items: Inventory;
};
unequippedSpell: {
unitId: string;
};
equippedSpell: {
unitId: string;
spell: Spells;
};
};
type CreateEventsEvents = <T extends keyof RawEvents>() => EventGroup<T>;
export type EventGroup<T extends keyof RawEvents> = [T, RawEvents[T]][];
export type BatchedEvents = {
[instance: string]: {
[character: string]: ReturnType<CreateEventsEvents>;
};
};
export type EventObjMap<T extends {}> = {
c: string;
i: InstanceName;
} & T;
type CreateIntentMap = <T extends keyof RawEvents, K>(obj: K) => {
[key in T]: (instance: string, charId: string, event: RawEvents[key]) => void;
};
export type EventMap = ReturnType<CreateIntentMap>;
/**
* Spell Groups?
*
* Spells
*
* // books have 9 spells?
*
* Nature - Very low mana cost, uses calories as well?
* Stone Skin - buff, instant, defense
* Iron Skin - buff, instant, defense
* Aid Digestion - buff, channel, regen
* Remove Poison - debuff, poison
* Cure Disease - debuff, disease
* Entangling Roots - debuff, root
* Regrowth - heal, heal over time
* Rejuvenation - heal, heal over time
*
* === Healer ===
* Holy Shield - buff, defense
* Flash - debuff, blind
* Heal - heal, heal
* Greater Heal - heal, heal
* Resurrection - heal, cast time, resurrect
* Lay on Hands - heal, instant, full health, no cost
*
*
* Warlock/Summoner - consumes some health as well as mana
* Summon Imp - summon, cast time, imp
* Summon Voidwalker - summon, cast time, voidwalker
* Summon Succubus - summon, cast time, succubus
* Summon Felhunter - summon, cast time, felhunter
* Summon Doomguard - summon, cast time, doomguard
* Summon Infernal - summon, cast time, infernal
* Fear - debuff, fear
* Convert - debuff, charm
* Sacrifice - buff, instant, sacrifice pet for health
*
* Time - very high mana cost, very low cooldown
* Haste - buff, movement speed
* Slow - debuff, movement speed
* Portal - long distance teleport, very expensive, very long cast
* Isolate - stun, instant, very expensive, very long cast
* Teleport - short distance teleport, longer than blink, instant, expensive
* Confuse - debuff, attack anyone
* Accelerate - buff, attack speed
* Decelerate - debuff, attack speed
*
* Mage
* Mana Shield - buff, defense
* Fireball - ranged, damage, cast time, burning effect
* Frostbolt - ranged, damage, cast time, slow effect
* Arcane Missiles - ranged, damage, channel, knockback effect
* Frost Nova - aoe, damage, cast time, slow effect
* Blink - teleport, instant, no cost
*
* Lightning Mage
* Energize - buff, mana
* Static Charge - summon mana, chance to fail
* Blink - teleport, instant, no cost
* Lightning Bolt - ranged, damage, cast time
* Chain Lightning - ranged, damage, cast time
* Lightning Storm - aoe, damage, channel
* Thunder - aoe, damage, cast time, silence effect
*
* Frost Mage
* Frostbolt - ranged, damage, cast time, slow effect
* Frost Nova - aoe, damage, cast time, slow effect
* Frost Burn - ranged debuff, lowers attack speed
* Blizzard - aoe, damage, channel, slow effect
* Freeze - ranged, damage, cast time, stun effect
* Ice Armor - buff, defense
*
* Fire Mage
* Fireball - ranged, damage, cast time, burning effect
* Flash Fire - range, damage, instant, burning effect
* Consuming Flames - ranged, damage, cast time, burning effect
* Flamethrower - ranged, damage, channel, burning effect
*
* Arcane Mage
* Arcane Missiles - ranged, damage, channel, knockback effect
* Arcane Explosion - aoe, damage, cast time, knockback effect
* Arcane Blast - short range, instant, long cooldown, large knockback effect
*/
export declare const sightRange = 10;
export declare const minRangedAttackRange = 2.5;
export type Party = Record<string, Omit<ClientSideUnit, "inventory">>;
export interface UnitStats {
/**
* Movement speed in meters per second.
*/
movementSpeed: number;
/**
* Mana regeneration rate in mana per second.
*/
mpRegen: number;
/**
* How much damage the unit can do relative to the target's defense.
*/
attack: number;
/**
* How much physical attack damage can be mitigated.
*/
defense: number;
/**
* The maximum mana this unit can have.
*/
maxMp: number;
/**
* The maximum health this unit can have.
*/
maxHp: number;
/**
* The maximum technique points this unit can have.
*/
maxTp: number;
/**
* How large the unit is in meters.
*/
radius: number;
}
export interface Position {
x: number;
y: number;
}
export declare enum UnitTypes {
npc = "npc",
player = "player",
monster = "monster"
}
/**
* @deprecated Use NewTrades ideally.
*/
export type Trades = {
wants: {
[key in Items]?: number;
};
offers: {
[key in Items]?: number;
};
};
export type NewTrades = {
buying: {
[key in Items]?: {
price: number;
quantity: number;
};
};
selling: {
[key in Items]?: {
price: number;
quantity: number;
};
};
};
type UnitStatusEffects = Partial<Record<StatusEffectName, {
duration: number;
source: string;
stacks: number;
target?: string;
effects: AppliesMechanics;
}>>;
type BaseUnit = {
unitsInSight: Set<string>;
calories: number;
role?: ROLES;
trades: {
/**
* @deprecated Use buying/selling instead.
*/
wants: Trades["wants"];
/**
* @deprecated Use buying/selling instead.
*/
offers: Trades["wants"];
buying: NewTrades["buying"];
selling: NewTrades["selling"];
};
id: string;
hp: number;
tp: number;
mp: number;
party: Record<string, true>;
lastUpdate: number;
position: Position;
race: RACE;
intent: Intent | null;
lastAction: number;
name: string;
npc: boolean;
type: UnitTypes;
action?: "cast" | "craft" | "equipSpell" | "harvest";
actionDuration?: number;
actionStart?: number;
actionTarget?: string;
actionUsing?: string;
stats: UnitStats;
inventory: Inventory;
statusEffects: UnitStatusEffects;
spellbook: Spells[];
};
export type StatusEffectName = "chill" | "regen" | "burn" | "freeze" | "iceArmor" | "snare" | "potionSickness" | "bandaged" | "pinningShot" | "headbutt" | "charge" | "shieldCharge" | "stunned";
export declare enum StatusEffectMechanics {
root = "root",
stun = "stun",
silence = "silence",
charm = "charm",
fear = "fear",
blind = "blind",
knockback = "knockback",
dot = "dot",
slow = "slow",
hot = "hot",
taunted = "taunted",
shield = "shield",
snare = "snare"
}
export type AppliesMechanics = {
stun?: boolean;
silence?: boolean;
hot?: number;
dot?: number;
snare?: boolean;
shield?: number;
damageMultiplier?: number;
attackMultiplier?: number;
movementMultiplier?: number;
stats?: Partial<UnitStats>;
};
interface Monster extends BaseUnit {
type: UnitTypes.monster;
monsterId: Monsters;
threat: Record<string, number>;
focus: string | null;
}
interface NPC extends BaseUnit {
id: string;
type: UnitTypes.npc;
banker: boolean;
}
export type PlayerEquipment = {
helm: Helms | null;
chest: Chests | null;
legs: Legs | null;
feet: Boots | null;
hands: Gloves | null;
weapon: Weapons | null;
offhand: OffhandEquipment | OneHandedWeapons | null;
amulet: Amulets | null;
ring1: Rings | null;
ring2: Rings | null;
earring1: Earrings | null;
earring2: Earrings | null;
};
type Earrings = never;
export type Inventory = Partial<Record<Items, number>>;
export declare enum IntentType {
move = "move",
attack = "attack",
respawn = "respawn",
summonMana = "summonMana",
eat = "eat",
cast = "cast",
/**
* @deprecated
*/
sell = "sell",
sellItems = "sellItems",
/**
* @deprecated
*/
buy = "buy",
buyItems = "buyItems",
use = "use",
equip = "equip",
unequip = "unequip",
setRole = "setRole",
inviteToParty = "inviteToParty",
seekParty = "seekParty",
acceptPartyInvite = "acceptPartyInvite",
declinePartyInvite = "declinePartyInvite",
leaveParty = "leaveParty",
craft = "craft",
weaponSkill = "weaponSkill",
/**
* @deprecated
*/
setSpellStones = "setSpellStones",
drop = "drop",
setTrade = "setTrade",
acceptQuest = "acceptQuest",
abandonQuest = "abandonQuest",
turnInQuest = "turnInQuest",
deposit = "deposit",
withdraw = "withdraw",
equipSpell = "equipSpell",
unequipSpell = "unequipSpell",
harvest = "harvest"
}
export type Intent = MoveIntent | AttackIntent | RespawnIntent | SummonManaIntent | EatIntent | CastIntent | SellIntent | SellItemsIntent | BuyIntent | BuyItemsIntent | UseIntent | DropIntent | SetRoleIntent | SeekPartyIntent | InviteToPartyIntent | AcceptPartyInviteIntent | DeclinePartyInviteIntent | LeavePartyIntent | EquipIntent | UnequipIntent | CraftIntent | WeaponSkillIntent<WeaponSkill> | SetSpellStonesIntent | SetTradeIntent | AcceptQuestIntent | AbandonQuestIntent | TurnInQuestIntent | DepositIntent | WithdrawIntent | EquipSpellIntent | UnequipSpellIntent | HarvestIntent;
export interface BaseIntent {
type: IntentType;
}
export interface AcceptQuestIntent extends BaseIntent {
type: IntentType.acceptQuest;
questId: string;
npcId: string;
}
export interface AbandonQuestIntent extends BaseIntent {
type: IntentType.abandonQuest;
questId: string;
}
export interface TurnInQuestIntent extends BaseIntent {
type: IntentType.turnInQuest;
questId: string;
npcId: string;
}
export interface DepositIntent extends BaseIntent {
type: IntentType.deposit;
until: Inventory;
npcId: string;
}
export interface WithdrawIntent extends BaseIntent {
type: IntentType.withdraw;
until: Inventory;
npcId: string;
}
export type WeaponSkillIntent<T extends WeaponSkill> = BaseIntent & {
type: IntentType.weaponSkill;
} & WeaponSkillSpecifics[T]["server"];
export interface CraftIntent {
type: IntentType.craft;
item: keyof typeof recipes;
from: Partial<Inventory>;
}
export interface SetTradeIntent {
type: IntentType.setTrade;
trades: Trades | NewTrades;
}
export interface SetSpellStonesIntent {
type: IntentType.setSpellStones;
item: Items;
name: string;
stones: Spells[];
}
export interface EquipIntent extends BaseIntent {
type: IntentType.equip;
item: Equipments;
slot: keyof PlayerEquipment;
}
export interface EquipSpellIntent extends BaseIntent {
type: IntentType.equipSpell;
spell: Spells;
}
export interface UnequipSpellIntent extends BaseIntent {
type: IntentType.unequipSpell;
}
export interface HarvestIntent extends BaseIntent {
type: IntentType.harvest;
target: string;
}
export interface UnequipIntent extends BaseIntent {
type: IntentType.unequip;
slot: keyof PlayerEquipment;
}
export interface AcceptPartyInviteIntent extends BaseIntent {
type: IntentType.acceptPartyInvite;
playerId: string;
}
export interface DeclinePartyInviteIntent extends BaseIntent {
type: IntentType.declinePartyInvite;
playerId: string;
}
export interface LeavePartyIntent extends BaseIntent {
type: IntentType.leaveParty;
}
export interface UseIntent {
type: IntentType.use;
item: UsableItems;
until: number;
target?: string;
}
export interface DropIntent {
type: IntentType.drop;
item: Items;
until: number;
}
/**
* @deprecated
*/
export interface BuyIntent extends BaseIntent {
type: IntentType.buy;
item: Items;
until: number;
from: string;
}
export interface BuyItemsIntent extends BaseIntent {
type: IntentType.buyItems;
items: {
[key in Items]?: number;
};
from: string;
}
export interface SetRoleIntent extends BaseIntent {
type: IntentType.setRole;
role: ROLES;
}
export interface SeekPartyIntent extends BaseIntent {
type: IntentType.seekParty;
}
export interface InviteToPartyIntent extends BaseIntent {
type: IntentType.inviteToParty;
playerId: string;
}
/**
* @deprecated
*/
export interface SellIntent extends BaseIntent {
type: IntentType.sell;
item: Items;
until: number;
to: string;
}
export interface SellItemsIntent extends BaseIntent {
type: IntentType.sellItems;
items: {
[key in Items]?: number;
};
to: string;
}
export interface EatIntent extends BaseIntent {
type: IntentType.eat;
item: Items;
save: number;
}
export interface AttackIntent extends BaseIntent {
type: IntentType.attack;
target: string;
}
export interface MoveIntent extends BaseIntent {
type: IntentType.move;
position: Position;
}
export interface RespawnIntent extends BaseIntent {
type: IntentType.respawn;
}
export interface SummonManaIntent extends BaseIntent {
type: IntentType.summonMana;
}
export interface Encounter {
id: string;
}
export {};