From 9a920d95eebc17d58da03ad1ae20585dc5a41edd Mon Sep 17 00:00:00 2001 From: Major- Date: Fri, 12 Feb 2016 16:29:57 +0000 Subject: [PATCH 1/6] Add support for Events defined in Ruby A slightly complicated and hacky change, because this requires working around JRuby issue 2359. --- data/plugins/bootstrap.rb | 56 +++++++++++++++---- data/plugins/navigation/door/door.rb | 30 ++++++++-- .../src/main/org/apollo/game/model/World.java | 24 ++++---- .../apollo/game/model/event/ProxyEvent.java | 52 +++++++++++++++++ .../game/model/event/ProxyEventListener.java | 52 +++++++++++++++++ .../game/plugin/RubyPluginEnvironment.java | 10 +--- 6 files changed, 189 insertions(+), 35 deletions(-) create mode 100644 game/src/main/org/apollo/game/model/event/ProxyEvent.java create mode 100644 game/src/main/org/apollo/game/model/event/ProxyEventListener.java diff --git a/data/plugins/bootstrap.rb b/data/plugins/bootstrap.rb index 75c90ef9..f36c1493 100644 --- a/data/plugins/bootstrap.rb +++ b/data/plugins/bootstrap.rb @@ -18,6 +18,9 @@ java_import 'org.apollo.game.model.World' java_import 'org.apollo.game.model.entity.Player' java_import 'org.apollo.game.model.event.EventListener' java_import 'org.apollo.game.model.event.PlayerEvent' +java_import 'org.apollo.game.model.event.impl.LoginEvent' +java_import 'org.apollo.game.model.event.ProxyEvent' +java_import 'org.apollo.game.model.event.ProxyEventListener' java_import 'org.apollo.game.model.entity.setting.PrivilegeLevel' java_import 'org.apollo.game.scheduling.ScheduledTask' java_import 'org.apollo.game.plugin.PluginContext' @@ -129,23 +132,26 @@ def schedule(*args, &block) end end -# Defines some sort of action to take upon an message. The following types of -# message are currently valid: +@@proxy_listener = ProxyEventListener.new +$world.listen_for(ProxyEvent.java_class, @@proxy_listener) + +# Defines some sort of action to take upon an message. The following types of message are currently +# valid: # # * :command # * :message # * :button # * Any valid Event, as a symbol in ruby snake_case form. # -# A command takes one or two arguments (the command name and optionally the -# minimum rights level to use it). The minimum rights level defaults to -# STANDARD. The block should have two arguments: player and command. +# A command takes one or two arguments (the command name and optionally the minimum rights level to +# use it). The minimum rights level defaults to STANDARD. The block should have two arguments: +# player and command. # -# An message takes no arguments. The block should have three arguments: the chain -# context, the player and the message object. +# An message takes no arguments. The block should have two arguments: the player and the message +# object. # -# A button takes one argument (the id). The block should have one argument: the -# player who clicked the button. +# A button takes one argument (the id). The block should have one argument: the player who clicked +# the button. def on(type, *args, &block) case type when :command then on_command(args, block) @@ -153,11 +159,41 @@ def on(type, *args, &block) when :button then on_button(args, block) else class_name = type.to_s.camelize.concat('Event') - type = Java::JavaClass.for_name("org.apollo.game.model.event.impl.#{class_name}") + + begin + type = Java::JavaClass.for_name("org.apollo.game.model.event.impl.#{class_name}") + rescue + @@proxy_listener.add(class_name, ProcEventListener.new(block)) + return + end + $world.listen_for(type, ProcEventListener.new(block)) end end +# Contains extension methods for World. +module WorldExtensions + + # Overrides World#submit, providing special-case behaviour for Events defined in Ruby, which + # need to be wrapped in a ProxyEvent, until https://github.com/jruby/jruby/issues/2359 is + # resolved. + def submit(event) + if event.java_class.name.end_with?(".Event", ".PlayerEvent") + event = ProxyEvent.new(event.class.name, event) + end + + super(event) + end + +end + +# Prepend the methods defined in WorldExtensions to World. +class World + prepend WorldExtensions +end + +private + # Defines an action to be taken upon a button press. def on_button(args, proc) fail 'Button must have one argument.' unless args.length == 1 diff --git a/data/plugins/navigation/door/door.rb b/data/plugins/navigation/door/door.rb index 4c7e7797..b3adf58f 100644 --- a/data/plugins/navigation/door/door.rb +++ b/data/plugins/navigation/door/door.rb @@ -1,5 +1,8 @@ java_import 'org.apollo.game.action.DistancedAction' +java_import 'org.apollo.game.model.event.Event' + +private # A distanced action which opens a door. class OpenDoorAction < DistancedAction @@ -24,10 +27,29 @@ class OpenDoorAction < DistancedAction end -# MessageListener for opening and closing doors. +# A PlayerEvent that is fired when a player attempts to open a door. +class OpenDoorEvent < PlayerEvent + attr_reader :door + + def initialize(player, door) + super(player) + @door = door + end + +end + + +# Listens for FirstObjectActions performed on doors. on :message, :first_object_action do |player, message| - if DoorUtil.door?(message.id) - door = DoorUtil.get_door_object(message.position, message.id) - player.start_action(OpenDoorAction.new(player, door)) unless door.nil? + id = message.id + + if DoorUtil.door?(id) + position = message.position + door = DoorUtil.get_door_object(position, id) + + if !door.nil? && $world.submit(OpenDoorEvent.new(player, door)) + player.start_action(OpenDoorAction.new(player, door)) + end end end + diff --git a/game/src/main/org/apollo/game/model/World.java b/game/src/main/org/apollo/game/model/World.java index 27536ab8..09ca1962 100644 --- a/game/src/main/org/apollo/game/model/World.java +++ b/game/src/main/org/apollo/game/model/World.java @@ -7,6 +7,7 @@ import java.util.Map; import java.util.Queue; import java.util.logging.Logger; +import com.google.common.base.Preconditions; import org.apollo.Service; import org.apollo.cache.IndexedFileSystem; import org.apollo.cache.decoder.ItemDefinitionDecoder; @@ -31,8 +32,6 @@ import org.apollo.game.scheduling.Scheduler; import org.apollo.game.scheduling.impl.NpcMovementTask; import org.apollo.util.NameUtil; -import com.google.common.base.Preconditions; - /** * The world class is a singleton which contains objects like the {@link MobRepository} for players and NPCs. It should * only contain things relevant to the in-game world and not classes which deal with I/O and such (these may be better @@ -86,6 +85,11 @@ public final class World { */ private final MobRepository npcRepository = new MobRepository<>(WorldConstants.MAXIMUM_NPCS); + /** + * The Queue of Npcs that have yet to be removed from the repository. + */ + private final Queue oldNpcs = new ArrayDeque<>(); + /** * The {@link MobRepository} of {@link Player}s. */ @@ -100,11 +104,6 @@ public final class World { * The Queue of Npcs that have yet to be added to the repository. */ private final Queue queuedNpcs = new ArrayDeque<>(); - - /** - * The Queue of Npcs that have yet to be removed from the repository. - */ - private final Queue oldNpcs = new ArrayDeque<>(); /** * This world's {@link RegionRepository}. @@ -209,8 +208,8 @@ public final class World { releaseNumber = release; SynchronousDecoder decoder = new SynchronousDecoder(new ItemDefinitionDecoder(fs), - new NpcDefinitionDecoder(fs), new GameObjectDecoder(fs, this), - EquipmentDefinitionParser.fromFile("data/equipment-" + release + "" + ".dat")); + new NpcDefinitionDecoder(fs), new GameObjectDecoder(fs, this), + EquipmentDefinitionParser.fromFile("data/equipment-" + release + "" + ".dat")); decoder.block(); @@ -315,8 +314,7 @@ public final class World { * @param npc The npc. */ public void unregister(final Npc npc) { - Preconditions.checkNotNull(npc, "Npc may not be null."); - + Preconditions.checkNotNull(npc, "Npc must not be null."); oldNpcs.add(npc); } @@ -362,7 +360,7 @@ public final class World { npcMovement.addNpc(npc); } } else { - logger.warning("Failed to register npc, repository capacity reached: [count=" + npcRepository.size() + "]"); + logger.warning("Failed to register npc (capacity reached): [count=" + npcRepository.size() + "]"); } } } @@ -373,7 +371,7 @@ public final class World { private void unregisterNpcs() { while (!oldNpcs.isEmpty()) { Npc npc = oldNpcs.poll(); - + Region region = regions.fromPosition(npc.getPosition()); region.removeEntity(npc); diff --git a/game/src/main/org/apollo/game/model/event/ProxyEvent.java b/game/src/main/org/apollo/game/model/event/ProxyEvent.java new file mode 100644 index 00000000..b59c3dca --- /dev/null +++ b/game/src/main/org/apollo/game/model/event/ProxyEvent.java @@ -0,0 +1,52 @@ +package org.apollo.game.model.event; + +/** + * An {@link Event} that wraps another {@link Event}. + * + * This is a workaround for JRuby issue 2359. This class + * should not be used in Java. + * + * @author Major + */ +public final class ProxyEvent extends Event { + + /** + * The Event created by a Ruby plugin. + */ + private final Event event; + + /** + * The name of the Ruby Event. + */ + private final String name; + + /** + * Creates the ProxyEvent. + * + * @param name The name of the {@link Event} defined in Ruby. + * @param event The Event created by a Ruby plugin. + */ + public ProxyEvent(String name, Event event) { + this.name = name; + this.event = event; + } + + /** + * Gets the name of the {@link Event} defined in Ruby. + * + * @return The name. + */ + public String getName() { + return name; + } + + /** + * Gets the {@link Event} created in a Ruby plugin. + * + * @return The Ruby {@link Event}. + */ + public Event getRuby() { + return event; + } + +} diff --git a/game/src/main/org/apollo/game/model/event/ProxyEventListener.java b/game/src/main/org/apollo/game/model/event/ProxyEventListener.java new file mode 100644 index 00000000..4c973ef4 --- /dev/null +++ b/game/src/main/org/apollo/game/model/event/ProxyEventListener.java @@ -0,0 +1,52 @@ +package org.apollo.game.model.event; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * An {@link EventListener} for {@link ProxyEvent}s. + * + * This is a workaround for JRuby issue 2359. + * + * @author Major + */ +public final class ProxyEventListener implements EventListener { + + /** + * The {@link Map} from Event names to {@link List}s of {@link EventListener}s. + */ + private final Map>> listeners = new HashMap<>(); + + /** + * Registers an {@link EventListener} to this proxy. This method is not type-safe, and must only + * be called from ruby. + * + * @param name The name of the Event. Must not be {@code null}. + * @param listener The {@link EventListener} to add. Must not be {@code null}. + */ + public void add(String name, EventListener listener) { + List> listeners = this.listeners.computeIfAbsent(name, n -> new ArrayList<>(2)); + listeners.add(listener); + } + + @Override + @SuppressWarnings("unchecked") + public void handle(ProxyEvent event) { + List> chain = listeners.get(event.getName()); + + if (chain != null) { + for (EventListener listener : chain) { + Event ruby = event.getRuby(); + listener.handle(ruby); + + if (ruby.terminated()) { + event.terminate(); + break; + } + } + } + } + +} diff --git a/game/src/main/org/apollo/game/plugin/RubyPluginEnvironment.java b/game/src/main/org/apollo/game/plugin/RubyPluginEnvironment.java index 3ec06194..9ac48c67 100644 --- a/game/src/main/org/apollo/game/plugin/RubyPluginEnvironment.java +++ b/game/src/main/org/apollo/game/plugin/RubyPluginEnvironment.java @@ -20,11 +20,6 @@ public final class RubyPluginEnvironment implements PluginEnvironment { */ private final ScriptingContainer container = new ScriptingContainer(); - /** - * The World this RubyPluginEnvironment is for. - */ - private final World world; - /** * Creates and bootstraps the Ruby plugin environment. * @@ -32,7 +27,7 @@ public final class RubyPluginEnvironment implements PluginEnvironment { * @throws IOException If an I/O error occurs during bootstrapping. */ public RubyPluginEnvironment(World world) throws IOException { - this.world = world; + container.put("$world", world); parseBootstrapper(); } @@ -42,7 +37,7 @@ public final class RubyPluginEnvironment implements PluginEnvironment { container.runScriptlet(is, name); } catch (Exception e) { e.printStackTrace(); - throw new RuntimeException("Error parsing scriptlet " + name + "."); + throw new RuntimeException("Error parsing scriptlet " + name + ".", e); } } @@ -61,7 +56,6 @@ public final class RubyPluginEnvironment implements PluginEnvironment { @Override public void setContext(PluginContext context) { container.put("$ctx", context); - container.put("$world", world); } } \ No newline at end of file From 0f32ec92c427c4fcbc7ffaaf74df9da670252372 Mon Sep 17 00:00:00 2001 From: Major- Date: Fri, 12 Feb 2016 16:31:26 +0000 Subject: [PATCH 2/6] Fix HintIconMessage.Type --- .../game/message/impl/HintIconMessage.java | 20 +++++++++---------- .../message/impl/PositionHintIconMessage.java | 15 +++++++------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/game/src/main/org/apollo/game/message/impl/HintIconMessage.java b/game/src/main/org/apollo/game/message/impl/HintIconMessage.java index 6c71c4fc..a6611262 100644 --- a/game/src/main/org/apollo/game/message/impl/HintIconMessage.java +++ b/game/src/main/org/apollo/game/message/impl/HintIconMessage.java @@ -25,24 +25,24 @@ public abstract class HintIconMessage extends Message { CENTER(2), /** - * A HintIcon that hovers north over a Position. + * A HintIcon that hovers west over a Position. */ - NORTH(3), - - /** - * A HintIcon that hovers south over a Position. - */ - SOUTH(4), + WEST(3), /** * A HintIcon that hovers east over a Position. */ - EAST(5), + EAST(4), /** - * A HintIcon that hovers west over a Position. + * A HintIcon that hovers south over a Position. */ - WEST(6), + SOUTH(5), + + /** + * A HintIcon that hovers north over a Position. + */ + NORTH(6), /** * A HintIcon that hovers over a Player. diff --git a/game/src/main/org/apollo/game/message/impl/PositionHintIconMessage.java b/game/src/main/org/apollo/game/message/impl/PositionHintIconMessage.java index 428f6806..763aaec6 100644 --- a/game/src/main/org/apollo/game/message/impl/PositionHintIconMessage.java +++ b/game/src/main/org/apollo/game/message/impl/PositionHintIconMessage.java @@ -1,8 +1,7 @@ package org.apollo.game.message.impl; -import org.apollo.game.model.Position; - import com.google.common.base.Preconditions; +import org.apollo.game.model.Position; /** * A {@link HintIconMessage} which displays a hint over a Position. @@ -16,20 +15,20 @@ public final class PositionHintIconMessage extends HintIconMessage { /** * Tests if the specified Type if valid for a Position HintIcon. - * + * * @param type The Type to test. * @return The Type if it was valid. */ private static Type testType(Type type) { Preconditions.checkArgument(type != Type.NPC && type != Type.PLAYER, - "Hint icons over a Position may not have a type of Player or Npc."); + "Hint icons over a Position may not have a type of Player or Npc."); return type; } /** * Creates a new {@link PositionHintIconMessage} which resets the current * HintIcon. - * + * * @return The new {@link PositionHintIconMessage}, never {@code null}. */ public static PositionHintIconMessage reset() { @@ -48,7 +47,7 @@ public final class PositionHintIconMessage extends HintIconMessage { /** * Constructs a new {@link PositionHintIconMessage}. - * + * * @param type The Type of the HintIcon. * @param position The Position of the hint icon. * @param height The display height of the hint icon. @@ -61,7 +60,7 @@ public final class PositionHintIconMessage extends HintIconMessage { /** * Gets the Position of the HintIcon. - * + * * @return The Position of the HintIcon. */ public Position getPosition() { @@ -70,7 +69,7 @@ public final class PositionHintIconMessage extends HintIconMessage { /** * Gets the display height of the HintIcon. - * + * * @return The display height of the HintIcon. */ public int getHeight() { From 8e6760c617ae6a699dfe26d090a3694bb64d2a42 Mon Sep 17 00:00:00 2001 From: Major- Date: Fri, 12 Feb 2016 17:21:45 +0000 Subject: [PATCH 3/6] Only fire door events when the door is reached --- data/plugins/navigation/door/door.rb | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/data/plugins/navigation/door/door.rb b/data/plugins/navigation/door/door.rb index b3adf58f..e0ee818b 100644 --- a/data/plugins/navigation/door/door.rb +++ b/data/plugins/navigation/door/door.rb @@ -16,8 +16,11 @@ class OpenDoorAction < DistancedAction end def executeAction - mob.turn_to(@door.position) - DoorUtil.toggle(@door) + if $world.submit(OpenDoorEvent.new(mob, @door)) + mob.turn_to(@door.position) + DoorUtil.toggle(@door) + end + stop end @@ -44,12 +47,8 @@ on :message, :first_object_action do |player, message| id = message.id if DoorUtil.door?(id) - position = message.position - door = DoorUtil.get_door_object(position, id) - - if !door.nil? && $world.submit(OpenDoorEvent.new(player, door)) - player.start_action(OpenDoorAction.new(player, door)) - end + door = DoorUtil.get_door_object(message.position, id) + player.start_action(OpenDoorAction.new(player, door)) unless door.nil? end end From 70c0856df804db917195192e600c10214afe416b Mon Sep 17 00:00:00 2001 From: Major- Date: Fri, 12 Feb 2016 17:31:17 +0000 Subject: [PATCH 4/6] Fix text-only dialogues with continues --- data/plugins/dialogue/dialogue.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/data/plugins/dialogue/dialogue.rb b/data/plugins/dialogue/dialogue.rb index aba43f4b..dd8d3666 100644 --- a/data/plugins/dialogue/dialogue.rb +++ b/data/plugins/dialogue/dialogue.rb @@ -254,7 +254,7 @@ class Dialogue def options @options.dup end - + # Sets the precondition of this dialogue. def precondition(player=nil, &block) @precondition = block unless block.nil? @@ -413,8 +413,11 @@ end # Sends a dialogue displaying only text. def send_text_dialogue(player, dialogue) - title = dialogue.title - send_generic_dialogue(player, dialogue, title, TEXT_DIALOGUE_IDS) + text = dialogue.text + dialogue_id = TEXT_DIALOGUE_IDS[text.size - 1] + + text.each_with_index { |line, index| set_text(player, dialogue_id + 1 + index, line) } + player.interface_set.open_dialogue(ContinueDialogueAdapter.new(player, dialogue.options[0]), dialogue_id) end # Sends a dialogue displaying the player's head. @@ -555,4 +558,4 @@ GLYPH_SPACING = [ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, # Gets the width of a single character. def get_width(char) return GLYPH_SPACING[char.ord] -end \ No newline at end of file +end From 9e20ecfe3903547d7b2292616220e823ebda166d Mon Sep 17 00:00:00 2001 From: Major- Date: Fri, 12 Feb 2016 18:46:14 +0000 Subject: [PATCH 5/6] Fix 377 FlashTabInterfaceMessageEncoder --- .../game/release/r377/FlashTabInterfaceMessageEncoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/game/src/main/org/apollo/game/release/r377/FlashTabInterfaceMessageEncoder.java b/game/src/main/org/apollo/game/release/r377/FlashTabInterfaceMessageEncoder.java index 3c0da5b2..8fce05d2 100644 --- a/game/src/main/org/apollo/game/release/r377/FlashTabInterfaceMessageEncoder.java +++ b/game/src/main/org/apollo/game/release/r377/FlashTabInterfaceMessageEncoder.java @@ -15,7 +15,7 @@ public final class FlashTabInterfaceMessageEncoder extends MessageEncoder Date: Sat, 13 Feb 2016 16:26:51 +0000 Subject: [PATCH 6/6] Fix many issues with the Tutorial Island plugin Amongst other things, this: * Stops the player from trying to leave the Runescape Guide's house if they have yet to speak to him. * Fixes the hint icon for both the Runescape Guide and the door. * Ensures all files pass rubocop. * Generally improves the code throughout the plugin. --- .../plugins/location/tutorial-island/guide.rb | 79 ++++++++++++++----- .../location/tutorial-island/instructions.rb | 3 +- .../location/tutorial-island/plugin.xml | 3 +- .../location/tutorial-island/stages.rb | 12 +-- .../location/tutorial-island/survival.rb | 6 +- 5 files changed, 73 insertions(+), 30 deletions(-) diff --git a/data/plugins/location/tutorial-island/guide.rb b/data/plugins/location/tutorial-island/guide.rb index a03de11e..74778a48 100644 --- a/data/plugins/location/tutorial-island/guide.rb +++ b/data/plugins/location/tutorial-island/guide.rb @@ -9,27 +9,48 @@ java_import 'org.apollo.game.model.Position' private -# The ids of tabs that are displayed when the player has yet to start the tutorial. -INITIAL_TABS = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2449, 904, -1, -1] +# Contains constants used during the Runescape Guide part of Tutorial Island. +module GuideConstants -# The character design interface id. -CHARACTER_DESIGN = 3559 + # The Runescape Guide Npc. + RUNESCAPE_GUIDE = spawn_npc name: :runescape_guide, x: 3093, y: 3107 -# The Runescape guide Npc -@runescape_guide = spawn_npc name: :runescape_guide, x: 3093, y: 3107 + # The character design interface id. + CHARACTER_DESIGN_INTERFACE = 3559 + + # The id of the door of the house new players spawn in. + DOOR_ID = 3014 + + # The Position of the door of the house new players spawn in. + DOOR_POSITION = Position.new(3098, 3107) + + # The HintIconMessage sent to display a hint arrow above the door of the house new players spawn + # in. + DOOR_HINT = PositionHintIconMessage.new(HintIconMessage::Type::WEST, DOOR_POSITION, 120) + + # The ids of tabs that are displayed when the player has yet to start the tutorial. + INITIAL_TABS = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2449, 904, -1, -1].freeze + + # The HintIconMessage sent to remove a hint arrow from above the door. + RESET_DOOR_HINT = PositionHintIconMessage.reset + + # The HintIconMessage sent to remove a hint arrow from an Npc. + RESET_NPC_HINT = MobHintIconMessage.reset(EntityType::NPC) + +end # Sends the appropriate data to the client when the player logs in to the game. on :login do |_event, player| if player.in_tutorial_island && player.privilege_level != RIGHTS_ADMIN TutorialInstructions.show_instruction(player) - INITIAL_TABS.each_with_index do |tab, index| + GuideConstants::INITIAL_TABS.each_with_index do |tab, index| player.send(SwitchTabInterfaceMessage.new(index, tab)) end if player.tutorial_island_progress == :not_started - show_hint_icon(player) - player.interface_set.open_window(CHARACTER_DESIGN) + player.interface_set.open_window(GuideConstants::CHARACTER_DESIGN_INTERFACE) + player.send(MobHintIconMessage.create(GuideConstants::RUNESCAPE_GUIDE)) end end end @@ -95,23 +116,43 @@ conversation :tutorial_runescape_guide do close do |player| if player.tutorial_island_progress < :runescape_guide_finished - reset_hint_icon(player) - # TODO: Maybe move this, define a constant for the Position and height - player.send(PositionHintIconMessage.new(HintIconMessage::Type::SOUTH, Position.new(3097, 3107), 120)) + player.send(GuideConstants::RESET_NPC_HINT) + + player.send(GuideConstants::DOOR_HINT) player.tutorial_island_progress = :runescape_guide_finished end TutorialInstructions.show_instruction(player) end end + + # The dialogue displayed if the player attempts to leave the Runescape Guide's house before they + # have spoken to him. + dialogue :talk_to_guide do + type :text + + text 'You need to talk to the Runescape Guide before you are allowed to proceed through this '\ + 'door.' + + close do |player| + TutorialInstructions.show_instruction(player) + end + end + end -# Enables the hint icon above the Runescape guide. -def show_hint_icon(player) - player.send(MobHintIconMessage.create(@runescape_guide)) +on :open_door do |event, player| + door = event.door + + if player.in_tutorial_island && door.position.equals(GuideConstants::DOOR_POSITION) + if player.tutorial_island_progress < :runescape_guide_finished + send_dialogue(player, get_dialogue(:tutorial_runescape_guide, :talk_to_guide)) + event.terminate + elsif player.tutorial_island_progress == :runescape_guide_finished + player.tutorial_island_progress = :moving_around + player.send(GuideConstants::RESET_DOOR_HINT) + TutorialInstructions.show_instruction(player) + end + end end -# Resets the hint icon. -def reset_hint_icon(player) - player.send(MobHintIconMessage.reset(EntityType::NPC)) -end diff --git a/data/plugins/location/tutorial-island/instructions.rb b/data/plugins/location/tutorial-island/instructions.rb index f4c7b4bc..49931ee4 100644 --- a/data/plugins/location/tutorial-island/instructions.rb +++ b/data/plugins/location/tutorial-island/instructions.rb @@ -18,7 +18,8 @@ module TutorialInstructions when :given_axe then :viewing_items when :cut_tree then :cut_tree when :cutting_tree then :please_wait - else fail 'No dialogue for current stage #{progress} exists.' + + else raise "No dialogue for current stage #{progress} exists." end dialogue = instructions.part(name) diff --git a/data/plugins/location/tutorial-island/plugin.xml b/data/plugins/location/tutorial-island/plugin.xml index 2306c8ec..72537461 100644 --- a/data/plugins/location/tutorial-island/plugin.xml +++ b/data/plugins/location/tutorial-island/plugin.xml @@ -17,7 +17,8 @@ dialogue + door entity-spawning quest - \ No newline at end of file + diff --git a/data/plugins/location/tutorial-island/stages.rb b/data/plugins/location/tutorial-island/stages.rb index 5e691cad..b5ac6cca 100644 --- a/data/plugins/location/tutorial-island/stages.rb +++ b/data/plugins/location/tutorial-island/stages.rb @@ -2,15 +2,15 @@ private # The array of stages in tutorial island. -STAGES = [] +@stages = [] # The stages that are used when interacting with the Runescape Guide. RUNESCAPE_GUIDE = [:not_started, :talk_to_people, :go_through_door, :runescape_guide_finished, - :moving_around] -STAGES.concat(RUNESCAPE_GUIDE) + :moving_around].freeze +@stages.concat(RUNESCAPE_GUIDE) # The stages that are used when interacting with the Survival Expert. -SURVIVAL_EXPERT = [:given_axe, :cut_tree, :cutting_tree] -STAGES.concat(SURVIVAL_EXPERT) +SURVIVAL_EXPERT = [:given_axe, :cut_tree, :cutting_tree].freeze +@stages.concat(SURVIVAL_EXPERT) -quest :tutorial_island, STAGES +quest :tutorial_island, @stages diff --git a/data/plugins/location/tutorial-island/survival.rb b/data/plugins/location/tutorial-island/survival.rb index 1f8d04bf..863110b6 100644 --- a/data/plugins/location/tutorial-island/survival.rb +++ b/data/plugins/location/tutorial-island/survival.rb @@ -42,7 +42,7 @@ conversation :tutorial_surivival_expert do ' tricks. First off we\'re going to start with the most basic survival skill of all: '\ 'making a fire.' - close(&:add_survival_items) + close { |player| add_survival_items(player) } end dialogue :hello_again do @@ -54,7 +54,7 @@ conversation :tutorial_surivival_expert do text 'Hello again. I\'m here to teach you a few survival tips and tricks. First off we\'re '\ 'going to start with the most basic survival skill of all: making a fire.' - close(&:add_survival_items) + close { |player| add_survival_items(player) } end # The dialogue displayed when the Survival Expert gives the player a bronze axe. @@ -123,7 +123,7 @@ def add_survival_items(player) unless inventory.contains(SurvivalConstants::TINDERBOX) inventory.add(SurvivalConstants::TINDERBOX) - dialogue = (dialogue == :give_bronze_axe) ? :give_axe_and_tinderbox : give_tinderbox + dialogue = (dialogue == :give_bronze_axe) ? :give_axe_and_tinderbox : :give_tinderbox end send_dialogue(player, get_dialogue(:tutorial_surivival_expert, dialogue))