Paste #75419: Untitled Paste

Date: 2020/09/08 20:05:33 UTC-07:00
Type: Denizen Script

View Raw Paste Download This Paste
Copy Link


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428


dragon_data:
    type: data
    health: 1000
    perch_phases:
    - SEARCH_FOR_BREATH_ATTACK_TARGET
    - BREATH_ATTACK
    - ROAR_BEFORE_ATTACK
    #Radius to check for potential targets
    fight_range: 150
    #How high the dragon must from the target be to send a teleport projectile
    teleport_height: 25
    #The radius a target needs to be within to send a dragon fire volley
    lower_volley_range: 15
    upper_volley_range: 75
    #Delay between attempting an attack, will be divided by players in fight range
    attack_delay: 5
    #Area players cannot exit unless they've slayed the dragon
    end_island_cuboid: world_the_end,150,-1000,150,-150,1000,-150
    #/ex note <script[dragon_data].data_key[end_island_cuboid].as_cuboid> as:end_island_cuboid

#Dragon trail effect
dragon_particle_tick:
    type: task
    #Definitions used by mob ticker
    definitions: mob
    debug: false
    script:
    - playeffect effect:DRAGON_BREATH at:<[mob].location.add[0,2,0]> quantity:2 offset:0.4 visibility:100

#Attempts to run every tick, but will be delayed using attack_delay
dragon_tick:
    type: task
    #Definitions used by mob ticker
    definitions: mob
    debug: false
    script:
        # | DEFINE TARGETS
        #Defining our target list
        - define nearby_targets <[mob].location.find.players.within[<script[dragon_data].data_key[fight_range]>]>
        - define nearby_targets <[nearby_targets].include[<[mob].location.find.entities[player_dummy].within[<script[dragon_data].data_key[fight_range]>]>]>

        #If no targets, reset dragon
        - if <[nearby_targets].size> == 0:
            - narrate targets:<server.flag[dragon_debug_list]||<empty>||<empty>> "<dark_gray>[Dragon] <gold>No targets in range"
            - run dragon_reset def:<[mob]>
        # | IF POTENTIAL TARGETS EXIST
        - else:
            - define volley_targets <list>
            - define teleport_targets <list>
            - define perch_targets <list>

            # | DETERMINE VIABLE ATTACKS
            - define perched <script[dragon_data].data_key[perch_phases].contains_any[<[mob].dragon_phase||empty>]>
            - foreach <[nearby_targets]> as:target:
                - define distance <[mob].location.distance[<[target].location>].horizontal>
                - define line_of_sight <[mob].eye_location.line_of_sight[<[target].location>]>
                - if !<[perched]>:
                    - if <[line_of_sight]>:
                        - if <script[dragon_data].data_key[lower_volley_range]> < <[distance]> && <[distance]> < <script[dragon_data].data_key[upper_volley_range]>:
                            - define volley_targets <[volley_targets].include[<[target]>]>
                        - if <[mob].location.distance[<[target].location>].vertical> > <script[dragon_data].data_key[teleport_height]>:
                            - define teleport_targets <[teleport_targets].include[<[target]>]>
                - else:
                    - define perch_targets <[perch_targets].include[<[target]>]>

            # | PICK ATTACK & ATTACK TARGET
            - define wait_time_base <script[dragon_data].data_key[attack_delay]>
            # What proportion of the wait time is subject to be random
            - define wait_time_random_proportion 0.5
            # Calculating wait time between attacks
            - define wait_time <[wait_time_base].add[<util.random.decimal[<[wait_time_base].mul[<[wait_time_random_proportion]>].mul[-1]>].to[<[wait_time_base].mul[<[wait_time_random_proportion]>]>]>].div[<[nearby_targets].size.max[1]>]>
            # Attack pool is the list of potentials attacks eg. VOLLEY | VOLLEY | TELEPORT | VOLLEY
            - define attack_pool <list>
            - define attack_pool <[attack_pool].include[<element[teleport].repeat_as_list[<[teleport_targets].size>]>]>
            - define attack_pool <[attack_pool].include[<element[volley].repeat_as_list[<[volley_targets].size>]>]>
            - define attack_pool <[attack_pool].include[<element[perch].repeat_as_list[<[perch_targets].size>]>]>
            # Pick a random attack from the pool
            - define attack <[attack_pool].random||empty>
            - choose <[attack]>:
                - case volley:
                    - define target <[volley_targets].random>
                    - narrate targets:<server.flag[dragon_debug_list]||<empty>||<empty>> "<dark_gray>[Dragon] <dark_aqua>Sending a dragon fire volley to <[target].name>"
                    - inject dragon_volley_task
                    - wait <[wait_time]>
                - case teleport:
                    - define target <[teleport_targets].random>
                    - narrate targets:<server.flag[dragon_debug_list]||<empty>||<empty>> "<dark_gray>[Dragon] <dark_aqua>Sending a teleport to <[target].name>"
                    - inject shoot_dragon_teleport
                    - wait <[wait_time]>
                - case perch:
                    - define perch_regen <element[2].sub[<[mob].health_percentage.div[100]>]>
                    - heal <[mob]> <[perch_regen]>
                    - wait 10t
                - default:
                    - narrate targets:<server.flag[dragon_debug_list]||<empty>||<empty>> "<dark_gray>[Dragon] <red>No viable attacks, stalling for a sec"
                    - wait 1

dragon_volley_task:
    type: task
    debug: false
    script:
        # | VOLLEY LOGIC
        - define chance <proc[chance_proc].context[<[mob].health_percentage.div[100]>|0.9|0.2|0.1|0.9]>
        - define random <util.random.decimal>
        #The fastest time between dragon fire
        - define base_speed 0.3
        #Time scaled based on the dragon's health, added to the base speed. Higher = Slower firing speed at higher health
        - define scaled_speed 1
        - if <[chance]> > <[random]>:
            - define volley_ammount <proc[chance_proc].context[<[mob].health_percentage.div[100]>|0.8|<element[2].div[5]>|0.20|1].mul[5].round_down>
            - narrate targets:<server.flag[dragon_debug_list]||<empty>||<empty>> "<dark_gray>[Dragon] <aqua>Dragon fire successful <gold>(<[chance].mul[100].round_to[2]><&pc>)"
            - repeat <[volley_ammount]>:
                - run shoot_dragon_fire def:<list_single[<[mob]>].include[<[target]>]>
                - wait <[base_speed].add[<[scaled_speed].mul[<[mob].health_percentage>].div[100]>]>
        - else:
            - narrate targets:<server.flag[dragon_debug_list]||<empty>||<empty>> "<dark_gray>[Dragon] <red>Dragon fire failed <gold>(<element[1].sub[<[chance]>].mul[100].round_to[2]><&pc>)"

shoot_dragon_fire:
    type: task
    definitions: shooter|target
    debug: false
    script:
    - define duration 40
    - define speed 2.5
    - define density 3
    - define origin <[shooter].location.add[0,1,0]>
    - define direction <[target].location.sub[<[origin]>].normalize>

    - playsound <[shooter].location> sound:ENTITY_BLAZE_DEATH sound_category:HOSTILE volume:6 pitch:2
    - playsound <[shooter].location> sound:ENTITY_ENDER_DRAGON_GROWL sound_category:HOSTILE volume:0.1 pitch:0.3
    - playsound <[shooter].location> sound:ENTITY_ZOMBIE_HORSE_AMBIENT volume:6 pitch:0.2 sound_category:HOSTILE

    - run projectile_task_2 def:shooter/<[shooter]>|origin/<[origin]>|direction/<[direction]>|speed/3|duration/3|subticks/10|subtick_task/dragon_fire_subtick

    # | Old deprecated projectile logic, switch to new one
    #- run projectile_task def:<list_single[<[shooter]>].include[<[origin]>].include[<[direction]>].include[<[duration]>].include[<[speed]>].include[<[density]>].include[dragon_fire_tick].include[dragon_fire_hit].include[dragon_fire_end]>

dragon_fire_subtick:
    type: task
    debug: false
    script:
    - if <[subtick_location].material.is_solid>:
        - inject dragon_fire_explosion
        - stop

    - define collided_entities <[subtick_location].find.living_entities.within[0.5]>
    - foreach <[collided_entities]> as:entity:
        - if <[entity]> != <[shooter]>:
            - inject dragon_fire_explosion
            - stop

    - playeffect effect:REDSTONE at:<[subtick_location]> quantity:2 offset:0.0 visibility:100 special_data:2|<color[255,50,200]>
    - playeffect effect:DRAGON_BREATH at:<[subtick_location]> quantity:2 offset:0.3 visibility:100

dragon_fire_explosion:
    type: task
    debug: false
    script:
    - playeffect effect:EXPLOSION_HUGE at:<[subtick_location]> visibility:100 quantity:1 offset:0.1
    - explode <[subtick_location]> power:1 fire
    - define minimum_force_distance 6
    - define knockback_force 3
    - define base_damage 60
    - define exploded_entities <[subtick_location].find.living_entities.within[<[minimum_force_distance]>]>
    - foreach <[exploded_entities]> as:entity:
        - define distance <[entity].eye_location.distance[<[subtick_location]>]>
        - define force <element[1].sub[<[distance].div[<[minimum_force_distance]>].max[0].min[1]>]>
        - define delta_vector <[entity].eye_location.sub[<[subtick_location].sub[<[velocity].mul[1]>]>].normalize>
        - adjust <[entity]> velocity:<[entity].velocity.add[<[delta_vector].mul[<[force].mul[<[knockback_force]>]>]>]>

        - define armor_damage <[entity].armor_bonus.mul[0.5]>
        - define damage <[force].mul[<[base_damage].add[<[armor_damage]>]>]>
        - hurt <[entity]> <[damage]> source:<[shooter]> cause:DRAGON_BREATH

        - narrate targets:<server.ops> "<[entity].name> - Force: <[force].mul[100].round_to[2]><&pc> RAW:<[base_damage]>+<[armor_damage].round_to[2]> RANGE ADJUSTED:<[damage].round_to[2]>"

dragon_handler:
    type: world
    debug: false
    events:
        on ender_dragon spawns:
        - adjust <context.entity> max_health:<script[dragon_data].data_key[health]>
        - adjust <context.entity> health:<context.entity.health_max>
        - adjust <context.entity> dragon_phase:CIRCLING
        - narrate targets:<server.ops> "<bold>Dragon Spawned! <red><bold>HP: <red><context.entity.health> / <context.entity.health_max> <blue><bold>PHASE: <blue><context.entity.dragon_phase>"

        on ender_dragon damaged:
            #Prevents dragaon from taking explosive damage - stops bed cheese strat
            - if <context.cause> == BLOCK_EXPLOSION:
                - determine cancelled

            #Prevents dragon from taking too much damage while perched
            - if <script[dragon_data].data_key[perch_phases].contains_any[<context.entity.dragon_phase>]||false>:
                - flag <context.entity> accumulated_damage:+:<context.final_damage>
            - if <context.entity.flag[accumulated_damage]||0> > <context.entity.health_percentage>:
                - narrate targets:<server.flag[dragon_debug_list]||<empty>||<empty>> "<dark_gray>[Dragon] <gray>Took too much damage while perched, changing phases!"
                - adjust <context.entity> dragon_phase:CIRCLING
                - flag <context.entity> accumulated_damage:!

        on player damages ender_dragon:
            #Lets players interrupt the dragon reset if they're quick enough
            - if <context.entity.flag[resetting]||false>:
                - narrate targets:<server.flag[dragon_debug_list]||<empty>> "<dark_gray>[Dragon] <gold>Reset interrupted by player"
                - flag <context.entity> resetting:!

            #Starts mob tick if its not running
            - if !<context.entity.flag[ticking]||false>:
                - narrate targets:<server.flag[dragon_debug_list]||<empty>> "<dark_gray>[Dragon] <gold>Starting mob tick: player damaged dragon"
                - run start_mob_tick def:<context.entity>

            #Damage list for storing how much damage players have done to the dragon
            - define identifier <context.damager>
            #If entity has a damage list
            - if <context.entity.has_flag[damage_list]>:
                #Make a copy of damage list
                - define damage_list <context.entity.flag[damage_list].as_map>
                #If copy has identifier
                - if <[damage_list].keys.contains[<[identifier]>]>:
                    #Take damage player has done previously and add new damage to it
                    - define damage_list <[damage_list].with[<[identifier]>].as[<[damage_list].get[<[identifier]>].add[<context.final_damage>]>]>
                    #Update mob's damage list to reflect changes
                    - flag <context.entity> damage_list:<[damage_list]>
                #If copy does not have the player's identifier
                - else:
                    #Add a new key as player's identifier, and set value to damage dealt
                    - flag <context.entity> damage_list:<[damage_list].with[<[identifier]>].as[<context.final_damage>]>
            #If entity does not have a damage list
            - else:
                #Create a new damage list, with the key of player's identifier set to the damage dealt
                - flag <context.entity> damage_list:<map.with[<[identifier]>].as[<context.final_damage>]>

        on player dies:
        #Check if a dragon is nearby the player
        - define nearby_dragons <context.entity.location.find.entities[ender_dragon].within[<script[dragon_data].data_key[fight_range]>]>
        - foreach <[nearby_dragons]> as:dragon:
            #If dragon is nearby, scan targets near dragon
           - define nearby_targets <[dragon].location.find.players.within[<script[dragon_data].data_key[fight_range]>]>
           - narrate targets:<server.flag[dragon_debug_list]||<empty>> "<dark_gray>[Dragon] <white>Player died nearby, players in range: <[nearby_targets].size>"
           #If the dragon has no targets, reset the dragon
           - if <[nearby_targets].size> = 0:
               - run dragon_reset def:<context.damager>

        on ender_dragon dies:
        #Give players dragonslayer title and a dragon tome if they did enough damage
        - define damage_list <context.entity.flag[damage_list]>
        - define total_damage <[damage_list].as_map.values.sum>
        - foreach <[damage_list].as_map.keys> as:key:
            - if <[key].is_player>:
                - define percent <[damage_list].as_map.get[<[key]>].div[<[total_damage]>].round_to[2]>
                - narrate targets:<server.ops> "<[key].name>: <[percent]>"
                - if <[percent]> > 0.1:
                    - narrate targets:<server.ops> "<[key].name> added to Dragon Slayer"
                    - group add dragonslayer player:<[key]>
                    - give player:<[key]> dragon_tome

        on player exits end_island_cuboid:
        #Prevents players from exiting the main island if they haven't killed the dragon
        - if !<player.in_group[dragonslayer]> && !<player.is_op> && <context.cause> != WORLD_CHANGE:
            - wait 1t
            - teleport <player> <context.from.with_pose[<player>]>
            - ratelimit <player> 10s
            - narrate "<light_purple>You must defeat the dragon before adventuring out!"

        on player starts gliding:
        #Prevents players from using elytra until they have slayed the dragon
        - if !<player.in_group[dragonslayer]>:
            - determine cancelled

dragon_reset:
    type: task
    debug: false
    definitions: dragon
    script:
        - narrate targets:<server.flag[dragon_debug_list]||<empty>> "<dark_gray>[Dragon] <gold>Resetting dragon"
        - run stop_mob_tick def:<[dragon]>
        - flag <[dragon]> resetting:true
        - narrate targets:<server.flag[dragon_debug_list]||<empty>> "<dark_gray>[Dragon] <gold>Regenning"
        - while <[dragon].health> < <[dragon].health_max> && <[dragon].flag[resetting]||false>:
            - heal <[dragon]> 1
            - wait 1t
        - flag <[dragon]> resetting:false
        - flag <[dragon]> damage_list:!
        - narrate targets:<server.flag[dragon_debug_list]||<empty>> "<dark_gray>[Dragon] <gold>Reset finished"

dragon_tome:
  type: item
  debug: false
  material: book
  display name: <red>Dragon Tome
  mechanisms:
    custom_model_data: 1

# Takes four numbers representing two coordinates
# as well as a percentage from 0-1
# then calculates new percentage as demonstrated:
#https://www.desmos.com/calculator/fhvksxvnmm
chance_proc:
    type: procedure
    debug: false
    definitions: percentage|x1|y1|x2|y2
    script:
        - define gradient <[y2].sub[<[y1]>].div[<[x2].sub[<[x1]>]>]>
        - define equation <[percentage].sub[<[x1]>].mul[<[gradient]>].add[<[y1]>]>
        - define output <[equation].max[<[y1]>].min[<[y2]>]>
        - determine <[output]>


# | TEMPORARY STUFF BELOW

test_mob:
    type: entity
    entity_type: ravager
    has_ai: false

player_dummy:
    type: entity
    entity_type: armor_stand
    marker: true

# | Old deprecated projectile logic, remove later
dragon_crystal_subtick:
    type: task
    debug: false
    script:
    - if <[subtick_location].material.is_solid>:
        - inject dragon_fire_explosion
        - stop

    - define collided_entities <[subtick_location].find.living_entities.within[0.5]>
    - foreach <[collided_entities]> as:entity:
        - if <[entity]> != <[shooter]>:
            - inject dragon_fire_explosion
            - stop

    - playeffect effect:REDSTONE at:<[subtick_location]> quantity:2 offset:0.0 visibility:100 special_data:2|<color[255,50,200]>
    - playeffect effect:DRAGON_BREATH at:<[subtick_location]> quantity:2 offset:0.3 visibility:100

# | Old deprecated projectile logic, remove later
dragon_fire_tick:
    type: task
    #Definitions used by projectile script
    definitions: shooter|current_increment_location
    debug: false
    script:
    - playeffect effect:REDSTONE at:<[current_increment_location]> quantity:2 offset:0.0 visibility:100 special_data:2|<color[255,50,200]>
    - playeffect effect:DRAGON_BREATH at:<[current_increment_location]> quantity:2 offset:0.3 visibility:100
# | Old deprecated projectile logic, remove later
dragon_fire_hit:
    type: task
    #Definitions used by projectile script
    definitions: shooter|target
    debug: false
    script:
    #- hurt <[target]> ammount:5 cause:DRAGON_BREATH source:<[shooter]>
    #- if <[target].is_player>:
    #    - narrate targets:<server.flag[dragon_debug_list]||<empty>||<empty>> "<[target].name> was hit directly!"
# | Old deprecated projectile logic, remove later
dragon_fire_end:
    type: task
    #Definitions used by projectile script
    definitions: shooter|target|current_location
    debug: false
    script:
        - playeffect effect:EXPLOSION_HUGE at:<[current_location]> visibility:100 quantity:2 offset:0.1
        - explode <[current_location]> power:1 fire
        - define range 3
        - define target_blacklist <list[ARMOR_STAND|ENDER_DRAGON|ENDERMAN]>
        - define targets <[current_location].find.living_entities.within[<[range]>]>
        - foreach <[targets]> as:target:
            - if !<[target_blacklist].contains_any[<[target].entity_type>]>:
                #Vector from explosion origin towards entity within blast radius
                - define delta_vector <[target].location.sub[<[current_location]>].normalize>
                #Distance from explosion to entity
                - define delta_distance <[target].location.distance[<[current_location]>]>
                #How far the entity will be launched
                - define force_multiplier 2.5
                #Force is inversely proportional to the distance, meaning the closer the entity, the larger the force
                - define force <element[1].div[<[delta_distance]>].mul[<[force_multiplier]>]>
                - adjust <[target]> velocity:<[target].velocity.add[<[delta_vector].mul[<[force]>]>]>
                - if <[target].is_player>:
                    #Should make a propper proc to calculate damage factoring the distance, force, and player's armor resistance
                    - hurt <[target]> ammount:<[force].mul[5].add[<[target].armor_bonus.mul[<[force]>].mul[1]>]> cause:DRAGON_BREATH source:<[shooter]>
# | Old deprecated projectile logic, remove later
shoot_dragon_teleport:
    type: task
    debug: false
    definitions: mob
    script:
        # | TELEPORT LOGIC
        - define duration 60
        - define speed 2
        - define density 1
        - define origin <[mob].location.add[0,1,0]>
        - define direction <[target].location.sub[<[origin]>].normalize>

        - playsound <[mob].location> sound:BLOCK_END_PORTAL_SPAWN volume:1 pitch:1 sound_category:HOSTILE

        - run projectile_task def:<list_single[<[mob]>].include[<[origin]>].include[<[direction]>].include[<[duration]>].include[<[speed]>].include[<[density]>].include[dragon_teleport_tick].include[dragon_teleport_hit].include[dragon_teleport_end]>
# | Old deprecated projectile logic, remove later
dragon_teleport_tick:
    type: task
    #Definitions used by projectile script
    definitions: shooter|current_increment_location
    debug: false
    script:
    - define search_area <ellipsoid[<[current_increment_location].xyz>,<[current_increment_location].world.name>,5,1,5]>
    #Revise how particles are shown - figure out a way to make particle ring that doesn't make server shit its self
    - foreach <[search_area].shell> as:point:
        - playeffect effect:REDSTONE at:<[point]> quantity:1 offset:0.0 visibility:100 special_data:2|<color[0,200,200]>
    - foreach <[search_area].players> as:target:
        - teleport <[target]> <[shooter].location>
# | Old deprecated projectile logic, remove later
dragon_teleport_hit:
    type: task
    #Definitions used by projectile script
    definitions: shooter|target
    debug: false
    script:
    - narrate targets:<server.flag[dragon_debug_list]||<empty>||<empty>> "<[target].name> was hit directly with dragon teleport"
    - teleport <[target]> <[shooter].location>
# | Old deprecated projectile logic, remove later
dragon_teleport_end:
    type: task
    #Definitions used by projectile script
    definitions: shooter|current_increment_location
    debug: false
    script:
    - narrate targets:<server.flag[dragon_debug_list]||<empty>||<empty>> "<dark_gray>Dragon teleport end"