Feast 2.0!
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

444 lines
11 KiB

  1. import { Place, Choice, Direction, World } from '../world'
  2. import { ProperNoun, ImproperNoun, MalePronouns, FemalePronouns, TheyPronouns } from '../language'
  3. import { Encounter, Stat, Damage, DamageType, Vigor, Side } from '../combat'
  4. import * as Creatures from '../creatures'
  5. import * as Items from '../items'
  6. import { LogLine, nilLog, LogLines } from '../interface'
  7. import { Creature } from '../creature'
  8. import { DevourAction } from '../combat/actions'
  9. import { SurrenderEffect } from '../combat/effects'
  10. import moment from 'moment'
  11. import { VoreAI } from '../ai'
  12. function makeParty (): Creature[] {
  13. const fighter = new Creatures.Human(new ProperNoun("Redgar"), MalePronouns, {
  14. stats: {
  15. Toughness: 20,
  16. Power: 20,
  17. Reflexes: 15,
  18. Agility: 15,
  19. Willpower: 15,
  20. Charm: 10
  21. }
  22. })
  23. fighter.title = "Lv. 6 Fighter"
  24. fighter.equip(new Items.Sword(), Items.EquipmentSlot.MainHand)
  25. const rogue = new Creatures.Human(new ProperNoun('Lidda'), FemalePronouns, {
  26. stats: {
  27. Toughness: 10,
  28. Power: 15,
  29. Reflexes: 20,
  30. Agility: 20,
  31. Willpower: 15,
  32. Charm: 20
  33. }
  34. })
  35. rogue.title = "Lv. 5 Rogue"
  36. rogue.equip(new Items.Dagger(), Items.EquipmentSlot.MainHand)
  37. const wizard = new Creatures.Human(new ProperNoun('Mialee'), FemalePronouns, {
  38. stats: {
  39. Toughness: 10,
  40. Power: 10,
  41. Reflexes: 15,
  42. Agility: 15,
  43. Willpower: 20,
  44. Charm: 25
  45. }
  46. })
  47. wizard.title = "Lv. 6 Wizard"
  48. wizard.equip(new Items.Wand(), Items.EquipmentSlot.MainHand)
  49. const cleric = new Creatures.Human(new ProperNoun('Jozan'), MalePronouns, {
  50. stats: {
  51. Toughness: 15,
  52. Power: 15,
  53. Reflexes: 10,
  54. Agility: 10,
  55. Willpower: 20,
  56. Charm: 15
  57. }
  58. })
  59. cleric.title = "Lv. 5 Cleric"
  60. cleric.equip(new Items.Mace(), Items.EquipmentSlot.MainHand)
  61. return [fighter, cleric, rogue, wizard]
  62. }
  63. export const Town = (): Place => {
  64. const home = new Place(
  65. new ProperNoun('Your home'),
  66. "A very home-y place"
  67. )
  68. const debug = new Place(
  69. new ProperNoun("Debug Room"),
  70. "Where weird stuff happens"
  71. )
  72. const westAve = new Place(
  73. new ImproperNoun('West Avenue'),
  74. "Streets of Sim City"
  75. )
  76. const northAve = new Place(
  77. new ImproperNoun('North Avenue'),
  78. "Streets of Sim City"
  79. )
  80. const eastAve = new Place(
  81. new ImproperNoun('East Avenue'),
  82. "Streets of Sim City"
  83. )
  84. const southAve = new Place(
  85. new ImproperNoun('South Avenue'),
  86. "Streets of Sim City"
  87. )
  88. const alley = new Place(
  89. new ImproperNoun('alley'),
  90. "A spooky alley"
  91. )
  92. const westRoad = new Place(
  93. new ImproperNoun('road'),
  94. "West of town"
  95. )
  96. const woods = new Place(
  97. new ImproperNoun('woods'),
  98. "Scary woods"
  99. )
  100. const bosses = new Place(
  101. new ProperNoun("BOSS ZONE"),
  102. "Extra scary"
  103. )
  104. const square = new Place(
  105. new ProperNoun("Central Square"),
  106. "The center of town"
  107. )
  108. woods.choices.push(
  109. new Choice(
  110. "Fight a wolf",
  111. "yolo",
  112. (world, executor) => {
  113. world.encounter = new Encounter(
  114. {
  115. name: "You punched a wolf",
  116. intro: (world: World) => new LogLine(`You punched a wolf. The wolf is angry.`)
  117. },
  118. [executor, new Creatures.Wolf()]
  119. )
  120. return new LogLine(`FIGHT TIME`)
  121. }
  122. )
  123. )
  124. woods.choices.push(
  125. new Choice(
  126. "Fight a dire wolf",
  127. "yolo",
  128. (world, executor) => {
  129. world.encounter = new Encounter(
  130. {
  131. name: "You punched a dire wolf",
  132. intro: (world: World) => new LogLine(`You punched a dire wolf. The wolf is angry.`)
  133. },
  134. [executor, new Creatures.DireWolf()]
  135. )
  136. return new LogLine(`FIGHT TIME`)
  137. }
  138. )
  139. )
  140. woods.choices.push(
  141. new Choice(
  142. "Fight a werewolf",
  143. "yolo",
  144. (world, executor) => {
  145. world.encounter = new Encounter(
  146. {
  147. name: "You punched a werewolf",
  148. intro: (world: World) => new LogLine(`You punched a werewolf. The werewolf is angry.`)
  149. },
  150. [executor, new Creatures.Werewolf()]
  151. )
  152. return new LogLine(`FIGHT TIME`)
  153. }
  154. )
  155. )
  156. woods.choices.push(
  157. new Choice(
  158. "Fight a dragon",
  159. "yolo",
  160. (world, executor) => {
  161. world.encounter = new Encounter(
  162. {
  163. name: "You punched a dragon",
  164. intro: (world: World) => new LogLine(`You punched a dragon. The dragon is angry.`)
  165. },
  166. [executor, new Creatures.Dragon()]
  167. )
  168. return new LogLine(`FIGHT TIME`)
  169. }
  170. )
  171. )
  172. const bossEncounters = [
  173. new Encounter(
  174. { name: "Withers & Kenzie", intro: (world: World) => nilLog },
  175. makeParty().concat([new Creatures.Withers(), new Creatures.Kenzie()])
  176. ),
  177. new Encounter(
  178. { name: "Goldeneye", intro: (world: World) => nilLog },
  179. makeParty().concat([new Creatures.Goldeneye()])
  180. ),
  181. new Encounter(
  182. { name: "Large Wah", intro: (world: World) => nilLog },
  183. makeParty().concat([new Creatures.Shingo()])
  184. ),
  185. new Encounter(
  186. { name: "Cafat", intro: (world: World) => nilLog },
  187. makeParty().concat([new Creatures.Cafat()])
  188. )
  189. ]
  190. home.choices.push(
  191. new Choice(
  192. "Nap",
  193. "Zzzzzz",
  194. (world, executor) => {
  195. return new LogLines(
  196. `You lie down for a nice nap...`,
  197. world.advance(moment.duration(1, "hour"))
  198. )
  199. }
  200. )
  201. )
  202. home.choices.push(
  203. new Choice(
  204. "Heal",
  205. "Become not dead and/or eaten",
  206. (world, executor) => {
  207. Object.keys(Vigor).forEach(vigor => {
  208. executor.vigors[vigor as Vigor] = executor.maxVigors[vigor as Vigor]
  209. })
  210. if (executor.containedIn !== null) {
  211. executor.containedIn.release(executor)
  212. }
  213. executor.statusEffects.forEach(effect => {
  214. executor.removeEffect(effect)
  215. })
  216. executor.destroyed = false
  217. return new LogLine(`You're healthy again`)
  218. }
  219. )
  220. )
  221. westAve.choices.push(
  222. new Choice(
  223. "Eat someone",
  224. "Slurp",
  225. (world, executor) => {
  226. const snack = new Creatures.Human(new ProperNoun(["Snack", "Treat", "Tasty", "Dinner", "Appetizer"][Math.floor(Math.random() * 5)]), [MalePronouns, FemalePronouns, TheyPronouns][Math.floor(Math.random() * 3)])
  227. snack.applyEffect(new SurrenderEffect())
  228. const options = executor.validActions(snack).filter(action => action instanceof DevourAction)
  229. return options[Math.floor(options.length * Math.random())].execute(executor, snack)
  230. }
  231. )
  232. )
  233. westAve.choices.push(
  234. new Choice(
  235. "Fight someone",
  236. "Ow",
  237. (world, executor) => {
  238. const enemy = new Creatures.Human(new ProperNoun("Nerd"), TheyPronouns)
  239. enemy.side = Side.Monsters
  240. enemy.ai = new VoreAI()
  241. const encounter = new Encounter(
  242. {
  243. name: "Fight some nerd",
  244. intro: world => new LogLine(`You find some nerd to fight.`)
  245. },
  246. [world.player, enemy]
  247. )
  248. world.encounter = encounter
  249. return nilLog
  250. }
  251. )
  252. )
  253. square.choices.push(
  254. new Choice(
  255. "Fight Geta",
  256. "yolo",
  257. (world, executor) => {
  258. world.encounter = new Encounter(
  259. {
  260. name: "You punched Geta",
  261. intro: (world: World) => new LogLine(`You punched Geta. Geta is angry.`)
  262. },
  263. [executor, new Creatures.Geta()]
  264. )
  265. return new LogLine(`FIGHT TIME`)
  266. }
  267. )
  268. )
  269. square.choices.push(
  270. new Choice(
  271. "Buy a shiny rock",
  272. "This rock has no use.",
  273. (world, executor) => {
  274. if (executor.wallet.Gold >= 500) {
  275. executor.wallet.Gold -= 500
  276. executor.items.push(
  277. new Items.KeyItem(new ProperNoun("Shiny Rock"), "Very shiny")
  278. )
  279. return new LogLine(`You buy a shiny rock`)
  280. } else {
  281. return new LogLine(`Shiny rocks are 500 gold coins, loser!`)
  282. }
  283. }
  284. )
  285. )
  286. alley.choices.push(
  287. new Choice(
  288. "Kuro",
  289. "Get eaten by a Luxray",
  290. (world, executor) => {
  291. const enemy = new Creatures.Kuro()
  292. enemy.ai = new VoreAI()
  293. const encounter = new Encounter(
  294. {
  295. name: "Luxray time",
  296. intro: world => new LogLine(`Luxray time!`)
  297. },
  298. [world.player, enemy]
  299. )
  300. world.encounter = encounter
  301. return nilLog
  302. }
  303. )
  304. )
  305. bossEncounters.forEach(encounter => {
  306. bosses.choices.push(
  307. new Choice(
  308. encounter.desc.name,
  309. "Boss fight!",
  310. (world, executor) => {
  311. world.encounter = encounter
  312. return nilLog
  313. }
  314. )
  315. )
  316. })
  317. debug.choices.push(
  318. new Choice(
  319. "Cut stats",
  320. "Make your stats less good-er",
  321. (world, executor) => {
  322. Object.keys(Stat).forEach(stat => {
  323. executor.baseStats[stat as Stat] -= 5
  324. executor.takeDamage(new Damage(
  325. { amount: 5, target: (stat as Stat), type: DamageType.Pure }
  326. ))
  327. })
  328. return new LogLine(`You're weaker now`)
  329. }
  330. )
  331. )
  332. debug.choices.push(
  333. new Choice(
  334. "Boost stats",
  335. "Make your stats more good-er",
  336. (world, executor) => {
  337. Object.keys(Stat).forEach(stat => {
  338. executor.baseStats[stat as Stat] += 5
  339. executor.takeDamage(new Damage(
  340. { amount: 5, target: (stat as Stat), type: DamageType.Heal }
  341. ))
  342. })
  343. return new LogLine(`You're stronger now`)
  344. }
  345. )
  346. )
  347. debug.choices.push(
  348. new Choice(
  349. "Grow",
  350. "Make yourself larger",
  351. (world, executor) => {
  352. executor.voreStats.Mass *= 1.5
  353. return new LogLine(`You're larger now`)
  354. }
  355. )
  356. )
  357. debug.choices.push(
  358. new Choice(
  359. "Shrink",
  360. "Make yourself smaller",
  361. (world, executor) => {
  362. executor.voreStats.Mass /= 1.5
  363. return new LogLine(`You're smaller now`)
  364. }
  365. )
  366. )
  367. debug.choices.push(
  368. new Choice(
  369. "Set Name",
  370. "Set your name",
  371. (world, executor) => {
  372. const input = prompt("Enter a name")
  373. if (input !== null) {
  374. executor.baseName = new ProperNoun(input)
  375. return new LogLine(`Your new name is ${executor.baseName}.`)
  376. } else {
  377. return new LogLine(`nvm`)
  378. }
  379. }
  380. )
  381. )
  382. debug.choices.push(
  383. new Choice(
  384. "Add money",
  385. "Get some money",
  386. (world, executor) => {
  387. executor.wallet.Gold += 1000
  388. return new LogLine(`$$$$$$$$$$$$$$$$$`)
  389. }
  390. )
  391. )
  392. home.biconnect(Direction.South, debug)
  393. debug.biconnect(Direction.South, bosses)
  394. home.biconnect(Direction.North, westAve)
  395. westAve.biconnect(Direction.West, westRoad)
  396. westAve.biconnect(Direction.North, alley)
  397. westRoad.biconnect(Direction.South, woods)
  398. square.biconnect(Direction.East, eastAve)
  399. square.biconnect(Direction.West, westAve)
  400. square.biconnect(Direction.North, northAve)
  401. square.biconnect(Direction.South, southAve)
  402. return home
  403. }