Feast 2.0!
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 

502 lines
14 KiB

  1. import { Place, Choice, Direction, World } from '@/game/world'
  2. import { ProperNoun, ImproperNoun, MalePronouns, FemalePronouns, TheyPronouns } from '@/game/language'
  3. import { Encounter, Stat, Damage, DamageType, Vigor, Side } from '@/game/combat'
  4. import * as Items from '@/game/items'
  5. import { LogLine, nilLog, LogLines } from '@/game/interface'
  6. import { Creature } from '@/game/creature'
  7. import { DevourAction } from '@/game/combat/actions'
  8. import { InstantDigestionEffect, SurrenderEffect } from '@/game/combat/effects'
  9. import moment from 'moment'
  10. import { VoreAI } from '@/game/ai'
  11. import { DeliciousPerk } from '@/game/combat/perks'
  12. import Inazuma from '../creatures/characters/inazuma'
  13. import Samuel from '../creatures/characters/Samuel'
  14. import Human from '../creatures/human'
  15. import Slime from '../creatures/monsters/slime'
  16. function makeParty (): Creature[] {
  17. const fighter = new Human(new ProperNoun("Redgar"), MalePronouns, {
  18. stats: {
  19. Toughness: 20,
  20. Power: 20,
  21. Reflexes: 15,
  22. Agility: 15,
  23. Willpower: 15,
  24. Charm: 10
  25. }
  26. })
  27. fighter.title = "Lv. 6 Fighter"
  28. fighter.equip(new Items.Sword(), Items.EquipmentSlot.MainHand)
  29. const rogue = new Human(new ProperNoun('Lidda'), FemalePronouns, {
  30. stats: {
  31. Toughness: 10,
  32. Power: 15,
  33. Reflexes: 20,
  34. Agility: 20,
  35. Willpower: 15,
  36. Charm: 20
  37. }
  38. })
  39. rogue.title = "Lv. 5 Rogue"
  40. rogue.equip(new Items.Dagger(), Items.EquipmentSlot.MainHand)
  41. const wizard = new Human(new ProperNoun('Mialee'), FemalePronouns, {
  42. stats: {
  43. Toughness: 10,
  44. Power: 10,
  45. Reflexes: 15,
  46. Agility: 15,
  47. Willpower: 20,
  48. Charm: 25
  49. }
  50. })
  51. wizard.title = "Lv. 6 Wizard"
  52. wizard.equip(new Items.Wand(), Items.EquipmentSlot.MainHand)
  53. const cleric = new Human(new ProperNoun('Jozan'), MalePronouns, {
  54. stats: {
  55. Toughness: 15,
  56. Power: 15,
  57. Reflexes: 10,
  58. Agility: 10,
  59. Willpower: 20,
  60. Charm: 15
  61. }
  62. })
  63. cleric.title = "Lv. 5 Cleric"
  64. cleric.equip(new Items.Mace(), Items.EquipmentSlot.MainHand)
  65. return [fighter, cleric, rogue, wizard]
  66. }
  67. export const Newtown = (): Place => {
  68. const home = new Place(
  69. new ProperNoun("Home"),
  70. "A place you can rest after long adventures"
  71. )
  72. const debug = new Place(
  73. new ProperNoun("Debug Room"),
  74. "Where weird stuff happens"
  75. )
  76. const southTownStreet = new Place(
  77. new ProperNoun("South Town Street"),
  78. "Town street south of the Town square"
  79. )
  80. const northTownStreet = new Place(
  81. new ProperNoun("North Town Street"),
  82. "Town street north of the Town square"
  83. )
  84. const northTownShop = new Place(
  85. new ProperNoun("North Town Shop"),
  86. "A shop for your impulsive buying needs"
  87. )
  88. const eastTownStreet = new Place(
  89. new ProperNoun("East Town Street"),
  90. "Town street east of the Town square"
  91. )
  92. const westTownStreet = new Place(
  93. new ProperNoun("West Town Street"),
  94. "Town street west of the Town square"
  95. )
  96. const townSquare = new Place(
  97. new ProperNoun("Town Square"),
  98. "The central-most part of town, and a hub of bustling activity"
  99. )
  100. const eastGate = new Place(
  101. new ProperNoun("East Gate"),
  102. "The towns gate, leading out into the wilderness"
  103. )
  104. const woods = new Place(
  105. new ProperNoun("The Woods"),
  106. "A scary part of the forest where monsters hide"
  107. )
  108. const deepwoods = new Place(
  109. new ProperNoun("Deep Woods"),
  110. "Extra scary"
  111. )
  112. deepwoods.choices.push(
  113. new Choice(
  114. "Fight Inazuma",
  115. "Go fight Inazuma!",
  116. (world, executor) => {
  117. const enemy = new Inazuma()
  118. const encounter = new Encounter(
  119. {
  120. name: "Fight some tough nerd",
  121. intro: () => new LogLine(`Inazuma Approaches!`)
  122. },
  123. [world.player, enemy].concat(world.party)
  124. )
  125. world.encounter = encounter
  126. return nilLog
  127. }
  128. )
  129. )
  130. const bossEncounters = [
  131. new Encounter(
  132. { name: "Inazuma", intro: () => nilLog },
  133. makeParty().concat([new Inazuma()])
  134. )
  135. ]
  136. home.choices.push(
  137. new Choice(
  138. "Nap",
  139. "Zzzzzz",
  140. (world) => {
  141. return new LogLines(
  142. `You lie down for a nice nap...`,
  143. world.advance(moment.duration(1, "hour"))
  144. )
  145. }
  146. )
  147. )
  148. home.choices.push(
  149. new Choice(
  150. "Heal",
  151. "Become not dead and/or eaten",
  152. (world, executor) => {
  153. Object.keys(Vigor).forEach(vigor => {
  154. executor.vigors[vigor as Vigor] = executor.maxVigors[vigor as Vigor]
  155. })
  156. if (executor.containedIn !== null) {
  157. executor.containedIn.release(executor)
  158. }
  159. executor.statusEffects.forEach(effect => {
  160. executor.removeEffect(effect)
  161. })
  162. executor.destroyed = false
  163. return new LogLine(`You're healthy again`)
  164. }
  165. )
  166. )
  167. home.choices.push(
  168. new Choice(
  169. "Grab potions",
  170. "Grab some potions",
  171. (world, executor) => {
  172. executor.items.push(new Items.HealthPotion())
  173. executor.items.push(new Items.AcidPotion())
  174. executor.items.push(new Items.ShrinkPotion())
  175. executor.items.push(new Items.StrengthPotion())
  176. return new LogLine("You grab some potions")
  177. }
  178. )
  179. )
  180. townSquare.choices.push(
  181. new Choice(
  182. "Eat someone",
  183. "Slurp",
  184. (world, executor) => {
  185. const snack = new Human(new ProperNoun(["Snack", "Treat", "Tasty", "Dinner", "Appetizer"][Math.floor(Math.random() * 5)]), [MalePronouns, FemalePronouns, TheyPronouns][Math.floor(Math.random() * 3)])
  186. snack.applyEffect(new SurrenderEffect())
  187. const options = executor.validActions(snack).filter(action => action instanceof DevourAction)
  188. return options[Math.floor(options.length * Math.random())].execute(executor, snack)
  189. }
  190. )
  191. )
  192. townSquare.choices.push(
  193. new Choice(
  194. "Fight someone",
  195. "Ow",
  196. (world) => {
  197. const enemy = new Human(new ProperNoun("Nerd"), TheyPronouns)
  198. enemy.side = Side.Monsters
  199. enemy.ai = new VoreAI(enemy)
  200. enemy.equip(new Items.Sword(), Items.EquipmentSlot.MainHand)
  201. enemy.addPerk(new DeliciousPerk())
  202. const encounter = new Encounter(
  203. {
  204. name: "Fight some tasty nerd",
  205. intro: () => new LogLine(`You find some nerd to fight.`)
  206. },
  207. [world.player, enemy].concat(world.party)
  208. )
  209. world.encounter = encounter
  210. return nilLog
  211. }
  212. )
  213. )
  214. townSquare.choices.push(
  215. new Choice(
  216. "Recruit someone",
  217. "Not ow",
  218. (world) => {
  219. const ally = new Human(new ProperNoun("Ally"), TheyPronouns)
  220. ally.side = Side.Heroes
  221. ally.ai = new VoreAI(ally)
  222. ally.equip(new Items.Sword(), Items.EquipmentSlot.MainHand)
  223. world.party.push(ally)
  224. return new LogLine(`You recruit a nerd`)
  225. }
  226. )
  227. )
  228. northTownShop.choices.push(
  229. new Choice(
  230. "Buy a shiny rock",
  231. "This rock has no use.",
  232. (world, executor) => {
  233. if (executor.wallet.Gold >= 500) {
  234. executor.wallet.Gold -= 500
  235. executor.items.push(
  236. new Items.KeyItem(new ProperNoun("Shiny Rock"), "Very shiny")
  237. )
  238. return new LogLine(`You buy a shiny rock`)
  239. } else {
  240. return new LogLine(`Shiny rocks are 500 gold coins, loser!`)
  241. }
  242. }
  243. )
  244. )
  245. northTownShop.choices.push(
  246. new Choice(
  247. "Buy a health potion",
  248. "50 Gold",
  249. (world, executor) => {
  250. if (executor.wallet.Gold >= 50) {
  251. executor.wallet.Gold -= 50
  252. executor.items.push(
  253. new Items.HealthPotion()
  254. )
  255. return new LogLine(`You buy a health potion.`)
  256. } else {
  257. return new LogLine(`Health potions are 50 gold coins.`)
  258. }
  259. }
  260. )
  261. )
  262. northTownShop.choices.push(
  263. new Choice(
  264. "Buy a strength potion",
  265. "40 Gold",
  266. (world, executor) => {
  267. if (executor.wallet.Gold >= 40) {
  268. executor.wallet.Gold -= 40
  269. executor.items.push(
  270. new Items.StrengthPotion()
  271. )
  272. return new LogLine(`You buy a strength potion.`)
  273. } else {
  274. return new LogLine(`Strength potions are 40 gold coins.`)
  275. }
  276. }
  277. )
  278. )
  279. northTownShop.choices.push(
  280. new Choice(
  281. "Buy an acid potion",
  282. "25 Gold",
  283. (world, executor) => {
  284. if (executor.wallet.Gold >= 25) {
  285. executor.wallet.Gold -= 25
  286. executor.items.push(
  287. new Items.AcidPotion()
  288. )
  289. return new LogLine(`You buy an acid potion.`)
  290. } else {
  291. return new LogLine(`Acid potions are 25 gold coins.`)
  292. }
  293. }
  294. )
  295. )
  296. northTownShop.choices.push(
  297. new Choice(
  298. "Buy a shrink potion",
  299. "10 Gold",
  300. (world, executor) => {
  301. if (executor.wallet.Gold >= 10) {
  302. executor.wallet.Gold -= 10
  303. executor.items.push(
  304. new Items.ShrinkPotion()
  305. )
  306. return new LogLine(`You buy a shrink potion.`)
  307. } else {
  308. return new LogLine(`Shrink potions are 10 gold coins.`)
  309. }
  310. }
  311. )
  312. )
  313. debug.choices.push(
  314. new Choice(
  315. "Cut stats",
  316. "Make your stats less good-er",
  317. (world, executor) => {
  318. Object.keys(Stat).forEach(stat => {
  319. executor.baseStats[stat as Stat] -= 5
  320. executor.takeDamage(new Damage(
  321. { amount: 5, target: (stat as Stat), type: DamageType.Pure }
  322. ))
  323. })
  324. return new LogLine(`You're weaker now`)
  325. }
  326. )
  327. )
  328. debug.choices.push(
  329. new Choice(
  330. "Boost stats",
  331. "Make your stats more good-er",
  332. (world, executor) => {
  333. Object.keys(Stat).forEach(stat => {
  334. executor.baseStats[stat as Stat] += 5
  335. executor.takeDamage(new Damage(
  336. { amount: 5, target: (stat as Stat), type: DamageType.Heal }
  337. ))
  338. })
  339. return new LogLine(`You're stronger now`)
  340. }
  341. )
  342. )
  343. debug.choices.push(
  344. new Choice(
  345. "Grow",
  346. "Make yourself larger",
  347. (world, executor) => {
  348. executor.voreStats.Mass *= 1.5
  349. return new LogLine(`You're larger now`)
  350. }
  351. )
  352. )
  353. debug.choices.push(
  354. new Choice(
  355. "Shrink",
  356. "Make yourself smaller",
  357. (world, executor) => {
  358. executor.voreStats.Mass /= 1.5
  359. return new LogLine(`You're smaller now`)
  360. }
  361. )
  362. )
  363. debug.choices.push(
  364. new Choice(
  365. "Instant Digestion",
  366. "Make your stomach REALLY powerful",
  367. (world, executor) => {
  368. executor.applyEffect(new InstantDigestionEffect())
  369. return new LogLine(`You're really gonna melt people now.`)
  370. }
  371. )
  372. )
  373. debug.choices.push(
  374. new Choice(
  375. "Set Name",
  376. "Set your name",
  377. (world, executor) => {
  378. const input = prompt("Enter a name")
  379. if (input !== null) {
  380. executor.baseName = new ProperNoun(input)
  381. return new LogLine(`Your new name is ${executor.baseName}.`)
  382. } else {
  383. return new LogLine(`nvm`)
  384. }
  385. }
  386. )
  387. )
  388. debug.choices.push(
  389. new Choice(
  390. "Add money",
  391. "Get some money",
  392. (world, executor) => {
  393. executor.wallet.Gold += 1000
  394. return new LogLine(`$$$$$$$$$$$$$$$$$`)
  395. }
  396. )
  397. )
  398. woods.choices.push(
  399. new Choice(
  400. "Fight a slime",
  401. "Go fight a slime",
  402. (world, executor) => {
  403. const enemy = new Slime()
  404. const encounter = new Encounter(
  405. {
  406. name: "Fight some tasty nerd",
  407. intro: () => new LogLine(`A slime draws near!`)
  408. },
  409. [world.player, enemy].concat(world.party)
  410. )
  411. world.encounter = encounter
  412. return nilLog
  413. }
  414. )
  415. )
  416. woods.choices.push(
  417. new Choice(
  418. "Fight Samuel",
  419. "Go fight a poor little wolf!",
  420. (world, executor) => {
  421. const enemy = new Samuel()
  422. const encounter = new Encounter(
  423. {
  424. name: "Fight some tasty nerd",
  425. intro: () => new LogLine(`Samuel pokes his head out from the bushes!`)
  426. },
  427. [world.player, enemy].concat(world.party)
  428. )
  429. world.encounter = encounter
  430. return nilLog
  431. }
  432. )
  433. )
  434. const bosses = new Place(
  435. new ProperNoun("BOSS ZONE"),
  436. "Extra scary"
  437. )
  438. bossEncounters.forEach(encounter => {
  439. bosses.choices.push(
  440. new Choice(
  441. encounter.desc.name,
  442. "Boss fight!",
  443. (world) => {
  444. world.encounter = encounter
  445. return nilLog
  446. }
  447. )
  448. )
  449. })
  450. home.biconnect(Direction.South, debug, "Walk", "Enter the debug room", "Leave", "Exit the debug room")
  451. home.biconnect(Direction.Northeast, townSquare, "Leave", "Go outside", "Enter", "Enter your home")
  452. townSquare.biconnect(Direction.North, northTownStreet, "Walk", "Go that way", "Walk", "Go that way")
  453. townSquare.biconnect(Direction.East, eastTownStreet, "Walk", "Go that way", "Walk", "Go that way")
  454. townSquare.biconnect(Direction.South, southTownStreet, "Walk", "Go that way", "Walk", "Go that way")
  455. townSquare.biconnect(Direction.West, westTownStreet, "Walk", "Go that way", "Walk", "Go that way")
  456. northTownShop.biconnect(Direction.West, northTownStreet, "Exit", "Leave the shop", "Enter", "Enter the shop")
  457. debug.biconnect(Direction.South, bosses, "Enter", "Boss Fight!", "Leave", "Go back to the debug room")
  458. eastTownStreet.biconnect(Direction.East, eastGate, "Walk", "Go that way", "Walk", "Go that way")
  459. eastGate.biconnect(Direction.East, woods, "Walk", "Enter the woods", "Approach", "Enter the city gates")
  460. woods.biconnect(Direction.North, deepwoods, "Walk", "Go deeper", "Walk", "Leave the deep woods")
  461. return home
  462. }