Compare commits

..

17 Commits

Author SHA1 Message Date
44530c5edf Update README.md 2026-02-04 09:20:43 +01:00
Rares Bozga
3046a7dfa0 Fix NPC related bug 2026-01-30 22:09:33 +02:00
Rares Bozga
4ff52e4876 Fix guns_gun bug and custom gun and taser sounds 2026-01-28 22:54:34 +02:00
Rares Bozga
a672aee477 Fix guns_gun bug 2026-01-28 22:21:38 +02:00
Rares Bozga
8549d27f8a Fix LiteProfiles Utils whitelisting and fix intro interactions atomic sequence 2026-01-27 22:05:24 +02:00
Rares Bozga
06de5efa1a Fix Storyboard malloc once and for all 2026-01-25 14:16:17 +02:00
Rares Bozga
763eff2db4 Update README.md 2026-01-25 13:50:46 +02:00
Rares Bozga
291a035a47 Update README.md 2026-01-25 13:50:25 +02:00
ac204fe207 Merge pull request 'Various bugfixes' (#6) from lib-cutscene into main
Reviewed-on: #6
2026-01-25 12:07:41 +01:00
ed27d2c62d Merge branch 'main' into lib-cutscene 2026-01-25 12:07:33 +01:00
Rares Bozga
dcc7f81705 Various bugfixes 2026-01-25 13:06:21 +02:00
Rares Bozga
7771b9041b Fix oversight in storyboard 2026-01-16 23:27:37 +02:00
dd126636c6 Merge pull request 'Completed cutscene library' (#5) from lib-cutscene into main
Reviewed-on: #5
2026-01-11 14:02:46 +01:00
Rares Bozga
06445b71fb Completed cutscene library 2026-01-11 15:02:17 +02:00
44ffc2b8d0 Merge pull request 'Added atomic handling for storyboard operations and fixed various bugs' (#4) from feature-storyboard-atomic into main
Reviewed-on: #4
2026-01-09 12:25:07 +01:00
Rares Bozga
01a4e7414c Various bugfixes 2026-01-09 13:24:07 +02:00
Rares Bozga
37268060a2 Initial variant of atomicity 2026-01-09 12:00:54 +02:00
16 changed files with 457 additions and 38 deletions

View File

@@ -1,5 +1,5 @@
# denizen-scripts # denizen-scripts
<img src="https://sakurafalls.net/data/assets/logo/logo-bg-new-rsc2.png" width="300"> <img src="https://sakurafalls.net/data/assets/logo/forumlogo4.png" width="180">
<img src="https://forum.denizenscript.com/data/assets/logo/logo.png" width="160"> <img src="https://forum.denizenscript.com/data/assets/logo/logo.png" width="160">
@@ -8,7 +8,7 @@
This repository contains the *Denizen* `scripts` and `data` folders of SakuraFalls. This repository contains the *Denizen* `scripts` and `data` folders of SakuraFalls.
It contains the actual code used on the server at this time. You are free to explore and to It contains the actual code used on the server at this time. You are free to explore and to
use the scripts that our server uses! We believe that gatekeeping roleplaying servers furhter use the scripts that our server uses! We believe that gatekeeping roleplaying servers further
only leads to less variety and creativity. We hope that the code here, although just given as only leads to less variety and creativity. We hope that the code here, although just given as
is without further instructions, will lead to a new generation of awesome roleplaying servers. is without further instructions, will lead to a new generation of awesome roleplaying servers.

View File

@@ -40,6 +40,9 @@ furniture_config:
iron_horse_armor,7: iron_horse_armor,7:
represents: Clipboard represents: Clipboard
collision: warped_trapdoor collision: warped_trapdoor
iron_horse_armor,8:
represents: Vending Machine
collision: barrier
# List of collision blocks - disables interaction without perms # List of collision blocks - disables interaction without perms
collision_blocks: collision_blocks:
#- skeleton_skull #- skeleton_skull

View File

@@ -20,17 +20,16 @@ guns_world_gun:
- if !<player.item_in_hand.has_flag[guns_gun]>: - if !<player.item_in_hand.has_flag[guns_gun]>:
- stop - stop
- ratelimit <player> 1s - ratelimit <player> 1s
# - playsound <player.location> custom sound:your_custom_sound - playsound <player.location> custom sound:item.anaconda
- playsound <player.location> sound:entity_arrow_shoot - define target <player.precise_target[25].if_null[null]>
- define target <player.precise_target[25]||null>
- if <[target]> == null: - if <[target]> == null:
- define location <player.cursor_on[25]||null> - define location <player.cursor_on[25].if_null[null]>
- if <[location]> == null: - if <[location]> == null:
- define location <player.location.forward[25]> - define location <player.location.forward[25]>
- playeffect effect:redstone at:<player.location.above[1].points_between[<[location]>].distance[0.1]> special_data:0.5|white visibility:16 quantity:6 offset:0,0,0 - playeffect effect:redstone at:<player.location.above[1].points_between[<[location]>].distance[0.1]> special_data:0.5|white visibility:16 quantity:6 offset:0,0,0
- stop - stop
- playeffect effect:redstone at:<player.location.above[1].points_between[<[target].location.above[1]>].distance[0.1]> special_data:0.5|white visibility:16 quantity:6 offset:0,0,0 - playeffect effect:redstone at:<player.location.above[1].points_between[<[target].location.above[1]>].distance[0.1]> special_data:0.5|white visibility:16 quantity:6 offset:0,0,0
- if <[target].type> != player: - if !<[target].is_player>:
- stop - stop
- if <[target].has_flag[guns_frozen]>: - if <[target].has_flag[guns_frozen]>:
- stop - stop
@@ -51,13 +50,12 @@ guns_world_taser:
- define target <player.precise_target[7]||null> - define target <player.precise_target[7]||null>
- if <[target]> == null: - if <[target]> == null:
- stop - stop
- if <[target].type> != player: - if !<[target].is_player>:
- stop - stop
- if <[target].has_flag[guns_frozen]>: - if <[target].has_flag[guns_frozen]>:
- stop - stop
- playeffect effect:redstone at:<player.location.above[1].points_between[<[target].location.above[1]>].distance[0.1]> special_data:0.5|white visibility:16 quantity:6 offset:0,0,0 - playeffect effect:redstone at:<player.location.above[1].points_between[<[target].location.above[1]>].distance[0.1]> special_data:0.5|white visibility:16 quantity:6 offset:0,0,0
# - playsound <player.location> custom sound:your_custom_sound - playsound <player.location> custom sound:item.taser
- playsound <player.location> sound:entity_armor_stand_hit
- animate <[target]> animation:sit - animate <[target]> animation:sit
- flag <[target]> guns_frozen:true - flag <[target]> guns_frozen:true
- run guns_unfreeze path:script def:<[target]> - run guns_unfreeze path:script def:<[target]>

View File

@@ -20,6 +20,13 @@ ball_create:
- define size <[ball_collision].bounding_box.get[1].sub[<[ball_collision].location>].x.abs.add[0.01]> - define size <[ball_collision].bounding_box.get[1].sub[<[ball_collision].location>].x.abs.add[0.01]>
- spawn zombie[silent=true;has_ai=false;gravity=false;visible=false] <[location].with_pitch[0].with_yaw[0].below[<[size].add[1]>]> save:ball_display - spawn zombie[silent=true;has_ai=false;gravity=false;visible=false] <[location].with_pitch[0].with_yaw[0].below[<[size].add[1]>]> save:ball_display
- define ball_display <entry[ball_display].spawned_entity> - define ball_display <entry[ball_display].spawned_entity>
- if <[ball_display].is_baby>:
- age <[ball_display]> adult lock
- if <[ball_display].is_inside_vehicle>:
# CHICKEN JOCKEEEEEEEEEEEEEEEEEEEEEEEEEY
- define chicken <[ball_display].vehicle>
- adjust <[chicken]> passengers:<list[]>
- remove <[chicken]>
- adjust <[ball_display]> equipment:<map[].with[helmet].as[<[display_item]>]> - adjust <[ball_display]> equipment:<map[].with[helmet].as[<[display_item]>]>
- flag <[ball_collision]> ball:<[id]> - flag <[ball_collision]> ball:<[id]>
- flag <[ball_collision]> ball_display:<[ball_display]> - flag <[ball_collision]> ball_display:<[ball_display]>

309
scripts/lib/cutscene.dsc Normal file
View File

@@ -0,0 +1,309 @@
#
# Cutscene - library for creating cool cutscenes similar to the Replay Mod
#
# Playing cutscenes can also be atomic, meaning that if the player leaves mid
# cutscene, the cutscene may interrupt the queue that called the task in order
# to prevent the script from continuing.
# Determines the set of points passing through the given points spaced by the given distance.
# Effectively, the points representing the lines going from p0 to p1, then p1 to p2, etc...
# The points have to be given escaped! So <[myinput].escaped>!
cutscene_concatenate_points_between:
debug: false
type: procedure
definitions: points|distance
script:
- define points <[points].unescaped>
- define result <list[]>
- repeat <[points].size.sub[1]> as:index:
- define result <[result].include[<[points].get[<[index]>].points_between[<[points].get[<[index].add[1]>]>].distance[<[distance]>]>]>
- determine <[result]>
# Determines the Catmull-Rom spline passing through the given points, taking the distance
# between the resulting equidistant points and the resolution of the computation into account.
# Note that the efficiency of this algorithm is not amazing necessarily, so you should cache
# the results. Higher resolutions also mean the algorithm will take longer to finish.
# The points have to be given escaped! So <[myinput].escaped>!
cutscene_catmull_rom_equidistant_spline:
debug: false
type: procedure
definitions: points|distance|resolution
script:
- define points <[points].unescaped>
- define distance <[distance].if_null[0.25]>
- define resolution <[resolution].if_null[100]>
- if <[points].size> < 2:
- determine <[points]>
- if <[points].size> == 2:
- determine <[points].get[1].points_between[<[points].get[2]>].distance[<[distance]>]>
- define spline_points <list[]>
- define cumulative_distances <list[<element[0]>]>
- repeat <[points].size.sub[1]> from:0 as:segment_index:
- if <[segment_index]> == 0:
- define p0 <[points].get[1].sub[<[points].get[2].sub[<[points].get[1]>]>]>
- define p1 <[points].get[1]>
- define p2 <[points].get[2]>
- define p3 <tern[<[points].size.is_more_than[2]>].pass[<[points].get[3]>].fail[<[points].get[2]>]>
- else if <[segment_index]> == <[points].size.sub[2]>:
- define p0 <[points].get[<[segment_index]>]>
- define p1 <[points].get[<[segment_index].add[1]>]>
- define p2 <[points].get[<[segment_index].add[2]>]>
- define p3 <[points].get[<[segment_index].add[2]>].add[<[points].get[<[segment_index].add[2]>].sub[<[points].get[<[segment_index].add[1]>]>]>]>
- else:
- define p0 <[points].get[<[segment_index]>]>
- define p1 <[points].get[<[segment_index].add[1]>]>
- define p2 <[points].get[<[segment_index].add[2]>]>
- define p3 <[points].get[<[segment_index].add[3]>]>
- define t 0
- while <[t]> < 1:
- define t2 <[t].mul[<[t]>]>
- define t3 <[t2].mul[<[t]>]>
- define px <element[0.5].mul[<[p1].x.mul[2].add[<[p2].x.sub[<[p0].x>].mul[<[t]>]>].add[<[p0].x.mul[2].sub[<[p1].x.mul[5]>].add[<[p2].x.mul[4]>].sub[<[p3].x>].mul[<[t2]>]>].add[<[p0].x.mul[-1].add[<[p1].x.mul[3]>].sub[<[p2].x.mul[3]>].add[<[p3].x>].mul[<[t3]>]>]>]>
- define py <element[0.5].mul[<[p1].y.mul[2].add[<[p2].y.sub[<[p0].y>].mul[<[t]>]>].add[<[p0].y.mul[2].sub[<[p1].y.mul[5]>].add[<[p2].y.mul[4]>].sub[<[p3].y>].mul[<[t2]>]>].add[<[p0].y.mul[-1].add[<[p1].y.mul[3]>].sub[<[p2].y.mul[3]>].add[<[p3].y>].mul[<[t3]>]>]>]>
- define pz <element[0.5].mul[<[p1].z.mul[2].add[<[p2].z.sub[<[p0].z>].mul[<[t]>]>].add[<[p0].z.mul[2].sub[<[p1].z.mul[5]>].add[<[p2].z.mul[4]>].sub[<[p3].z>].mul[<[t2]>]>].add[<[p0].z.mul[-1].add[<[p1].z.mul[3]>].sub[<[p2].z.mul[3]>].add[<[p3].z>].mul[<[t3]>]>]>]>
- define point <location[<[px]>,<[py]>,<[pz]>,<[points].get[1].world.name>]>
- if <[spline_points].size> > 0:
- define last_point <[spline_points].get[-1]>
- define cumulative_distance <[last_point].distance[<[point]>]>
- define cumulative_distances <[cumulative_distances].include[<[cumulative_distances].get[-1].add[<[cumulative_distance]>]>]>
- define spline_points <[spline_points].include[<[point]>]>
- define t <[t].add[<element[1].div[<[resolution]>]>]>
- define equidistant_points <list[<[spline_points].get[1]>]>
- define total_length <[cumulative_distances].get[-1]>
- define current_distance 0
- define current_index 1
- while <[current_distance]> < <[total_length]>:
- define target_distance <[current_distance].add[<[distance]>]>
- if <[target_distance]> > <[total_length]>:
- while stop
- while <[current_index]> < <[cumulative_distances].size> && <[cumulative_distances].get[<[current_index].add[1]>]> < <[target_distance]>:
- define current_index <[current_index].add[1]>
- define t1 <[cumulative_distances].get[<[current_index]>]>
- define t2 <[cumulative_distances].get[<[current_index].add[1]>]>
- define alpha <[target_distance].sub[<[t1]>].div[<[t2].sub[<[t1]>]>]>
- define p1 <[spline_points].get[<[current_index]>]>
- define p2 <[spline_points].get[<[current_index].add[1]>]>
- define x <[p1].x.add[<[alpha].mul[<[p2].x.sub[<[p1].x>]>]>]>
- define y <[p1].y.add[<[alpha].mul[<[p2].y.sub[<[p1].y>]>]>]>
- define z <[p1].z.add[<[alpha].mul[<[p2].z.sub[<[p1].z>]>]>]>
- define point <location[<[x]>,<[y]>,<[z]>,<[points].get[1].world.name>]>
- define equidistant_points <[equidistant_points].include[<[point]>]>
- define current_distance <[target_distance]>
- define last_control_point <[points].get[-1]>
- define last_generated <[equidistant_points].get[-1]>
- if <[last_generated].distance[<[last_control_point]>]> >= <[distance].div[2]>:
- define equidistant_points <[equidistant_points].include[<[last_control_point]>]>
- determine <[equidistant_points]>
# Previews the given path for the given player, where the source definition are the points that
# the resulting path must pass through, for the specified duration_tag. Note for the duration_tag
# that a <duration[]> is required, and it will not work if using simple <element[]>, like '5s'.
cutscene_preview_path:
debug: false
type: task
definitions: player|source|result|duration_tag
script:
- define duration_tag <[duration_tag].if_null[<duration[5s]>]>
- define now <util.current_time_millis>
- while <util.current_time_millis.sub[<[now]>]> < <[duration_tag].in_milliseconds>:
- if !<[player].is_online>:
- stop
- playeffect at:<[source]> targets:<[player]> effect:CLOUD offset:0,0,0 quantity:1 velocity:0,0,0 visibility:1000
- playeffect at:<[result]> targets:<[player]> effect:ENCHANTED_HIT offset:0,0,0 quantity:1 velocity:0,0,0 visibility:1000
- wait 5t
# Simple linear interpolation.
# Given as parameter to cutscene_follow_path_by_interpolation.
cutscene_interpolate_linear:
debug: false
type: procedure
definitions: step
script:
- determine 0.5
# Ease in interpolation.
# Given as parameter to cutscene_follow_path_by_interpolation.
cutscene_interpolate_ease_in:
debug: false
type: procedure
definitions: step
script:
- determine <[step].mul[<util.pi.div[2]>].sin>
# Ease out interpolation.
# Given as parameter to cutscene_follow_path_by_interpolation.
cutscene_interpolate_ease_out:
debug: false
type: procedure
definitions: step
script:
- determine <[step].mul[<util.pi.div[2]>].add[<util.pi.div[2]>].sin>
# Ease in-out interpolation.
# Given as parameter to cutscene_follow_path_by_interpolation.
cutscene_interpolate_ease_in_out:
debug: false
type: procedure
definitions: step
script:
- determine <[step].mul[<util.pi>].sin>
# Makes the player follow the given path at the given speed, using the provided interpolation.
# Note that the speed is an arbitrary construct, but higher numbers will make the player follow
# the path faster.
cutscene_follow_path_by_interpolation:
debug: false
type: task
definitions: player|path|look_at|speed|interpolation_procedure
script:
- if <[path].size> == 0:
- stop
- define look_at_is_list <tern[<[look_at].get[1].if_null[null].equals[null]>].pass[false].fail[true]>
- teleport <[player]> <[path].get[1]>
- define time_unit <[path].size.div[<[speed].mul[20]>]>
- define should_await_time 0
- define index 1
- while <[index]> < <[path].size>:
- define point <[path].get[<[index]>]>
- define step <[index].sub[1].div[<[path].size>]>
- define await_time <element[1].sub[<proc[<[interpolation_procedure]>].context[<[step]>]>].mul[<[time_unit]>]>
- define should_await_time <[should_await_time].add[<[await_time]>]>
- if <[should_await_time]> < 1:
- define index <[index].add[1]>
- while next
- wait <[should_await_time].round_down>t
- define should_await_time <[should_await_time].sub[<[should_await_time].round_down>]>
- define direction <[look_at].sub[<[point]>].normalize>
- define quaternion_pitch <[direction].quaternion_between_vectors[0,1,0].represented_angle.sub[<util.pi.div[2]>].to_degrees>
- define result_point <[point].with_pitch[<[quaternion_pitch]>].with_yaw[<[point].direction[<[look_at]>].yaw>]>
- if !<[player].is_online>:
- determine false
- teleport <[player]> <[result_point].add[0,-1,0]> offthread_repeat:8
- define index <[index].add[1]>
- if !<[player].is_online>:
- determine false
- teleport <[player]> <[path].get[-1]>
- determine true
# Creates and saves a cutscene.
# Definitions explanation:
# - name: The name of the cutscene. Must be unique, case sensitive.
# - points: The source points to generate the path from.
# - look_at: The location that the player should look at throughout the entire path follow
# - compute_spline: Whether to use straight lines for the path, or to compute a smooth spline.
# - interpolation_procedure: A procedure to interpolate the speed of the path follower.
#
# If the cutscene already exists, it will not create it and silently fail.
# Determines true if the cutscene was created, or false if it already exists.
cutscene_create_and_save:
debug: false
type: task
definitions: name|points|look_at|speed|compute_spline|interpolation_procedure
script:
- if <server.flag[cutscene].if_null[<map[]>].contains[<[name]>]>:
- determine false
- if !<[compute_spline]>:
- define result <proc[cutscene_concatenate_points_between].context[<[points].escaped>|0.33]>
- else:
- define result <proc[cutscene_catmull_rom_equidistant_spline].context[<[points].escaped>|0.33|50]>
- definemap cutscene:
name: <[name]>
source: <[points]>
result: <[result]>
look_at: <[look_at]>
speed: <[speed]>
interpolation_procedure: <[interpolation_procedure]>
- flag server cutscene:<server.flag[cutscene].if_null[<map[]>].with[<[name]>].as[<[cutscene]>]>
- determine true
# Destroys an existing cutscnee.
# If the cutscene doesn't exist, it will fail silently.
# Determines true if the cutscene was destroyed, or false if it did not yet exist.
cutscene_destroy:
debug: false
type: task
definitions: name
script:
- if !<server.flag[cutscene].if_null[<map[]>].contains[<[name]>]>:
- determine false
- flag server cutscene:<server.flag[cutscene].if_null[<map[]>].exclude[<[name]>]>
- determine false
# Previews the given path for the given player, using a saved cutscene as the source.
# Note for the duration_tag that a <duration[]> is required, and it will not work if
# using simple <element[]>, like '5s'.
cutscene_preview_path_by_name:
debug: false
type: task
definitions: name|player|duration_tag
script:
- if !<server.flag[cutscene].if_null[<map[]>].contains[<[name]>]>:
- debug error "Cannot preview path by name! <[name]> @ <[player]>"
- stop
- define cutscene <server.flag[cutscene].get[<[name]>]>
- run cutscene_preview_path def.player:<[player]> def.source:<[cutscene].get[source]> def.result:<[cutscene].get[result]> def.duration_tag:<[duration_tag]>
# Plays the given cutscene by name.
# If the player disconnects, the cutscene will stop playing, but the queue that
# called this task will continue. Consider cutscene_play_atomic in case you would
# like to stop the queue that called this task.
# Determines true if the cutscene completed, false otherwise.
# Should be ~waited for.
cutscene_play:
debug: false
type: task
definitions: name|player
script:
- run cutscene_stop def.player:<[player]>
- if !<server.flag[cutscene].if_null[<map[]>].contains[<[name]>]>:
- determine false
- define cutscene <server.flag[cutscene].get[<[name]>]>
- flag <[player]> cutscene:<map[].with[gamemode].as[<player.gamemode>].with[location].as[<player.location>]>
- adjust <[player]> gamemode:spectator
- run cutscene_follow_path_by_interpolation def.player:<[player]> def.path:<[cutscene].get[result]> def.look_at:<[cutscene].get[look_at]> def.speed:<[cutscene].get[speed]> def.interpolation_procedure:<[cutscene].get[interpolation_procedure]> save:result
- define queue <entry[result].created_queue>
- flag <[player]> cutscene_queue:<[queue]>
- waituntil <[queue].state.equals[running]> max:5t
- waituntil <[queue].state.equals[running].not>
- define ok <[queue].determination.get[1]>
- run cutscene_stop def.player:<player>
- determine <[ok]>
# Plays the cutscene atomically.
# See cutscene_play for an explanation.
# Should be ~waited for.
cutscene_play_atomic:
debug: false
type: task
definitions: name|player|queue
script:
- ~run cutscene_play def.name:<[name]> def.player:<[player]> save:result
- define result <entry[result].created_queue.determination.get[1]>
- if !<[result].if_null[false]>:
- debug log "Cancelled atomic cutscene: <[player].name> @ <[name]>"
- queue stop <[queue]>
# Stops the currently playing cutscene from playing.
# If no cutscene is playing, it silently fails.
cutscene_stop:
debug: false
type: task
definitions: player
script:
- if !<[player].has_flag[cutscene]>:
- stop
- define save <[player].flag[cutscene]>
- if <[player].flag[cutscene_queue]> != null:
- queue stop <[player].flag[cutscene_queue]>
- adjust <[player]> gamemode:<[save].get[gamemode]>
- teleport <[player]> <[save].get[location]>
- flag <[player]> cutscene:!
## Internal only!
cutscene_world:
debug: false
type: world
events:
on player joins:
- run cutscene_stop def.player:<player>

View File

@@ -35,7 +35,7 @@ textbox_write:
- queue stop <[queue]> - queue stop <[queue]>
- run textbox_flush def.player:<[player]> - run textbox_flush def.player:<[player]>
- stop - stop
- define lines <[line3s].split[$$nl].parse_tag[<[parse_value].trim>]> - define lines <[line3s].split[$$nl].parse_tag[<[parse_value].trim.replace[<&0>].with[<&6>]>]>
- flag <[player]> textbox_state:writing - flag <[player]> textbox_state:writing
- flag <[player]> textbox_input:<[lines]> - flag <[player]> textbox_input:<[lines]>
- flag <[player]> textbox_lines:<[lines].size> - flag <[player]> textbox_lines:<[lines].size>
@@ -57,7 +57,7 @@ textbox_write:
- stop - stop
- if !<[player].is_online>: - if !<[player].is_online>:
- stop - stop
- bossbar update textbox_<[player].uuid>_<[loop_index]> title:<black><bold><[line].substring[1,<[value]>]> - bossbar update textbox_<[player].uuid>_<[loop_index]> title:<&6><&l><[line].substring[1,<[value]>]>
- if <[value].sub[1].mod[3]> == 0: - if <[value].sub[1].mod[3]> == 0:
- playsound sound:textbox.text <[player]> custom pitch:<util.random.decimal[0.98].to[1]> volume:<proc[settings_get].context[<[player]>|sound_textbox_volume].div[100].if_null[1]> - playsound sound:textbox.text <[player]> custom pitch:<util.random.decimal[0.98].to[1]> volume:<proc[settings_get].context[<[player]>|sound_textbox_volume].div[100].if_null[1]>
- wait <[write_speed]>t - wait <[write_speed]>t
@@ -100,7 +100,7 @@ textbox_skip:
- bossbar create textbox_<[player].uuid>_<[value]> players:<[player]> title:<empty> - bossbar create textbox_<[player].uuid>_<[value]> players:<[player]> title:<empty>
- define lines <[player].flag[textbox_input]> - define lines <[player].flag[textbox_input]>
- foreach <[lines]> as:line: - foreach <[lines]> as:line:
- bossbar update textbox_<[player].uuid>_<[loop_index]> title:<black><bold><[line]> - bossbar update textbox_<[player].uuid>_<[loop_index]> title:<&6><&l><[line]>
- flag <[player]> textbox_state:continue - flag <[player]> textbox_state:continue
# Clears textbox and flushes all flag memory values # Clears textbox and flushes all flag memory values
@@ -208,12 +208,12 @@ textbox_handle_click:
- ratelimit <player> 5t - ratelimit <player> 5t
- else if <[state]> == continue: - else if <[state]> == continue:
- determine cancelled passively - determine cancelled passively
- playsound sound:textbox.close <player> custom volume:<proc[settings_get].context[<[player]>|sound_textbox_volume].div[100].if_null[1]> - playsound sound:textbox.close <player> custom volume:<proc[settings_get].context[<player>|sound_textbox_volume].div[100].if_null[1]>
- ~run textbox_flush def.player:<player> - ~run textbox_flush def.player:<player>
- ratelimit <player> 10t - ratelimit <player> 10t
- else if <[state]> == choice: - else if <[state]> == choice:
- determine cancelled passively - determine cancelled passively
- playsound sound:input.ok <player> custom volume:<proc[settings_get].context[<[player]>|sound_textbox_volume].div[100].if_null[1]> - playsound sound:input.ok <player> custom volume:<proc[settings_get].context[<player>|sound_textbox_volume].div[100].if_null[1]>
- flag <player> textbox_choice_select:<player.flag[textbox_choices].get[current]> - flag <player> textbox_choice_select:<player.flag[textbox_choices].get[current]>
- ~run textbox_flush def.player:<player> - ~run textbox_flush def.player:<player>
- ratelimit <player> 10t - ratelimit <player> 10t
@@ -250,7 +250,13 @@ textbox_choice:
- teleport <[player]> <[player].location.below.above.with_y[<[player].location.below.above.y.round_down>]> - teleport <[player]> <[player].location.below.above.with_y[<[player].location.below.above.y.round_down>]>
- else: - else:
- stop - stop
- waituntil <[player].flag[textbox_state].if_null[null]> == null - waituntil <[player].flag[textbox_state].if_null[null]> == null || !<[player].is_online>
- if !<[player].is_online>:
- if <[queue].if_null[null]> != null:
- debug log "[Textbox] Choice; cancelled queue <[queue].numeric_id><&at><[queue].script.name> for <[player].name>; offline"
- queue stop <[queue]>
- run textbox_flush def.player:<[player]>
- stop
- ~run textbox_flush def.player:<[player]> - ~run textbox_flush def.player:<[player]>
- flag <[player]> textbox_state:choice - flag <[player]> textbox_state:choice
- flag <[player]> textbox_choices:<map[].with[data].as[<[choices]>].with[current].as[left]> - flag <[player]> textbox_choices:<map[].with[data].as[<[choices]>].with[current].as[left]>
@@ -284,35 +290,35 @@ textbox_internal_choice_select:
- bossbar create textbox_<[player].uuid>_bottom players:<[player]> title:<empty> - bossbar create textbox_<[player].uuid>_bottom players:<[player]> title:<empty>
- define choices <[player].flag[textbox_choices].get[data]> - define choices <[player].flag[textbox_choices].get[data]>
# #
- define left <&0><&l><[choices].get[left].get[text].if_null[null]> - define left <&6><&l><[choices].get[left].get[text].if_null[null]>
- define right <&0><&l><[choices].get[right].get[text].if_null[null]> - define right <&6><&l><[choices].get[right].get[text].if_null[null]>
- define top <&0><&l><[choices].get[top].get[text].if_null[null]> - define top <&6><&l><[choices].get[top].get[text].if_null[null]>
- define bottom <&0><&l><[choices].get[bottom].get[text].if_null[null]> - define bottom <&6><&l><[choices].get[bottom].get[text].if_null[null]>
# #
- if <[choice_dir]> == left: - if <[choice_dir]> == left:
- if <[left]> == <&0><&l>null: - if <[left]> == <&6><&l>null:
- stop - stop
- define left "<&4>❤ <&0><&l><[left]>" - define left "<&4>❤ <&6><&l><[left]>"
- else if <[choice_dir]> == right: - else if <[choice_dir]> == right:
- if <[right]> == <&0><&l>null: - if <[right]> == <&6><&l>null:
- stop - stop
- define right "<&4>❤ <&0><&l><[right]>" - define right "<&4>❤ <&6><&l><[right]>"
- else if <[choice_dir]> == top: - else if <[choice_dir]> == top:
- if <[top]> == <&0><&l>null: - if <[top]> == <&6><&l>null:
- stop - stop
- define top "<&4>❤ <&0><&l><[top]>" - define top "<&4>❤ <&6><&l><[top]>"
- else: - else:
- if <[bottom]> == <&0><&l>null: - if <[bottom]> == <&6><&l>null:
- stop - stop
- define bottom "<&4>❤ <&0><&l><[bottom]>" - define bottom "<&4>❤ <&6><&l><[bottom]>"
# #
- define mid_padding <element[<&sp>].repeat[<element[30].sub[<[left].strip_color.length>].sub[<[right].strip_color.length>]>]> - define mid_padding <element[<&sp>].repeat[<element[30].sub[<[left].strip_color.length>].sub[<[right].strip_color.length>]>]>
# #
- if <[top]> != <&0><&l>null: - if <[top]> != <&6><&l>null:
- bossbar update textbox_<[player].uuid>_top title:<[top]> - bossbar update textbox_<[player].uuid>_top title:<[top]>
- if <[left]> != <&0><&l>null || <[right]> != <&0><&l>null: - if <[left]> != <&6><&l>null || <[right]> != <&6><&l>null:
- bossbar update textbox_<[player].uuid>_mid title:<[left]><[mid_padding]><[right]> - bossbar update textbox_<[player].uuid>_mid title:<[left]><[mid_padding]><[right]>
- if <[bottom]> != <&0><&l>null: - if <[bottom]> != <&6><&l>null:
- bossbar update textbox_<[player].uuid>_bottom title:<[bottom]> - bossbar update textbox_<[player].uuid>_bottom title:<[bottom]>
- flag <[player]> textbox_choices:<map[].with[data].as[<[choices]>].with[current].as[<[choice_dir]>]> - flag <[player]> textbox_choices:<map[].with[data].as[<[choices]>].with[current].as[<[choice_dir]>]>
- playsound BLOCK_NOTE_BLOCK_BIT <[player]> pitch:2 volume:<proc[settings_get].context[<[player]>|sound_textbox_volume].div[100].if_null[1]> - playsound BLOCK_NOTE_BLOCK_BIT <[player]> pitch:2 volume:<proc[settings_get].context[<[player]>|sound_textbox_volume].div[100].if_null[1]>

View File

@@ -66,6 +66,10 @@ liteprofilesutils_world:
- narrate <[joinleavedata].get[join].parsed> targets:<[setting_enabled_players]> - narrate <[joinleavedata].get[join].parsed> targets:<[setting_enabled_players]>
## prevent /profile remove ## prevent /profile remove
on command: on command:
- if <context.source_type> != player:
- stop
- if <player.is_op>:
- stop
- if <context.command.to_lowercase> == profile || <context.command.to_lowercase> == account || <context.command.to_lowercase> == pf: - if <context.command.to_lowercase> == profile || <context.command.to_lowercase> == account || <context.command.to_lowercase> == pf:
- if <context.args.get[1].to_lowercase.if_null[null]> == remove: - if <context.args.get[1].to_lowercase.if_null[null]> == remove:
- determine cancelled passively - determine cancelled passively
@@ -95,3 +99,11 @@ liteprofilesutils_world:
- else if <[data].get[type]> == free: - else if <[data].get[type]> == free:
- execute as_player "profile add" - execute as_player "profile add"
- run liteprofilesutils_show_menu def.player:<player> - run liteprofilesutils_show_menu def.player:<player>
## patch whitelisting
on player prelogin:
- define uuid <context.uuid>
- define master <proc[liteprofilesutils_get_master_uuid].context[<player[<[uuid]>]>]>
- if <[master]> == <[uuid]>:
- stop
- adjust <player[<[uuid]>]> whitelisted:<player[<[master]>].is_whitelisted>

View File

@@ -22,7 +22,7 @@ compatibility_check_world:
after player joins: after player joins:
- if <proc[settings_get].context[<player>|general_ignore_version_compatibility_check]>: - if <proc[settings_get].context[<player>|general_ignore_version_compatibility_check]>:
- stop - stop
- define player_version <player.viaversion_version.split[-].get[1]> - define player_version <player.viaversion_version.split[-].get[2]>
- define server_version <server.version.split[(].get[2].split[:].get[2].split[)].get[1].trim> - define server_version <server.version.split[(].get[2].split[:].get[2].split[)].get[1].trim>
- if <proc[compatibility_check_compare_versions].context[<[player_version]>|<[server_version]>]> == -1: - if <proc[compatibility_check_compare_versions].context[<[player_version]>|<[server_version]>]> == -1:
- wait 5s - wait 5s

View File

@@ -2,9 +2,11 @@ ch1_1_preassign:
debug: false debug: false
type: world type: world
events: events:
on player joins: after player joins:
- wait 1s
- if <proc[storyboard_player_state_get].context[<player>|preassign]> == null: - if <proc[storyboard_player_state_get].context[<player>|preassign]> == null:
- run storyboard_npc_memalloc "def:<player>|marie|player|<location[-4,2,-15,world]>|Marie Ayashibayomi|true|<script[storyboard_skin_dump].data_key[marie].get[a]>" - if !<proc[storyboard_npc_exists].context[<player>|marie]>:
- run storyboard_npc_memalloc "def:<player>|marie|player|<location[-4,2,-15,world]>|Marie Ayashibayomi|true|<script[storyboard_skin_dump].data_key[marie].get[a]>"
- run storyboard_npc_set_assignment def.player:<player> def.name:marie def.assignment:ch1_1_marie_assign - run storyboard_npc_set_assignment def.player:<player> def.name:marie def.assignment:ch1_1_marie_assign
- run storyboard_player_state_set def.player:<player> def.key:preassign def.value:true - run storyboard_player_state_set def.player:<player> def.key:preassign def.value:true
@@ -34,6 +36,7 @@ ch1_1_marie_interact:
1: 1:
click trigger: click trigger:
script: script:
- run storyboard_player_begin_atomic_sequence def.queue:<queue> def.player:<player>
- if <player.flag[textbox_state].if_null[null]> != null: - if <player.flag[textbox_state].if_null[null]> != null:
- stop - stop
- engage player duration:999999s - engage player duration:999999s
@@ -97,9 +100,11 @@ ch1_1_marie_interact:
- run storyboard_npc_state_set def.player:<player> def.name:marie def.key:opinion def.value:-1 - run storyboard_npc_state_set def.player:<player> def.name:marie def.key:opinion def.value:-1
- zap 2 - zap 2
- disengage player - disengage player
- run storyboard_player_end_atomic_sequence def.queue:<queue> def.player:<player>
2: 2:
click trigger: click trigger:
script: script:
- run storyboard_player_begin_atomic_sequence def.queue:<queue> def.player:<player>
- if <player.flag[textbox_state].if_null[null]> != null: - if <player.flag[textbox_state].if_null[null]> != null:
- stop - stop
- engage player duration:999999s - engage player duration:999999s
@@ -128,6 +133,7 @@ ch1_1_marie_interact:
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:* Mkay." def.avatar_unicode:<script[storyboard_avatar_dump].data_key[marie].get[upset]> - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:* Mkay." def.avatar_unicode:<script[storyboard_avatar_dump].data_key[marie].get[upset]>
- wait 1s - wait 1s
- disengage player - disengage player
- run storyboard_player_end_atomic_sequence def.queue:<queue> def.player:<player>
- stop - stop
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:* Hm. Are you now?" def.avatar_unicode:<script[storyboard_avatar_dump].data_key[marie].get[upset]> - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:* Hm. Are you now?" def.avatar_unicode:<script[storyboard_avatar_dump].data_key[marie].get[upset]>
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:* You know, that was kind of$$nlmean of you." def.avatar_unicode:<script[storyboard_avatar_dump].data_key[marie].get[upset]> - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:* You know, that was kind of$$nlmean of you." def.avatar_unicode:<script[storyboard_avatar_dump].data_key[marie].get[upset]>
@@ -235,3 +241,4 @@ ch1_1_marie_interact:
- inventory update - inventory update
- zap 3 - zap 3
- disengage player - disengage player
- run storyboard_player_end_atomic_sequence def.queue:<queue> def.player:<player>

View File

@@ -14,6 +14,7 @@ dialogue_npc_kobayashi:
1: 1:
click trigger: click trigger:
script: script:
- run storyboard_player_begin_atomic_sequence def.queue:<queue> def.player:<player>
- if <player.flag[textbox_state].if_null[null]> != null: - if <player.flag[textbox_state].if_null[null]> != null:
- stop - stop
- engage player - engage player
@@ -45,3 +46,4 @@ dialogue_npc_kobayashi:
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:Indeed, luv." - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:Indeed, luv."
- wait 1s - wait 1s
- disengage player - disengage player
- run storyboard_player_end_atomic_sequence def.queue:<queue> def.player:<player>

View File

@@ -14,6 +14,7 @@ dialogue_npc_patchouli:
1: 1:
click trigger: click trigger:
script: script:
- run storyboard_player_begin_atomic_sequence def.queue:<queue> def.player:<player>
- if <player.flag[textbox_state].if_null[null]> != null: - if <player.flag[textbox_state].if_null[null]> != null:
- stop - stop
- engage player - engage player
@@ -23,3 +24,4 @@ dialogue_npc_patchouli:
- wait 1s - wait 1s
- disengage player - disengage player
- ratelimit <player> 10t - ratelimit <player> 10t
- run storyboard_player_end_atomic_sequence def.queue:<queue> def.player:<player>

View File

@@ -14,6 +14,7 @@ dialogue_npc_ryuko:
1: 1:
click trigger: click trigger:
script: script:
- run storyboard_player_begin_atomic_sequence def.queue:<queue> def.player:<player>
- if <player.flag[textbox_state].if_null[null]> != null: - if <player.flag[textbox_state].if_null[null]> != null:
- stop - stop
- engage player - engage player
@@ -29,3 +30,4 @@ dialogue_npc_ryuko:
- wait 1s - wait 1s
- disengage player - disengage player
- ratelimit <player> 10t - ratelimit <player> 10t
- run storyboard_player_end_atomic_sequence def.queue:<queue> def.player:<player>

View File

@@ -15,11 +15,13 @@ intro_interact_posters_task:
debug: false debug: false
type: task type: task
script: script:
- run storyboard_player_begin_atomic_sequence def.queue:<queue> def.player:<player>
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:Book-related posters are on the wall." - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:Book-related posters are on the wall."
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:<&o><&dq>Screw that. I'm running away.<&dq>" - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:<&o><&dq>Screw that. I'm running away.<&dq>"
- ~run textbox_write def.player:<player> def.queue:<queue> def.line3s:<&o><&dq>Where?<&dq> - ~run textbox_write def.player:<player> def.queue:<queue> def.line3s:<&o><&dq>Where?<&dq>
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:<&o><&dq>Dunno. Do you want to come?<&dq>" - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:<&o><&dq>Dunno. Do you want to come?<&dq>"
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:<&o><&dq>Yes,<&dq> I said without thinking." - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:<&o><&dq>Yes,<&dq> I said without thinking."
- run storyboard_player_end_atomic_sequence def.queue:<queue> def.player:<player>
# Cirno # Cirno
intro_interact_cirno: intro_interact_cirno:
@@ -38,8 +40,10 @@ intro_interact_cirno_task:
debug: false debug: false
type: task type: task
script: script:
- run storyboard_player_begin_atomic_sequence def.queue:<queue> def.player:<player>
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:A quality, soft plushie of a beloved$$nlcharacter." - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:A quality, soft plushie of a beloved$$nlcharacter."
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:It seems familiar, as if there are a$$nlsubstantial amount of images circulating$$nlaround with this character." - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:It seems familiar, as if there are a$$nlsubstantial amount of images circulating$$nlaround with this character."
- run storyboard_player_end_atomic_sequence def.queue:<queue> def.player:<player>
# Laptop # Laptop
intro_interact_laptop: intro_interact_laptop:
@@ -58,12 +62,14 @@ intro_interact_laptop_task:
debug: false debug: false
type: task type: task
script: script:
- run storyboard_player_begin_atomic_sequence def.queue:<queue> def.player:<player>
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:It looks like a game is booted up.$$nlYou can see a city, and it looks like..." - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:It looks like a game is booted up.$$nlYou can see a city, and it looks like..."
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:. . ." - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:. . ."
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:It's <bold>you!$$nl. . .$$nlWell, it's your character." - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:It's <bold>you!$$nl. . .$$nlWell, it's your character."
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:You should give your character$$nla cool name, right?" - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:You should give your character$$nla cool name, right?"
- waituntil <player.has_flag[textbox_state].not> max:5s - waituntil <player.has_flag[textbox_state].not> max:5s
- ~run textbox_flush def.player:<player> - ~run textbox_flush def.player:<player>
- run storyboard_player_end_atomic_sequence def.queue:<queue> def.player:<player>
- run anvil_input def.player:<player> "def.prompt:Character Name" def.callback:intro_interact_laptop_task_name_callback - run anvil_input def.player:<player> "def.prompt:Character Name" def.callback:intro_interact_laptop_task_name_callback
intro_interact_laptop_task_name_callback: intro_interact_laptop_task_name_callback:
@@ -71,14 +77,21 @@ intro_interact_laptop_task_name_callback:
type: task type: task
definitions: player|input definitions: player|input
script: script:
- run storyboard_player_begin_atomic_sequence def.queue:<queue> def.player:<player>
- define __player <[player]> - define __player <[player]>
- define name <[input].substring[1,24]> - define name <[input].substring[1,24]>
- if <server.flag[character_rpnames].contains[<[name]>]>:
- narrate targets:<[player]> "<&c>That RP name is already taken. Try a different one!"
- wait 1s
- run anvil_input def.player:<player> "def.prompt:Character Name" def.callback:intro_interact_laptop_task_name_callback
- stop
- execute as_player player:<[player]> "rpname <[name]>" - execute as_player player:<[player]> "rpname <[name]>"
- ~run textbox_write def.player:<player> def.queue:<queue> def.line3s:<[name]> - ~run textbox_write def.player:<player> def.queue:<queue> def.line3s:<[name]>
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:How nice!" - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:How nice!"
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:Let's give them a description.$$nlDescribe their physical attributes." - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:Let's give them a description.$$nlDescribe their physical attributes."
- waituntil <player.has_flag[textbox_state].not> max:5s - waituntil <player.has_flag[textbox_state].not> max:5s
- ~run textbox_flush def.player:<player> - ~run textbox_flush def.player:<player>
- run storyboard_player_end_atomic_sequence def.queue:<queue> def.player:<player>
- run anvil_input def.player:<player> def.prompt:Description def.callback:intro_interact_laptop_task_description_callback - run anvil_input def.player:<player> def.prompt:Description def.callback:intro_interact_laptop_task_description_callback
intro_interact_laptop_task_description_callback: intro_interact_laptop_task_description_callback:
@@ -86,6 +99,7 @@ intro_interact_laptop_task_description_callback:
type: task type: task
definitions: player|input definitions: player|input
script: script:
- run storyboard_player_begin_atomic_sequence def.queue:<queue> def.player:<player>
- define __player <[player]> - define __player <[player]>
- execute as_player player:<[player]> "setdesc <[input]>" - execute as_player player:<[player]> "setdesc <[input]>"
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:Great, your character's almost ready." - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:Great, your character's almost ready."
@@ -94,6 +108,7 @@ intro_interact_laptop_task_description_callback:
- ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:For complete beginners, we recommend$$nlstarting out as a student." - ~run textbox_write def.player:<player> def.queue:<queue> "def.line3s:For complete beginners, we recommend$$nlstarting out as a student."
- waituntil <player.has_flag[textbox_state].not> max:5s - waituntil <player.has_flag[textbox_state].not> max:5s
- ~run textbox_flush def.player:<player> - ~run textbox_flush def.player:<player>
- run storyboard_player_end_atomic_sequence def.queue:<queue> def.player:<player>
- run intro_interact_laptop_task_role_menu def.player:<player> - run intro_interact_laptop_task_role_menu def.player:<player>
intro_interact_laptop_task_role_menu: intro_interact_laptop_task_role_menu:
@@ -123,6 +138,7 @@ intro_interact_laptop_task_role_callback:
type: task type: task
definitions: player|input definitions: player|input
script: script:
- run storyboard_player_begin_atomic_sequence def.queue:<queue> def.player:<player>
- inventory close player:<[player]> - inventory close player:<[player]>
- define __player <[player]> - define __player <[player]>
- define adult <[input].to_lowercase.trim.equals[yes]> - define adult <[input].to_lowercase.trim.equals[yes]>
@@ -197,3 +213,4 @@ intro_interact_laptop_task_role_callback:
- adjust <player> show_to_players - adjust <player> show_to_players
- flag <player> intro:done - flag <player> intro:done
- execute as_player player:<player> spawn - execute as_player player:<player> spawn
- run storyboard_player_end_atomic_sequence def.queue:<queue> def.player:<player>

View File

@@ -39,8 +39,10 @@ storyboard_npc_memalloc:
- define npc_id npc_<[player].uuid>_<[name]> - define npc_id npc_<[player].uuid>_<[name]>
- if !<server.npcs[<[registry]>].if_null[<list[]>].contains[<[npc_id]>]>: - if !<server.npcs[<[registry]>].if_null[<list[]>].contains[<[npc_id]>]>:
- define npcs <[player].flag[storyboard_state].get[npcs].if_null[<map[]>]> - define npcs <[player].flag[storyboard_state].get[npcs].if_null[<map[]>]>
- chunkload <[at].chunk> duration:10s
- create <[type]> <[npc_id]> <[at]> registry:<[registry]> save:npc - create <[type]> <[npc_id]> <[at]> registry:<[registry]> save:npc
- define npc <entry[npc].created_npc> - define npc <entry[npc].created_npc>
- playeffect at:<[npc].location.above[1]> offset:0.35,1,0.35 effect:SOUL_FIRE_FLAME quantity:20
- define npc_state <map[]> - define npc_state <map[]>
- define assignment null - define assignment null
- if <[npcs].contains[<[name]>]>: - if <[npcs].contains[<[name]>]>:
@@ -83,7 +85,7 @@ storyboard_npc_memalloc:
- adjust <[npc]> skin_blob:<[skin_blob]> - adjust <[npc]> skin_blob:<[skin_blob]>
- if <[assignment]> != null: - if <[assignment]> != null:
- assignment set script:<[assignment]> to:<[npc]> - assignment set script:<[assignment]> to:<[npc]>
- wait 2t - wait 1t
- run storyboard_npc_internal_show_to_player def.player:<[player]> def.npc:<[npc]> - run storyboard_npc_internal_show_to_player def.player:<[player]> def.npc:<[npc]>
- else: - else:
- define index <server.npcs[<[registry]>].find[<[npc_id]>]> - define index <server.npcs[<[registry]>].find[<[npc_id]>]>
@@ -98,7 +100,7 @@ storyboard_npc_by_name:
script: script:
- define registry registry_<[player].uuid> - define registry registry_<[player].uuid>
- define npc_id npc_<[player].uuid>_<[name]> - define npc_id npc_<[player].uuid>_<[name]>
- determine <server.npcs[<[registry]>].filter_tag[<[filter_value].name.equals[<[npc_id]>]>].get[1]> - determine <server.npcs[<[registry]>].filter_tag[<[filter_value].name.equals[<[npc_id]>]>].get[1].if_null[null]>
# Frees an NPC from memory, but does not destroy its state. # Frees an NPC from memory, but does not destroy its state.
# #
@@ -137,6 +139,14 @@ storyboard_npc_memdestroy:
- define npc <proc[storyboard_npc_by_name].context[<[player]>|<[name]>]> - define npc <proc[storyboard_npc_by_name].context[<[player]>|<[name]>]>
- remove <[npc]> - remove <[npc]>
# Checks if an NPC exists for the given player.
storyboard_npc_exists:
debug: false
type: procedure
definitions: player|name
script:
- determine <proc[storyboard_npc_by_name].context[<[player]>|<[name]>].if_null[null].equals[null].not>
# Flags the NPC by name, mapping the given key to the given value. # Flags the NPC by name, mapping the given key to the given value.
storyboard_npc_state_set: storyboard_npc_state_set:
debug: false debug: false
@@ -215,6 +225,7 @@ storyboard_npc_internal_auto_memory_management:
type: world type: world
events: events:
after player joins: after player joins:
- wait 1s
- define npcs <player.flag[storyboard_state].get[npcs].if_null[<map[]>]> - define npcs <player.flag[storyboard_state].get[npcs].if_null[<map[]>]>
- foreach <[npcs]> key:name as:data: - foreach <[npcs]> key:name as:data:
- define allocated <[data].get[allocated].if_null[null]> - define allocated <[data].get[allocated].if_null[null]>

View File

@@ -60,6 +60,37 @@ storyboard_player_unfreeze:
- adjust <player> walk_speed:<player.flag[storyboard_freeze_speed]> - adjust <player> walk_speed:<player.flag[storyboard_freeze_speed]>
- flag <player> storyboard_freeze_speed:! - flag <player> storyboard_freeze_speed:!
# Marks the script after this task as an atomic sequence, meaning that
# the script either fully completes or is restored back to this point.
# This task does not ensure the atomicity, instead it will block any
# futher executions of the given script (deduced from the queue) until
# storyboard_player_end_atomic_sequence is called, or until the player
# logs off (which basically negates the atomicity). The developer must
# ensure that the script enclosed by the begin and end tasks is atomic.
storyboard_player_begin_atomic_sequence:
debug: false
type: task
definitions: queue|player
script:
- if <[player].flag[storyboard_atomic].if_null[<map[]>].contains[<[queue].script.name>]>:
- queue <[queue]> stop
- stop
- flag <[player]> storyboard_atomic:<[player].flag[storyboard_atomic].if_null[<map[]>].with[<[queue].script.name>].as[<util.time_now>]>
# Ends the atomic sequence above this task. See the sibling task
# storyboard_player_begin_atomic_sequence for more details.
storyboard_player_end_atomic_sequence:
debug: false
type: task
definitions: queue|player
script:
- if !<[player].flag[storyboard_atomic].if_null[<map[]>].contains[<[queue].script.name>]>:
- debug error "Tried ending storyboard atomic sequence <[queue].script.name> before storyboard_player_begin_atomic_sequence was called! (Player UUID <[player].uuid>)"
- stop
- waituntil !<player.has_flag[textbox_state]>
- wait 5t
- flag <[player]> storyboard_atomic:<[player].flag[storyboard_atomic].if_null[<map[]>].exclude[<[queue].script.name>]>
## Internal only! ## Internal only!
storyboard_player_freeze_check: storyboard_player_freeze_check:
debug: false debug: false
@@ -68,3 +99,12 @@ storyboard_player_freeze_check:
on player joins: on player joins:
- if <player.has_flag[storyboard_freeze_speed]>: - if <player.has_flag[storyboard_freeze_speed]>:
- run storyboard_player_unfreeze def.player:<player> - run storyboard_player_unfreeze def.player:<player>
storyboard_player_atomic_sequence_disconnect_handler:
debug: false
type: world
events:
on player quit:
- flag <player> storyboard_atomic:!
on player joins:
- flag <player> storyboard_atomic:!

View File

@@ -4,7 +4,10 @@ tabcomplete_config:
groups: groups:
default: default:
commands: commands:
# please keep these here...
- plugins - plugins
- denizenclickable
# anything else
- sit - sit
- lay - lay
- crawl - crawl