Feast 2.0!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

383 lines
9.7 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 Human from '../creatures/human'
  14. import Slime from '../creatures/monsters/slime'
  15. import Werewolf from '../creatures/monsters/werewolf'
  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 Town = (): Place => {
  68. const home = new Place(
  69. new ProperNoun("Home"),
  70. "A very home-y place"
  71. )
  72. const debug = new Place(
  73. new ProperNoun("Debug Room"),
  74. "Where weird stuff happens"
  75. )
  76. const alley = new Place(
  77. new ImproperNoun('alley'),
  78. "A spooky alley"
  79. )
  80. const westRoad = new Place(
  81. new ImproperNoun('road'),
  82. "West of town"
  83. )
  84. const woods = new Place(
  85. new ImproperNoun('woods'),
  86. "Scary woods"
  87. )
  88. const bosses = new Place(
  89. new ProperNoun("BOSS ZONE"),
  90. "Extra scary"
  91. )
  92. const square = new Place(
  93. new ProperNoun("Central Square"),
  94. "The center of town"
  95. )
  96. const bossEncounters = [
  97. new Encounter(
  98. { name: "Inazuma", intro: () => nilLog },
  99. makeParty().concat([new Inazuma()])
  100. )
  101. ]
  102. home.choices.push(
  103. new Choice(
  104. "Nap",
  105. "Zzzzzz",
  106. (world) => {
  107. return new LogLines(
  108. `You lie down for a nice nap...`,
  109. world.advance(moment.duration(1, "hour"))
  110. )
  111. }
  112. )
  113. )
  114. home.choices.push(
  115. new Choice(
  116. "Heal",
  117. "Become not dead and/or eaten",
  118. (world, executor) => {
  119. Object.keys(Vigor).forEach(vigor => {
  120. executor.vigors[vigor as Vigor] = executor.maxVigors[vigor as Vigor]
  121. })
  122. if (executor.containedIn !== null) {
  123. executor.containedIn.release(executor)
  124. }
  125. executor.statusEffects.forEach(effect => {
  126. executor.removeEffect(effect)
  127. })
  128. executor.destroyed = false
  129. return new LogLine(`You're healthy again`)
  130. }
  131. )
  132. )
  133. home.choices.push(
  134. new Choice(
  135. "Grab potions",
  136. "Grab some potions",
  137. (world, executor) => {
  138. executor.items.push(new Items.HealthPotion())
  139. executor.items.push(new Items.AcidPotion())
  140. executor.items.push(new Items.ShrinkPotion())
  141. executor.items.push(new Items.StrengthPotion())
  142. return new LogLine("You grab some potions")
  143. }
  144. )
  145. )
  146. square.choices.push(
  147. new Choice(
  148. "Eat someone",
  149. "Slurp",
  150. (world, executor) => {
  151. const snack = new Human(new ProperNoun(["Snack", "Treat", "Tasty", "Dinner", "Appetizer"][Math.floor(Math.random() * 5)]), [MalePronouns, FemalePronouns, TheyPronouns][Math.floor(Math.random() * 3)])
  152. snack.applyEffect(new SurrenderEffect())
  153. const options = executor.validActions(snack).filter(action => action instanceof DevourAction)
  154. return options[Math.floor(options.length * Math.random())].execute(executor, snack)
  155. }
  156. )
  157. )
  158. square.choices.push(
  159. new Choice(
  160. "Fight someone",
  161. "Ow",
  162. (world) => {
  163. const enemy = new Human(new ProperNoun("Nerd"), TheyPronouns)
  164. enemy.side = Side.Monsters
  165. enemy.ai = new VoreAI(enemy)
  166. enemy.equip(new Items.Sword(), Items.EquipmentSlot.MainHand)
  167. enemy.addPerk(new DeliciousPerk())
  168. const encounter = new Encounter(
  169. {
  170. name: "Fight some tasty nerd",
  171. intro: () => new LogLine(`You find some nerd to fight.`)
  172. },
  173. [world.player, enemy].concat(world.party)
  174. )
  175. world.encounter = encounter
  176. return nilLog
  177. }
  178. )
  179. )
  180. square.choices.push(
  181. new Choice(
  182. "Recruit someone",
  183. "Not ow",
  184. (world) => {
  185. const ally = new Human(new ProperNoun("Ally"), TheyPronouns)
  186. ally.side = Side.Heroes
  187. ally.ai = new VoreAI(ally)
  188. ally.equip(new Items.Sword(), Items.EquipmentSlot.MainHand)
  189. world.party.push(ally)
  190. return new LogLine(`You recruit a nerd`)
  191. }
  192. )
  193. )
  194. square.choices.push(
  195. new Choice(
  196. "Buy a shiny rock",
  197. "This rock has no use.",
  198. (world, executor) => {
  199. if (executor.wallet.Gold >= 500) {
  200. executor.wallet.Gold -= 500
  201. executor.items.push(
  202. new Items.KeyItem(new ProperNoun("Shiny Rock"), "Very shiny")
  203. )
  204. return new LogLine(`You buy a shiny rock`)
  205. } else {
  206. return new LogLine(`Shiny rocks are 500 gold coins, loser!`)
  207. }
  208. }
  209. )
  210. )
  211. bossEncounters.forEach(encounter => {
  212. bosses.choices.push(
  213. new Choice(
  214. encounter.desc.name,
  215. "Boss fight!",
  216. (world) => {
  217. world.encounter = encounter
  218. return nilLog
  219. }
  220. )
  221. )
  222. })
  223. debug.choices.push(
  224. new Choice(
  225. "Cut stats",
  226. "Make your stats less good-er",
  227. (world, executor) => {
  228. Object.keys(Stat).forEach(stat => {
  229. executor.baseStats[stat as Stat] -= 5
  230. executor.takeDamage(new Damage(
  231. { amount: 5, target: (stat as Stat), type: DamageType.Pure }
  232. ))
  233. })
  234. return new LogLine(`You're weaker now`)
  235. }
  236. )
  237. )
  238. debug.choices.push(
  239. new Choice(
  240. "Boost stats",
  241. "Make your stats more good-er",
  242. (world, executor) => {
  243. Object.keys(Stat).forEach(stat => {
  244. executor.baseStats[stat as Stat] += 5
  245. executor.takeDamage(new Damage(
  246. { amount: 5, target: (stat as Stat), type: DamageType.Heal }
  247. ))
  248. })
  249. return new LogLine(`You're stronger now`)
  250. }
  251. )
  252. )
  253. debug.choices.push(
  254. new Choice(
  255. "Grow",
  256. "Make yourself larger",
  257. (world, executor) => {
  258. executor.voreStats.Mass *= 1.5
  259. return new LogLine(`You're larger now`)
  260. }
  261. )
  262. )
  263. debug.choices.push(
  264. new Choice(
  265. "Shrink",
  266. "Make yourself smaller",
  267. (world, executor) => {
  268. executor.voreStats.Mass /= 1.5
  269. return new LogLine(`You're smaller now`)
  270. }
  271. )
  272. )
  273. debug.choices.push(
  274. new Choice(
  275. "Instant Digestion",
  276. "Make your stomach REALLY powerful",
  277. (world, executor) => {
  278. executor.applyEffect(new InstantDigestionEffect())
  279. return new LogLine(`You're really gonna melt people now.`)
  280. }
  281. )
  282. )
  283. debug.choices.push(
  284. new Choice(
  285. "Set Name",
  286. "Set your name",
  287. (world, executor) => {
  288. const input = prompt("Enter a name")
  289. if (input !== null) {
  290. executor.baseName = new ProperNoun(input)
  291. return new LogLine(`Your new name is ${executor.baseName}.`)
  292. } else {
  293. return new LogLine(`nvm`)
  294. }
  295. }
  296. )
  297. )
  298. woods.choices.push(
  299. new Choice(
  300. "Fight a slime",
  301. "Go fight a slime",
  302. (world, executor) => {
  303. const enemy = new Slime()
  304. const encounter = new Encounter(
  305. {
  306. name: "Fight some tasty nerd",
  307. intro: () => new LogLine(`A slime draws near!`)
  308. },
  309. [world.player, enemy].concat(world.party)
  310. )
  311. world.encounter = encounter
  312. return nilLog
  313. }
  314. )
  315. )
  316. woods.choices.push(
  317. new Choice(
  318. "Fight a werewolf",
  319. "Go fight a werewolf",
  320. (world, executor) => {
  321. const enemy = new Werewolf()
  322. enemy.location = world.player.location
  323. const encounter = new Encounter(
  324. {
  325. name: "Fight some tasty nerd",
  326. intro: () => new LogLine(`A werewolf draws near!`)
  327. },
  328. [world.player, enemy].concat(world.party)
  329. )
  330. world.encounter = encounter
  331. return nilLog
  332. }
  333. )
  334. )
  335. debug.choices.push(
  336. new Choice(
  337. "Add money",
  338. "Get some money",
  339. (world, executor) => {
  340. executor.wallet.Gold += 1000
  341. return new LogLine(`$$$$$$$$$$$$$$$$$`)
  342. }
  343. )
  344. )
  345. home.biconnect(Direction.South, debug)
  346. debug.biconnect(Direction.South, bosses)
  347. home.biconnect(Direction.North, square)
  348. westRoad.biconnect(Direction.South, woods)
  349. square.biconnect(Direction.West, westRoad)
  350. return home
  351. }