UNPKG

programming-game

Version:

The client for programming game, an mmorpg that you interact with entirely through code.

923 lines (922 loc) 23.9 kB
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 {};