# +--------------- # | # | d S e n t r y # | # | Sentry rescripted in Denizen! # # @author mcmonkey # @date 2015 / 03 / 07 # @build 1568 # @version 0.7.3 # # Installation: # Just copy the script to your scripts folder and /denizen reload scripts # # Usage: # Create NPCs as normal, and use the /dsentry commands to upgrade them. # Example NPC setup path: # /npc create JoeTheKiller # Create and spawn the NPC # /dsentry create # Turn it into a dSentry # /ex equip hand:bow # Give the dSentry a bow # # The dSentry is now a complete and working bowguard, targetting monsters by default # # Feel free to adjust the targets to your liking, or any other setting you desire. # # # ---------------------------- END HEADER ---------------------------- dsentry_equipment_values: type: yaml data armor: air: helmet: 0 chestplate: 0 leggings: 0 boots: 0 air: 0 leather: helmet: 0.04 chestplate: 0.12 leggings: 0.08 boots: 0.04 gold: helmet: 0.08 chestplate: 0.20 leggings: 0.12 boots: 0.04 chainmail: helmet: 0.08 chestplate: 0.20 leggings: 0.16 boots: 0.04 iron: helmet: 0.08 chestplate: 0.24 leggings: 0.20 boots: 0.08 diamond: helmet: 0.12 chestplate: 0.32 leggings: 0.24 boots: 0.12 dsentry_world_handler: type: world debug: false events: on server start: - inject locally "events.on reload scripts" on reload scripts: - if !contains dsentry_saves { - if { - yaml load:dsentry_saves.yml id:dsentry_saves } else { - yaml create id:dsentry_saves } } - define queues - foreach %queues% { - queue %value% stop } - wait 5s - run dsentry_task_logic delay:10t - foreach { - if { - vulnerable npc:%value% - health npc:%value% } } on npc spawns: - if ! queue clear - vulnerable - health - heal on player damaged by player: - foreach { - if ! || != null { - foreach next } - if !contains PvP { - foreach next } - if != { - foreach next } - if ]> < { - flag dsentry.target: } } on entity damaged by player: - if queue clear - if queue clear - foreach { - if ! || != null { - foreach next } - if !contains PvE { - foreach next } - if != { - foreach next } - if ]> < { - flag dsentry.target: } } on npc damaged by player: - if flag dsentry.target: # TODO: Better way to prevent accidental damage #on npc damaged by npc: #- if && determine cancelled # TODO: calculate NPC armor properly on npc damaged: - if ! { - queue clear } - define armor npc: - determine ]> on npc damages entity: - if ! { - queue clear } - determine npc: dsentry_command_handler: type: command name: dsentry debug: false aliases: - ds description: Control Denizen-powered guard NPCs. usage: /dsentry help permission: dsentry.command script: - if { - define mynpc } else { - define mynpc } - if %mynpc% == null && != 0 { - narrate "<&6>You do not have an NPC selected!" - queue clear } - if ! && != 0 && ! { - narrate "<&6>Your selected NPC is not a dSentry!" - queue clear } - define arg1 - define argList li@create|save|range|followrange|speed|attackrate|damage|add|remove|info|guard|armor|health - if { - inject locally dsentry_command_%arg1% } else { - narrate "<&6>/dSentry create [save-type]" - narrate "<&6>/dSentry save <<>save-type<>>" - narrate "<&6>/dSentry range <<>range<>>" - narrate "<&6>/dSentry followrange <<>range<>>" - narrate "<&6>/dSentry speed <<>speed<>>" - narrate "<&6>/dSentry damage <<>damage<>>" - narrate "<&6>/dSentry attackrate <<>attackrate<>>" - narrate "<&6>/dSentry health <<>max-health-amount<>>" - narrate "<&6>/dSentry armor <<>armor-rating<>>" - narrate "<&6>/dSentry add <<>target<>>" - narrate "<&6>/dSentry remove <<>target<>>" - narrate "<&6>/dSentry guard [player-name]" - narrate "<&6>/dSentry info" } dsentry_command_info: - narrate "<&6>Your selected NPC <&2>is<&6> a dSentry with stats<&co>" - narrate "<&6>Range<&co> <&b>" - narrate "<&6>Damage<&co> <&b>" - narrate "<&6>Health<&co> <&b><&f>/<&b>" - if == -1 { - define armor - narrate "<&6>Armor Rating<&co> <&b>% (Calculated)" } else { - narrate "<&6>Armor Rating<&co> <&b>% (User Defined)" } - narrate "<&6>Walk speed<&co> <&b>" - narrate "<&6>Attack rate<&co> <&b>" - if == 0 { - narrate "<&6>Targets<&co> <&b>" } else { - narrate "<&6>Targets<&co> <&b><&6>, or players flagged <&b>" } # added a line to show who dSentry is guarding - if { - narrate "<&6>Currently Guarding<&co> <&b>" } dsentry_command_guard: - if { - flag %mynpc% dsentry.follow_target:! - narrate "<&c>Guarding nothing." - queue clear } - if ]> { - define player ]||null> - if %player% == null { - narrate "<&c>Unknown player or npc." - queue clear } - flag %mynpc% dsentry.follow_target:%player% - narrate "<&c>Guarding <&b><&c>!" } else if ]> { - define npc ]||null> - if %npc% == null { - narrate "<&c>Unknown player or npc." - queue clear } - flag %mynpc% dsentry.follow_target:%npc% - narrate "<&c>Guarding <&b><&c>!" } else { - narrate "<&c>Unknown player or npc." - queue clear } dsentry_command_add: - if { - narrate "<&6>/dSentry add <<>target<>>" - narrate "<&6>Target = an entity type, EG creeper or pig" - narrate "<&6>You can also do flagged:FlagName" - narrate "<&6>or event:PvP, or event:PvE" - queue clear } # section deals with adding flag targets - if ]> { - if ]>]||false> { - narrate "<&6>That flag target is already set." - queue clear } - flag %mynpc% dsentry.flagtargets:->:]> - narrate "<&6>Flag target added." - queue clear } # section deals with adding event targets - if ]> { - if ]>]> { - narrate "<&6>That event target is already set." - queue clear } - if 'PvP|PvE' !contains ]> { - narrate "<&6>dSentry only accepts PvP or PvE as event targets" - queue clear } - flag %mynpc% dsentry.eventtargets:->:]> - narrate "<&6>Event target added." - queue clear } # section deals with adding entity type targets - if !]> { - narrate "<&6>That target doesn't look like a proper entity type." - queue clear } - if ]||false> { - narrate "<&6>That target is already set." - queue clear } - flag %mynpc% dsentry.targets:->: - if flag %mynpc% dsentry.targets:<-:none - narrate "<&6>Added target." dsentry_command_remove: - if { - narrate "<&6>/dSentry remove <<>target<>>" - narrate "<&6>Target = an entity type, EG creeper or pig" - narrate "<&6>You can also do flagged:FlagName" - narrate "<&6>or event:PvP, or event:PvE" - queue clear } # section deals with removing flag targets - if ]> { - if { - flag %mynpc% dsentry.flagtargets:! - narrate "<&6>All flag targets cleared." - queue clear } - if !]>]||false> { - narrate "<&6>That flag target isn't set." - queue clear } - flag %mynpc% dsentry.flagtargets:<-:]> - narrate "<&6>Flag target removed." - queue clear } # section deals with removing event targets - if ]> { - if { - flag %mynpc% dsentry.eventtargets:! - narrate "<&6>All event targets cleared." - queue clear } - if !]>]> { - narrate "<&6>That event target isn't set." - queue clear } - flag %mynpc% dsentry.eventtargets:<-:]> - narrate "<&6>Event target removed." - queue clear } # section deals with removing entity targets - if !]> { - narrate "<&6>That target doesn't look like a proper entity type." - queue clear } - if { # flag set to 'none' to prevent console spam of "no targets set message" - flag %mynpc% dsentry.targets:none - narrate "<&6>All entity type targets cleared." - queue clear } - if !]||false> { - narrate "<&6>That target isn't set." - queue clear } - flag %mynpc% dsentry.targets:<-: - narrate "<&6>Removed target." dsentry_command_range: - if { - narrate "<&6>/dSentry range <<>range<>>" - narrate "<&6>Range = a number representing how far away (in blocks) the dSentry can attack targets at" - queue clear } - if !]> { - narrate "<&6>That range value doesn't look like a proper number." - queue clear } - if ! { - narrate "<&6>That range value doesn't look like a proper number." - queue clear } - flag %mynpc% dsentry.range: - narrate "<&6>Range set." dsentry_command_followrange: - if { - narrate "<&6>/dSentry followrange <<>range<>>" - narrate "<&6>Range = a number representing how far away (in blocks) the dSentry can follow players at" - queue clear } - if !]> { - narrate "<&6>That range value doesn't look like a proper number." - queue clear } - if ! { - narrate "<&6>That range value doesn't look like a proper number." - queue clear } - flag %mynpc% dsentry.follow_range: - narrate "<&6>Follow range set." dsentry_command_damage: - if { - narrate "<&6>/dSentry damage <<>damage<>>" - narrate "<&6>Damage = a number representing how many hearts of damage the NPC deals when it attacks" - queue clear } - if !]> { - narrate "<&6>That damage value doesn't look like a proper number." - queue clear } - if ! { - narrate "<&6>That damage value doesn't look like a proper number." - queue clear } - flag %mynpc% dsentry.damage: - narrate "<&6>Damage set." dsentry_command_armor: - if { - narrate "<&6>/dSentry armor <<>armor<>>" - narrate "<&6>Armor = what percentage of damage to take away" - queue clear } - if !]> { - narrate "<&6>That armor value doesn't look like a proper number." - queue clear } - if ! { - narrate "<&6>That armor value doesn't look like a proper number." - queue clear } - flag %mynpc% dsentry.armor: - narrate "<&6>Armor set." dsentry_command_health: - if { - narrate "<&6>/dSentry health <<>max-health-amount<>>" - queue clear } - if !]> { - narrate "<&6>That health value doesn't look like a proper number." - queue clear } - if ! { - narrate "<&6>That health value doesn't look like a proper number." - queue clear } - flag %mynpc% dsentry.health: - health npc:%mynpc% - narrate "<&6>Health set." dsentry_command_speed: - if { - narrate "<&6>/dSentry speed <<>speed<>>" - narrate "<&6>Speed = a number representing how fast the NPC should walk while attacking" - queue clear } - if !]> { - narrate "<&6>That speed value doesn't look like a proper number." - queue clear } - if ! { - narrate "<&6>That speed value doesn't look like a proper number." - queue clear } - flag %mynpc% dsentry.walkspeed: - narrate "<&6>Speed set." dsentry_command_attackrate: - if { - narrate "<&6>/dSentry attackrate <<>attackrate<>>" - narrate "<&6>AttackRate = a number representing how many ticks should pass between an NPC's attacks" - narrate "<&6>The minimum is 10. All higher values must be multiples of 10." - queue clear } - if !]> { - narrate "<&6>That attackrate value doesn't look like a proper number." - queue clear } - if ! { - narrate "<&6>That attackrate value doesn't look like a proper number." - queue clear } - flag %mynpc% dsentry.attackrate: - flag %mynpc% dsentry.attackping:0 - narrate "<&6>AttackRate set." dsentry_command_save: - if { - narrate "<&6>/dSentry save <<>save-type<>>" - narrate "<&6>Save-type = a name that can be used to recreate the dSentry with later" - queue clear } - if !]> { - narrate "<&6>That save name looks potentially problematic." - queue clear } - yaml write:dsentry..valid value:true id:dsentry_saves - yaml write:dsentry..range value: id:dsentry_saves - yaml write:dsentry..follow_range value: id:dsentry_saves - yaml write:dsentry..follow_target value: id:dsentry_saves - yaml write:dsentry..attackrate value: id:dsentry_saves - yaml write:dsentry..walkspeed value: id:dsentry_saves - yaml write:dsentry..damage value: id:dsentry_saves - yaml write:dsentry..armor value: id:dsentry_saves - yaml write:dsentry..health value: id:dsentry_saves - yaml write:dsentry..targets value: id:dsentry_saves - yaml write:dsentry..flagtargets value: id:dsentry_saves - yaml write:dsentry..eventtargets value: id:dsentry_saves - yaml write:dsentry..hand value: id:dsentry_saves - yaml write:dsentry..helmet value: id:dsentry_saves - yaml write:dsentry..chestplate value: id:dsentry_saves - yaml write:dsentry..leggings value: id:dsentry_saves - yaml write:dsentry..boots value: id:dsentry_saves - yaml savefile:dsentry_saves.yml id:dsentry_saves - narrate "<&6>dSentry type saved!" dsentry_command_create: - if { - flag %mynpc% dsentry.range:15 - flag %mynpc% dsentry.follow_range:3 - flag %mynpc% dsentry.follow_target:! - flag %mynpc% dsentry.walkspeed:1 - flag %mynpc% dsentry.attackrate:30 - flag %mynpc% dsentry.attackping:0 - flag %mynpc% dsentry.armor:-1 - flag %mynpc% dsentry.health:20 - flag %mynpc% dsentry.damage:2 - flag %mynpc% dsentry.targets:! - flag %mynpc% dsentry.targets:|:zombie|creeper|spider|skeleton|witch - flag %mynpc% dsentry.flagtargets:! - flag %mynpc% dsentry.eventtargets:! - adjust %mynpc% teleport_on_stuck:true - flag %mynpc% dsentry.is_dsentry - adjust %mynpc% teleport_on_stuck:false - narrate "<&6>NPC turned into a default dSentry." - queue clear } - if !]> { - narrate "<&6>That save name looks potentially problematic." - queue clear } - define base dsentry.. - if != true { - narrate "<&6>There are no saves by that name." - queue clear } - equip %mynpc% hand: head: chest: legs: boots: - flag %mynpc% dsentry.follow_range: - flag %mynpc% dsentry.follow_target: - flag %mynpc% dsentry.range: - flag %mynpc% dsentry.walkspeed: - flag %mynpc% dsentry.attackrate: - flag %mynpc% dsentry.attackping:0 - flag %mynpc% dsentry.damage: - flag %mynpc% dsentry.armor: - flag %mynpc% dsentry.health: - flag %mynpc% dsentry.targets:! - flag %mynpc% dsentry.targets:|: - flag %mynpc% dsentry.flagtargets:! - flag %mynpc% dsentry.flagtargets:|: - flag %mynpc% dsentry.eventtargets:! - flag %mynpc% dsentry.eventtargets:|: - flag %mynpc% dsentry.is_dsentry - narrate "<&6>NPC turned into a custom dSentry." # Runs repeatedly as the dSentry logic loop dsentry_task_logic: type: task debug: false script: - while true { - foreach { - if { - run dsentry_task_attack npc: instantly - if == null { - resume waypoints npc:%value% } } } - wait 10t } # Chooses a nearby target dsentry_proc_picktarget: type: procedure debug: false script: - if != null { - if { - if ]> < { - if ]> { - determine } } } } - if == 0 { - announce to_console "<&6>NPC is marked as a dSentry but does not have a targets list!" - queue clear } - define entities |player].within[].exclude[]> - define entity null - foreach %entities% { - if { - define entities } } - foreach %entities% { - if { - define playrar %value% - define TEMP_PLAYER_PASS - foreach { - if != null { - define TEMP_PLAYER_PASS true } } - if == CREATIVE { - define TEMP_PLAYER_PASS false } - if !%TEMP_PLAYER_PASS% { - define entities } } } - foreach %entities% { - if { - define entity %value% - foreach stop } } - determine # Makes a dSentry NPC attack the target dsentry_task_attack: type: task debug: false script: - flag npc dsentry.attackping: - if >= { - flag npc dsentry.attackping:0 } else { - queue clear } - if == null { - flag npc dsentry.target: } else { - if !]||false> || !]||false> { - flag npc dsentry.target: } } - define valid false - if { - if define valid true } else if { - if define valid true } - if %valid% { - if ]> > 100 { - teleport } - if == null || == bow { - if ]> > { - walk auto_range radius: } } } - if == null { - if == player animate animation:stop_use_item - queue clear } - if != bow { - pause waypoints } - define loc - look %loc% - if == bow { # TODO: should critical=true be enabled in some cases? (corrupts damage calc) - define settings knockback=1 - if contains ARROW_FIRE { - define settings %settings%;fire_time=1m } - if == player animation:stop_use_item - shoot arrow[%settings%] origin: destination:%loc% speed:50 lead: script:dsentry_task_removearrow - wait 1t - if == player animate animation:start_use_item } else if > 3 { - walk %loc% speed: } else { - if == player animate animation:arm_swing - hurt - if != i@air { - if contains FIRE_ASPECT { - adjust fire_time:10s } } } dsentry_task_removearrow: type: task debug: false script: - if %hit_entities% == li@ remove %shot_entities% dsentry_proc_calculatearmor: type: procedure debug: false script: # flag npc armor '-1' to use calculated armor, otherwise, trust the flag value - if >= 0 { - determine } - define total 0 - foreach helmet|chestplate|leggings|boots { - define material - define total ]> } - determine dsentry_proc_calculatedamage: type: procedure debug: false script: # flag npc damage '-1' to use calculated damage, otherwise, trust the flag value - if >= 0 { - determine } # TODO: calculate damage based on held item # TODO: Make the default damage -1