# Boss Fight - Multistage and Highly Configurable # Citizens 2 (build #991) # Denizen 0.9.3 (build #1341) # Sentry 1.5.3 # # To assign to an NPC, literally type: # /npc assign --set "bossname" # # DISCLAIMER: # =========== # This is an advanced script. You should test this script # before you use it on your LIVE server. Some of the item drops # ignore ZONE PROTECTION. So if you play on a strict # server you will want to disable those items by # removing them from the "BossName Determine Loot" script. # # DESCRIPTION: # ============ # # This is a four stage boss fight with a bunch of simple configuration # options that will allow you to create a unique boss fight. # You can decide how many stages you want to enable, how difficult the # boss should be (health, armor, strength), whether it should spawn # minions and if so, how many, how difficult etc. The boss has several # different 'special attacks' that can be used directly on players or # inside a "cuboid", which you have to specify in the constant values # at the top of the script. # # The boss can heal or reset itself if no one is in range. # # When the boss is killed, it can drop random loot (from a series of # item scripts that's located towards the bottom of this script) directly # into players inventory, on the floor around the boss or into secure chests # for each of the boss fighters. # # At the end of the fight, it will show a text scoreboard that shows total # damage, hit count, minion kills etc for each player. # # FEATURES: # ========= # * Boss and/or Minions (quantity, health, armor, strength) # * Special Attacks (arrow spells, lightning storm, arrows dropping from ceiling) # * Boss heal/reset itself if inactive # * Unique item drops, using item scripts and world events # * Text scoreboard showing battle summary stats # * Shows health bar when you right click boss or minion. # # NOTE: # ==== # If you want to use this on more than one NPC you simply need to do # a FIND on the word 'BossName' and REPLACE it with your NPC name. Then # make another copy of the script and do another FIND/REPLACE for every # boss NPC that will use this. # # CREDITS: # ======== # Thanks to aufdemrand, davidcernat and mcmonkey for fixing/adding things in # Denizen. Thanks to Matterom and blankiito for example scripts on the work # they've done on custom items and effects. # # # @author mythanical # @script version 0.2 # @last-updated October 22 2013 # @irc EsperNet IRC Network #denizen-dev # @Minecraft Server - minecraft.geek.nz # @Donate Bitcoin: 1Fzacc2gZ5NGRMXg5jWP6NcUkWei34xjzt # @Donate Litecoin: LhsaGa1QzmVLjMYwg4ZPTVnmSgnBDGc75U "BossName": type: assignment default constants: # -------------------------------------------------------------------------------------------------------- # NOTE: 'Player' entity type NPC's are fully supported by Sentry, but other types may give you some # interesting, unexpected or undesired results. Especially when you try and equip them with a # weapon. # # The following NPC types are available as part of Citizens (http://wiki.citizensnpcs.com/Types): # # blaze, bat, cave_spider, chicken, creeper, cow, enderman (goes crazy in rain), # ender_dragon (do not recommend), ghast (do not recommend), giant (massive zombie!), iron_golem, # magma_cube (careful! damages nearby players), mushroom_cow, ocelot, pig, pig_zombie, # player (will use skin of player with same name), sheep, silverfish, squid (can't walk on land...duh), # snowman, wolf, skeleton, slime, spider, witch, witherboss (does not move), villager, # zombie (burns in sunlight, but invulnerable) # -------------------------------------------------------------------------------------------------------- Boss Entity Type: player # adult (Normal NPC type) # baby (Cause the Boss to be a baby. Note: Not all entity types have a baby version) Boss Age: adult # The following Sentry weapons are fully supported by 'player' type entity (http://wiki.citizensnpcs.com/Sentry): # bow (Archer - Range is 50 meters on flat ground.) # redstone_torch_on (Pyromancer I - Shoot small, non-incendiary fireballs) # torch (Pyromancer II - Shoot fireballs that set the land on fire) # blaze_rod (Pyromancer III - Shoot large, explosive fireballs that set the land on fire) # snow_ball (Ice Magi - Throw snowballs which slow enemies on contact. Snowballs have a range of about 25 blocks on flat ground) # egg (Bombardiers - explode? Eggs have a range of about 25 blocks on flat ground) # potion (Witch Doctor - Will throw a splash version of whatever potion type it is equipped with) # paper (Stormcaller I - Strike single targets with bolts of electricity) # book (Stormcaller II - Smite multiple foes. This lightning's damage is atmospheric and therefore is not affected by the Sentry's strength) # book_and_quill (Stormcaller III - Bolts instantly kill any living thing they touch regardless of health, armor, or play mode) # ender_pearl (Warlock I - Fling targets high into the air) # skull_item (Warlock II - Mid-range warlock shoots black explosive wither skulls at the enemy) # none (Brawler - Swords, axes, picks, shovels, rocks, bricks, or even fish, the brawlers take the fight to the enemy, hand to hand) Boss Weapon: none # The sentry values for the boss, you can check out what these mean at: # http://wiki.citizensnpcs.co/Sentry Boss Health: 500 Boss Strength: 1 Boss Armor: 1 Boss Agro Range: 15 # Awareness range will still trigger special attacks. Boss Awareness Range: 30 Boss Movement Speed: 1 # If all players have left the boss proximity, this enables the boss to heal itself slowly. Boss Exit Proximity Self Healing: "Yes" # Set the location where your boss will respawn Boss Spawn Location: "-151,65,80,world" # Set to -1 if you never want the boss to respawn and be permanently destroyed on death. Boss Respawn Delay: 600 # On default, boss fight will reset after 120s of inactivity. Set to 0 if you don't ever want it to reset # and allow players to come back later to finish it. Boss Reset Timer: 120 # The item scripts for the loot is located at the bottom. It will give each player, that hit the boss or a minion # at least once, a random item. Drop Loot on Death: "Yes" # The specifies how much loot per player Loot Quantity: 1 # This specifies how the loot should be distributed. # player (Put the item into the players inventory) # boss (Drop the loot on the ground around the boss) # chest (Spawn a chest with all the loot inside it where the boss died) # playerchest (Create a chest next to each player that only they can access) Loot Distribution: playerchest # To prevent any loot chests from staying forever, give them any value other than 0 # and they will expire..dropping all the loot on the floor. Loot Chest Expiry: 600 # Enable scoreboard (on right side of screen) to show either Minion Kills or Boss Health Damage by each player # during the fight. This gets removed when the boss is killed. # bosshealth (Show running damage dealt to boss by each player) # minionkills (Show a count for number of minions killed by players) # minionhealth (Show the running damage dealt to minions by each player) # none (No running battle scoreboard) Scoreboard: bosshealth # The cuboid is the square area (a room) where most of the fighting will take place. This area can be used in the options below # to allow mobs to be spawned in it or to have some of the boss special fighting skills to take place in. Cuboid Spawn Area Poss 1: "-162,68,77,world" Cuboid Spawn Area Poss 2: "-141,63,105,world" # What will trigger the start of the boss fight? # proximity (Activate if a player walks into the proximity specified in the "Boss Awareness Range" constant value above) # damage (Activate boss fight when damaged by a player) Bossfight Activator: damage # Currently the script supports 4 battle stages. A stage is reached/unlocked when the boss is down to a specified health percentage. # You decide the boss health percentage, minion names, the quantity to spawn, NPC types and how/where they spawn. # If you want less stages, simply remove them from the list. If you don't want any, type in "none". Make sure to type it as "One|Two|Three|Four". # If you only want the first two stages, type it as: One|Two Enabled Boss Stages: One|Two|Three|Four # The sections below detail the values for each of the 4 stages of the boss fight. You should modify these to make each boss fight unique. Stage One Boss Health Percentage: 95 # none (No effect around NPC) # flame (Create a fiery effect around the boss) # heart (Surrounds the boss with love hearts - kill you with love??) # smoke (Create a smokey 'pop' effect around the boss) # ender (Create the Enderman particles around NPC) # potbreak (Not very good, also makes the pot break sound) # explosion (Creeper explosion effect, causes no damage) Stage One Boss Aura: smoke # "Poison Arrow" (Shoot a poisonous arrow towards a randomly chosen player. Only casts when the player is hit) # "Wither Arrow" (Cast wither...) # "Weakness Arrow" (Cast weakness...) # "Slowness Arrow" (Cast slowness...) # "Rain Arrows" (Rain arrows from the sky - note: you need provide values for the "Cuboid Spawn Area Poss x" above for this to work) # "Lightning Bolt" (Hit a single random player with a lightning bolt - this never misses) # "Lightning Storm" (Several damaging lightning bolts - note: you to need provide values for the "Cuboid Spawn Area Poss x" above for this to work) # "TNT" (Boss tosses a block of primed tnt at a random player) # "TNT Drop" (Drop 5 blocks of TNT in random locations in the cuboid - Minecraft/Bukkit bug prevents this from working) # "Throw" (This will cause 3 players to be thrown from their current position to a random location inside the cuboid) # "Firestarter" (Ignite 10 random blocks in the cuboid) # none (No special attack) Stage One Boss Special Attack: "Poison Arrow" # Run the special attack on a loop, once every 20 seconds. Stage One Boss Special Attack Delay: 20s Stage One Spawn Minions: "Yes" Stage One Minion Type: zombie Stage One Minion Age: baby Stage One Minion Name: RotWalker Stage One Minion Weapon: wood_sword Stage One Minion Health: 30 Stage One Minion Quantity: 5 Stage One Minion Strength: 2 Stage One Minion Armor: 3 Stage One Minion Speed: 0.5 # lightning (lightning bolt with sound) # explode (harmless explosion effect with sound) # none (no effect) Stage One Minion Spawn Effect: none # player: spawn around random player # boss: spawn around boss # cuboid: spawn anywhere inside the cuboid values you specified above Stage One Minion Spawn Location: player # Boss - Stage Two Stage Two Boss Health Percentage: 75 Stage Two Boss Aura: ender Stage Two Boss Special Attack: "Wither Arrow" Stage Two Boss Special Attack Delay: 30s Stage Two Spawn Minions: "Yes" Stage Two Minion Type: cave_spider Stage Two Minion Age: adult Stage Two Minion Name: Crawler Stage Two Minion Weapon: none Stage Two Minion Health: 5 Stage Two Minion Quantity: 15 Stage Two Minion Strength: 1 Stage Two Minion Armor: 1 Stage Two Minion Speed: 1.5 Stage Two Minion Spawn Effect: lightning Stage Two Minion Spawn Location: cuboid # Boss - Stage Three Stage Three Boss Health Percentage: 50 Stage Three Boss Aura: flame Stage Three Boss Special Attack: Firestarter Stage Three Boss Special Attack Delay: 20s Stage Three Spawn Minions: "Yes" Stage Three Minion Type: blaze Stage Three Minion Age: adult Stage Three Minion Name: FireElement Stage Three Minion Weapon: none Stage Three Minion Health: 30 Stage Three Minion Quantity: 5 Stage Three Minion Strength: 2 Stage Three Minion Armor: 8 Stage Three Minion Speed: 1 Stage Three Minion Spawn Effect: explode Stage Three Minion Spawn Location: boss # Boss - Stage Four Stage Four Boss Health Percentage: 25 Stage Four Boss Aura: heart Stage Four Boss Special Attack: "TNT Drop" Stage Four Boss Special Attack Delay: 20s Stage Four Spawn Minions: "Yes" Stage Four Minion Type: iron_golem Stage Four Minion Age: adult Stage Four Minion Name: Terminator Stage Four Minion Weapon: none Stage Four Minion Health: 50 Stage Four Minion Quantity: 5 Stage Four Minion Strength: 3 Stage Four Minion Armor: 8 Stage Four Minion Speed: 1.2 Stage Four Minion Spawn Effect: lightning Stage Four Minion Spawn Location: cuboid #WARNING# Only continue past this point if you know what you're doing!! #WARNING# interact scripts: - 10 BossName Script actions: on assignment: # For this script, the click trigger is only used to return the boss's health. - trigger name:click toggle:true # Proximity set to a radius of 30, you should increase this in the # "Boss Awareness Range" constant above if you're fighting in a large arena. - trigger name:proximity toggle:true "radius:<cons:Boss Awareness Range>" # Damage trigger does a whole bunch of stuff which I'll explain in that section. - trigger name:damage toggle:true # Create a NPC flag called "cuboid" that stores the cuboid values in a simple # shorter name which makes it easy for reuse. - flag npc "cuboid:cu@<cons:Cuboid Spawn Area Poss 1>|<cons:Cuboid Spawn Area Poss 2>" # The following commands sets up the Boss using the values specified in the # constants above. - execute as_server "npc sel <npc.id>" - execute as_server "npc type <cons:Boss Entity Type>" - if "<cons:Boss Age>" == baby age <npc> baby - execute as_server "npc speed <cons:Boss Movement Speed>" - execute as_server "npc lookclose" - execute as_server "trait sentry" - execute as_server "sentry health <cons:Boss Health>" - execute as_server "sentry respawn <cons:Boss Respawn Delay>" - execute as_server "sentry speed <cons:Boss Movement Speed>" - execute as_server "sentry strength <cons:Boss Strength>" - execute as_server "sentry armor <cons:Boss Armor>" - execute as_server "sentry range <cons:Boss Agro Range>" - if "<cons:Boss Weapon>" != none execute as_server "sentry equip <cons:Boss Weapon>" # Put the boss stages into a flag - this will be used throughout to check which boss # stages should be activated. - flag npc "Enabled Boss Stages:<cons:Enabled Boss Stages>" # This is used in world events further down to prevent self/minion harm. - flag global ListOfBosses:<npc> # This is used by the minions to prevent teleporting to players when the player exits # their awareness range. (Temporary until Sentry is fixed) - flag npc "Minion Awareness Range:<cons:Boss Awareness Range>" on spawn: # Teleport boss back to starting point. - teleport <npc> "location:<cons:Boss Spawn Location>" # Every time the boss spawns after it's been killed, it'll run through the following process # to do some 'clean-up' from the previous battle. # # First it runs through a global "minion" list and check to see whether they are despanwed and # if they have a "creator". It then removes them from the global list and executes the "remove" # command to permanently get rid of them. # # Clear the Sentry target list, so it doesn't attack players unprovoked. # # Remove the "R.I.P" sign it placed when and where it died. # # Set up the Minecraft scoreboard. # First it checks to see if its meant to create a Scoreboard, if so, it'll flag the # NPC with what the scoreboard should show: # * bosshealth # * minionkills # * miniondamage # # It uses the "substring" to put a limit in place for the length of the boss's name because # if the name is too long, the scoreboard will fail to create. - if <npc.flag[BossDied]> { - flag npc BossDied:! - foreach <global.flag[AllMinions].aslist> { - if <npc[%value%].is_spawned> != true && <npc[%value%].flag[MinionCreator]> != null { - flag global AllMinions:<-:%value% - remove %value% } } - execute as_server "npc sel <npc.id>" - execute as_server "sentry target clear" - if "<location[<npc.flag[DeathLocation]>].block.sign_contents>" contains <npc.name> modifyblock <npc.flag[DeathLocation]> air - if <cons:Scoreboard> != none && <npc.flag[Scoreboard]> == null { - flag <npc> Scoreboard:<cons:Scoreboard> - if <npc.flag[Scoreboard]> == "bosshealth" { - execute as_server "scoreboard objectives add <npc.name.substring[1,9]>.Damage dummy" - execute as_server "scoreboard objectives setDisplay sidebar <npc.name.substring[1,9]>.Damage" } else if <npc.flag[Scoreboard]> == "minionkills" { - execute as_server "scoreboard objectives add <npc.name.substring[1,5]>.MinionKills dummy" - execute as_server "scoreboard objectives setDisplay sidebar <npc.name.substring[1,5]>.MinionKills" } else { - execute as_server "scoreboard objectives add <npc.name.substring[1,6]>.MinionDmg dummy" - execute as_server "scoreboard objectives setDisplay sidebar <npc.name.substring[1,6]>.MinionDmg" } } } on death: # When the boss dies, there is a bunch of clean-up that needs to happen. # # It goes through a couple of 'foreach' loops to remove all the minions that were created # during the various stages. Each minion was added to the boss flag list and now it simply # iterates through removing each minion by substituting %value% with their NPC ID, e.g. n@123 - foreach "<npc.flag[Enabled Boss Stages].aslist>" { - foreach "<npc.flag[Stage%value%Minions].aslist>" { - if <npc> != %value% remove <npc[%value%]> } } # It then clears the minion list for each battle stage. - foreach "<npc.flag[Enabled Boss Stages].aslist>" { - flag <npc> "Stage%value%Minions:!" } # Remove the next 2 lines if you don't like it. What it does is flag where the boss died and put a # sign into the ground with the boss's name, followed by "was defeated here". The "|" means go onto # the next line on the sign. - flag npc DeathLocation:<npc.location.simple> - sign <npc.flag[DeathLocation]> "<npc.name>|was defeated|here." # The following section builds the text scoreboard that is displayed in the Minecraft chat when # the boss has been killed. # # The IF checks to see if anybody hit the boss at any point (using the "BossHitList" flag). # You'll see further down that this list is populated by the damage trigger when the boss is hit # by a player. # # It then announces to the server the result of the battle. It uses a foreach loop to cycle through # all players that hit the boss (even those that didn't penetrate its amor) and shows for each player # how much damage, their overall damage percentage and the number of times they hit the boss. # # If the player also damaged and killed minions, it will show another line with minion total damage, # hit count and number of minions killed. # # This is all recorded into flags during the damage trigger and on death action for the boss and minions. # # At the bottom it shows a list of all players that got into the "Boss Awareness Range" but never # damaged/hit the boss or minions, e.g SPECTATORS. # # During the foreach loop, it also clears all the player flags to ready them for the next battle. # # Lastly, it checks to see if the "Drop Loot on Death" is set to "Yes", and if so it runs the task # called "BossName Drop the Loot" instantly. - if <npc.flag[BossHitList]> != null { - announce "<red>BOSS EVENT<&co> <white><npc.name><red> has been killed by <yellow><npc.flag[BossHitList].formatted><red>." - announce "<green>------------------------------------------" - announce "<green><underline>Battle Stats<&co>" - announce "" - announce "<red><npc.name> Total Health<&co> <npc.health.max.as_int>" - foreach <npc.flag[BossHitList].aslist> { - define bosspercentage <util.as_element[<m:<player[%value%].flag[BossPlayerTotalDamage]>/<npc.health.max>*100>].asint> - announce "<yellow><%value%.name>|" - announce "<aqua>Boss Damage <gold><player[%value%].flag[BossPlayerTotalDamage].as_int> (<%bosspercentage%><&pc>) <aqua>- Hits| <gold><player[%value%].flag[BossPlayerHitCount].as_int>" - if <player[%value%].flag[MinionTotalDamage]> != null { - announce "<aqua>Combined Minion Damage <gold><player[%value%].flag[MinionTotalDamage].as_int || 0> <aqua>- Hits| <gold><player[%value%].flag[MinionHitCount].as_int || 0> <aqua>- Minions Killed| <gold><player[%value%].flag[MinionsKilledCount].as_int || 0>" } - flag player:%value% BossPlayerTotalDamage:! - flag player:%value% BossPlayerHitCount:! - flag player:%value% MinionsKilledCount:! - flag player:%value% MinionHitCount:! - flag player:%value% MinionTotalDamage:! } - announce "<green>------------------------------------------" - foreach <npc.flag[BossSpectatorList].aslist> { - if <npc.flag[BossHitList].aslist> contains %value% flag npc BossSpectatorList:<-:%value% } - if <npc.flag[BossSpectatorList].size> >= 1 announce "Spectators| <npc.flag[BossSpectatorList].formatted>" - if "<cons:Drop Loot on Death>" == "Yes" run "BossName Drop the Loot" instantly } # Remove any visual effects applied at fight stages and clear sentry targets. - execute as_server "npc sel <npc.id>" - execute as_server "npc effect --play none" - execute as_server "sentry target clear" # If the scoreboard was enabled, this will remove it so it doesn't stay behind on player's screens. - if <npc.flag[Scoreboard]> != null { - if <npc.flag[Scoreboard]> == "bosshealth" execute as_server "scoreboard objectives remove <npc.name.substring[1,9]>.Damage" else if <npc.flag[Scoreboard]> == "minionkills" execute as_server "scoreboard objectives remove <npc.name.substring[1,5]>.MinionKills" else if <npc.flag[Scoreboard]> == "minionhealth" execute as_server "scoreboard objectives remove <npc.name.substring[1,6]>.MinionDmg" } # Clear all the flags used during the fight to set boss up for the next fight. - flag npc BossHitList:! - flag npc BossSpectatorList:! - flag npc BossStage:! - flag npc BossPlayerList:! - flag npc BadLoopProtect:! - flag npc ActiveSpecialAttackStage:! - flag npc MinionSpawnedStage:! - flag npc Scoreboard:! - flag npc AllMyMinions:! - flag npc BossResetTimer:! - flag npc HealActive:! # This flag is used to prevent certain "on spawn" commands from running unless the boss actually died. - flag npc BossDied "BossName Script": type: interact steps: 1: click trigger: script: # Right clicking the boss will run the "BossName Health Status" task that'll construct a # text based health bar that will show in the Minecraft chat window. - run "BossName Health Status" proximity trigger: entry: script: # When a player enters the proximity set in the "Boss Awareness Range" constant value, it'll check to see # if they are already on the list and if not it will add them to the "BossPlayerList" flag. This is used for # targetted narrate messages throughout the fight. - if <npc.flag[BossPlayerList].aslist> !contains <player> && <player.name> != <npc.name> flag npc BossPlayerList:->:<player> # Add players to the spectator list, which shows up in the battle stats after the boss fight. - if <npc.flag[BossSpectatorList].aslist> !contains <player> && <player.name> != <npc.name> flag npc BossSpectatorList:->:<player> # If proximity was set as the "BossName Fight Activator" in the constant values at the top, this will # start the fight if there isn't already an active fight stage. - if "<cons:Bossfight Activator>" == "proximity" && <npc.flag[BossStage]> == null { - flag npc BossStage:One - run "BossName Fight" } else if <npc.flag[BossStage]> != null run "BossName Fight" # This resets the timer when a player enters proximity so the boss does NOT get reset after the period # of inactivity specified in the "BossName Reset Timer" constant value up top. - flag npc BossResetTimer:! exit: script: - if <npc.navigator.target_entity> == <player> && "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 attack <npc> "target:<npc.location.find.players.within[<cons:Boss Awareness Range>].get[1]>" else attack stop # The wait 10 allows for a buffer where players are on the edge of the proximity moving in an out. - wait 10 # If the fight has been activated (it hasn't got a null boss stage), and there are no players in proximity # and self healing has been enabled, run the "BossName Self Heal" task. - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" < 1 && <npc.flag[BossStage]> != null && "<cons:Boss Exit Proximity Self Healing>" == "Yes" { - run "BossName Self Heal" id:<npc.name>_BossHeal } # Same as above, except this kicks off the overall "BossName Reset" task with a delay timer (set in # "BossName Reset Timer" constant above). - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" < 1 && <npc.flag[BossStage]> != null && "<cons:Boss Reset Timer>" >= 1 && <npc.flag[BossResetTimer]> == null { - flag <npc> BossResetTimer - run "BossName Reset" id:<npc.name>_ResetTimer "delay:<cons:Boss Reset Timer>" } damage trigger: script: # Every time the boss is hit (whether they are actually damaged or not), it will the commands below. # # The first IF is so save save the current boss health into a defined value called "phealth". - ^if <npc.is_spawned> define phealth <npc.health.as_int> # This tick is necessary to allow time for the damage value to be applied to the NPC. - wait 1t # If the player managed to get through the "entry proximity" without being added to the "BossPlayerList" # it will do it now. - ^if <npc.flag[BossPlayerList].aslist> !contains <player> && <player.name> != <npc.name> flag <npc> BossPlayerList:->:<player> # Start counting the number of times the player has hit the boss. Add "+1" every time they trigger this. - ^flag player BossPlayerHitCount:++ # Add the player into the "BossHitList" if they aren't already. - ^if <npc.flag[BossHitList].aslist> !contains <player> && <player.name> != <npc.name> flag <npc> BossHitList:->:<player> # The following IF is used to check the boss's current health. If their health is lower than the specified # percentage in the "Stage One/Two/Three/Four Boss Health Percentage" constant values, it will activate the # next fighting stage. # It flags (flag npc BossStage:One etc) the stage it's at because this is used to control the flow of # stages and also used during the "Special Attack" loop tasks further down. - ^if "<npc.flag[Enabled Boss Stages].aslist>" contains One && <npc.flag[BossStage]> == null && <npc.health.percentage.as_int> <= "<cons:Stage One Boss Health Percentage>" { - flag npc BossStage:One - run "BossName Fight" } else if "<npc.flag[Enabled Boss Stages].aslist>" contains Two && <npc.flag[BossStage]> == One && <npc.health.percentage.as_int> <= "<cons:Stage Two Boss Health Percentage>" { - flag npc BossStage:Two - run "BossName Fight" } else if "<npc.flag[Enabled Boss Stages].aslist>" contains Three && <npc.flag[BossStage]> == Two && <npc.health.percentage.as_int> <= "<cons:Stage Three Boss Health Percentage>" { - flag npc BossStage:Three - run "BossName Fight" } else if "<npc.flag[Enabled Boss Stages].aslist>" contains Four && <npc.flag[BossStage]> == Three && <npc.health.percentage.as_int> <= "<cons:Stage Four Boss Health Percentage>" { - flag npc BossStage:Four - run "BossName Fight" } # The new NPC remaining value is then subtracted off the previous damage value. This is then # added into a player flag as the total damage value they inflicted. - ^if <npc.is_spawned> define finaldamage <el@val[<m:%phealth%-<npc.health>>].asint> else define finaldamage %phealth% - ^flag player BossPlayerTotalDamage:+:%finaldamage% # Add the damage amount into the Minecraft scoreboard. (Right hand side of players screen). - if <npc.flag[Scoreboard]> == bosshealth && %finaldamage% != 0 execute as_server "scoreboard players add <player.name> <npc.name.substring[1,9]>.Damage %finaldamage%" "BossName Fight": type: task script: # Every time a stage kicks off, this is the part of the script it runs. # Initially it announces the boss health percentage to the "BossPlayerList" (so not everyone on the server # gets the message, only the participants. It also runs the "BossName Health Status" script which displays # a dynamic text based health bar. - ^narrate "<red>Boss Stage <npc.flag[BossStage]> - Health <npc.health.percentage.as_int>%" targets:<npc.flag[BossPlayerList].aslist> - ^run "BossName Health Status" # Flags the boss with the current stage special attack, used by the special attack tasks to run (or not # if it's not relevant for that stage anymore). - ^flag npc "CurrentSpecialAttack:<cons:Stage <npc.flag[BossStage]> Boss Special Attack>" # Each stage can also have a different effect play around/near the boss, this is checked here and # applied with the "execute as_server" command. # If there is no effect for this stage, it removes it with the "--play none" parameter below. - ^if flame|heart|smoke|ender|potbreak|explosion contains "<cons:Stage <npc.flag[BossStage]> Boss Aura>" { - execute as_server "npc sel <npc.id>" - execute as_server "npc effect --play none" - execute as_server "npc effect --play <cons:Stage <npc.flag[BossStage]> Boss Aura>" } else { - execute as_server "npc sel <npc.id>" - execute as_server "npc effect --play none" } # The next section is where the minions are spawned, if enabled, for the relevant boss stage. # For the "repeat" command, it runs the number of times based on the number of minions you've set # to spawn in the "... Minion Qunatity" constant values at the top for each stage. # # It uses a global flag (TempBossId) to store the boss's NPC ID which is then put into a for each of # the minions - so it creates a relationship of sorts between the boss & minions so they can be # despawned when the boss dies for example. # # It checks to see where the minions should spawn based on your set spawn location, 'player', # 'cuboid' or 'boss'. Then it uses a great tag combination "get_spawnable_blocks.random" to pick # a random "safe" location for the minion to spawn. This prevents *most* NPC's from spawning inside # walls. # # Then, once its got the location it runs the "BossName Spawn Minion" task instantly. This is explained further # down when you get to the task. # # Once the minion has been created, it'll make it a baby if a) you enabled it b) if the NPC type # supports it. It then applies all the sentry values you've set at each stage in the constants # at the top of the script. Lastly, it adds "player" type to it's Sentry target list, picks a random # player from the BossPlayerList and..well.. attacks it. - if "<cons:Stage <npc.flag[BossStage]> Spawn Minions>" == "Yes" && <npc.flag[MinionSpawnedStage]> != <npc.flag[BossStage]> { - flag <npc> MinionSpawnedStage:<npc.flag[BossStage]> - repeat "<cons:Stage <npc.flag[BossStage]> Minion Quantity>" { - flag global TempBossId:<npc> - if "<cons:Stage <npc.flag[BossStage]> Minion Spawn Location>" == "player" { - define selplayer "<npc.flag[BossPlayerList].aslist.random>" - flag <npc> SpawnLocation:<cu@<player[%selplayer%].location.add[-4,0,-4].simple>|<player[%selplayer%].location.add[4,1,4].simple>.get_spawnable_blocks.random> - run "BossName Spawn Minion" instantly } else if "<cons:Stage <npc.flag[BossStage]> Minion Spawn Location>" == cuboid { - flag <npc> SpawnLocation:<cu@<npc.flag[cuboid]>.get_spawnable_blocks.random> - run "BossName Spawn Minion" instantly } else if "<cons:Stage <npc.flag[BossStage]> Minion Spawn Location>" == "boss" { - flag <npc> SpawnLocation:<cu@<npc.location.add[-4,0,-4].simple>|<npc.location.add[4,1,4].simple>.get_spawnable_blocks.random> - run "BossName Spawn Minion" instantly } } - if <npc.flag[Stage<npc.flag[BossStage]>Minions].size> >= 1 { - foreach <npc.flag[Stage<npc.flag[BossStage]>Minions].aslist> { - execute as_server "npc sel <%value%.id>" - if "<cons:Stage <npc.flag[BossStage]> Minion Weapon>" != none equip %value% "hand:<cons:Stage <npc.flag[BossStage]> Minion Weapon>" - if "<cons:Stage <npc.flag[BossStage]> Minion Age>" == baby age %value% baby - execute as_server "sentry respawn -1" - execute as_server "sentry health <cons:Stage <npc.flag[BossStage]> Minion Health>" - execute as_server "sentry strength <cons:Stage <npc.flag[BossStage]> Minion Strength>" - execute as_server "sentry armor <cons:Stage <npc.flag[BossStage]> Minion Armor>" - execute as_server "sentry target add entity<&co>player" - attack %value% target:<npc.flag[BossPlayerList].aslist.random> } } } # The server then select the boss ID again and also adds "player" type as it's target. - ^execute as_server "npc sel <npc.id>" - ^execute as_server "sentry target add entity<&co>player" # Each stage can have a different special attack. This is where that process kicks off. First it checks # what the attack is for the particular stage the boss is on, then flags the NPC with the # "ActiveSpecialAttackStage" which is used by the special attack tasks to run or cancel further down. - ^if "Poison Arrow|Wither Arrow|Weakness Arrow|Slowness Arrow" contains "<cons:Stage <npc.flag[BossStage]> Boss Special Attack>" { - flag <npc> ActiveSpecialAttackStage:Arrows - run "BossName Special Attack - Arrows" } else if "<cons:Stage <npc.flag[BossStage]> Boss Special Attack>" == "Rain Arrows" { - flag <npc> "ActiveSpecialAttackStage:Rain Arrows" - run "BossName Special Attack - Rain Arrows" } else if "<cons:Stage <npc.flag[BossStage]> Boss Special Attack>" == "Lightning Bolt" { - flag <npc> "ActiveSpecialAttackStage:Lightning Bolt" - run "BossName Special Attack - Lightning Bolt" } else if "<cons:Stage <npc.flag[BossStage]> Boss Special Attack>" == "Lightning Storm" { - flag <npc> "ActiveSpecialAttackStage:Lightning Storm" - run "BossName Special Attack - Lightning Storm" } else if "<cons:Stage <npc.flag[BossStage]> Boss Special Attack>" == "TNT" { - flag <npc> "ActiveSpecialAttackStage:TNT" - run "BossName Special Attack - TNT" } else if "<cons:Stage <npc.flag[BossStage]> Boss Special Attack>" == "TNT Drop" { - flag <npc> "ActiveSpecialAttackStage:TNT Drop" - run "BossName Special Attack - TNT Drop" } else if "<cons:Stage <npc.flag[BossStage]> Boss Special Attack>" == "Throw" { - flag <npc> "ActiveSpecialAttackStage:Throw" - run "BossName Special Attack - Throw" } else if "<cons:Stage <npc.flag[BossStage]> Boss Special Attack>" == "Firestarter" { - flag <npc> "ActiveSpecialAttackStage:Firestarter" - run "BossName Special Attack - Firestarter" } else if "<cons:Stage <npc.flag[BossStage]> Boss Special Attack>" == none flag <npc> ActiveSpecialAttackStage:! # If for some reason Sentry is delayed (known issue which I've logged here: https://github.com/jrbudda/Sentry/issues/161) this will # make sure if it's got no target to pick the closest player and attack them. - ^if <npc.navigator.target_entity> == null attack <npc> "target:<npc.location.find.players.within[<cons:Boss Awareness Range>].get[1]>" "BossName Spawn Minion": type: task script: # Here it initially defines the boss stage and then use that to pick: # 1) Which effect is used to spawn the minion # 2) Give it a name, a type, speed and make it a Sentry. - define bosstage <npc.flag[BossStage]> - if "<cons:Stage %bosstage% Minion Spawn Effect>" == lightning strike no_damage location:<npc.flag[SpawnLocation]> else if "<cons:Stage %bosstage% Minion Spawn Effect>" == explode explode power:1 location:<npc.flag[SpawnLocation]> # The most effective way to create an NPC is to fit as MANY of the possible parameters into the "npc create" command # as possible. This avoids a scenario where the players can witness the NPC's changing or being teleported to where # you intended etc. - execute as_server "npc create <cons:Stage %bosstage% Minion Name> --at <npc.flag[SpawnLocation]> --type <cons:Stage %bosstage% Minion Type> --speed <cons:Stage %bosstage% Minion Speed> --trait sentry" # This sets the minions owner to be the boss. It's not really used in this scrpt but I do it anyway. - execute as_server "npc owner <npc.name>" # Assign the "BossName Minion Basics" script below to each minion. - execute as_server 'npc assign --set "BossName Minion Basics"' "BossName Minion Basics": type: assignment actions: on assignment: - trigger name:click toggle:true - trigger name:damage toggle:true # Add this NPC id to a global "AllMinions" list.. this is checked by the boss on spawn # to clean up any left behind NPC's if something went wrong or server shutdown midway # through a fight. - ^flag global AllMinions:->:<npc> # Flag the minion with the boss ID. This allows the minion to updates flags on the boss, # e.g. the "BossPlayerList" or to add itself to the "AllMyMinions" list which is checked # during the "BossName Prevent Self Harm" script. - ^flag <npc> MinionCreator:<global.flag[TempBossId]> # Minion adds itself into the boss's minion list flags. - ^flag <npc[<npc.flag[MinionCreator]>]> Stage<npc[<npc.flag[MinionCreator]>].flag[BossStage]>Minions:->:<npc> - ^flag <npc[<npc.flag[MinionCreator]>]> AllMyMinions:->:<npc> # If player exits this proximity range the minion will stop attacking. (Temporary until Sentry is fixed) - ^flag npc "Minion Awareness Range:<npc[<npc.flag[MinionCreator]>].flag[Minion Awareness Range]>" - ^trigger name:proximity toggle:true "radius:<npc.flag[Minion Awareness Range]>" on death by player: # When the minion is killed by a player (rather than by other mobs or the environment) it # will add 1 to player flag keeping a count of minions killed. - flag player MinionsKilledCount:++ # Remove the minion from the "AllMinions" global flag (used to clean up if minions left # behind for whatever reason). - flag global AllMinions:<-:<npc> # Remove the minion from the boss's minion list. - flag <npc[<npc.flag[MinionCreator]>]> AllMyMinions:<-:<npc> # If the scoreboard is set to record minions killed count, add one to the player score. - if <npc[<npc.flag[MinionCreator]>].flag[Scoreboard]> == minionkills execute as_server "scoreboard players add <player.name> <npc[<npc.flag[MinionCreator]>].name.substring[1,5]>.MinionKills 1" interact scripts: - 5 BossName Minion Damage "BossName Minion Damage": type: interact steps: 1: damage trigger: script: # This damage trigger is very similar to the boss's, so won't explain what happens here. - ^if <npc.is_spawned> define phealth <npc.health> - ^define mincreator <npc.flag[MinionCreator]> - wait 1t - ^if <npc[%mincreator%].flag[BossPlayerList].aslist> !contains <player> && <player.name> != <npc[%mincreator%].name> flag <npc[%mincreator%]> BossPlayerList:->:<player> - ^if <npc[%mincreator%].flag[BossHitList].aslist> !contains <player> && <player.name> != <npc[%mincreator%].name> flag <npc[%mincreator%]> BossHitList:->:<player> - ^if <npc.is_spawned> define finaldamage <el@val[<m:%phealth%-<npc.health>>].asint> else define finaldamage <el@val[%phealth%].asint> - ^flag player MinionTotalDamage:+:%finaldamage% - ^flag player MinionHitCount:++ - ^if <npc[%mincreator%].flag[Scoreboard]> == minionhealth && %finaldamage% != 0 execute as_server "scoreboard players add <player.name> <npc[%mincreator%].name.substring[1,6]>.MinionDmg %finaldamage%" click trigger: script: - run "BossName Health Status" proximity trigger: exit: script: - if <npc.navigator.target_entity> == <player> && "<npc.location.find.players.within[<npc.flag[Minion Awareness Range]>].size>" >= 1 attack <npc> "target:<npc.location.find.players.within[<npc.flag[Minion Awareness Range]>].get[1]>" else attack stop #-------------------------------------------------------------------------------# # There is a chance the NPC (boss or minions) can hurt themselves, so even # though it's not the most effective world script, it will at least check to # see if the "damager" is the boss or a minion and if so, cancel the damage # # I'm specifically checking the NPC flags so it doesn't cancel damage on other # NPC's on the server. # #-------------------------------------------------------------------------------# "BossName Prevent Self Harm": type: world events: on npc damaged: - if <context.entity> == <context.damager> && <global.flag[ListOfBosses].aslist> contains <context.entity> determine cancelled else if <context.entity> == <context.damager> && <global.flag[AllMinions].aslist> contains <context.entity> determine cancelled else if <context.damager> == <npc.flag[MinionCreator]> determine cancelled else if <npc.flag[AllMyMinions].aslist> contains <context.damager> determine cancelled #-------------------------------------------------------------------------------# # If you typed "Yes" in the "Boss Exit Proximity Self Healing" constant value, # a exit proximity trigger will check to see if there are any players left in # proximity.. if not, it will run this task below which will heal the NPC 1 # health every 5 seconds. # # If players enter proximity, this task is cancelled and the boss will stop # healing. # #-------------------------------------------------------------------------------# "BossName Self Heal": type: task script: - if <npc.health> < <npc.health.max> && "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" < 1 && <npc.flag[HealActive]> == null { - flag <npc> HealActive - heal <npc> 1 - wait 5 - flag <npc> HealActive:! - run "BossName Self Heal" } #-------------------------------------------------------------------------------# # The following script builds up a health bar for the NPC. It does # this by dividing their current health by 10, the result of that, say 7.2 is # then rounded down to 7. It then repeats a loop 7 times, each time adding # 10 "|" characters into a flag. So 7 x ||||||||||.. the remaining 2 (7.2) # then just gets added onto that, e.g. || # # The reason I did it this way was so that it didn't repeat the loop 70 times to # build up the number of health bars. # # In the example, 72 bars will be <GREEN> and the remaining 28 bars will be # <RED>. # # This can be used with any NPC regardless of how much health they have # because it uses their "percentage" of health rather than max value health. #-------------------------------------------------------------------------------# "BossName Health Status": type: task script: - ^if <npc.health.percentage> == 100 narrate "<red><npc.name.substring[1,12]> Health<&co><white> [<green>||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||<white>]" else { - ^define GreenTenCount <el@val[<m:floor(<npc.health.percentage>/10)>].asint> - ^define GreenTenTotal <el@val[<m:%GreenTenCount%*10>].asint> - ^define GreenOneCount <el@val[<m:<npc.health.percentage>-%GreenTenTotal%>].asint> - ^define RedTenCount <el@val[<m:floor(<m:100-<npc.health.percentage>>/10)>].asint> - ^define RedTenTotal <el@val[<m:%RedTenCount%*10>].asint> - ^define RedOneCount <el@val[<m:<m:100-<npc.health.percentage>>-%RedTenTotal%>].asint> - ^repeat %GreenTenCount% { - flag <npc> "GreenBars:<npc.flag[GreenBars].replace[null]>||||||||||" } - ^repeat %GreenOneCount% { - flag <npc> "GreenBars:<npc.flag[GreenBars].replace[null]>|" } - ^repeat %RedTenCount% { - flag <npc> "RedBars:<npc.flag[RedBars].replace[null]>||||||||||" } - ^repeat %RedOneCount% { - flag <npc> "RedBars:<npc.flag[RedBars].replace[null]>|" } - ^if <npc.flag[RedBars]> == null narrate "<red><npc.name.substring[1,12]> Health<&co><white> [<green><npc.flag[GreenBars]><white>]" else narrate "<red><npc.name.substring[1,12]> Health<&co><white> [<green><npc.flag[GreenBars]><red><npc.flag[RedBars].replace[null]><white>]" - ^flag npc GreenBars:! - ^flag npc RedBars:! } #-------------------------------------------------------------------------------# # The next script is used to RESET the boss back to start (health back to 100%, # all spawned minions removed, all player damage/counter flags reset, all boss # targets, effects and flags cleared and Minecraft scoreboard removed. # # This task will only run if the "Boss Reset Timer" constant value is set to # 1 or higher and when the last player leaves the boss proximity. When a # player enters proximity, the "BossResetTimer" flag timer is NULL'ed, so when # the task runs it fails on the first IF and boss is not reset. #-------------------------------------------------------------------------------# "BossName Reset": type: task script: - ^if <npc.flag[BossResetTimer]> != null { - foreach "<npc.flag[Enabled Boss Stages].aslist>" { - foreach <npc.flag[Stage%value%Minions].aslist> { - if <npc> != %value% remove <npc[%value%]> } } - foreach "<npc.flag[Enabled Boss Stages].aslist>" { - flag <npc> Stage%value%Minions:! } - announce "<red>BOSS EVENT<&co> <white><npc.name><red> has been reset." - foreach <npc.flag[BossHitList].aslist> { - flag player:%value% BossPlayerTotalDamage:! - flag player:%value% BossPlayerHitCount:! - flag player:%value% MinionsKilledCount:! - flag player:%value% MinionHitCount:! - flag player:%value% MinionTotalDamage:! } - foreach <npc.flag[BossSpectatorList].aslist> { - if <npc.flag[BossHitList].aslist> contains %value% flag <npc> BossSpectatorList:<-:%value% } - execute as_server "npc sel <npc.id>" - execute as_server "npc effect --play none" - execute as_server "sentry target clear" - if <npc.flag[Scoreboard]> != null { - if <npc.flag[Scoreboard]> == bosshealth execute as_server "scoreboard objectives remove <npc.name.substring[1,9]>.Damage" else if <npc.flag[Scoreboard]> == minionkills execute as_server "scoreboard objectives remove <npc.name.substring[1,5]>.MinionKills" else if <npc.flag[Scoreboard]> == minionhealth execute as_server "scoreboard objectives remove <npc.name.substring[1,6]>.MinionDmg" } - teleport "<npc>" "location:<cons:Boss Spawn Location>" - heal <npc> - flag <npc> BossHitList:! - flag <npc> BossSpectatorList:! - flag <npc> BossStage:! - flag <npc> BossPlayerList:! - flag <npc> BadLoopProtect:! - flag <npc> ActiveSpecialAttackStage:! - flag <npc> MinionSpawnedStage:! - flag <npc> Scoreboard:! - flag <npc> AllMyMinions:! - flag <npc> BossResetTimer:! - flag <npc> HealActive:! } #-------------------------------------------------------------------------------# # The following section contains several scripts that are all used by the # "special attack" that is enabled in the constant values "Stage One/Two/Three # /Four Boss Special Attack" at the top of the script. # # When the task is executed, it checks the following criteria: # * PreventDoubleAttack: This flag is to prevent the task from running # when it's already active. If the flag wasn't there it would've happened when # another player entered the boss's proximity. # # * Find players within a radius specified in constant "Boss Awareness Range" # from the NPC: This prevents the task from running if no one is there. # # * Boss Stage: This is used to check if the boss is in an attack stage, e.g. # the fight isn't over. # # * Active Special Attack Stage: Checks if the "Arrows" attack is still # relevant for the particular boss stage we're in. # # If all of those are met, it waits 5 seconds and then runs the task again. If # the criteria isn't met, it moves onto the "else if" section where it # checks whether the ActiveSpecialAttackStage is null (first time a special # attack script is executed) OR whether it's looping for a second time and # "Arrows" is still the relevant special attack. It then does another check to # see if there are players within a "Boss Awareness Range" block radius. # # After that, it flags the NPC with its current active special attack and puts # the "PreventDoubleAttack" protection flag in place, with an expiry (just in # time for the next intended delayed attack). It then finds a random player # within a "Boss Awareness Range" block radius and uses the "shoot" command to # shoot the arrow towards their location. Each arrow (entity) that gets fired is # recorded into a global flag called "ArrowList". This list is used later in the # world script to check who the arrow came from and what "special attack" to # apply. e.g. poison, blindness etc. # # It then waits for the period of time specified in the "Stage One/Two/Three/Four # Boss Special Attack Delay", does a quick check to see if there are at least # one player in proximity and also if this attack is still relevant, e.g. the # boss isn't into the next stage which may be using another special attack. #-------------------------------------------------------------------------------# "BossName Special Attack - Arrows": type: task script: - ^if <npc.flag[PreventDoubleAttack]> != null && "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Arrows" { - wait 5s - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Arrows" run "BossName Special Attack - Arrows" id:Boss<npc.id>SpecialAttack } else if <npc.flag[ActiveSpecialAttackStage]> == null || <npc.flag[ActiveSpecialAttackStage]> == "Arrows" { - if "<npc.location.find.players.within[<cons:Boss Awareness Range>]>" != null { - flag <npc> ActiveSpecialAttackStage:Arrows - flag <npc> PreventDoubleAttack "duration:<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - define arrowplayer "<npc.location.find.players.within[<cons:Boss Awareness Range>].random>" - narrate "<red><npc.name> shoots a <npc.flag[CurrentSpecialAttack]> towards <yellow><%arrowplayer%.name><red>..." targets:<npc.flag[BossPlayerList].aslist> - shoot i@arrow origin:<npc> destination:<player[%arrowplayer%].location> Height:0.1 save:shot - ^foreach <entry[shot].shot_entities> { - flag global ArrowList:->:%value% } - wait "<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Arrows" run "BossName Special Attack - Arrows" id:Boss<npc.id>SpecialAttack } } #-------------------------------------------------------------------------------# # This script uses a "Cuboid" which are the two values you specified in the # constant values "Cuboid Spawn Area Poss 1" and "Cuboid Spawn Area Poss 2" at # the top of the script. # # The cuboid should be a square INSIDE your fighting room. If the cuboid is # larger than your room, you'll have arrows spawning outside of the room. # # If you want to see where your cuboid outline is, type the following command in # Minecraft, with the NPC selected, and it'll create fake glass blocks that will # disappear in 10 seconds: # # /ex showfake glass <<npc.flag[cuboid]>.get_outline> duration:10s #-------------------------------------------------------------------------------# "BossName Special Attack - Rain Arrows": type: task script: - ^if <npc.flag[PreventDoubleAttack]> != null && "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Rain Arrows" { - wait 5s - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Rain Arrows" run "BossName Special Attack - Rain Arrows" id:Boss<npc.id>SpecialAttack } else if <npc.flag[ActiveSpecialAttackStage]> == null || <npc.flag[ActiveSpecialAttackStage]> == "Rain Arrows" { - if "<npc.location.find.players.within[<cons:Boss Awareness Range>]>" != null { - flag <npc> "ActiveSpecialAttackStage:Rain Arrows" - flag <npc> PreventDoubleAttack "duration:<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - narrate "<red><npc.name> causes it to <npc.flag[CurrentSpecialAttack]>..." targets:<npc.flag[BossPlayerList].aslist> - repeat 50 { - define roof <cu@<npc.flag[cuboid]>.max.y.add[-1]> - define Xrange <util.random.int[<cu@<npc.flag[cuboid]>.min.x.add[+1].as_int>].to[<cu@<npc.flag[cuboid]>.max.x.add[-1].as_int>]> - define Zrange <util.random.int[<cu@<npc.flag[cuboid]>.min.z.add[+1].as_int>].to[<cu@<npc.flag[cuboid]>.max.z.add[-1].as_int>]> - spawn i@arrow origin:%Xrange%,%roof%,%Zrange%,world } - wait "<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Rain Arrows" run "BossName Special Attack - Rain Arrows" id:Boss<npc.id>SpecialAttack } } "BossName Special Attack - Lightning Bolt": type: task script: - ^if <npc.flag[PreventDoubleAttack]> != null && "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Lightning Bolt" { - wait 5s - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Lightning Bolt" run "BossName Special Attack - Lightning Bolt" id:Boss<npc.id>SpecialAttack } else if <npc.flag[ActiveSpecialAttackStage]> == null || <npc.flag[ActiveSpecialAttackStage]> == "Lightning Bolt" { - if "<npc.location.find.players.within[<cons:Boss Awareness Range>]>" != null { - flag <npc> "ActiveSpecialAttackStage:Lightning Bolt" - flag <npc> PreventDoubleAttack "duration:<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - define lightningplayer "<npc.location.find.players.within[<cons:Boss Awareness Range>].random>" - narrate "<red><npc.name> calls a <npc.flag[CurrentSpecialAttack]> to hit <yellow><%lightningplayer%.name><red>..." targets:<npc.flag[BossPlayerList].aslist> - strike destination:<player[%lightningplayer%].location> - wait "<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Lightning Bolt" run "BossName Special Attack - Lightning Bolt" } } "BossName Special Attack - Lightning Storm": type: task script: - ^if <npc.flag[PreventDoubleAttack]> != null && "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Lightning Storm" { - wait 5s - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Lightning Storm" run "BossName Special Attack - Lightning Storm" id:Boss<npc.id>SpecialAttack } else if <npc.flag[ActiveSpecialAttackStage]> == null || <npc.flag[ActiveSpecialAttackStage]> == "Lightning Storm" { - if "<npc.location.find.players.within[<cons:Boss Awareness Range>]>" != null { - flag <npc> "ActiveSpecialAttackStage:Lightning Storm" - flag <npc> PreventDoubleAttack "duration:<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - narrate "<red><npc.name> calls a <npc.flag[CurrentSpecialAttack]> ..." targets:<npc.flag[BossPlayerList].aslist> - repeat 10 { - define floor <cu@<npc.flag[cuboid]>.min.y> - define Xrange <util.random.int[<cu@<npc.flag[cuboid]>.min.x.add[+1].as_int>].to[<cu@<npc.flag[cuboid]>.max.x.add[-1].as_int>]> - define Zrange <util.random.int[<cu@<npc.flag[cuboid]>.min.z.add[+1].as_int>].to[<cu@<npc.flag[cuboid]>.max.z.add[-1].as_int>]> - strike "destination:%Xrange%,%floor%,%Zrange%,world" } - wait "<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Lightning Storm" run "BossName Special Attack - Lightning Storm" } } "BossName Special Attack - TNT": type: task script: - ^if <npc.flag[PreventDoubleAttack]> != null && "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "TNT" { - wait 5s - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "TNT" run "BossName Special Attack - TNT" id:Boss<npc.id>SpecialAttack } else if <npc.flag[ActiveSpecialAttackStage]> == null || <npc.flag[ActiveSpecialAttackStage]> == "TNT" { - if "<npc.location.find.players.within[<cons:Boss Awareness Range>]>" != null { - flag <npc> ActiveSpecialAttackStage:TNT - flag <npc> PreventDoubleAttack "duration:<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - define targetplayer "<npc.location.find.players.within[<cons:Boss Awareness Range>].random>" - narrate "<red><npc.name> lobs <npc.flag[CurrentSpecialAttack]> at <yellow><%targetplayer%.name><red>..." targets:<npc.flag[BossPlayerList].aslist> - playsound location:<player[%targetplayer%].location> sound:fuse - shoot e@primed_tnt origin:<npc> destination:<player[%targetplayer%].location.simple> Height:0.5 - wait "<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "TNT" run "BossName Special Attack - TNT" id:Boss<npc.id>SpecialAttack } } "BossName Special Attack - TNT Drop": type: task script: - ^if <npc.flag[PreventDoubleAttack]> != null && "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "TNT Drop" { - wait 5s - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "TNT Drop" run "BossName Special Attack - TNT Drop" id:Boss<npc.id>SpecialAttack } else if <npc.flag[ActiveSpecialAttackStage]> == null || <npc.flag[ActiveSpecialAttackStage]> == "TNT Drop" { - if "<npc.location.find.players.within[<cons:Boss Awareness Range>]>" != null { - flag <npc> "ActiveSpecialAttackStage:TNT Drop" - flag <npc> PreventDoubleAttack "duration:<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - narrate "<red><npc.name> drops primed TNT.. TAKE COVER!" targets:<npc.flag[BossPlayerList].aslist> - repeat 5 { - define roof <cu@<npc.flag[cuboid]>.max.y.add[-1]> - define Xrange <util.random.int[<cu@<npc.flag[cuboid]>.min.x.add[+1].as_int>].to[<cu@<npc.flag[cuboid]>.max.x.add[-1].as_int>]> - define Zrange <util.random.int[<cu@<npc.flag[cuboid]>.min.z.add[+1].as_int>].to[<cu@<npc.flag[cuboid]>.max.z.add[-1].as_int>]> - spawn e@primed_tnt origin:%Xrange%,%roof%,%Zrange%,world } - wait "<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "TNT Drop" run "BossName Special Attack - TNT Drop" id:Boss<npc.id>SpecialAttack } } # The section below is disabled until https://github.com/aufdemrand/Denizen/issues/408 is fixed. # #"BossName Special Attack - Invisible": # type: task # # script: # - ^if <npc.flag[ActiveSpecialAttackStage]> == null || <npc.flag[ActiveSpecialAttackStage]> == "Invisible" flag npc ActiveSpecialAttackStage:Invisible # - ^if "<npc.location.find.players.within[<cons:Boss Awareness Range>]>" != null { # - narrate "<red><npc.name> goes <npc.flag[CurrentSpecialAttack]>..." "targets:<npc.flag[BossPlayerList].aslist>" # - execute as_server "npc sel <npc.id>" # - execute as_server "npc effect --play none" # - invisible npc state:true # - flag npc NoBlood # - define teleportplayer "<npc.location.find.players.within[<cons:Boss Awareness Range>].random>" # - teleport "<npc>" "location:%teleportplayer%" # - wait 10 # - invisible npc state:false # - flag npc NoBlood:! # - narrate "<red><npc.name> reappears from thin air..." "targets:<npc.flag[BossPlayerList].aslist>" # - execute as_server "npc effect --play <cons:Stage <npc.flag[BossStage]> Boss Aura> # - wait "<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" # - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "TNT" run "BossName Special Attack - TNT" id:Boss<npc.id>SpecialAttack # } "BossName Special Attack - Throw": type: task script: - ^if <npc.flag[PreventDoubleAttack]> != null && "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Throw" { - wait 5s - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Throw" run "BossName Special Attack - Throw" id:Boss<npc.id>SpecialAttack } else if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Throw" { - flag <npc> PreventDoubleAttack "duration:<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - if <npc.flag[ActiveSpecialAttackStage]> == null || <npc.flag[ActiveSpecialAttackStage]> == "Throw" flag <npc> ActiveSpecialAttackStage:Throw - if "<npc.location.find.players.within[<cons:Boss Awareness Range>]>" != null { - flag <npc> "ThrowList:|:<npc.location.find.players.within[<cons:Boss Awareness Range>].random[3]>" - narrate "<red><npc.name> throws <npc.flag[Throwlist].formatted>..." targets:<npc.flag[BossPlayerList].aslist> - foreach <npc.flag[Throwlist].aslist> { - flag <npc> ThrowList:<-:%value% - define roof <cu@<npc.flag[cuboid]>.max.y.add[-1]> - define Xrange <util.random.int[<cu@<npc.flag[cuboid]>.min.x.as_int>].to[<cu@<npc.flag[cuboid]>.max.x.as_int>]> - define Zrange <util.random.int[<cu@<npc.flag[cuboid]>.min.z.as_int>].to[<cu@<npc.flag[cuboid]>.max.z.as_int>]> - shoot %value% origin:<player[%value%].location.simple> destination:%Xrange%,%roof%,%Zrange%,world height:1.8 gravity:0.32 } - flag <npc> ThrowList:! - wait "<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Throw" run "BossName Special Attack - Throw" id:Boss<npc.id>SpecialAttack } } "BossName Special Attack - Firestarter": type: task script: - ^if <npc.flag[PreventDoubleAttack]> != null && "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Firestarter" { - wait 5s - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == Firestarter run "BossName Special Attack - Firestarter" id:Boss<npc.id>SpecialAttack } else if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == Firestarter { - flag <npc> PreventDoubleAttack "duration:<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - if <npc.flag[ActiveSpecialAttackStage]> == null || <npc.flag[ActiveSpecialAttackStage]> == Firestarter flag <npc> ActiveSpecialAttackStage:Firestarter - if "<npc.location.find.players.within[<cons:Boss Awareness Range>]>" != null { - narrate "<red><npc.name> sets the place on fire..." targets:<npc.flag[BossPlayerList].aslist> - repeat 10 { - modifyblock location:<cu@<npc.flag[cuboid]>.get_spawnable_blocks.random> fire } - wait "<cons:Stage <npc.flag[BossStage]> Boss Special Attack Delay>" - if "<npc.location.find.players.within[<cons:Boss Awareness Range>].size>" >= 1 && <npc.flag[BossStage]> != null && <npc.flag[ActiveSpecialAttackStage]> == "Firestarter" run "BossName Special Attack - Firestarter" id:Boss<npc.id>SpecialAttack } } #-------------------------------------------------------------------------------# # This section is primarily to handle the different types of arrows the boss # can shoot as part of it's special attacks. It determines which spell to "cast" # based on what the current active special attack is. # # It'll also narrate a random message to the boss player list about who got hit # and what the effect is. # # The other purpose here is to show the "blood" effect when you hit the NPC. It # uses the the "drip_lava" effect but draws 300 of them to make it look like a # bloody mist. Thanks to blankiito for this effect! #-------------------------------------------------------------------------------# "BossName Special Attack Handler": type: world events: on npc damaged by player: - if <context.entity> contains <global.flag[ListOfBosses]> && <npc[<context.entity>].flag[NoBlood]> == null { - playeffect location:<context.entity.location> effect:DRIP_LAVA radius:10 qty:300 offset:0.15 } on player damaged by arrow: - ^if <context.projectile> contains <global.flag[ArrowList]> { - flag global ArrowList:<-:<context.projectile> - if <npc[<context.damager>].flag[CurrentSpecialAttack]> == "Poison Arrow" { - cast poison duration:3 power:1 <context.entity> - random { - narrate "<red>...and hits <yellow><context.entity.name><red>, causing them to bleed from the ears." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> - narrate "<red>...and hits <yellow><context.entity.name><red>, causing agonising pain and loss of health." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> - narrate "<red>...and hits <yellow><context.entity.name><red>, causing itchy and burning skin blisters." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> } } else if <npc[<context.damager>].flag[CurrentSpecialAttack]> == "Wither Arrow" { - cast wither duration:3 power:1 <context.entity> - random { - narrate "<red>...and hits <yellow><context.entity.name><red>, causing their skin to peel off." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> - narrate "<red>...and hits <yellow><context.entity.name><red>, causing their limbs to decay." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> - narrate "<red>...and hits <yellow><context.entity.name><red>, causing their skin to ooze." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> } } else if <npc[<context.damager>].flag[CurrentSpecialAttack]> == "Weakness Arrow" { - cast weakness duration:3 power:1 <context.entity> - random { - narrate "<red>...and hits <yellow><context.entity.name><red>, causing them to become weak and tired." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> - narrate "<red>...and hits <yellow><context.entity.name><red>, causing them to deal less damage." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> - narrate "<red>...and hits <yellow<context.entity.name><red>, causing them to hit like a little girl." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> } } else if <npc[<context.damager>].flag[CurrentSpecialAttack]> == "Slowness Arrow" { - cast slow duration:10 power:3 <context.entity> - random { - narrate "<red>...and hits <yellow><context.entity.name><red>, causing them to become slow and lazy." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> - narrate "<red>...and hits <yellow><context.entity.name><red>, causing them to walk at a snails pace." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> - narrate "<red>...and hits <yellow><context.entity.name><red>, causing them to be slower than a speeding microorganism." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> - narrate "<red>...and hits <yellow><context.entity.name><red>, causing them to be slower than a 1 legged dog on tranquilizers." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> - narrate "<red>...and hits <yellow><context.entity.name><red>, causing them to be slower than a geriatric slug on a salted snowed-in street." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> - narrate "<red>...and hits <yellow><context.entity.name><red>, causing them to be slower than a snail traveling through peanut butter." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> - narrate "<red>...and hits <yellow><context.entity.name><red>, causing them to be slower than Java." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> - narrate "<red>...and hits <yellow><context.entity.name><red>, causing them to be slower than quadriplegic in a sack race." targets:<npc[<context.damager>].flag[BossPlayerList].aslist> } } } #-------------------------------------------------------------------------------# # Loot can be delivered in 3 different ways. # 1) In the player inventory, using the "give" command. # 2) Drop around where the boss died. # 3) Inside a chest that spawns in close proximity to where the boss died. # # How does it decide the loot? By using a procedure script of course! This # type of script returns us a single value. Further explained in the next # section. #-------------------------------------------------------------------------------# "BossName Drop the Loot": type: task script: - if "<cons:Loot Distribution>" == "player" { - foreach <npc.flag[BossHitList].aslist> { - flag <npc> Looter:%value% - repeat "<cons:Loot Quantity>" { - give to:<player[<npc.flag[looter]>].inventory> "i@<proc:BossName Determine Loot>" } } } else if "<cons:Loot Distribution>" == boss { - foreach <npc.flag[BossHitList].aslist> { - repeat "<cons:Loot Quantity>" { - drop "i@<proc:BossName Determine Loot>" location:<npc.flag[DeathLocation]> } } } else if "<cons:Loot Distribution>" == chest { - define chestlocation <cu@<npc.location.add[-2,0,-2].simple>|<npc.location.add[2,1,2].simple>.get_spawnable_blocks.random> - modifyblock location:%chestlocation% chest - foreach <npc.flag[BossHitList].aslist> { - repeat "<cons:Loot Quantity>" { - give "i@<proc:BossName Determine Loot>" to:<in@location[%chestlocation%]> } } } else if "<cons:Loot Distribution>" == playerchest { - foreach <npc.flag[BossHitList].aslist> { - define chestlocation <cu@<%value%.location.add[-2,0,-2].simple>|<%value%.location.add[2,1,2].simple>.get_spawnable_blocks.random.as_location.block> - flag %value% LootChestLocation:%chestlocation% - flag <npc> LootChestLocationList:->:%chestlocation% - flag global GlobalLootChestLocationList:->:%chestlocation% - modifyblock location:%chestlocation% chest - repeat "<cons:Loot Quantity>" { - give "i@<proc:BossName Determine Loot>" to:<in@location[%chestlocation%]> } } - flag <npc> PlayersGettingChest:<npc.flag[BossHitList]> } - if <npc.flag[LootChestLocationList].size> >= 1 && "<cons:Loot Chest Expiry>" >= 1 run "BossName Loot Chest Expiry" "delay:<cons:Loot Chest Expiry>" #-------------------------------------------------------------------------------# # This task will run with a delay specified in the "Loot Chest Expiry" constant # value at the top of the script. # # It simply removes the chests and drop the items on the floor. #-------------------------------------------------------------------------------# "BossName Loot Chest Expiry": type: task script: - ^foreach <npc.flag[LootChestLocationList].aslist> { - if <location[%value%].block.material> == m@chest { - flag global GlobalLootChestLocationList:<-:%value% - modifyblock %value% air } } - ^foreach <npc.flag[PlayersGettingChest].aslist> { - flag %value% LootChestLocation:! } - ^flag <npc> PlayersGettingChest:! - ^flag <npc> LootChestLocationList:! #-------------------------------------------------------------------------------# # The next section is a PROCEDURE script used to return a SINGLE value back to # our main script. In this case, we just want an ITEM SCRIPT name to be returned. # # The script "rolls" a value between 0 to a 100 for each player. If # it rolls between 0 to 40, set the quality to "Common". If its anywhere between # 40 to 70, set it to "Uncommon" etc etc. # # Then, after the quality has been defined, check which section we'll be getting # the item from. So, if the %quality% is "Common", it'll go into the # corresponding braces and run the first command "random 8", which will then # jump to any one of the following 8 lines. # # If it then lands on "Durable Diamond Helmet", that's the value the procedure # script will return to the main boss script and that's the item that will # dropped/given to the player. #-------------------------------------------------------------------------------# "BossName Determine Loot": type: procedure script: - define roll <util.random.int[1].to[100]> - if %roll% >= 0 && %roll% < 40 define quality "Common" else if %roll% >= 40 && %roll% < 70 define quality "Uncommon" else if %roll% >= 70 && %roll% < 85 define quality "Rare" else if %roll% >= 85 && %roll% < 95 define quality "Epic" else if %roll% >= 95 define quality "Legendary" - if %quality% == Common random { - determine "Trusty Diamond Axe" - determine "Trusty Diamond Sword" - determine "Trusty Diamond Hoe" - determine "Trusty Diamond Spade" - determine "Durable Diamond Helmet" - determine "Thorny Diamond Chestplate" - determine "Diamond Sword of Looting" - determine "Efficient Diamond Pickaxe" } else if %quality% == Uncommon random { - determine "Herder" - determine "MerryGoRound" - determine "FoolsGold" - determine "Doppelganger" - determine "PTD" } else if %quality% == Rare random { - determine "Aquamarine" - determine "Karthlan Warrior Axe" - determine "Flamebane" - determine "PhaseShifter" } else if %quality% == Epic random { - determine "Meteorite" - determine "Sunflare" - determine "Heartburn" } else if %quality% == Legendary random { - determine "Bow of Decay" - determine "Hammer of the Gods" - determine "Lifestealer" - determine "Bloodsucker" - determine "Mobcorn" } #-------------------------------------------------------------------------------# # This section of the script defines the items, their lore and Minecraft # enchantments. To replace/add enchantments check out the following link: # # http://jd.bukkit.org/rb/apidocs/org/bukkit/enchantments/Enchantment.html # # To get one of these items without fighting the boss, as op, simply substitute # the name of the item and type the following into your Minecraft chat: # # /ex drop "item:Hammer of the Gods" "location:<player.location>" # #--------------------------------- Common Items --------------------------------# "Trusty Diamond Axe": type: item material: diamond_axe display name: "Trusty Diamond Axe" lore: - A trusty diamond axe. - Common Item enchantments: - durability:1 - damage_all:1 "Trusty Diamond Sword": type: item material: diamond_sword display name: "Trusty Diamond Sword" lore: - A trusty diamond sword. - Common Item enchantments: - durability:1 - damage_all:1 "Trusty Diamond Hoe": type: item material: diamond_hoe display name: "Trusty Diamond Hoe" lore: - A trusty diamond hoe. - Common Item enchantments: - durability:1 "Trusty Diamond Spade": type: item material: diamond_spade display name: "Trusty Diamond Spade" lore: - A trusty diamond spade. - Common Item enchantments: - durability:1 "Durable Diamond Helmet": type: item material: diamond_helmet display name: "Durable Diamond Helmet" lore: - A durable diamond helmet. - Common Item enchantments: - durability:1 "Thorny Diamond Chestplate": type: item material: diamond_chestplate display name: "Thorny Diamond Chestplate" lore: - A thorny diamond chestplate. - Common Item enchantments: - durability:2 - thorns:1 "Diamond Sword of Looting": type: item material: diamond_sword display name: "Diamond Sword of Looting" lore: - Increased loot drops with this diamond - sword. - Common Item enchantments: - loot_bonus_mobs:1 - durability:2 "Efficient Diamond Pickaxe": type: item material: diamond_pickaxe display name: "Efficient Diamond Pickaxe" lore: - A fast and durable pickaxe. enchantments: - durability:2 - dig_speed:5 #-------------------------------- Uncommon Items -------------------------------# "MerryGoRound": type: item material: bow display name: "MerryGoRound" lore: - A twisted circus owner forged this to - use on his 'less willing' performers. - Uncommon Item enchantments: - durability:3 "PhaseShifter": type: item material: diamond_sword display name: "PhaseShifter" lore: - Now you see me.. now you don't. - Uncommon Item enchantments: - durability:3 "Herder": type: item material: diamond_hoe display name: "Herder" lore: - Capture up to 3 friendly mobs inside - this magical hoe. - Uncommon Item enchantments: - durability:3 "FoolsGold": type: item material: gold_nugget display name: "Fool's Gold" lore: - Lure your victims with Fool's Gold - and strike them from behind! - Uncommon Item "Doppelganger": type: item material: feather display name: "Doppelganger" lore: - Doppelganger is a paranormal double - of a living enity. - Uncommon Item "PTD": type: item material: diamond_sword display name: "PTD" lore: - Personal Teleportation Device v0.3 - Uncommon Item #--------------------------------- Rare Items --------------------------------# "Flamebane": type: item material: diamond_chestplate display name: "Flamebane" lore: - Forged in the fires of Mount Regaros - for workers to survive extreme mining - conditions. - Rare Item enchantments: - protection_explosions:4 - protection_fire:4 - protection_environmental:4 "Aquamarine": type: item material: diamond_helmet display name: "Aquamarine" lore: - Created by the Great Engineers of Karthlan - to allow working and mining underwater. - Rare Item enchantments: - water_worker:1 - oxygen:3 - durability:3 "Karthlan Warrior Axe": type: item material: diamond_axe display name: "Karthlan Warrior Axe" lore: - A super durable 2000 year old axe from the - destroyed Karthlan dynasty. - Rare Item enchantments: - knockback:2 - damage_all:5 - durability:3 #--------------------------------- Epic Items --------------------------------# "Meteorite": type: item material: stick display name: "Meteorite" lore: - Same as dodgeball, but with flaming - hot, explosive magma. - Epic Item enchantments: - durability:3 "Sunflare": type: item material: diamond_sword display name: "Sunflare" lore: - A forgotten elementalist imbued this sword with - the power of the sun to set its victims on fire. - Epic Item enchantments: - fire_espect:2 - damage_all:5 - durability:3 "Heartburn": type: item material: bow display name: "Heartburn" lore: - Coated arrow tips set alight even - with the slightest wind friction. - Epic Item enchantments: - arrow_fire:2 - damage_all:5 - durability:3 #----------------------------- Legendary Items -----------------------------# "Bow of Decay": type: item material: bow display name: "Bow of Decay" lore: - A legion of tormented souls imprisoned in this bow fills - each arrow with a millenia of despair and insanity. - Legendary Item enchantments: - durability:3 "Hammer of the Gods": type: item material: diamond_axe display name: "Hammer of the Gods" lore: - Long lost where even the gods couldn't find it, yet this - hammer mysteriously ended up in your hands. - Legendary Item enchantments: - durability:3 - damage_all:5 "Lifestealer": type: item material: diamond_sword display name: "Lifestealer" lore: - A sacrifice gone wrong, the sword was removed from - the hands of a baby, dressed in necromancer robes. - Legendary Item enchantments: - durability:3 - damage_all:5 "Mobcorn": type: item material: stick display name: "Mobcorn" lore: - What happens when you put a magnetron inside - a cow? Only one way to find out. - Legendary Item "Mobcorn Time": type: task script: - narrate "<white><<%1%>.entity_type><red> is going to explode in..." targets:<player.location.find.players.within[10]> - if <%1%.is_spawned> { - narrate "<red>3...." targets:<player.location.find.players.within[10]> - playsound location:<%1%.location> sound:fuse - playeffect location:<%1%.location> effect:fireworks_spark qty:10 } else { - queue clear - flag player "Mobcorn Cooldown:!" } - wait 1 - if <%1%.is_spawned> { - narrate "<red>2...." targets:<player.location.find.players.within[10]> - playeffect location:<%1%.location> effect:fireworks_spark qty:10 } else { - queue clear - flag player "Mobcorn Cooldown:!" } - wait 1 - if <%1%.is_spawned> { - narrate "<red>1...." targets:<player.location.find.players.within[10]> - playeffect location:<%1%.location> effect:fireworks_spark qty:10 } else { - queue clear - flag player "Mobcorn Cooldown:!" } - wait 1 - if <%1%.is_spawned> { - explode power:2 location:<%1%.location> fire breakblocks - if <%1%.is_spawned> remove %1% } else { - queue clear - flag player "Mobcorn Cooldown:!" } #------------------- Bloodsucker Legendary Item Section -------------------# # This item requires its own section because it does a little more than # the other items. Below is a script similar to the minion script above # but a lot simpler. # # The primary points here are: # 1) Create the bats # 2) Add bats to player flag and remove them permanently on death # 3) Remove bats if their owner or their target exits their proximity. # 4) Remove the bat after 60 seconds regardless of what it's doing. # # Further down there are a couple of world events to remove the bats when # the player dies or quits the server. #------------------- Bloodsucker Legendary Item Section -------------------# "Bloodsucker": type: item material: diamond_sword display name: "Bloodsucker" lore: - Those squeaky noises, glowing red eyes.. - .... I hope my end is quick. - Legendary Item enchantments: - durability:3 "Spawn Bloodsucker Bat": type: task script: - playeffect location:%1% effect:LARGE_SMOKE - execute as_server "npc create Bloodsucker --at %1% --type bat --speed 1.3" - execute as_server "npc owner <player.name>" - execute as_server 'npc assign --set "Bloodsucker Bat"' "Bloodsucker Bat": type: assignment actions: on assignment: - flag <npc.owner> "BloodsuckerBatList:->:<npc>" - trigger name:proximity toggle:true radius:15 - trigger name:damage toggle:true - execute as_server "npc sel <npc.id>" - execute as_server "npc lookclose" - execute as_server "npc vulnerable" - execute as_server "npc health --set 1" - flag <npc> Exists - run "Bloodsucker Despawn Timer" delay:60s on death: - flag <npc.owner> "BloodsuckerBatList:<-:<npc>" - flag <npc> Exists:! - remove <npc> interact scripts: - 5 Bloodsucker Interaction "Bloodsucker Interaction": type: interact steps: 1: damage trigger: script: - playsound location:<npc.location> sound:bat_idle proximity trigger: exit: script: - ^if "<player[<npc.owner>].flag[Bloodsucker Target]>" == <player> || <player.name> == <npc.owner> { - flag <npc.owner> "BloodsuckerBatList:<-:<npc>" - remove <npc> } "Bloodsucker Despawn Timer": type: task script: - if <npc.flag[Exists]> remove <npc> #-------------------------------------------------------------------------------# # The section below handles the world events to make all the "cool stuff" # possible. It means that every time one of these events occur in the world, it # will be evaluated against some criteria to see if the "cool stuff" should # happen. # # For example, every time any entity (<context.entity>) in the world is damaged # by an arrow, it checks to see if the person (<context.damager>) that fired the # arrow is holding an item with the following two lore descriptions: # # * A legion of tormented souls imprisoned in this bow fills # * A twisted circus owner forged this to # # If they are and there are no cooldowns in effect, it'll run the relevant # (cast or rotate) commands on the entity that got hit. #-------------------------------------------------------------------------------# "Legendary and Epic Item Effects": type: world events: on entity damaged by arrow: - if "<player[<context.damager>].item_in_Hand.lore.contains[A legion of tormented souls imprisoned in this bow fills]>" == true { - cast wither duration:10 power:1 <context.entity> - playsound location:<context.entity.location> sound:wither_death volume:2 pitch:0.01 - if <context.entity.is_player> && "<player[<context.entity>].flag[Hit by Bow of Decay]>" == null { - flag <context.entity> "Hit by Bow of Decay" duration:120s - narrate "<red>You feel your flesh peeling away...strange voices in your head..so much hate.." targets:<context.entity> } } else if "<player[<context.damager>].item_in_Hand.lore.contains[A twisted circus owner forged this to]>" == true { - if <context.entity.is_player> && "<player[<context.entity>].flag[Hit by MerryGoRound]>" == null { - flag <context.entity> "Hit by MerryGoRound" duration:5s - narrate "<red>The eery twisted music of a deserted, foggy circus makes you turn...round and round..." targets:<context.entity> } - rotate <context.entity> duration:5s } # This handles the effect on an entity getting hit directly by a player. Since it knows # who the player is, you can just use <player...> rather than <context.damager>. Which # makes it a bit easier to flag the player etc. # # It compares 3 different weapons, using the "lore" as the method, in this case, to # identify which weapon was used. on entity damaged by player: - if "<player.item_in_Hand.lore.contains[Long lost where even the gods couldn't find it, yet this]>" { - if <context.entity.is_player> && "<player.flag[Hit by Hammer of the Gods]>" == null { - flag <player> "Hit by Hammer of the Gods" duration:120s - narrate "<red>The gods curse you... your end is near..." targets:<context.entity> } - strike destination:<context.entity.location> } else if "<player.item_in_Hand.lore.contains[A sacrifice gone wrong, the sword was removed from]>" { - playsound location:<context.entity.location> sound:enderdragon_growl volume:0.2 pitch:0.01 - heal <context.damager> 1 - hurt <context.entity> 1 } else if "<player.item_in_Hand.lore.contains[Those squeaky noises, glowing red eyes..]>" { - if "<player.flag[Bloodsucker Cooldown]>" == null && "<player.flag[BloodsuckerBatList].size>" == 0 && <context.entity> !contains <player.flag[BloodsuckerBatList].aslist> { - flag <player> "Bloodsucker Cooldown" duration:10s - flag <player> "Bloodsucker Target:<context.entity>" - foreach <cu@<context.entity.location.add[-2,0,-2].simple>|<context.entity.location.add[2,1,2].simple>.get_spawnable_blocks.random[3]> { - run instantly "Spawn Bloodsucker Bat" context:%value% } - foreach <player.flag[BloodsuckerBatList].aslist> { - attack %value% target:<context.entity> } } else if <player.flag[BloodsuckerBatList].size> >= 1 && <context.entity> contains <player.flag[BloodsuckerBatList].aslist> { - flag <player> "Bloodsucker Target:<context.entity>" - foreach <player.flag[BloodsuckerBatList].aslist> { - playeffect location:<cu@<context.entity.location.add[-2,0,-2].simple>|<context.entity.location.add[2,2,2].simple>.get_spawnable_blocks.random> effect:large_smoke - teleport %value% location:<cu@<context.entity.location.add[-2,-1,-2].simple>|<context.entity.location.add[2,1,2].simple>.get_spawnable_blocks.random> } - foreach <player.flag[BloodsuckerBatList].aslist> { - attack %value% target:<context.entity> } } } else if "<player.item_in_Hand.lore.contains[Personal Teleportation Device v0.3]>" determine cancelled on player right clicks with i@PTD: - if "<player.flag[PTD Locations]>" != null { - playsound location:<player.location> sound:enderman_teleport - playeffect location:<player.location> effect:large_smoke - narrate "<red>Teleporting to Saved Location [<yellow><player.flag[PTD Locations].size><red>]<&co><white> <player.flag[PTD Locations].get[<player.flag[PTD Locations].size>]>" - teleport <player> "location:<player.flag[PTD Locations].get[<player.flag[PTD Locations].size>]>" - flag <player> "PTD Locations[<player.flag[PTD Locations].size>]:<-" - playsound location:<player.location> sound:enderman_teleport - playeffect location:<player.location> effect:large_smoke } else narrate "<red>You have no coordinates loaded in your PTD..." on player left clicks block with i@PTD: - if "<player.flag[PTD Locations]>" == null { - flag <player> "PTD Locations:<player.location.cursor_on.add[0,1,0].simple>" - narrate "<red>Saved Location [<yellow><player.flag[PTD Locations].size>/3<red>]<&co><white> <player.flag[PTD Locations].get[<player.flag[PTD Locations].size>]>" } else if "<player.flag[PTD locations].size>" = 1 { - flag <player> "PTD Locations:->:<player.location.cursor_on.add[0,1,0].simple>" - narrate "<red>Saved Location [<yellow><player.flag[PTD Locations].size>/3<red>]<&co><white> <player.flag[PTD Locations].get[<player.flag[PTD Locations].size>]>" } else if "<player.flag[PTD locations].size>" = 2 { - flag <player> "PTD Locations:->:<player.location.cursor_on.add[0,1,0].simple>" - narrate "<red>Saved Location [<yellow><player.flag[PTD Locations].size>/3<red>]<&co><white> <player.flag[PTD Locations].get[<player.flag[PTD Locations].size>]>" } else narrate "<red>Your PTD v0.3 is out of memory. You cannot store any more coordinates." # Here we specifically only fire this event if the player right clicks, an entity (mobs only), using the item "Herder". # It checks the entity type and store the value inside a player flag. It then "removes" the entity but # makes it seem like their soul was captured inside the Herder. on player right clicks entity with i@Herder: - if <player.flag[HerderList].size> >= 3 narrate "<red>The <white>Herder<red> is full and cannot capture any more souls..." else if <context.entity.is_mob> { - flag <player> HerderList:->:<context.entity.entity_type> - playeffect location:<context.entity.location> effect:witch_magic - remove <context.entity> - if <player.flag[HerderList].size> == 1 narrate "<red>You have trapped the soul of a <player.flag[HerderList].formatted>..." else if <player.flag[HerderList].size> >= 2 narrate "<red>You have trapped the souls of <player.flag[HerderList].formatted>.." } # In this event, it checks to see if there are any entity types in the "HerderList" player flag, if so it # spawns the mobs at the cursor location, using the "safe spawn" tag "get_spawnable_blocks". on player right clicks block with i@Herder: - if <player.flag[HerderList]> != null { - narrate "<red>Releasing <player.flag[HerderList].formatted>..." - foreach <player.flag[HerderList].aslist> { - spawn %value% location:<cu@<player.location.cursor_on.add[-1,0,-1].simple>|<player.location.cursor_on.add[1,2,1].simple>.get_spawnable_blocks.random> } - flag <player> "HerderList:!" } # This section also uses the "get_spawnable_blocks" tag to find an appropriate location to "showfake" # a few valuable blocks. They automatically despawn after 120s unless they are destroyed earlier. # WARNING: Will allow spawning fake blocks in protected areas. on player right clicks block with i@FoolsGold: - if "<player.flag[Fools Gold Cooldown]>" == null { - flag player "Fools Gold Cooldown" duration:120s - showfake diamond_block location:<cu@<player.location.cursor_on.add[-1,0,-1].simple>|<player.location.cursor_on.add[1,2,1].simple>.get_spawnable_blocks.random> duration:120s - showfake gold_block location:<cu@<player.location.cursor_on.add[-1,0,-1].simple>|<player.location.cursor_on.add[1,2,1].simple>.get_spawnable_blocks.random> duration:120s - showfake chest location:<cu@<player.location.cursor_on.add[-1,0,-1].simple>|<player.location.cursor_on.add[1,2,1].simple>.get_spawnable_blocks.random> duration:120s } else narrate "<white><player.flag[Fools Gold Cooldown].expiration.formatted><red> before you can use <white>Fool's Gold<red> again." # This item script checks to see if the entity clicked is a mob and if the cooldown expired, # then runs a script called "Mobcorn Time", which provides a count down timer before # the mob explodes! # WARNING: Can probably damage and set protected zones on fire!! on player right clicks entity with i@Mobcorn: - if "<player.flag[Mobcorn Cooldown]>" == null && <context.entity.is_mob> { - flag <player> "Mobcorn Cooldown" duration:10s - run "Mobcorn Time" def:<context.entity> } else if "<player.flag[Mobcorn Cooldown]>" != null narrate "<red>Please wait for Mobcorn to cooldown..." on player right clicks entity with i@Doppelganger: - if <context.entity.equipment.helmet.skin> == <player.name> narrate "<red>Entity is already your Doppelganger." else if <context.entity.is_mob> || <context.entity.is_player> { - if "<player.flag[Doppelganger Cooldown]>" == null { - if "<context.entity.equipment.helmet>" != null && <context.entity.is_player> { - give to:<context.entity.inventory> <context.entity.equipment.helmet> } - flag <player> "Doppelganger Cooldown" duration:30s - head <context.entity> skin:<player> } } else if "<player.flag[Doppelganger Cooldown]>" != null narrate "<white><player.flag[Doppelganger Cooldown].expiration.formatted><red> before you can use <white>Doppelganger<red> again." # Shoot fireballs in the direction of where the cursor is, they have "weight" so it gives # a "bullet drop" effect. # WARNING: Can probably damage and set protected zones on fire!! on player right clicks with i@Meteorite: - if "<player.flag[Meteorite Cooldown]>" == null { - flag <player> "Meteorite Cooldown" duration:3s - shoot e@fireball height:0.05 gravity:0.01 } # This script will teleport any player, where no cooldown is in effect, to a "safe" location within # a 20 block radius. Above or below ground. # WARNING: This will allow players to get into protected buildings!! on player right clicks with i@PhaseShifter: - if "<player.flag[PhaseShifter Cooldown]>" == null { - flag <player> "PhaseShifter Cooldown" duration:3s - if "<player.flag[PhaseShifter Narrate Cooldown]>" == null { - random { - narrate "<white><player.name><red> shimmer and disappears..." targets:<player.location.find.players.within[10]> - narrate "<white><player.name><red> teleports to a nearby location..." targets:<player.location.find.players.within[10]> - narrate "<white>With a puff of smoke, <white><player.name><red> teleports not too far away.." targets:<player.location.find.players.within[10]> } } - flag <player> "PhaseShifter Narrate Cooldown" duration:30s - playsound location:<player.location> sound:enderman_teleport - playeffect location:<player.location> effect:large_smoke - teleport <player> location:<cu@<player.location.add[-20,-10,-20].simple>|<player.location.add[20,20,20].simple>.get_spawnable_blocks.random> - playsound location:<player.location> sound:enderman_teleport - playeffect location:<player.location> effect:large_smoke } # This section is relevant if the boss drop uses the "playerchest" method. It controls who can # access the contents of the chest. If the player flag "LootChestLocation" does not match # the location of the chest it uses "determine cancelled" to prevent the inventory window from # showing up. on player opens chest: - if <global.flag[GlobalLootChestLocationList].aslist> contains <context.inventory.location> { - if <player.flag[LootChestLocation]> != <context.inventory.location> { - narrate "<red>You cannot access the contents of this chest." - determine cancelled } } # If the chest location is on the player flag and the global "GlobalLootChestLocation" list # it will despawn when it's closed. on player closes chest: - if <player.flag[LootChestLocation]> == <context.inventory.location> && <global.flag[GlobalLootChestLocationList].aslist> contains <context.inventory.location> && <context.inventory.location> != null { - narrate "<red>Chest has been despawned..." - flag <player> LootChestLocation:! - flag global GlobalLootChestLocationList:<-:<context.inventory.location> - modifyblock <context.inventory.location> air } # The following two events run when a player quits or dies. This is to clean up/remove # any bats that were spawned with the Bloodsucker item. on player quits: - if <player.flag[BloodsuckerBatList].size> >= 1 { - foreach <player.flag[BloodsuckerBatList].aslist> { - flag <player> BloodsuckerBatList:<-:%value% - remove %value% } - flag <player> BloodsuckerBatList:! } on player dies: - if <player.flag[BloodsuckerBatList].size> >= 1 { - foreach <player.flag[BloodsuckerBatList].aslist> { - flag <player> BloodsuckerBatList:<-:%value% - remove %value% } - flag <player> BloodsuckerBatList:! }
I have no idea how to make the boss do damage. like his minions do damage to me, but I can't hurt neither the boss or minions, and the boss doesn't do anything but run up to me
Found a solution! pvp was disabled on the world I spawned him on for some reason
This script may be out of date? The boss battle randomly works and generally never re-spawns right off the default script. Is this still a supported script?
Jabeltoo updated this script, available here: https://github.com/Jabelpeeps/My-Denizen-scripts