------------------------------- name = "Kvothe's Quest" description = "Kvothe Spider killing quest" # This timeout ensures that the quest doesn't get stuck if a player decides to take off # When the initial state starts, you may want to perform some "cleanup" and remove all residual spiders from in and around the house, but # I'll help you cross that bridge when we come to it timeout = 30 minutes ----------------------------- # This is the inside of the house const $house = box <-301, 56, 400> to <-289, 67, 415> # This is where spiders in the basement spawn const $basement = box < -299, 57, 401 > to < -291, 60, 410 > # This is where spiders on the roof spawn const $roof = box < -299, 77, 401 > to < -291, 81, 413 > # This is the bounding box areas for each of the rooms const $room201 = box < -294, 67, 401 > to < -291, 70, 407 > const $room202 = box < -299, 67, 401 > to < -296, 70, 407 > const $room301 = box < -294, 72, 401 > to < -291, 75, 407 > const $room302 = box < -299, 72, 401 > to < -296, 75, 407 > # It's always good practice to make the subject of the quest a lazy binding. # This is to ensure that players are not 'captured' until the first stages of a quest are initiated const $nearby = each lazy &player ~ &container inside $house # It's good practice to use "eager" for anything coming from "context", recall that "eager" means it evaluates immediately const $Kvothe = first eager &npc from context # You may want to make this pure or lazy, it all depends on when you want it to actually go looking for the jukebox const $jukebox = first eager &container ~ &fixture at < -292, 62, 403 > # The first set of spiders var $`first spiders` <: list of (&entity ~ &living) = nil # We have a new state when the right music plays start `playing Chandree music` once when @jukebox\inventory contains == 1 &minecraft:record_11 define `playing Chandree music` { # Wait a two seconds before Kvothe realizes that you're playing something bad and complains to everyone (everyone as in he's not entirely sure who put the disc in there) say to @nearby, "Oh now you have gone and done it, turn that off quick before the Chandree show up" as @Kvothe when 2000 milliseconds elapses # If the music still in there after time 10 seconds, then we complain and then enter a new state when 10 seconds elapses then { say to @nearby, "Fine I will do it my self!" as @Kvothe start `Pathing Kvothe to Jukebox` } # "start stopping" haha, I like the bad English, I am making fun of my own language! # Basically "stopping" is Kvothe saying "phewf" just before we stop the whole script start `stopping` when @jukebox\inventory contains == 0 &minecraft:record_11 define `Pathing Kvothe to Jukebox` { const $jukespot = < -292, 62, 402 > # If after time 5 seconds Kvothe still isn't at the Jukebox, then try again path @Kvothe to $jukespot when started path @Kvothe to $jukespot every 5 seconds # When Kvothe reaches the jukebox, then remove the record and start hoping when @Kvothe inside radius 2 about $jukespot then { move 1 &minecraft:record_11 from @jukebox\inventory to < -292, 63, 403 > start `hoping` } # If it takes Kvoth more than time 15 seconds to get to the Jukebox, he's probably retarded, # so we move onto `hoping` to continue the quest start `hoping` when 15 seconds elapses } } # Oh gee, I sure hope the Chandree don't show up... define `hoping` { var $`spider definitions` <: list of (mob horde) = (chance of 9..13 ⊗ lazy place inside $basement mob &Spider) :: (chance of 3..5 ⊗ lazy place inside $room201 mob &Spider) :: (chance of 3..5 ⊗ lazy place inside $room202 mob &Spider) :: (3 ⊗ lazy place inside $room301 mob &Spider) :: (3 ⊗ lazy place inside $room302 mob &Spider) say to @nearby, "I sure hope for your sake that they did not hear that" as @Kvothe when 2 seconds elapses # Spawn the basement spiders as soon as one of our "nearby" players leaves the house say to @nearby, "Quick come back in here! I need to you clear my basement, spiders are everywhere!" as @Kvothe when @nearby not all inside $house when @nearby not all inside $house then { let $`first spiders` = spawn $`spider definitions` start `First Spider Event` } } define `First Spider Event` { # Will contain the second set of spiders if and only if the the first set are not dispatched quickly enough var $`second spiders` <: list of (&entity ~ &living) = nil # Wait a moment for Kvothe to realize what just happened, the spiders in the basement spawned say to @nearby, "That's it now you have gone and done it. Go clean up this mess" as @Kvothe when 700 milliseconds elapses # Whenever the a player leaves the house (either goes to the basement or goes outside) we start a new state with a 1 minute timer. # When the 1 minute timer elapses, more spiders spawn (unless the a player kills all of the basement spiders first) start `Basement` once when @nearby not all inside $house # If the a player is cowardly (or lazy, or too slow) and the spiders are not all dead after 2 minutes then we just immediately skip to the second # spider event and spawn more spiders on the roof when 2 minutes elapses then { let $`second spiders` = spawn 24 ⊗ lazy place inside $roof mob &CaveSpider start `Second Spider Event` } # Although it's named "Basement" remember that it just means the a player left the house (probably not the best name for it) define `Basement` { # We check our @`first spiders` binding to ensure that they are "all" dead, and if they are, then we transition to "Good Riddance" # There's something very clever happening behind the scenes with "when @`first spiders` all dead" and I'll explain how this is actually structured below: # trigger ::= when (expression) # expression ::= left operator right # left ::= binding (@`first spiders`) # right ::= constant (LifeState.dead) # all ::= singleton membership operator (list or stream or option of x) -> x # ERROR! Morph Mismatch! @`first spiders` does not apply to LifeState! # - Recover: is @`first spiders` a morph of &stream of &living ? # - Answer: YES! # - Then: Extend @`first spiders` to @`first spiders`\life # Retry: Success! @`first spiders`\life does apply to LifeState.dead! # expanded expression ::= @`first spiders`\life all LifeState.dead # for trigger assert that expression evaluates to "yes" # # This whole concept works for spatial objects too, which is why you can do this: # "when @player not inside $house" # This programming paradigm is known as implicit conversions by way of type-classes. # The type-classes employed by Olivine are entirely internal and extremely complex, which is why this is behind the scenes "magic" # NOTE: This is currently broken for inventory containers, which is why you still have to do stuff like this: # "when @chest\inventory contains >= 64 &rotten_flesh" # Very complex stuff and it's hard to keep it consistent, but when it shines, it looks just like.... start `Good Riddance` when @`first spiders` all dead } # Recall that this transition is called when we spawned the second spiders on the roof # What happens if I do a "start `Second Spider Event` like normal without a spawn statement? # Well I'm glad you asked! Short answer: nothing! Long answer: The state will still transition # but your @`second spiders` binding will be empty define `Second Spider Event` { # Kvothe hears some trompling on the roof, he's kind of old and slow so it takes him a second to realize this # You may want to tweak these "elapses" timers for Kvothe responses. I think "when started" is too fast, because # nobody is going to realize what just happened the very instant it happens, everyone takes a split second to # clue in (except for Bruce Lee, I believe it takes him only a split of a split second) say to @nearby, "You were too slow, now they are on the roof!" as @Kvothe when 1100 milliseconds elapses # You can bind multiple checks together using "&&" for AND and "||" for OR. I opted for the symbols instead of the words # in order to keep the code legible and balanced. I think too much wording is just as bad as too many symbols. start `Good Riddance` when @`first spiders` all dead && @`second spiders` all dead } } # Oh yay, you did it, gratz define `Good Riddance` { # Only a split of a split second wait for Kvothe here because he was eagerly waiting with baited breath for all the spiders to be dead say to @nearby, "Good riddance! I think you got all of them" as @Kvothe when 3500 milliseconds elapses when 9400 milliseconds elapses then { # Another delay before he gives you your token give item &mmm:avenger_token to @nearby stop } # when time 9400 milliseconds elapses # Delay again for Kvothe's next message when 6 seconds elapses then { say to @nearby, "Something about this does not seam right bring this to an OLD friend of mine. He lives up the road not far from here in a large tower. Just give him the token and he will know what to do. But please don't say it was from me. It will be better for you this way." as @Kvothe } } # To start stopping is to stop starting ;) # On a more sincere note, this transition is not called if you successfully complete the quest, only if you successfully prevent spiders from spawning define `stopping` { when 3 seconds elapses then { say to @nearby, "Lets hope that was quick enough" as @Kvothe stop } }