Anmelden

Archiv verlassen und diese Seite im Standarddesign anzeigen : (RGSS1) Mordechajs Scripting-Fragen



Mordechaj
08.01.2017, 20:08
EDIT: Ich erwarte, immer mal wieder mit Fragen hier anzukommen; es wird wohl unpraktisch sein, dafür jedes Mal ein neues Thema zu eröffnen. Deshalb widme ich diesen Thread einfach mal um.


Ich teste gerade folgendes Script aus.


# Code by Mobius XVI
# Based on SirBilly's Player Turn & Move script for VX Ace
# Requested by Crydsch
# Causes player to turn before moving
# (Mord) ++ Waits are decreased from 7 to 4 ++ (Mord)
class Game_Player < Game_Character
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
@wait_time = 0
super
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
# Alias old method
alias mobius_turn_step_update update
# Redefine update
def update
# Decrease wait time
@wait_time -= 1
# Remember whether or not moving in local variables
last_moving = moving?
# If moving, event running, move route forcing, and message window
# display are all not occurring
unless moving? or $game_system.map_interpreter.running? or
@move_route_forcing or $game_temp.message_window_showing
# Move player in the direction the directional button is being pressed
case Input.dir4
# When Down
when 2
if Input.trigger?(Input::DOWN) and self.direction == 2
move_down
elsif Input.trigger?(Input::DOWN)
@wait_time = 4
turn_down
elsif @wait_time <= 0
move_down
end
# When Left
when 4
if Input.trigger?(Input::LEFT) and self.direction == 4
move_left
elsif Input.trigger?(Input::LEFT)
@wait_time = 4
turn_left
elsif @wait_time <= 0
move_left
end
# When right
when 6
if Input.trigger?(Input::RIGHT) and self.direction == 6
move_right
elsif Input.trigger?(Input::RIGHT)
@wait_time = 4
turn_right
elsif @wait_time <= 0
move_right
end
# When Up
when 8
if Input.trigger?(Input::UP) and self.direction == 8
move_up
elsif Input.trigger?(Input::UP)
@wait_time = 4
turn_up
elsif @wait_time <= 0
move_up
end
end
end
# Remember coordinates in local variables
last_real_x = @real_x
last_real_y = @real_y
super
# If character moves down and is positioned lower than the center
# of the screen
if @real_y > last_real_y and @real_y - $game_map.display_y > CENTER_Y
# Scroll map down
$game_map.scroll_down(@real_y - last_real_y)
end
# If character moves left and is positioned more let on-screen than
# center
if @real_x < last_real_x and @real_x - $game_map.display_x < CENTER_X
# Scroll map left
$game_map.scroll_left(last_real_x - @real_x)
end
# If character moves right and is positioned more right on-screen than
# center
if @real_x > last_real_x and @real_x - $game_map.display_x > CENTER_X
# Scroll map right
$game_map.scroll_right(@real_x - last_real_x)
end
# If character moves up and is positioned higher than the center
# of the screen
if @real_y < last_real_y and @real_y - $game_map.display_y < CENTER_Y
# Scroll map up
$game_map.scroll_up(last_real_y - @real_y)
end
# If not moving
unless moving?
# If player was moving last time
if last_moving
# Event determinant is via touch of same position event
result = check_event_trigger_here([1,2])
# If event which started does not exist
if result == false
# Disregard if debug mode is ON and ctrl key was pressed
unless $DEBUG and Input.press?(Input::CTRL)
# Encounter countdown
if @encounter_count > 0
@encounter_count -= 1
end
end
end
end
# If C button was pressed
if Input.trigger?(Input::C)
# Same position and front event determinant
check_event_trigger_here([0])
check_event_trigger_there([0,1,2])
end
end
end
end
# Class End

Was das Script tut, ist bei Antippen der entsprechenden Richtungstaste den Character erst in die entsprechende Richtung zu drehen und erst danach die Bewegung um ein Tile auszuführen. Der dafür notwendige wait-Befehl kommt mir nun aber bei einigen Gameplay-Elementen in die Quere. Ich würde gern eine Bedingung einfügen (Script-Befehl oder Switch), die das Script deaktiviert, bis es wieder aktiviert wird, oder eben umgekehrt. Wie vielleicht schon am Code zu erkennen ist, habe ich das Script nur kopiert und die @wait_time-Werte geändert. Zu viel mehr bin ich coding-mäßig leider auch nicht in der Lage.

Lässt sich das vielleicht recht einfach umsetzen? Ob mir jemand weiterhelfen könnte? ^_^

Kelven
11.01.2017, 08:57
Ich bin kein Ruby-Experte, aber was du versuchen könntest:


# If moving, event running, move route forcing, and message window
# display are all not occurring
unless moving? or $game_system.map_interpreter.running? or
@move_route_forcing or $game_temp.message_window_showing
# Move player in the direction the directional button is being pressed
if $game_switches[hier die Nummer vom Switch einsetzen]
case Input.dir4
# When Down
when 2
if Input.trigger?(Input::DOWN) and self.direction == 2
move_down
elsif Input.trigger?(Input::DOWN)
@wait_time = 4
turn_down
elsif @wait_time <= 0
move_down
end
# When Left
when 4
if Input.trigger?(Input::LEFT) and self.direction == 4
move_left
elsif Input.trigger?(Input::LEFT)
@wait_time = 4
turn_left
elsif @wait_time <= 0
move_left
end
# When right
when 6
if Input.trigger?(Input::RIGHT) and self.direction == 6
move_right
elsif Input.trigger?(Input::RIGHT)
@wait_time = 4
turn_right
elsif @wait_time <= 0
move_right
end
# When Up
when 8
if Input.trigger?(Input::UP) and self.direction == 8
move_up
elsif Input.trigger?(Input::UP)
@wait_time = 4
turn_up
elsif @wait_time <= 0
move_up
end
end
else
# Bewegung ohne Drehen
case Input.dir4
when 2
move_down
when 4
move_left
when 6
move_right
when 8
move_up
end
end
end
# Remember coordinates in local variables

Mit $game_switches[Nummer] greift man auf die Standard-Switches vom Maker zu. Die Methode fragt ab, ob der Switch an ist und falls ja, wird zuerst die Drehung ausgeführt, falls nein, bewegt sich die Figur ganz normal.

Cepanks
11.01.2017, 17:57
Vermutlich könnte man auch bei aktiviertem Switch einfach die ursprüngliche update-Methode von Game_Player aufrufen, der Originalautor hat ja ein Alias erstellt.

# Alias old method
alias mobius_turn_step_update update
# Redefine update
def update
if $game_switches[hier die Nummer vom Switch einsetzen]
# Run original Game_Player#update instead
mobius_turn_step_update
return
end
# restlicher Code...

Mordechaj
12.01.2017, 11:32
Ich danke euch beiden sehr, es klappt einwandfrei! :)

Mordechaj
09.12.2017, 13:16
So. Ich habe mal wieder ein Anliegen, und zwar diesmal ein wahrscheinlich ungleich schwierigeres als zuvor.

Ich möchte gern, und zwar je nach Event entschieden, Folgen von Show-Message-Befehlen so einrichten, dass der Spieler dabei immer noch Kontrolle über den Char hat, und die Message abbrechen kann, indem er sich zu weit vom Event wegbewegt. (A la Chrono Trigger, sagt man mir.)

Zum Beispiel also: Der Spieler quatscht irgendnen NPC an, weil ... das macht man halt so. Und der fängt jetzt an seine Lebensgeschichte von der Wiege bis in den Sarg zu erzählen, und den Spieler nervt das. Traditionell muss er jetzt aber Message Box für Message Box einzeln nacheinander wegdrücken und läuft dabei Gefahr, den NPC am Ende nochmal zu aktivieren, der dann wieder seine ganze Lebensgeschichte erzählt. Stattdessen soll der Spieler sich frei bewegen können und einfach ein paar Tiles weiterlaufen, um dem Opi nicht mehr zuhören zu müssen.

Es gibt bereits ein Script, das das kann, nämlich Wachungas Multiple Message Windows in der Version von Heretic86 (Code von v1.56 im Spoiler).


#-----------------------------------------
#--- ---
#--- Multiple Message Windows ---
#------- HERETIC REVISION ------------
#------- Version 1.56 ------------
#------- ------------
#-----------------------------------------
#
# NO LONGER REQUIRES SDK. It will work fine with or without the SDK now!
#
# *NOTE* - This script should go ABOVE the CATERPILLAR SCRIPT
#
#
#
#==============================================================================
# ** Multiple Message Windows (SDK and Non SDK Bundle!)
#------------------------------------------------------------------------------
# Wachunga
# 1.5
# 2006-11-17
#==============================================================================

=begin


Version History: (Heretic)
1.56 - Sunday, April 19th, 2015
- Fixed a minor issue with Sticky
- Fixed an issue with \b and \i causing delays when Letter by Letter is off
- Fixed a bug with set_max_dist causing List Termination when an NPC
moved away from the Player.
- Fixed a bug where \$ and \% caused a Crash in Non Floating Windows
- Added code for compatability with Sprite Zooming and Floating for
both Heretic's Vehicles and Heretic's Rotate, Zoom, and Pendulums
- Added code for compatability with Heretic's Loop Maps
- Added "comma_skip_delay" so players can speed through dialogue
- Added "save = true / false" Option for MMW Settings in set_max_dist(N)
- Added "clear_max_dist" Option for NPCs and Signs with Cutscenes

--- SET MAX DIST and CLEAR MAX DIST ---

Players tend to get BORED with Dialogue Heavy NPCs, and the easiest way to
prevent Players from quitting the game is to allow them to WALK AWAY from
an NPC while they are talking. When the Human Player gets trapped into any
very long dialogue from RANDOM NPCs, that is when they get BORED the most
and you run the risk of them quitting your game as a result. Important
NPC Character Dialogue is one thing, but for Towns Folk and Signs and
other places you've written OPTIONAL DIALOGUE, the best thing to do is
to allow the Player to WALK AWAY. Initially, this will cause you some
issues if you need to change MMW Settings for the course of that NPC
or Event Dialogue, such as Fonts or Floating or Speed. What happens
is once those MMW Settings are changed, they are used on the Next Event
that is executed by the Player. Thus, set_max_dist(N) was implemented
to allow the Player to WALK AWAY and not cause any changes to what you
want as your "Normal MMW Settings" on the Next Event.

The command 'set_max_dist(N, save = true[default] / false)' is most useful
on Events where you change a MMW Setting during Event Execution so if the
Player walks away, your MMW Settings are automatically restored. This
helps to simplify your NPCs and Signs so you don't have to configure all
your MMW Settings for each and every event, only the ones you want to
change during the execution of that event. The trouble is by setting
a Maximum Distance (in Tiles), with an NPC that takes control of the
Player and moves them to more than the Maximum Distance you specify, the
Event will Exit Event Execution. Thus, you can CLEAR the Maximum Distance
on an Event by running a script 'clear_max_dist' which will not affect
any Saved MMW Settings, but will allow you to move the Player or Event
to any distance from each other. If you need to do this, also use
the feature 'message.move_during = false' while doing whatever you do
at a Distance from the Event.

Example NPC or Sign where Player moves away from Event:

@>set_max_dist(2)
@>\$Let me show you something!
@>(Change MMW Setting, stored by set_max_dist(2))
@>clear_max_dist # No MMW changes, but now NO Max Distance!
@>message.move_during = false
@>(Move Player away from NPC / Sign / Event)
@>(More Text, but at a distance greater than your Max Dist) # Cant Walk Away
@>(Other move commands)
@>(Move back to Sign)
@>message.move_during = true # (Allow walking away again)
@>set_max_dist(2, save = false) # (Doesnt change the stored MMW Settings)
@>(More Text) # Here, Player can walk away again!

When Events dont change any of the MMW Settings at all, then set_max_dist(N)
is still useful because while Messages are displayed, Touch Events do
not Trigger at all. Thus, calling set_max_dist(N) helps to make sure that
the Touch Events still trigger properly.



Example Typical NPC:

(NPC has a Move Route to move at Random)

set_max_dist(2)
@>Set Move Route: Turn Toward Player (Repeat)
@>\$\F+Hi there! This is some text.\F-
@>\$\F+This is more text.\F-
@>\$\F+Even more text where the player gets bored and walks away.\F-
@>Set Move Route: Turn Toward Player (No Repeat)

Player moves away more than Two Tiles from NPC and Dialogue Window closes.



Example Typical Sign (MMW Settings are changed)

(Event does not move and has Direction Fix set to ON)

set_max_dist(1)
@>\P[0]The \bSign\b says:
@>Script: message.floating = false
message.letter_by_letter = false
@>(Sign Text)
@>Script: message.floating = true
message.letter_by_letter = true

Here, the MMW Settings are changed. Change them back at the end of the
list of Event Commands. If the Player WALKS AWAY from the sign, the
stored MMW Settings are recalled and helps save you a TON of work because
the next Event will use the recalled MMW Settings. As a result, you don't
have to set message.floating = true on EVERY Event. Just change the stuff
you need to change for that part of the NPC or Event Dialogue.


When using REPOSITION ON TURN, you need to have several things:
- First, save your MMW Settings and set Max Dist with "set_max_dist(N)"
- Next, your "N" or Distance must be higher than 1
- Turn the Event toward the Player and turn on Repeat
- Run your Dialogue
- Clear the Repeating Move Route on the Event with another Set Move Route

If you don't want the NPC to "pay attention" to the Player, you can
simply use an "N" value of 1 so as soon as the Player steps even
adjacently, the Message Bubble will close. I like using a value of 2
because it implies the NPC is "paying attention" to the actions
of the Player. Repeating Move Routes will also RESET if the Player
walks away, but be sure to use a Non Repeating Move Route as the LAST
of the List of Event Commands, otherwise, the Event will "get stuck"
always paying attention to the Player.



1.55
- Removed SDK Dependancy
- Script will work either WITH or WITHOUT the SDK now automatically
* NOTE: Different methods are defined and replaced depending on whether
or not the SDK is installed or not.

1.54
- Added Option for Variable Text with \v[Tn]
$game_system.mmw_text[0] = "Hello World!"
In the "Show Text..." box, put in \v[T0] to display Hello World!

- Added Player Sticky

This means that Event and Player Message Stickyness are now independant.
When the player moves around, I tried to reposition the Message Bubble to
maximize player visibility by placing the Message Bubble out of where I
think they are intending to go. For example, when the player presses
Right, the Players Character faces to the Right, so in order to make sure
the Player can see where they are trying to go, the Message Bubble is
repositioned to the left of the Players Character.

Repositioning can cause some issues with making some Messages off screen
and unable to be read. In order to work around this, Sticky was added to
favor the Top and Bottom positions. A Sticky Message can start anywhere,
but once it is moved, it will try to stick to the Top or the Bottom because
position on the Left and Right causes some long messages to go offscreen
and become unreadable.

That is what Sticky means.

- $game_player.sticky is set to FALSE by Default, and will RESET to FALSE
at the end of Event Execution.

- Added Windowskin as a Saved Variable. That way if you walk away from
a sign that has a different Windowskin, that Windowskin will also be
reset when you walk away from a sign before the Event complets its list
of commands to execute.

- Fixed a Visual Bug where a Non Floating Message Window would change
the Windowskin while fading out. Redefined Window_Base update to
fix this bug.

- Changed set_max_dist to allow a Zero Distance. This is useful for
Passable Events.

- Fixed some Visual Glitches caused by other features I added becoming
read in characters in version 1.04 of the engine. 1.02 seems to
work just fine and caused me to miss these.

- Fixed a bug with set_max_dist(N). Cutscenes where the Player is moved
around by Event Commands would cause Event to stop executing. Changed
to require move_during to be True and $game_player.move_route_forcing
to be False for Message Windows to automatically close. So if you
set message.move_during = false, a Cutscene is assumed and Windows
will not be closed.

1.53 (Heretic)

- Added SOUNDS while text is printing out. Think Banjo Kazooie

What you NEED to know: When an Event has finished its commands, or if
you walk away from it, your Sound Settings will RESET. This is intentional.
It was implemented to save you work. Although it is quite possible to do,
the way a non scripter would end up trying to do this would be tremendous.
Thus, I did it for you.

There are several things you should know about SOUNDS.

#1 - Sound does NOT play for every single character. It plays a sound every
several characters. Im not psychic, so I dont know what sound you will
be using, if any at all. Because of this, the duration of that sound might
be different than some of the samples I've included. As a result, you may
decide that it sounds better to play your sound every character or every 5
characters. Thus, it is totally optional. The option is called
message.sound_frequency

#2 - It only plays sounds for Letters and Numbers, so non alphanumeric
characters do not play sounds. This includes spaces, and special characters
used for any of the message script options. This is just something that I
thought you should be aware of.

#3 - The Audio File you use needs to be imported into Sound Effects, under
Materialbase -> Audio/SE (its the one at the very bottom of the list).
I ran into a couple of files that caused both the editor and the game to
crash when I tried to play them, so you may need to convert problematic
audio files to a different format.

Several of the files I've imported I got from FlashKit.com. Not all of
these files were compatible. Other than that, it does have a good selection
of royalty free sound files.

http://www.flashkit.com/soundfx/

I considered setting up sound properties for each event and NPC, but decided
to pass on that because it caused more problems than it appeared to solve.
Also being considered are options to change the sound properties from within
the text itself. The same way as you can make characters bold, delay, or
other features already built into the script. If there is interest, I will
put them in, but for now, once a window starts to display its text, there
arent any options to change it until the next message window is displayed.

----- SOUND OPTIONS -----

These can be changed at any time with scripts.

message.sound = true / false # Enables or Disables Text Sounds
message.sound_audio = '001-System01' # Audio SE (in DB) to play
message.sound_volume = 80 # Text Sound Volume
message.sound_pitch = 80 # Text Sound Pitch
message.sound_pitch_range = 20 # How Much to vary the Pitch
message.sound_vary_pitch = true # Whether to Vary the Pitch or not
message.sound_frequency = 2 # Plays a sound this many letters


1.52 (Heretic)

- Added ability to "Auto Close" Non Floating Messages based on proximity
to the triggered event. You'll have to set a script for Every Event
you want this to occur on.
"set_max_dist(n)" where n the Distance in Steps. One is Minimum.

Notes: set_max_dist will SAVE all of your MMW settings, and in the
event that the event execution is terminated early, it will restore
these settings you originally had. This is done automatically in
order to prevent you from having to do unnecessary work. I find
it was most useful for Signs where you might set message.floating = false
which would have resulted in you needing to put in floating = true
for every other event. It just saves you work. SO if you do want
to have a more permanent adjustment to your MMW settings, call them
BEFORE you call "set_max_dist(n)"

If you expect the event to play out in its entirety, consider
using message.move_during = false. This is intended to allow the event
to NOT COMPLETE all the entries in an event by allowing the player to
walk away and close the window.

- Added the ability to "flip" a Message Bubble (non floating) on NPC Turn.

This was done to allow the player to see where they are going. When
the player moves around, they need to be able to see where they are
going, and a Message Bubble can sometimes get in their way. I also
set it up so that once an NPC is moved (not turned), this feature
turns itself off because it assumes a Cutscene.

This requires several things to work.
#1: reposition_on_turn is enabled (message.reposition_on_turn = true)
#2: NPC is set to turn_toward_player(repeat)
#3: NPC has NOT been moved (there are ways around this)
#4: Message Window is Auto Oriented using \$ or \%

If you feel like re-enabling this feature after an NPC has been
moved, you can use a Move Route Script @allow_flip = true for
that NPC.

- Added the Auto Flipping Message Windows to be "Sticky"

What this means is that when a Message Window is repositioned, the
next window will appear in the same location as the previous window.

Change it with message.sticky = true / false

1.51b

- Added \G+ and \G- to allow Gold Window to be at the Top or Bottom
of the screen. \G can still be used. It just positions opposite
of where the player is at. Just a bit more control over the
position of the Gold Window.

1.51a

- By Request, added the \F* option to put the "Other Foot Forward"

1.51

- Added \* option to display next message at ANY time

- Added \$ and \$ options to Auto Orient Message Bubbles relative to
the direction the Speaker is facing.

- Added "Foot Forward" commands available with \F+ and \F-

- Added automatic features to reset a Speaking NPC to its original Stance
and make it Continue its Move Route.

*NOTE* - The links provided in the comments may be out of date.

This custom message system adds numerous features on top of the default
message system, the most notable being the ability to have multiple message
windows open at once. The included features are mostly themed around turning
messages into speech (and thought) balloons, but default-style messages are
of course still possible.

Note:
This version of the script uses the SDK, available from:
http://www.rmxp.org/forums/showthread.php?t=1802

FEATURES

New in 1.5:
* \C[#ffffff] for hexadecimal color
* \C for return to default color
* display name of item, weapon, armor or skill
* \N[In] = display name of item with id n (note the "I")
* \N[Wn] = display name of weapon with id n (note the "W")
* \N[An] = display name of armor with id n (note the "A")
* \N[Sn] = display name of skill with id n (note the "S")
* display icon of item, weapon, armor or skill
* \I[In] = display icon of item with id n (note the "I")
* \I[Wn] = display icon of weapon with id n (note the "W")
* \I[An] = display icon of armor with id n (note the "A")
* \I[Sn] = display icon of skill with id n (note the "S")
* display icon and name of item, weapon, armor or skill
* \I&N[In] = display icon and name of item with id n (note the "I")
* \I&N[Wn] = display icon and name of weapon with id n (note the "W")
* \I&N[An] = display icon and name of armor with id n (note the "A")
* \I&N[Sn] = display icon and name of skill with id n (note the "S")
* new windowskins available
* speech windowskin now definable separately from default windowskin
* fixed bold bug where degree sign would occasionally appear
* input number window now shares parent window's font
* changed \Var[n] back to default of \V[n]

New in 1.1:
* message.autocenter for automatically centering text within messages
* \N[en] for displaying name of enemy with id n (note the "e")
* \MAP for displaying the name of the current map

At a glance:
* multiple message windows
* speech balloons
* position over player/event (follows movement and scrolling)
* optional message tail (for speech or thought balloons)
* can specify location relative to player/event (up, down, left, right)
* thought balloons
* can use different windowskin, message tail and font color
* letter-by-letter mode
* variable speed (and delays)
* skippable on button press
* autoresize messages
* player movement allowed during messages
* if speaker moves offscreen, message closes (like ChronoTrigger)
* everything also works during battle
* settings configurable at anytime

Full list of options:

(Note that all are case *insensitive*.)

=============================================================================
Local (specified in message itself and resets at message end)
=============================================================================
- \L = letter-by-letter mode toggle
- \A = auto-pause mode toggle for ,.?! characters
- \S[n] = set speed at which text appears in letter-by-letter mode
- \D[n] = set delay (in frames) before next text appears
- \P[n] = position message over event with id n
* use n=0 for player
* in battle, use n=a,b,c,d for actors (e.g. \P[a] for first actor)
and n=1,...,n for enemies (e.g. \P[1] for first enemy)
where order is actually the reverse of troop order (in database)
- \P[Cn] = Tie-In with Caterpillar. Positions Message over Cat Actor
in n Position of Caterpillar. 1 for First Cat Actor, etc...
* example: \P[C2] for 2nd Cat Actor, or 3rd Actor in Caterpillar
* n excludes Player
- \P = position message over current event (default for floating messages)
- \^ = message appears directly over its event
- \v = message appears directly below its event
- \< = message appears directly to the left of its event
- \> = message appears directly to the right of its event
- \$ = message appears above actor unless facing up, then appears below
- \% = message appears behind actor relative to direction
- \B = bold text
- \I = italic text
- \C[#xxxxxx] = change to color specified by hexadecimal (eg. ffffff = white)
- \C = change color back to default
- \! = message autoclose
- \? = wait for user input before continuing
- \+ = make message appear at same time as preceding one
* note: must be at the start of message to work
- \* = displays the next message immediately if available
* note: next event command must be text, choice, or number input
- \@ = thought balloon
- \N[En] = display name of enemy with id n (note the "E")
- \N[In] = display name of item with id n (note the "I")
- \N[Wn] = display name of weapon with id n (note the "W")
- \N[An] = display name of armor with id n (note the "A")
- \N[Sn] = display name of skill with id n (note the "S")
- \I[In] = display icon of item with id n (note the "I")
- \I[Wn] = display icon of weapon with id n (note the "W")
- \I[An] = display icon of armor with id n (note the "A")
- \I[Sn] = display icon of skill with id n (note the "S")
- \I&N[In] = display icon and name of item with id n (note the "I")
- \I&N[Wn] = display icon and name of weapon with id n (note the "W")
- \I&N[An] = display icon and name of armor with id n (note the "A")
- \I&N[Sn] = display icon and name of skill with id n (note the "S")
- \MAP = display the name of the current map

* Foot Forward Notes * - Sprite Sheets only have 16 total Frames of Animation
and of which, 4 are duplicates. Foot Forward Options allow access to
ALL of the frames of animation available in Default Sprite Sheets.

- \F+ = character puts their Foot Forward
- \F* = character puts their Other Foot Forward
- \F- = character resets their Foot Forward

*NOTE* - Foot Forward Animation will RESET if the event is moved off screen.
- Change @auto_ff_reset if this feature causes you trouble with
character animations.

It also ONLY works with the following conditions
- Direction Fix is OFF
- Move Animation is ON
- Stop Animation is OFF (technically thats Step, they typo'd)
- @auto_ff_reset is TRUE
- * These settings are the DEFAULT when a New Event is created

You can disable the "Auto Foot Forward Off" feature by adding \no_ff
to an Event's Name. IE: Bill\no_ff

---- Resets ----

These occur when the player walks away from a Speaking NPC

Put these strings in an Event's Name to use!

\no_ff - If you don't want a specific event to be RESET, you can add
\no_ff to the Event's Name. EV041\no_ff and Event will
not be affected by Foot Forward Reset when Player Walks off screen

\no_mc - No Move Continue - In the event you dont want a specific event to
continue its Move Route from where it left off when it is moved
off-screen, put \no_mc in the Event's Name. I.E. EV12\no_mc

These are, of course, in addition to the default options:
- \V[n] = display value of variable n
- \V[Tn] = display value of text variable n
- \N[n] = display name of actor with id n
- \C[n] = change color to n
- \G = display gold window - Screen Opposite of Player's Position
- \G+ = display gold window at the Top of the Screen
- \G- = display gold window at the Bottom of the Screen
- \\ = show the '\' character

=============================================================================
Global (specified below or by Call Script and persist until changed)
=============================================================================
Miscellaneous:
- message.move_during = true/false
* allow/disallow player to move during messages
- message.show_pause = true/false
* show/hide "waiting for player" pause graphic
- message.autocenter = true/false
* enable/disable automatically centering text within messages
- message.auto_comma_pause = true/false
* inserts a delay before the next character after these characters ,!.?
* expects correct punctuation. One space after a comma, the rest 2 spaces
- message.comma_skip_delay = true/false
* allows skipping delays inserted by commans when Player skips to end of msg
- message.auto_comma_delay = n
* changes how long to wait after a pausable character
- message.auto_ff_reset = true/false
* resets a Foot Forward stance if a message wnidow is closed for off-screen
* set to false if it causes animation problems, or, dont use Foot Forward
on a specific NPC or Event
- message.auto_move_continue = true/false
* when moving an event off screen while speaking, resets previous move route
- message.dist_exit = true/false
* close messages if the player walks too far away
- message.dist_max = n
* the distance away from the player before windows close
- message.reposition_on_turn = true / false
* Repeat Turn Toward Player NPC's Reorient Message Windows if they Turn
- message.sticky
* If Message was Repositioned, next message will go to that Location

Auto Repositioning Message Windows
- Cannot be Player
- NPC MUST have some form of Repeating Turn, usually toward Player
- NPC MUST NOT MOVE. Turning is Fine, but cant MOVE

- set_max_dist(n)
* Useful for allowing player to walk away from signs
* Saves your MMW Config in case of a Walk-Away Closure
* call from Event Editor => Scripts

Speech/thought balloon related:
- message.resize = true/false
* enable/disable automatic resizing of messages (only as big as necessary)
- message.floating = true/false
* enable/disable positioning messages above current event by default
(i.e. equivalent to including \P in every message)
- message.location = TOP, BOTTOM, LEFT or RIGHT
* set default location for floating messages relative to their event
- message.show_tail = true/false
* show/hide message tail for speech/thought balloons

Letter-by-letter related:
- message.letter_by_letter = true/false
* enable/disable letter-by-letter mode (globally)
- message.text_speed = 0-20
* set speed at which text appears in letter-by-letter mode (globally)
- message.skippable = true/false
* allow/disallow player to skip to end of message with button press

Font:
- message.font_name = font
* set font to use for text, overriding all defaults
(font can be any TrueType from Windows/Fonts folder)
- message.font_size = size
* set size of text (default 18), overriding all defaults
- message.font_color = color
* set color of text, overriding all defaults
* you can use same 0-7 as for \C[n] or "#xxxxxx" for hexadecimal

Set Move Route:
- foot_forward_on (frame)
* Optional Parameter - frame
* foot_forward_on(0) is default, treated as just foot_forward_on
* foot_forward_on(1) puts the "Other" Foot Forward
- foot_forward_off

Note that the default thought and shout balloon windowskins don't
stretch to four lines very well (unfortunately).

Thanks:
XRXS code for self-close and wait for input
Slipknot for a convenient approach to altering settings in-game
SephirothSpawn for bitmap rotate method

=end

#------------------------------------------------------------------------------
# * SDK Log Script
#------------------------------------------------------------------------------
#SDK.log('Multiple Message Windows', 'Wachunga', 1.5, '2006-11-17')

#------------------------------------------------------------------------------
# * Begin SDK Enabled Check
#------------------------------------------------------------------------------
#if SDK.state('Multiple Message Windows') == true

#==============================================================================
# Settings
#==============================================================================

#----------------------------------------------------------------------------
# Windowskins
#----------------------------------------------------------------------------
# Note: all files must be in the Graphics/Windowskins/ folder
# Tip: tails don't look right on windowskins with gradient backgrounds

# filenames of tail and windowskin used for speech balloons
FILENAME_SPEECH_TAIL = "white-tail_speech.png"
FILENAME_SPEECH_WINDOWSKIN = "white-windowskin_speech.png"

# filenames of tail and windowskin used for thought balloons
FILENAME_THOUGHT_TAIL = "white-tail_thought.png"
FILENAME_THOUGHT_WINDOWSKIN = "white-windowskin_thought.png"

#----------------------------------------------------------------------------
# Fonts
#----------------------------------------------------------------------------
# Note: if floating or resize (i.e. "speech balloons") are disabled,
# Font.default_name, Font.default_size and Font.default_color are used
# (you can change these in Main)
# During gameplay, you can use message.font_name etc to override all defaults

# defaults for speech text
SPEECH_FONT_COLOR = "#000000"
SPEECH_FONT_NAME = "Komika Slim","Comic Sans MS"
SPEECH_FONT_SIZE = 18



# defaults for thought text
THOUGHT_FONT_COLOR = "#000000"
THOUGHT_FONT_NAME = "Komika Slim","Comic Sans MS"
THOUGHT_FONT_SIZE = 16

# note that you can use an array of fonts for SPEECH_FONT_NAME, etc.
# e.g. ['Komika Slim', 'Arial']
# (if Verdana is not available, MS PGothic will be used instead)

#----------------------------------------------------------------------------
# Misc
#----------------------------------------------------------------------------
# If using a specialty windowskin (e.g. the default thought balloon one),
# you can force the window width to always be a multiple of the number
# specified in this constant (even when using the resize feature).
# This allows, for example, the windowskin frame to be designed to
# repeat every 16 pixels so that the frame never looks cut off.
THOUGHT_WIDTH_MULTIPLE = 16
# (set to 0 if you're not using any such windowskins)

class Game_Message

# Any of the below can be changed by a Call Script event during gameplay.
# E.g. turn letter-by-letter mode off with: message.letter_by_letter = false

def initialize
# whether or not messages appear one letter at a time
@letter_by_letter = true
# note: can also change within a single message with \L

# the default speed at which text appears in letter-by-letter mode
@text_speed = 0
# note: can also change within a single message with \S[n]

# this is defined as a user setting that can be changed during gameplay
@text_speed_player = 0

# Heretic's Notes:
#
# This is a placeholder for the default user setting in the event that
# a character needs to speak at a different speed without destroying
# the users preferences...
# Call by message.text_speed = message.text_speed_player
# YOU HAVE TO ENTER A NEWLINE (PRESS ENTER) BEFORE 2ND VARIABLE
# DUE TO WRAPPING TEXT BUG WITH SCRIPTS IN EVENT SCRIPTS
# Otherwise you get errors

# whether or not players can skip to the end of (letter-by-letter) messages
@skippable = true

# whether or not messages are automatically resized based on the message
@resize = true

# whether or not message windows are positioned above
# characters/events by default, i.e. without needing \P every message
# (only works if resize messages enabled -- otherwise would look very odd)
@floating = true

# whether or not to automatically center lines within the message
@autocenter = true

# whether or not event-positioned messages have a tail(for speech balloons)
# (only works if floating and resized messages enabled -- otherwise would
# look very odd indeed)
@show_tail = true

# whether or not to display "waiting for user input" pause graphic
# (probably want this disabled for speech balloons)
@show_pause = false

# whether the player is permitted to move while messages are displayed
@move_during = true

# the default location for floating messages (relative to the event)
# note that an off-screen message will be "flipped" automatically
@location = TOP

# font details
# overrides all defaults; leave nil to just use defaults (e.g. as above)
@font_name = nil
@font_size = nil
@font_color = nil

# pause on these characters ,.?!
# pause for delay number of frames if this is true, toggle with \A in Text
@auto_comma_pause = true
# inserts this number of frames to ,!.? characters, nil for off
@auto_comma_delay = 5
# Skip Commas, Exclamation Points, Periods, and Question Marks when Skipped
@comma_skip_delay = true

# designers can allow or disallow choices, why not number windows too?
@allow_cancel_numbers = true
# speeds up text display a bit so players dont get bored waiting
@update_text_while_fading = true

# reset foot_forwad stance on auto-close due to Event going off-screen
@auto_ff_reset = true
# continues Move Route when NPC is speaking and goes off screen
@auto_move_continue = true

# exit if distance from speaker is too great
@dist_exit = true
# distance player can be before window closes
@dist_max = 4

# allow message windows to float off screen instead of flipping
@allow_offscreen = true

# reposition the message window if the speaker turns
@reposition_on_turn = true

# if Msg Windows were Reoriented by Player Movement, sticky to that spot
@sticky = true

# Sounds While Speaking Related
@sound = false # Enables or Disables Text Sounds
@sound_audio = '001-System01' # Audio SE (in DB) to play
@sound_volume = 80 # Text Sound Volume
@sound_pitch = 100 # Text Sound Pitch
@sound_pitch_range = 20 # How Much to vary the Pitch
@sound_vary_pitch = true # Whether to Vary the Pitch or not
@sound_frequency = 3 # Plays a sound this many letters

# Save these settings - DONT EDIT
save_sound_settings
end

attr_accessor :move_during # Walk around while speaking
attr_accessor :letter_by_letter # Display msg letter by letter
attr_accessor :text_speed # How fast text is displayed
attr_accessor :text_speed_player # Saves Player Preference
attr_accessor :skippable # Msg can be skipped
attr_accessor :resize # Resizes Message Window
attr_accessor :floating # Messages are Speech Bubbles
attr_accessor :autocenter # Centers Text in Window
attr_accessor :show_tail # Speech Bubble Tail
attr_accessor :show_pause # Shows Icon to press a button
attr_accessor :location # Relative to Speaker Top Bottom etc
attr_accessor :font_name # Name of Font to be used
attr_accessor :font_size # Size of Font
attr_accessor :font_color # Color of Font
attr_accessor :auto_comma_pause # Pauses on these characters ?,.!
attr_accessor :auto_comma_delay # How many Frames to Delay
attr_accessor :comma_skip_delay # Ignore Auto Comma Pause on Skip
attr_accessor :allow_cancel_numbers # Allows cancelling Number Input
attr_accessor :auto_ff_reset # Foot Forward Animation reset
attr_accessor :auto_move_continue # Continues Previous Move Route
attr_accessor :update_text_while_fading # Update Text while Fading In
attr_accessor :dist_exit # Auto Close Window if true
attr_accessor :dist_max # Dist Max Player from Speaker
attr_accessor :allow_offscreen # Allows Msg Windows Off Screen
attr_accessor :reposition_on_turn # Reposition Windows if Speaker Turn
attr_accessor :sticky # Msgs "Prefer" Sticky Locations
# Sound Related
attr_accessor :sound # Enables or Disables Text Sounds
attr_accessor :sound_audio # Audio SE (in DB) to play
attr_accessor :sound_volume # Text Sound Volume
attr_accessor :sound_pitch # Text Sound Pitch
attr_accessor :sound_pitch_range # How Much to vary the Pitch
attr_accessor :sound_vary_pitch # Whether to Vary the Pitch or not
attr_accessor :sound_frequency # Plays a sound this many letters



# Used for storing the Default Sound Configuration
def save_sound_settings
# Allows Saving ONCE
return if @default_sounds_audio
# Stores the Default Values
@default_sound_audio = @sound_audio
@default_sound_volume = @sound_volume
@default_sound_pitch = @sound_pitch
@default_sound_pitch_range = @sound_pitch_range
@default_sound_vary_pitch = @sound_vary_pitch
@default_sound_frequency = @sound_frequency
end

# Loads the Default Sound Settings
def load_sound_settings
# If settings have not been saved
return if not @default_sound_audio

# Default System Sound Configuration
@sound_audio = @default_sound_audio
@sound_volume = @default_sound_volume
@sound_pitch = @default_sound_pitch
@sound_pitch_range = @default_sound_pitch_range
@sound_vary_pitch = @default_sound_vary_pitch
@sound_frequency = @default_sound_frequency
end
end

#==============================================================================
# Private constants (don't edit)
#==============================================================================

# used for message.location
TOP = 8
BOTTOM = 2
LEFT = 4
RIGHT = 6

#------------------------------------------------------------------------------

class Game_Character
attr_accessor :move_route # Character's Move Route
attr_accessor :direction # Used for changing bubble orientation
attr_accessor :direction_fix # Character locked facing a direction
attr_accessor :walk_anime # Character steps when moves
attr_accessor :step_anime # Character is Stepping
attr_accessor :erased # Erased Flag
attr_accessor :original_move_speed # Characters original Move Speed
attr_accessor :original_move_frequency # Characters original Move Speed
attr_accessor :no_ff # Prevents Auto Foot Forward Off
attr_accessor :no_mc # No 'M'ove Continue
attr_accessor :dist_kill # Closes ALL windows if Player X Dist

unless self.method_defined?('heretic_char_mmw_initialize')
alias heretic_char_mmw_initialize initialize
end

def initialize
# Run Original
heretic_char_mmw_initialize
# Add New Properties
@original_move_speed = 4
@original_move_frequency = 6
@no_ff = nil
@no_mc = nil
@dist_kill = nil
# Game Player - Sticky
if self.is_a?(Game_Player)
@sticky = false
end
end
end

class Game_Event < Game_Character
unless self.method_defined?('heretic_event_mmw_initialize')
alias heretic_event_mmw_initialize initialize
end

def initialize(map_id, event, *args)
heretic_event_mmw_initialize(map_id, event, *args)
check_no_auto_ff(event)
check_no_mc(event)
end

# These occur when Windows are Auto Closed for going Off Screen

# Check for no Auto Foot Forward Off - In the event of Animation Problems...
def check_no_auto_ff(event)
event.name.gsub(/\\no_ff/i) {@no_ff = true}
end

# Check for no MC - 'M'ove 'C'ontinue - Restores Original Move Route...
def check_no_mc(event)
event.name.gsub(/\\no_mc/i) {@no_mc = true}
end
end

class Window_Message < Window_Selectable
attr_accessor :choice_window # Allows Multi Windows with Choice Selection

#==============================================================================
# Private constants (don't edit)
#==============================================================================

# Characters that produce Text Sounds - a to z and 0 thru 9
CHARACTERS = [('a'..'z'),('0'..'9')].map{|i| i.to_a}.flatten

#------------------------------------------------------------------------------


#--------------------------------------------------------------------------
# * Initialize
#--------------------------------------------------------------------------

def initialize(msgindex = 0)
super(80, 304, 480, 160)
self.contents = Bitmap.new(width - 32, height - 32)
self.visible = false
self.z = 9000 + msgindex * 5 # permits messages to overlap legibly
@fade_in = false
@fade_out = false
@contents_showing = false
@cursor_width = 0
self.active = false
self.index = -1
@msgindex = msgindex
@tail = Sprite.new
@tail.bitmap =
if @msgindex == 0
RPG::Cache.windowskin(FILENAME_SPEECH_TAIL)
else
# don't use cached version or else all tails
# are rotated when multiple are visible at once
Bitmap.new("Graphics/Windowskins/"+FILENAME_SPEECH_TAIL)
end
# keep track of orientation of tail bitmap
if @tail.bitmap.orientation == nil
@tail.bitmap.orientation = 0
end
# make origin the center, not top left corner
@tail.ox = @tail.bitmap.width / 2
@tail.oy = @tail.bitmap.height / 2
# Removed due to Tail Overlap on Secondary Message Bubbles
#@tail.z = 9999
# Increase Z Index
@tail.z = self.z + 4
@tail.visible = false
if $game_system.message.floating and $game_system.message.resize
@windowskin = FILENAME_SPEECH_WINDOWSKIN
else
# use windowskin specified in database
@windowskin = $game_system.windowskin_name
end
if $game_system.message.floating and $game_system.message.resize
# if used as speech balloons, use constants
@font_name = SPEECH_FONT_NAME
@font_color = check_color(SPEECH_FONT_COLOR)
@font_size = SPEECH_FONT_SIZE
else
# use defaults
@font_name = Font.default_name
@font_color = Font.default_color
@font_size = Font.default_size
end
# override defaults if necessary
if $game_system.message.font_name != nil
@font_name = $game_system.message.font_name
end
if $game_system.message.font_color != nil
@font_color = check_color($game_system.message.font_color)
end
if $game_system.message.font_size != nil
@font_size = $game_system.message.font_size
end
@update_text = true
@letter_by_letter = $game_system.message.letter_by_letter
@text_speed = $game_system.message.text_speed
# id of character for speech balloons
@float_id = nil
# location of box relative to speaker
@location = $game_system.message.location
# insert a pause for commas, periods and other special characters
@auto_comma_pause = $game_system.message.auto_comma_pause
@auto_comma_delay = $game_system.message.auto_comma_delay
# allows number windows to be cancelled
@allow_cancel_numbers = $game_system.message.allow_cancel_numbers
# allows windows to update text while fading in
@update_text_while_fading = $game_system.message.update_text_while_fading
# resets foot forward animation when off screen
@auto_ff_reset = $game_system.message.auto_ff_reset
# resets foot forward animation when off screen
@auto_move_continue = $game_system.message.auto_move_continue
# allows a specific window to be flagged if choices are displayed
@choice_window = nil

# Close a Window if distance from speaker is too great
@dist_exit = $game_system.message.dist_exit
# Maximum Distance player can be away from speaker before closing
@dist_max = $game_system.message.dist_max

# Sounds While Speaking Related
@sound = $game_system.message.sound
@sound_audio = $game_system.message.sound_audio
@sound_volume = $game_system.message.sound_volume
@sound_pitch = $game_system.message.sound_pitch
@sound_pitch_range = $game_system.message.sound_pitch_range
@sound_vary_pitch = $game_system.message.sound_vary_pitch
@sound_frequency = $game_system.message.sound_frequency
@sound_counter = 0
end

def dispose
terminate_message
# have to check all windows before claiming that no window is showing
if $game_temp.message_text.compact.empty?
$game_temp.message_window_showing = false
end

if @input_number_window != nil
@input_number_window.dispose
end
super
end
#--------------------------------------------------------------------------
# * Terminate Message
#--------------------------------------------------------------------------

def terminate_message
return if $game_temp.input_in_window == true
self.active = false
self.pause = false
self.index = -1
self.contents.clear
# Clear showing flag
@contents_showing = false

# Clear variables related to text, choices, and number input
@tail.visible = false
# note that these variables are now indexed arrays
$game_temp.message_text[@msgindex] = nil
# Call message callback
if $game_temp.message_proc[@msgindex] != nil
# make sure no message boxes are displaying
if $game_temp.message_text.compact.empty?
$game_temp.message_proc[@msgindex].call
end
$game_temp.message_proc[@msgindex] = nil
end
self.choice_window = nil
@update_text = true
$game_temp.choice_start = 99
$game_temp.choice_max = 0
$game_temp.choice_cancel_type = 0
$game_temp.choice_proc = nil
$game_temp.num_input_start = 99
$game_temp.num_input_variable_id = 0
$game_temp.num_input_digits_max = 0
# Open gold window
if @gold_window != nil
@gold_window.dispose
@gold_window = nil
end
end

#--------------------------------------------------------------------------
# * Refresh Message Window
#--------------------------------------------------------------------------

def refresh
self.contents.clear
@x = @y = 0 # now instance variables
@float_id = nil
@location = $game_system.message.location
if $game_system.message.floating and $game_system.message.resize
@windowskin = FILENAME_SPEECH_WINDOWSKIN
else
# use windowskin specified in database
@windowskin = $game_system.windowskin_name
end
if $game_system.message.floating and $game_system.message.resize
# if used as speech balloons, use constants
@font_name = SPEECH_FONT_NAME
@font_color = check_color(SPEECH_FONT_COLOR)
@font_size = SPEECH_FONT_SIZE
else
# use default font
@font_name = Font.default_name
@font_color = Font.default_color
@font_size = Font.default_size
end
# override font defaults
if $game_system.message.font_name != nil
@font_name = $game_system.message.font_name
end
if $game_system.message.font_color != nil
@font_color = check_color($game_system.message.font_color)
end
if $game_system.message.font_size != nil
@font_size = $game_system.message.font_size
end
@line_widths = nil
@wait_for_input = false
@tail.bitmap =
if @msgindex == 0
RPG::Cache.windowskin(FILENAME_SPEECH_TAIL)
else
Bitmap.new("Graphics/Windowskins/"+FILENAME_SPEECH_TAIL)
end
RPG::Cache.windowskin(FILENAME_SPEECH_TAIL)
@tail.bitmap.orientation = 0 if @tail.bitmap.orientation == nil
@text_speed = $game_system.message.text_speed
@letter_by_letter = $game_system.message.letter_by_letter
@auto_comma_pause = $game_system.message.auto_comma_pause
@auto_comma_delay = $game_system.message.auto_comma_delay
@comma_skip_delay = $game_system.message.comma_skip_delay
@allow_cancel_numbers = $game_system.message.allow_cancel_numbers
@auto_ff_reset = $game_system.message.auto_ff_reset
@auto_move_continue = $game_system.message.auto_move_continue
@update_text_while_fading = $game_system.message.update_text_while_fading
@dist_exit = $game_system.message.dist_exit
@dist_max = $game_system.message.dist_max
@dist_max = 1 if @dist_max < 1
@auto_orient = nil
@delay = @text_speed
@player_skip = false
# Sound Related
@sound = $game_system.message.sound
@sound_volume = $game_system.message.sound_volume
@sound_pitch = $game_system.message.sound_pitch
@sound_pitch_range = $game_system.message.sound_pitch_range
@sound_vary_pitch = $game_system.message.sound_vary_pitch
@sound_frequency = $game_system.message.sound_frequency
@sound_counter = 0
# End Sound Related
@cursor_width = 0
# Indent if choice
if $game_temp.choice_start == 0
@x = 8
end
# If waiting for a message to be displayed
if $game_temp.message_text[@msgindex] != nil
@text = $game_temp.message_text[@msgindex] # now an instance variable
# Control text processing
begin
last_text = @text.clone
@text.gsub!(/\\[V]\[[T]([0-9]+)\]/i) { $game_system.mmw_text[$1.to_i] }
@text.gsub!(/\\[Vv]\[([0-9]+)\]/) { $game_variables[$1.to_i] }
end until @text == last_text
@text.gsub!(/\\[Nn]\[([0-9]+)\]/) do
$game_actors[$1.to_i] != nil ? $game_actors[$1.to_i].name : ""
end
# Change "\\\\" to "\000" for convenience
@text.gsub!(/\\\\/) { "\000" }
@text.gsub!(/\\[Gg][\+]/) { "\023" } # Gold Window at TOP
@text.gsub!(/\\[Gg][\-]/) { "\024" } # Gold Window at Bottom
@text.gsub!(/\\[Gg]/) { "\002" } # Gold Window Auto, based on Player Loc

# display icon of item, weapon, armor or skill
@text.gsub!(/\\[Ii]\[([IiWwAaSs][0-9]+)\]/) { "\013[#{$1}]" }
# display name of enemy, item, weapon, armor or skill
@text.gsub!(/\\[Nn]\[([EeIiWwAaSs])([0-9]+)\]/) do
case $1.downcase
when "e"
entity = $data_enemies[$2.to_i]
when "i"
entity = $data_items[$2.to_i]
when "w"
entity = $data_weapons[$2.to_i]
when "a"
entity = $data_armors[$2.to_i]
when "s"
entity = $data_skills[$2.to_i]
end
entity != nil ? entity.name : ""
end
# display icon and name of item, weapon, armor or skill
@text.gsub!(/\\[Ii]&[Nn]\[([IiWwAaSs])([0-9]+)\]/) do
case $1.downcase
when "e"
entity = $data_enemies[$2.to_i]
when "i"
entity = $data_items[$2.to_i]
when "w"
entity = $data_weapons[$2.to_i]
when "a"
entity = $data_armors[$2.to_i]
when "s"
entity = $data_skills[$2.to_i]
end
entity != nil ? "\013[#{$1+$2}] " + entity.name : ""
end
# display name of current map
@text.gsub!(/\\[Mm][Aa][Pp]/) { $game_map.name }
# change font color
@text.gsub!(/\\[Cc]\[([0-9]+|#[0-9A-Fa-f]{6,6})\]/) { "\001[#{$1}]" }
# return to default color
@text.gsub!(/\\[Cc]/) { "\001" }
# toggle letter-by-letter mode
@text.gsub!(/\\[Ll]/) { "\003" }
# toggle auto_comma_pause mode
@text.gsub!(/\\[Aa]/) { "\016" }
# trigger Foot Forward Animation
@text.gsub!(/\\[Ff]\+/) { "\020" }
# trigger Foot Forward Animation Alter Frame
@text.gsub!(/\\[Ff]\*/) { "\022" }
# trigger Reset Foot Forward Animation
@text.gsub!(/\\[Ff]\-/) { "\021" }
# change text speed (for letter-by-letter)
@text.gsub!(/\\[Ss]\[([0-9]+)\]/) { "\004[#{$1}]" }
# insert delay
@text.gsub!(/\\[Dd]\[([0-9]+)\]/) { "\005[#{$1}]" }

# insert delays for commas, periods, questions and exclamations
@text.gsub!(/, /) { ", \015" } # Comma with One Space
@text.gsub!(/! /) { "! \015" } # Exclamation Point with Two Spaces
@text.gsub!(/\? /) { "? \015" } # Question Mark with Two Spaces
@text.gsub!(/\. /) { ". \015" } # Period with Two Spaces

# self close message
@text.gsub!(/\\[!]/) { "\006" }
# wait for button input
@text.gsub!(/\\[?]/) { "\007" }
# bold
@text.gsub!(/\\[Bb]/) { "\010" }
# italic
@text.gsub!(/\\[Ii]/) { "\011" }
# add msg with \*
@text.gsub!(/\\ /) { "\014" }
# thought balloon
if @text.gsub!(/\\[@]/, "") != nil
@windowskin = FILENAME_THOUGHT_WINDOWSKIN
@font_name = THOUGHT_FONT_NAME
@font_size = THOUGHT_FONT_SIZE
@font_color = check_color(THOUGHT_FONT_COLOR)
@tail.bitmap =
if @msgindex == 0
RPG::Cache.windowskin(FILENAME_THOUGHT_TAIL)
else
Bitmap.new("Graphics/Windowskins/"+FILENAME_THOUGHT_TAIL)
end
@tail.bitmap.orientation = 0 if @tail.bitmap.orientation == nil
end
# Get rid of "\+" (multiple messages)
@text.gsub!(/\\[+]/, "")
# Get rid of "\*" (multiple messages)
@text.gsub!(/\\ /, "")
# Get rid of "\\^", "\\v", "\\<", "\\>" (relative message location)
if @text.gsub!(/\\\^/, "") != nil
@location = 8
elsif @text.gsub!(/\\[Vv]/, "") != nil
@location = 2
elsif @text.gsub!(/\\[<]/, "") != nil
@location = 4
elsif @text.gsub!(/\\[>]/, "") != nil
@location = 6
end
# Get rid of "\\P" (position window to given character)
if @text.gsub!(/\\[Pp]\[([0-9]+)\]/, "") != nil
@float_id = $1.to_i
elsif @text.gsub!(/\\[Pp]\[([a-zA-Z])\]/, "") != nil and
$game_temp.in_battle
@float_id = $1.downcase
# Tie-In with Caterpillar, use \P[Cn] for a Cat Actor or Follower \P[C1]
elsif @text.gsub!(/\\[Pp]\[[Cc]([0-9]+)\]/, "") != nil and
!$game_temp.in_battle and
Interpreter.method_defined?('get_cat_position_id')
# This only works with Heretic's Caterpillar
if $1.to_i == 0
@float_id = 0 # Player
elsif $1.to_i > 0 and $1.to_i <= $game_system.caterpillar.actors.size
# temporary shortuct to keep on one line
s = $game_system.map_interpreter
# Returns the Event ID of the Cat Actor in that position
@float_id = s.get_cat_position_id($1.to_i - 1)
end
elsif @text.gsub!(/\\[Pp]/, "") != nil or
($game_system.message.floating and $game_system.message.resize) and
!$game_temp.in_battle
# Just assigns the Event ID of the \P[x] Event
@float_id = $game_system.map_interpreter.event_id
end
# Orient to Behind Events Direction with \%
if @text.gsub!(/\\[%]/, "") != nil and !$game_temp.in_battle and
$game_system.message.floating
# Set Direction of Bubble based on Direction of Character
d = (@float_id > 0) ?
$game_map.events[@float_id].direction : $game_player.direction
# Allows Window to Reorient if the Speaker Turns
@auto_orient = 1
# If Sticky is Disabled...
if !$game_system.message.sticky
# Unset any possible Stickys
$game_map.events[@float_id].preferred_loc = nil if @float_id > 0
# Game Player Sticky
if @float_id == 0 and not $game_player.sticky
# Reset Game Player Preferred Location
$game_player.preferred_loc = nil
end
end
if @float_id > 0 and $game_map.events[@float_id].preferred_loc and
$game_map.events[@float_id].allow_flip
# This just helps to keep the position the same
@location = $game_map.events[@float_id].preferred_loc
elsif @float_id == 0 and $game_player.preferred_loc and
$game_player.allow_flip
# Set Location to Players Preferred Location.
@location = $game_player.preferred_loc
else
if d == 2
@location = 8
if @float_id == 0 and $game_player.sticky
$game_player.preferred_loc = 8
elsif @float_id and $game_system.message.sticky and
@float_id.is_a?(Numeric) and @float_id > 0
$game_map.events[@float_id].preferred_loc = 8
end
elsif d == 4
@location = 6
elsif d == 6
@location = 4
elsif d == 8
@location = 2
if @float_id == 0 and $game_player.sticky
$game_player.preferred_loc = 8
elsif $game_system.message.sticky and
@float_id.is_a?(Numeric) and @float_id > 0
$game_map.events[@float_id].preferred_loc = 2
end
else
@location = 8
end
end
end
# Orient Above unless facing UP, then Down
if @text.gsub!(/\\[\$]/, "") != nil and !$game_temp.in_battle and
$game_system.message.floating
# This Allows Top / Bottom Flipping if the Speaker Turns
@auto_orient = 2
d = (@float_id > 0) ?
$game_map.events[@float_id].direction : $game_player.direction
# Check for "Sticky" messages
if !$game_system.message.sticky
# Unset any possible Stickys
$game_map.events[@float_id].preferred_loc = nil if @float_id > 0
if @float_id == 0 and not $game_player.sticky
$game_player.preferred_loc = nil
end
end
# If the message got flipped due to Character Turning, then Prefer
pl = (@float_id > 0) ? $game_map.events[@float_id].preferred_loc :
(@float_id == 0) ? $game_player.preferred_loc : nil
if ((@float_id > 0 and $game_map.events[@float_id].allow_flip) or
(@float_id == 0 and $game_player.allow_flip)) and
(pl == 2 or pl == 8)

# Set Location to the Preferred Location. Only works if Triggered
# Other Events are NOT included in this "Stickyness"
@location = pl
else
# Orient by Direction
case d
when 8
@location = 2
else
@location = 8
end
end
# Set Preferred Location for Sticky
if $game_system.message.sticky
# Set Sticky for Player
if @float_id == 0 and $game_player.preferred_loc == nil and
$game_player.sticky
# Set Sticky for Player, expires at end of Event Processing
$game_player.preferred_loc = @location
# Set Sticky for Event
elsif @float_id > 0 and
$game_map.events[@float_id].preferred_loc == nil
# Set Sticky for Event, expires at end of Event Processing
$game_map.events[@float_id].preferred_loc = @location
end
end
end
if $game_system.message.resize or $game_system.message.autocenter
# calculate length of lines
text = @text.clone
temp_bitmap = Bitmap.new(1,1)
temp_bitmap.font.name = @font_name
temp_bitmap.font.size = @font_size
@line_widths = [0,0,0,0]
for i in 0..3
line = text.split(/\n/)[3-i]
if line == nil
next
end
line.gsub!(/[\001-\007](\[[#A-Fa-f0-9]+\])?/, "")
line.gsub!(/\013\[[IiWwAaSs][0-9]+\]/, "\013")
line.chomp.split(//).each do |c|


# C for Characters in Size of Message Bubble

case c
when "\000"
c = "\\"
when "\010"
# bold
temp_bitmap.font.bold = !temp_bitmap.font.bold
c = '' # Set character artifacts to a non character
next
when "\011"
# italics
temp_bitmap.font.italic = !temp_bitmap.font.italic
c = '' # Set character artifacts to a non character
next
when "\013"
# icon
@line_widths[3-i] += 24
next
when "\014","\015","\016","\020","\021","\022","\023","\024"
# Featres Heretic added, causes garbage to appear
next
end
@line_widths[3-i] += temp_bitmap.text_size(c).width
end
if (3-i) >= $game_temp.choice_start
# account for indenting
@line_widths[3-i] += 8 unless $game_system.message.autocenter
end
end
if $game_temp.num_input_variable_id > 0
# determine cursor_width as in Window_InputNumber
# (can't get from @input_number_window because it doesn't exist yet)
cursor_width = temp_bitmap.text_size("0").width + 8
# use this width to calculate line width (+8 for indent)
input_number_width = cursor_width*$game_temp.num_input_digits_max
input_number_width += 8 unless $game_system.message.autocenter
@line_widths[$game_temp.num_input_start] = input_number_width
end
temp_bitmap.dispose
end
resize
reposition if @float_id != nil
self.contents.font.name = @font_name
self.contents.font.size = @font_size
self.contents.font.color = @font_color
self.windowskin = RPG::Cache.windowskin(@windowskin)
# autocenter first line if enabled
# (subsequent lines are done as "\n" is encountered)
if $game_system.message.autocenter and @text != ""
@x = (self.width-40)/2 - @line_widths[0]/2
end
end
end

#--------------------------------------------------------------------------
# * Resize Window
#--------------------------------------------------------------------------
def resize
if !$game_system.message.resize
# reset to defaults
self.width = 480
self.height = 160
self.contents = Bitmap.new(width - 32, height - 32)
self.x = 80 # undo any centering
return
end
max_x = @line_widths.max
max_y = 4
@line_widths.each do |line|
max_y -= 1 if line == 0 and max_y > 1
end
if $game_temp.choice_max > 0
# account for indenting
max_x += 8 unless $game_system.message.autocenter
end
new_width = max_x + 40
if @windowskin == FILENAME_THOUGHT_WINDOWSKIN and THOUGHT_WIDTH_MULTIPLE >0
# force window width to be a multiple of THOUGHT_WIDTH_MULTIPLE
# so that specialty windowskins (e.g. thought balloon) look right
if new_width % THOUGHT_WIDTH_MULTIPLE != 0
new_width += THOUGHT_WIDTH_MULTIPLE-(new_width%THOUGHT_WIDTH_MULTIPLE)
end
end
self.width = new_width
self.height = max_y * 32 + 32
self.contents = Bitmap.new(width - 32, height - 32)
self.x = 320 - (self.width/2) # center
end

def triggered_id?(event_id)
return false if not $scene.is_a?(Scene_Map)
# If the Event Speaking is the one that was Triggered in max_dist_id
return true if $game_system.map_interpreter.max_dist_id ==
$game_system.map_interpreter.event_id
end

#--------------------------------------------------------------------------
# * Reposition Window
#--------------------------------------------------------------------------
def reposition
if $game_temp.in_battle
if "abcd".include?(@float_id) # must be between a and d
@float_id = @float_id[0] - 97 # a = 0, b = 1, c = 2, d = 3
if $scene.spriteset.actor_sprites[@float_id] == nil
@tail.visible = false
return
end
sprite = $scene.spriteset.actor_sprites[@float_id]
else
@float_id -= 1 # account for, e.g., player entering 1 for index 0
if $scene.spriteset.enemy_sprites[@float_id] == nil
@tail.visible = false
return
end
sprite = $scene.spriteset.enemy_sprites[@float_id]
end

if sprite.height != nil
char_height = sprite.height
char_width = sprite.width
char_x = sprite.x
char_y = sprite.y - char_height/2
else
# This prevents GAME CRASH Enemy doesnt exist
return
end

else # not in battle...
char = (@float_id == 0 ? $game_player : $game_map.events[@float_id])
if char == nil
# no such character
@float_id = nil
return
end
# close message (and stop event processing) if speaker is off-screen
# or the window itself is completely off-screen
if char.screen_x <= 0 or char.screen_x >= 640 or
char.screen_y <= 0 or char.screen_y > 480 or
($game_system.message.move_during and
not triggered_id?(char.id) and
@dist_exit and char.allow_flip and
@float_id > 0 and not char.within_range?(@dist_max, @float_id)) or
($game_system.message.allow_offscreen and !$game_temp.in_battle and
(self.height - self.y > 480 or self.height + self.y < 0 or
self.width - self.x > 640 or self.width + self.x < 0))
# Moved Off Screen or out of range so close Window
terminate_message
# 115 Breaks Event Processing
$game_system.map_interpreter.command_115
# reset foot forward on speak stance
if @auto_ff_reset and not char.no_ff
char.foot_forward_off
end
# reset 'M'ove 'C'ontinue
if @auto_move_continue and not char.no_mc
char.event_move_continue(@float_id, true)
end
# Instanced for this Msg Window, prevents calling Resets multiple times
@auto_ff_reset = false
# Turn off the Triggered Flag
char.allow_flip = false
char.preferred_loc = nil
# Load the Default Sound Settings because Player walked away
$game_system.message.load_sound_settings
return
end
char_height = RPG::Cache.character(char.character_name,0).height / 4
char_width = RPG::Cache.character(char.character_name,0).width / 4
# Patch for Zooming Sprites from Heretic's Rotate and Pendulum Script
if char.respond_to?(:sprite_zoom_y) and char.sprite_zoom_y
# Adjust the Position for Sprite Zoom
char_height *= char.sprite_zoom_y
end
# record coords of character's center
char_x = char.screen_x
char_y = char.screen_y - char_height/2
end
params = [char_height, char_width, char_x, char_y]
# position window and message tail
vars = new_position(params)
x = vars[0]
y = vars[1]
# check if need to flip because of Speaker Direction
flip = need_flip?(@float_id, @location, x, y, params)
# check if any window locations need to be "flipped"
# because of Window Location
if @location == 4 and
((x < 0 and
(not $game_system.message.allow_offscreen or $game_temp.in_battle)) or
flip)
# if the msg is an Auto Oriented Msg and it needs to be flipped
if @auto_orient == 1 and need_flip?(@float_id, @location, x, y)
@location = put_behind(@float_id, 6)
else
# switch to right
@location = 6
end
vars = new_position(params)
x = vars[0]
if x + self.width > 640 and
(!$game_system.message.allow_offscreen or $game_temp.in_battle)
# right is no good either...
if y >= 0
# switch to top
@location = 8
vars = new_position(params)
else
# switch to bottom
@location = 2
vars = new_position(params)
end
end
if $game_system.message.sticky
$game_map.events[@float_id].preferred_loc = @location if @float_id > 0
if @float_id == 0 and [2,8].include?(@location)
if $game_player.allow_flip and $game_player.sticky
$game_player.preferred_loc = @location
else
$game_player.preferred_loc = nil
end
end
else
$game_map.events[@float_id].preferred_loc = nil if @float_id > 0
end
elsif @location == 6 and
((x + self.width > 640 and
(!$game_system.message.allow_offscreen or $game_temp.in_battle)) or
flip)
# if the msg is an Auto Oriented Msg and it needs to be flipped
if @auto_orient == 1 and need_flip?(@float_id, @location, x, y)
@location = put_behind(@float_id, 4)
else
# switch to left
@location = 4
end
vars = new_position(params)
x = vars[0]
if x < 0 and
(!$game_system.message.allow_offscreen or $game_temp.in_battle)
# left is no good either...
if y >= 0
# switch to top
@location = 8
vars = new_position(params)
else
# switch to bottom
@location = 2
vars = new_position(params)
end
end
if $game_system.message.sticky
$game_map.events[@float_id].preferred_loc = @location if @float_id > 0
if @float_id == 0 and [2,8].include?(@location)
if $game_player.allow_flip and $game_player.sticky
$game_player.preferred_loc = @location
else
$game_player.preferred_loc = nil
end
end
else
$game_map.events[@float_id].preferred_loc = nil if @float_id > 0
end
elsif @location == 8 and
((y < 0 and
(!$game_system.message.allow_offscreen or $game_temp.in_battle)) or
flip)
# if the msg is an Auto Oriented Msg and it needs to be flipped
if @auto_orient == 1 and need_flip?(@float_id, @location, x, y)
@location = put_behind(@float_id, 2)
else
# switch to bottom
@location = 2
end
vars = new_position(params)
y = vars[1]

if y + self.height > 480 and
(!$game_system.message.allow_offscreen or $game_temp.in_battle)
# bottom is no good either...
# note: this will probably never occur given only 3 lines of text
# note: heretic - yeah right. Wait till I get ahold of your code!
x = vars[0]
if x >= 0
# switch to left
@location = 4
vars = new_position(params)
else
# switch to right
@location = 6
vars = new_position(params)
end
end
if not $game_temp.in_battle
if $game_system.message.sticky
$game_map.events[@float_id].preferred_loc = @location if @float_id > 0
if @float_id == 0 and [2,8].include?(@location)
if $game_player.allow_flip and $game_player.sticky
$game_player.preferred_loc = @location
else
$game_player.preferred_loc = nil
end
end
else
$game_map.events[@float_id].preferred_loc = nil if @float_id > 0
end
end
elsif @location == 2 and
((y + self.height > 480 and
(!$game_system.message.allow_offscreen or $game_temp.in_battle)) or
flip)
# if the msg is an Auto Oriented Msg and it needs to be flipped
if @auto_orient == 1 and need_flip?(@float_id, @location, x, y)
@location = put_behind(@float_id, 8)
else
# switch to top
@location = 8
end
vars = new_position(params)
y = vars[1]
if y < 0 and
(!$game_system.message.allow_offscreen or $game_temp.in_battle)
# top is no good either...
# note: this will probably never occur given only 3 lines of text
# note: heretic - yeah right. Wait till I get ahold of your code!
x = vars[0]
if x >= 0
# switch to left
@location = 4
vars = new_position(params)
else
# switch to right
@location = 6
vars = new_position(params)
end
end
if not $game_temp.in_battle
if $game_system.message.sticky
$game_map.events[@float_id].preferred_loc = @location if @float_id > 0
if @float_id == 0 and [2,8].include?(@location)
if $game_player.allow_flip and $game_player.sticky
$game_player.preferred_loc = @location
else
$game_player.preferred_loc = nil
end
end
else
$game_map.events[@float_id].preferred_loc = nil if @float_id > 0
end
end
end
x = vars[0]
y = vars[1]
tail_x = vars[2]
tail_y = vars[3]
# adjust windows if near edge of screen
if not $game_system.message.allow_offscreen or $game_temp.in_battle
if x < 0
x = 0
elsif (x + self.width) > 640
x = 640 - self.width
end
if y < 0
y = 0
elsif (y + self.height) > 480
y = 480 - self.height
elsif $game_temp.in_battle and @location == 2 and (y > (320 - self.height))
# when in battle, prevent enemy messages from overlapping battle status
# (note that it could still happen from actor messages, though)
y = 320 - self.height
tail_y = y
end
end
# finalize positions
self.x = x
self.y = y
@tail.x = tail_x
@tail.y = tail_y
end

#--------------------------------------------------------------------------
# * Need Flip? - Prevent Player from walking under Message Bubbles
#--------------------------------------------------------------------------
def need_flip?(event_id, loc, x, y, params = nil)
return false if !@auto_orient or
@fade_out or
event_id.nil? or
(event_id != 0 and
$game_map.events[event_id].erased) or
$game_temp.in_battle or
!$game_system.message.reposition_on_turn or
!$game_system.message.move_during
# vars for speaker
event = (event_id > 0) ? $game_map.events[event_id] : $game_player
dir = event.direction

# if an argument is passed called params and not allowed offscreen
if params and not $game_system.message.allow_offscreen
case loc
when 2
new_loc = 8
when 4
new_loc = 6
when 6
new_loc = 4
when 8
new_loc = 2
end
# check what the new coordinates of a repositioned window will be
new_vars = new_position(params, new_loc, no_rotate = true)
new_x = new_vars[0]
new_y = new_vars[1]
# return false if not allowed off screen and new position is off screen
if (new_x < 0 and new_loc == 4) or
(new_x + self.width > 640) or
(new_y < 0) or
(new_y + self.height > 480)
# if not allowed offscreen and trying to flip offscreen
return false
end
end

# default result
result = false
result = true if @auto_orient == 2 and
event.allow_flip and
dir == loc

if @auto_orient == 1
if event_id > 1
# If Auto Orient Any Direction, try to put preference on top / bottom
# Top / Bottom Preference was made for readability of Msgs
# because it is easier to go off screen left and right
if dir == loc or
((dir == 2 or dir == 8) and (loc == 4 or loc == 6))
result = true
end
elsif event_id == 0 and $game_player.allow_flip

# if Game Player Message is Sticky
if $game_player.sticky and
((dir == 2 and loc != 8) or
(dir == 8 and loc != 2) or
(
(not $game_player.preferred_loc) and
((dir == 4 and loc != 6) or (dir == 6 and loc != 4))
)
)
# Return that Message needs to be Flipped
result = true
# If Game Player Non Sticky Message not behind Player
elsif not $game_player.sticky and
((dir == 2 and loc != 8) or
(dir == 4 and loc != 6) or
(dir == 6 and loc != 4) or
(dir == 8 and loc != 2))
# Return that Message needs to be Flipped
result = true
end
end
end
return result
end

#--------------------------------------------------------------------------
# Place Message Bubble behind Speaker
#--------------------------------------------------------------------------
def put_behind(event_id, default_loc)
return default_loc if event_id.nil? or $game_temp.in_battle
dir = (event_id > 0 ) ? $game_map.events[event_id].direction :
$game_player.direction
return 2 if dir == 8
return 4 if dir == 6
return 6 if dir == 4
return 8 if dir == 2
return default_loc
end

#--------------------------------------------------------------------------
# * Determine New Window Position
#--------------------------------------------------------------------------
def new_position(params, location = @location, no_rotate = nil)
char_height = params[0]
char_width = params[1]
char_x = params[2]
char_y = params[3]
if location == 8
# top
x = char_x - self.width/2
y = char_y - char_height/2 - self.height - @tail.bitmap.height/2
@tail.bitmap.rotation(0) if not no_rotate
tail_x = x + self.width/2
tail_y = y + self.height
elsif location == 2
# bottom
x = char_x - self.width/2
y = char_y + char_height/2 + @tail.bitmap.height/2
@tail.bitmap.rotation(180) if not no_rotate
tail_x = x + self.width/2
tail_y = y
elsif location == 4
# left
x = char_x - char_width/2 - self.width - @tail.bitmap.width/2
y = char_y - self.height/2
@tail.bitmap.rotation(270) if not no_rotate
tail_x = x + self.width
tail_y = y + self.height/2
elsif location == 6
# right
x = char_x + char_width/2 + @tail.bitmap.width/2
y = char_y - self.height/2
@tail.bitmap.rotation(90) if not no_rotate
tail_x = x
tail_y = y + self.height/2
end
return [x,y,tail_x,tail_y]
end

#--------------------------------------------------------------------------
# * Text Sound
#--------------------------------------------------------------------------

def play_text_sound(c)
sound = "Audio/SE/" + $game_system.message.sound_audio
volume = @sound_volume

if @sound_vary_pitch and @sound_pitch
# Prevent Negative Numbers...
sound_pitch_range = (@sound_pitch_range > @sound_pitch) ?
@sound_pitch : @sound_pitch_range
# If we want to Randomize the Sounds
if @sound_vary_pitch == "random"
# Random within the Range
pitch = rand(sound_pitch_range * 2) + @sound_pitch - sound_pitch_range
# Vary Sound Pitch to be based on Letter Sounds
else

# Note to Self - Reorganize based on actual Letter Sounds, not so Random
if ['l','m','n','q','u','w','2'].include?(c)
pitch = @sound_pitch - sound_pitch_range
elsif ['a','f','h','j','k','o','r','x','1','4','7','8'].include?(c)
pitch = @sound_pitch - sound_pitch_range / 2
elsif ['b','c','d','e','g','p','t','v','z','0','3','6'].to_a.include?(c)
pitch = @sound_pitch
elsif ['s','7'].to_a.include?(c)
pitch = @sound_pitch + sound_pitch_range / 2
elsif ['i','y','5','9'].to_a.include?(c)
pitch = @sound_pitch + sound_pitch_range
else
pitch = rand(@sound_pitch_range * 2) + @sound_pitch
end
end
else
pitch=(@sound_pitch and @sound_pitch.is_a?(Numeric)) ? @sound_pitch : 100
end

# Play the Sound
Audio.se_play(sound, volume, pitch)
end

#--------------------------------------------------------------------------
# * Update Text
#--------------------------------------------------------------------------
def update_text
if @text != nil
# Get 1 text character in c (loop until unable to get text)
while ((c = @text.slice!(/./m)) != nil)
# Plays Sounds for each Letter, Numbers and Spaces Excluded
if @sound and @letter_by_letter and !@player_skip and
CHARACTERS.include?(c.downcase)
# Increment for each Letter Sound Played
@sound_counter += 1
# Prevents Division by Zero, allows 0 to play a sound every letter
frequency = (@sound_frequency == 0) ?
@sound_counter : @sound_frequency
# Play Sound for each New Word or if Remainder is 0
if @sound_counter == 1 or @sound_counter % frequency == 0
# Play correct sound for each letter
play_text_sound(c.downcase)
end
else
@sound_counter = 0
end
# If \\
if c == "\000"
# Return to original text
c = "\\"
end
# If \C[n] or \C[#xxxxxx] or \C
if c == "\001"
# Change text color
@text.sub!(/\[([0-9]+|#[0-9A-Fa-f]{6,6})\]/, "")
if $1 != nil
self.contents.font.color = check_color($1)
else
# return to default color
if $game_system.message.font_color != nil
color = check_color($game_system.message.font_color)
elsif $game_system.message.floating and $game_system.message.resize
color = check_color(SPEECH_FONT_COLOR)
else
# use defaults
color = Font.default_color
end
self.contents.font.color = color
end
# go to next text
next
end
# If \G+ (Gold Window at the Top)
if c == "\023"
# Make gold window
if @gold_window == nil
@gold_window = Window_Gold.new
@gold_window.x = 560 - @gold_window.width
if $game_temp.in_battle
@gold_window.y = 192
else
@gold_window.y = 32
end
@gold_window.opacity = self.opacity
@gold_window.back_opacity = self.back_opacity
end
# Dont take up space in window, next character
next
end
# If \G- (Gold Window at the Bottom)
if c == "\024"
# Make gold window
if @gold_window == nil
@gold_window = Window_Gold.new
@gold_window.x = 560 - @gold_window.width
if $game_temp.in_battle
@gold_window.y = 192
else
@gold_window.y = 384
end
@gold_window.opacity = self.opacity
@gold_window.back_opacity = self.back_opacity
end
# Dont take up space in window, next character
next
end
# If \G
if c == "\002"
# Make gold window
if @gold_window == nil
@gold_window = Window_Gold.new
@gold_window.x = 560 - @gold_window.width
if $game_temp.in_battle
@gold_window.y = 192
else
@gold_window.y = self.y >= 128 ? 32 : 384
end
@gold_window.opacity = self.opacity
@gold_window.back_opacity = self.back_opacity
end
# go to next text
next
end
# If \L
if c == "\003"
# toggle letter-by-letter mode
@letter_by_letter = !@letter_by_letter
# go to next text
next
end
# If \S[n]
if c == "\004"
@text.sub!(/\[([0-9]+)\]/, "")
speed = $1.to_i
if speed >= 0
@text_speed = speed
# reset player skip after text speed change
@player_skip = false
end
return
end
# If \D[n]
if c == "\005"
@text.sub!(/\[([0-9]+)\]/, "")
delay = $1.to_i
if delay >= 0
@delay += delay
# reset player skip after delay
@player_skip = false
end
return
end
# If \!
if c == "\006"
# close message and return from method
terminate_message
return
end
# If \?
if c == "\007"
@wait_for_input = true
return
end
# If \B or \b
if c == "\010"
# bold
self.contents.font.bold = !self.contents.font.bold
#return - removed, glitches when letter_by_letter is false
next
end
# If \I or \i
if c == "\011"
# italics
self.contents.font.italic = !self.contents.font.italic
#return - removed, glitches when letter_by_letter is false
next
end
if c == "\013"
# display icon of item, weapon, armor or skill
@text.sub!(/\[([IiWwAaSs])([0-9]+)\]/, "")
case $1.downcase
when "i"
item = $data_items[$2.to_i]
when "w"
item = $data_weapons[$2.to_i]
when "a"
item = $data_armors[$2.to_i]
when "s"
item = $data_skills[$2.to_i]
end
if item == nil
next
end
bitmap = RPG::Cache.icon(item.icon_name)
self.contents.blt(4+@x, 32*@y+4, bitmap, Rect.new(0, 0, 24, 24))
@x += 24
#self.contents.draw_text(x + 28, y, 212, 32, item.name)
next
end
# if \* - Display the next message
if c == "\014"
if $scene.is_a?(Scene_Battle)
# Set Variables in the Battle Interpreter to display Next Window
$game_system.battle_interpreter.set_multi
elsif $scene.is_a?(Scene_Map)
# Set Variables in the Map Interpreter to display Next Window
$game_system.map_interpreter.set_multi
end
return
end
# if ", " or ". " or "! " or "? " characters with spaces
if c == "\015"
if @auto_comma_pause and @letter_by_letter == true and
(not @player_skip or (@player_skip and not @comma_skip_delay))
delay = @text_speed + @auto_comma_delay
if delay >= 0
@delay += delay
# reset player skip after delay
@player_skip = false
end
end
next
end
# if \A (Auto Pause for Commas, Periods, Exclamation and Question Marks)
if c == "\016"
# toggle auto comma pause
@auto_comma_pause = !@auto_comma_pause
next
end
# if \F+ (Foot Forward Animation On)
if c == "\020" and @float_id
speaker = (@float_id > 0) ? $game_map.events[@float_id] : $game_player
speaker.foot_forward_on
# Dont take up space in window, next character
next
end
# if \F- (Foot Forward Animation Off)
if c == "\021" and @float_id
speaker = (@float_id > 0) ? $game_map.events[@float_id] : $game_player
speaker.foot_forward_off
# Dont take up space in window, next character
next
end
# if \F* (Foot Forward Animation On "Other" Foot)
if c == "\022" and @float_id
speaker = (@float_id > 0) ? $game_map.events[@float_id] : $game_player
speaker.foot_forward_on(frame = 1)
# Dont take up space in window, next character
next
end
# If new line text
if c == "\n"
# Update cursor width if choice
if @y >= $game_temp.choice_start
width = $game_system.message.autocenter ? @line_widths[@y]+8 : @x
@cursor_width = [@cursor_width, width].max
end
# Add 1 to y
@y += 1
if $game_system.message.autocenter and @text != ""
@x = (self.width-40)/2 - @line_widths[@y]/2
else
@x = 0
# Indent if choice
if @y >= $game_temp.choice_start
@x = 8
end
end
# go to next text
next
end
# Draw text
self.contents.draw_text(4 + @x, 32 * @y, 40, 32, c)
# Add x to drawn text width
@x += self.contents.text_size( c ).width
# add text speed to time to display next character
@delay += @text_speed unless !@letter_by_letter or @player_skip
return if @letter_by_letter and !@player_skip
end
end
# If choice and window has choices set to be displayed
if $game_temp.choice_max > 0 and @choice_window
@item_max = $game_temp.choice_max
self.active = true
if $choice_index and $choice_index.is_a?(Integer) and
$choice_index < $game_temp.choice_max
self.index = $choice_index
else
self.index = 0
end
end
# If number input and this window shows choices and no number window exists
if $game_temp.num_input_variable_id > 0 and @choice_window and
not @input_number_window
digits_max = $game_temp.num_input_digits_max
number = $game_variables[$game_temp.num_input_variable_id]
@input_number_window = Window_InputNumber.new(digits_max)
@input_number_window.set_font(@font_name, @font_size, @font_color)
@input_number_window.number = number
@input_number_window.x =
if $game_system.message.autocenter
offset = (self.width-40)/2-@line_widths[$game_temp.num_input_start]/2
self.x + offset + 4
else
self.x + 8
end
@input_number_window.y = self.y + $game_temp.num_input_start * 32
end
@update_text = false
end
#--------------------------------------------------------------------------
# * Reset Window
#--------------------------------------------------------------------------
def reset_window
if $game_temp.in_battle
self.y = 16
else
case $game_system.message_position
when 0 # up
self.y = 16
when 1 # middle
self.y = 160
when 2 # down
self.y = 304
end
end
if $game_system.message_frame == 0
self.opacity = 255
else
self.opacity = 0
end
# transparent speech balloons don't look right, so keep opacity at 255
# self.back_opacity = 160
@tail.opacity = 255
end
#--------------------------------------------------------------------------
# * Update
#--------------------------------------------------------------------------
def update
super
# Terminate ANY Messages if Player too far away, useful for signs
if $scene.is_a?(Scene_Map)
if $game_system.map_interpreter.event_id != 0
e_id = $game_system.map_interpreter.event_id
ev = $game_map.events[e_id]
if ev and $game_map.events[e_id].dist_kill
if not ev.within_range?(ev.dist_kill, e_id) and
not $game_player.move_route_forcing and
$game_system.message.move_during and
(not ev.move_route_forcing or ev.move_route.repeat)
# Player moved too far away so kill windows and event processing
if @input_number_window != nil
# Dispose of number input window
@input_number_window.dispose
@input_number_window = nil
end
# Terminate This Msg - Leave Others so each handles their @float_id
terminate_message
# 115 Breaks Event Processing
$game_system.map_interpreter.command_115

# If there is someone speaking
if @float_id
# Player
# Note: No Move Continue because moving away
# is a Player initiated Action
if @float_id == 0
# reset foot forward on speak stance
if @auto_ff_reset and not $game_player.no_ff
# Command to turn Foot Forward Poses Off
$game_player.foot_forward_off
end
$game_player.allow_flip = false
$game_player.preferred_loc = nil
elsif @float_id > 0
# reset foot forward on speak stance
if @auto_ff_reset and not $game_map.events[@float_id].no_ff
# Command to turn Foot Forward Poses Off
$game_map.events[@float_id].foot_forward_off
end
# reset 'M'ove 'C'ontinue
if @auto_move_continue and not $game_map.events[@float_id].no_mc
# Continue doing what it was doing before
event_to_reset = $game_map.events[@float_id]
event_to_reset.event_move_continue(@float_id, true, 1)
end
$game_map.events[@float_id].allow_flip = false
$game_map.events[@float_id].preferred_loc = nil
end
end
# Instanced for this Msg Window, prevents calling Resets multiple times
@auto_ff_reset = false
# Turn off the Triggered Flag
ev.allow_flip = false
ev.preferred_loc = nil

if $game_temp.message_text.compact.empty?
ev.dist_kill = nil
$game_system.map_interpreter.restore_mmw_vars
#$game_map.need_refresh = true
if not $game_map.events[e_id].no_mc
$game_map.events[e_id].event_move_continue(e_id, true, 1)
$game_system.map_interpreter.max_dist_id = nil
end
end
# Load the Default Sound Settings because Player walked away
$game_system.message.load_sound_settings
end
end
end
end

# If fade in
if @fade_in
self.contents_opacity += 24
if @input_number_window != nil
@input_number_window.contents_opacity += 24
end
if self.contents_opacity == 255
@fade_in = false
end
# allow text to be updated while window is fading in
return if not $game_system.message.update_text_while_fading
end
# If inputting number
if @input_number_window != nil
@input_number_window.update
# Confirm
if Input.trigger?(Input::C)
# Allows windows to be closed
$game_temp.input_in_window = false
# play sound effect
$game_system.se_play($data_system.decision_se)
# Set Variable to identify the Number Window was Cancelled
$game_system.number_cancelled = false
# if variable_id was lost, refer to backup
if $game_temp.num_input_variable_id == 0
$game_variables[$game_temp.num_input_variable_id_backup] =
@input_number_window.number
else
$game_variables[$game_temp.num_input_variable_id] =
@input_number_window.number
end
$game_map.need_refresh = true
# Dispose of number input window
@input_number_window.dispose
@input_number_window = nil
if $scene.message_window.size > 1
for msg in $scene.message_window
msg.terminate_message
end
else
terminate_message
end
# Cancel, if allowed
# *NOTE* - use "number_cancelled?" to checks if Cancel Button was pushed
elsif Input.trigger?(Input::B) and
$game_system.message.allow_cancel_numbers
# play cancel sound effect
$game_system.se_play($data_system.cancel_se)
# Allows windows to be closed
$game_temp.input_in_window = false
# Set Variable to identify the Number Window was Cancelled
$game_system.number_cancelled = true
# Dispose of number input window
@input_number_window.dispose
@input_number_window = nil
if $scene.message_window.size > 1
for msg in $scene.message_window
msg.terminate_message
end
else
terminate_message
end
end
# prevent terminating windows and destroying variables
return
end
# If message is being displayed
if @contents_showing
# Confirm or cancel finishes waiting for input or message
if Input.trigger?(Input::C) or Input.trigger?(Input::B)
if @wait_for_input
@wait_for_input = false
self.pause = false
elsif $game_system.message.skippable
@player_skip = true
end
# Dont close the window if waiting for choices to be displayed
if $game_temp.input_in_window and
$game_temp.message_text.compact.size > 1 and
not $input_window_wait
# wait until next input to confirm any choices
$input_window_wait = true
return
else
$input_window_wait = false
end
end
if need_reposition?
reposition # update message position for character/screen movement
if @contents_showing == false
# i.e. if char moved off screen
return
end
end
if @update_text and !@wait_for_input
if @delay == 0
update_text
else
@delay -= 1
end
return
end

# If choice isn't being displayed, show pause sign
if !self.pause and ($game_temp.choice_max == 0 or @wait_for_input)
self.pause = true unless !$game_system.message.show_pause
end
# Cancel
if Input.trigger?(Input::B)
if $game_temp.choice_max > 0 and $game_temp.choice_cancel_type > 0
# Allow ALL windows to be closed
$game_temp.input_in_window = false
# Play Sound Effect
$game_system.se_play($data_system.cancel_se)
# Process the Choice
$game_temp.choice_proc.call($game_temp.choice_cancel_type - 1)
# If multi window cancel choice
if $scene.message_window.size > 1
for msg in $scene.message_window
msg.terminate_message
end
else
terminate_message
end
end
# personal preference: cancel button should also continue
terminate_message
end
# Confirm
if Input.trigger?(Input::C)
# Allow ALL windows to be closed
$game_temp.input_in_window = false
# if choice is displayed in one of multiple windows
if $game_temp.choice_max > 0
if $scene.message_window.size > 1
for i in 0...$scene.message_window.size
if $scene.message_window[i].choice_window
# return selection position by index of the choice window
@index = $scene.message_window[i].index
end
end
end
$game_system.se_play($data_system.decision_se)
$game_temp.choice_proc.call(self.index)
end
# If Preceeding Window not closed because choice displayed
if $scene.message_window.size > 1
choice = false
for i in 0...$scene.message_window.size
if $scene.message_window[i].choice_window
choice = true
break
end
end
# If window is a choice window and other windows held open
if choice
# close all the message windows
for msg in $scene.message_window
msg.terminate_message
end
else
# close the single message window
terminate_message
end
else
if $game_temp.choice_max > 0
$game_system.se_play($data_system.decision_se)
$game_temp.choice_proc.call(self.index)
end
terminate_message
end
end
return
end
# If display wait message or choice exists when not fading out
if @fade_out == false and $game_temp.message_text[@msgindex] != nil
@contents_showing = true
$game_temp.message_window_showing = true
reset_window
refresh
Graphics.frame_reset
self.visible = true
if show_message_tail?
@tail.visible = true
elsif @tail.visible
@tail.visible = false
end
self.contents_opacity = 0
if @input_number_window != nil
@input_number_window.contents_opacity = 0
end
@fade_in = true
return
end
# If message which should be displayed is not shown, but window is visible
if self.visible
@fade_out = true
self.opacity -= 96
@tail.opacity -= 96 if @tail.opacity > 0
if need_reposition?
# update message position for character/screen movement
reposition
end
if self.opacity == 0
self.visible = false
@fade_out = false
@tail.visible = false if @tail.visible
# have to check all windows before claiming that no window is showing
if $game_temp.message_text.compact.empty?
$game_temp.message_window_showing = false
end
end
return
end
end

#--------------------------------------------------------------------------
# * Repositioning Determination
#--------------------------------------------------------------------------
def need_reposition?
if !$game_temp.in_battle and $game_system.message.floating and
$game_system.message.resize and @float_id != nil
if $game_system.message.move_during and @float_id == 0 and
(($game_player.last_real_x != $game_player.real_x) or
($game_player.last_real_y != $game_player.real_y))
# player with floating message moved
# (note that relying on moving? leads to "jumpy" message boxes)
return true
elsif ($game_map.last_display_y != $game_map.display_y) or
($game_map.last_display_x != $game_map.display_x)
# player movement or scroll event caused the screen to scroll
return true
else
char = $game_map.events[@float_id]
if char != nil and
((char.last_real_x != char.real_x) or
(char.last_real_y != char.real_y))
# character moved
return true
end
end
end
return false
end

#--------------------------------------------------------------------------
# * Show Message Tail Determination
#--------------------------------------------------------------------------
def show_message_tail?
if $game_system.message.show_tail and $game_system.message.floating and
$game_system.message.resize and $game_system.message_frame == 0 and
@float_id != nil
return true
end
return false
end
#--------------------------------------------------------------------------
# * Update Cursor Posotion
#--------------------------------------------------------------------------
def update_cursor_rect
if @index >= 0
n = $game_temp.choice_start + @index
if $game_system.message.autocenter
x = 4 + (self.width-40)/2 - @cursor_width/2
else
x = 8
end
self.cursor_rect.set(x, n * 32, @cursor_width, 32)
else
self.cursor_rect.empty
end
end

end

#------------------------------------------------------------------------------

class Game_Character
attr_reader :last_real_x # last map x-coordinate
attr_reader :last_real_y # last map y-coordinate
attr_accessor :move_frequency # allows resetting if interrupted
attr_accessor :allow_flip # if event was triggered by player
attr_accessor :preferred_loc # triggered after Msg Reposition

alias heretic_game_ch_mmw_initialize initialize
def initialize
# Original
heretic_game_ch_mmw_initialize
# Used with Flip and Sticky Options...
@preferred_loc = nil
end

alias wachunga_game_char_update update
def update
@last_real_x = @real_x
@last_real_y = @real_y
wachunga_game_char_update
end

def within_range?(range = 4, id = @event_id)
e = $game_map.events[id]
radius = (Math.hypot((e.x - $game_player.x), (e.y - $game_player.y))).abs
return (range >= radius)
end
# If Heretic's Loop Maps is installed
if Game_Map.method_defined?(:map_loop_passable?)
#--------------------------------------------------------------------------
# * Within Range - Game_Character
# - Checks Distance between Player and Speaking Character
# - Uses Character Distance Method from Loop Maps for determining the
# difference in distance between Player and Event on Looping Maps
#--------------------------------------------------------------------------
def within_range?(range = 4, id = @event_id)
# Get Distance Difference between Player and Event
dx, dy = character_distance($game_player)
radius = Math.hypot(dx,dy).abs
return (range >= radius)
end
end

#----------------------------------------------------------------------------
# * Allows Animation Change regardless of Direction
#----------------------------------------------------------------------------

unless self.method_defined?('foot_forward_on')
def foot_forward_on(frame = 0)
return if @direction_fix or !@walk_anime or @step_anime or
$game_temp.in_battle
if frame == 0
case @direction
when 2
@pattern = 3
when 4, 6, 8
@pattern = 1
else
@pattern = 0
end
@original_pattern = @pattern
elsif frame == 1
case @direction
when 2
@pattern = 1
when 4, 6, 8
@pattern = 3
else
@pattern = 0
end
@original_pattern = @pattern
end
end

def foot_forward_off
# If called by walking off screen, dont affect a Sign or Stepping Actor
return if $game_temp.in_battle or @direction_fix or !@walk_anime or @no_ff
@pattern, @original_pattern = 0, 0
end
end

# Call from Event Editor => Scripts
# DO NOT call from Set Move Route => Scripts
def event_move_continue(event_id, valid = false, alt = false)
# return if Event has a No 'M'ove 'C'ontinue flag
return if @no_mc
# Restore Original Move Route if Event went off the screen while talking
# This may be buggy if multiple event pages are used
if @ff_original_move_route != nil and valid
# Release forced move route
@move_route_forcing = false
# Restore original values
@move_speed = @ff_original_move_speed
@move_frequency = @ff_original_move_frequency
@move_route = @ff_original_move_route
@move_route_index = @ff_original_move_route_index
# Release storing variables
@ff_original_move_index = nil
@ff_original_move_speed = nil
@ff_original_move_frequency = nil
@ff_original_move_route = nil
@original_move_route = nil
@original_move_route_index = nil
elsif @original_move_route != nil and valid and alt
# Release forced move route
@move_route_forcing = false
@move_route = @original_move_route
@move_route_index = @original_move_route_index
@original_move_route = nil
@original_move_route_index = nil
end
end

unless self.method_defined?('heretic_mmw_lock')
alias heretic_mmw_lock lock
alias heretic_mmw_unlock unlock
end

def lock
# Call Original
heretic_mmw_lock
# Store Movement Variables in case player walks away
@ff_original_move_route_index = @move_route_index
@ff_original_move_speed = @move_speed
@ff_original_move_frequency = @move_frequency
@ff_original_move_route = @move_route
# Store Variable that Event was Triggered by Player
@allow_flip = true
end

def unlock
# Call Original
heretic_mmw_unlock
# Unset Variable that Event was Triggered by Player
@allow_flip = false
@preferred_loc = nil
# Reset Player as well...
$game_player.allow_flip = false
$game_player.preferred_loc = nil
$game_player.sticky = false

# Unset any possible dist kill flags
if $game_temp.message_text.compact.empty?
$game_map.events[@id].dist_kill = nil if @id
$game_system.map_interpreter.max_dist_id = nil
end

# Reset Choice Index
$choice_index = 0

# Loads the Default Sound Settings at the End of Event Interaction
$game_system.message.load_sound_settings if $game_system.message.sound
end

end

#------------------------------------------------------------------------------

class Game_Player < Game_Character

attr_accessor :sticky # Used for Positioning Msg Bubbles

alias wachunga_mmw_game_player_update update
def update
# The conditions are changed so the player can move around while messages
# are showing (if move_during is true), but not if user is making a
# choice or inputting a number
# Note that this check overrides the default one (later in the method)
# because it is more general
unless moving? or
@move_route_forcing or
($game_system.map_interpreter.running? and
!$game_temp.message_window_showing) or
($game_temp.message_window_showing and
!$game_system.message.move_during) or
($game_temp.choice_max > 0 or $game_temp.num_input_digits_max > 0)
update_player_movement
end
wachunga_mmw_game_player_update
end

end

#------------------------------------------------------------------------------

class Game_Temp
alias wachunga_mmw_game_temp_initialize initialize
def initialize
wachunga_mmw_game_temp_initialize
@message_text = []
@message_proc = []
end
end

#------------------------------------------------------------------------------

class Sprite_Battler < RPG::Sprite
# necessary for positioning messages relative to battlers
attr_reader :height
attr_reader :width
end

#------------------------------------------------------------------------------

class Scene_Battle
# necessary for accessing actor/enemy sprites in battle
attr_reader :spriteset
end

#------------------------------------------------------------------------------

class Spriteset_Battle
# necessary for accessing actor/enemy sprites in battle
attr_reader :actor_sprites
attr_reader :enemy_sprites
end

#------------------------------------------------------------------------------

class Scene_Map
attr_accessor :message_window
# SDK Compatability
if Module.constants.include?('SDK')
def main_draw
# Make sprite set
@spriteset = Spriteset_Map.new
# Make message window
@message_window = []
@message_window[0] = Window_Message.new(0)
# Transition run
Graphics.transition
end

alias wachunga_mmw_scene_map_main_dispose main_dispose
def main_dispose
wachunga_mmw_scene_map_main_dispose
for mw in @message_window
mw.dispose
end
end

def update_graphics
# Update sprite set
@spriteset.update
# Update message window
for mw in @message_window
mw.update
end
end
end

#--------------------------------------------------------------------------
# * Scene_Map - New Message Window Addition
#--------------------------------------------------------------------------
def new_message_window(index)
if @message_window[index] != nil
# clear message windows at and after this index
last_index = @message_window.size - 1
last_index.downto(index) do |i|
if @message_window[i] != nil
@message_window[i].dispose
@message_window[i] = nil
end
end
@message_window.compact!
end
new_message = Window_Message.new(index)
@message_window.push(new_message)
end

end

#------------------------------------------------------------------------------

class Scene_Battle
attr_accessor :message_window

# If SDK is installed
if Module.constants.include?('SDK')
def main_windows
# Make other windows
@party_command_window = Window_PartyCommand.new
@help_window = Window_Help.new
@help_window.back_opacity = 160
@help_window.visible = false
@status_window = Window_BattleStatus.new
@message_window = []
@message_window[0] = Window_Message.new(0)
end

def main_dispose
# Dispose of windows
@actor_command_window.dispose
@party_command_window.dispose
@help_window.dispose
@status_window.dispose
for mw in @message_window
mw.dispose
end
@skill_window.dispose unless @skill_window == nil
@item_window.dispose unless @item_window == nil
@result_window.dispose unless @result_window == nil
# Dispose of sprite set
@spriteset.dispose
$choice_index = 0
end

def update_objects
# Update windows
@help_window.update
@party_command_window.update
@actor_command_window.update
@status_window.update
for mw in @message_window
mw.update
end
# Update sprite set
@spriteset.update
end

# End SDK / Non SDK Compatability Test
end

#--------------------------------------------------------------------------
# * Scene_Battle - New Message Window Addition
#--------------------------------------------------------------------------
def new_message_window(index)
if @message_window[index] != nil
# clear message windows at and after this index
last_index = @message_window.size - 1
last_index.downto(index) do |i|
if @message_window[i] != nil
@message_window[i].dispose
@message_window[i] = nil
end
end
@message_window.compact!
end
@message_window.push(Window_Message.new(index))
end

end

#------------------------------------------------------------------------------

class Game_System
attr_accessor :number_cancelled # Allows detection if a Number Input Cancel
attr_accessor :mmw_text # Holds Strings to show in Msgs \v[Tn]
attr_reader :message # Shortcut, allows message without $game_

alias wachunga_mmw_game_system_init initialize
def initialize
wachunga_mmw_game_system_init
@message = Game_Message.new
# allows detection if a Number Input was Cancelled
@number_cancelled = false
# Holds Strings to show in Msgs
@mmw_text = []
end
end

#------------------------------------------------------------------------------

class Interpreter
attr_reader :event_id
attr_reader :list
attr_accessor :index
attr_accessor :max_dist_id

alias wachunga_mmw_interp_setup setup
def setup(list, event_id)
wachunga_mmw_interp_setup(list, event_id)
# index of window for the message
@msgindex = 0
# whether multiple messages are displaying
@multi_message = false
# Id of Event that is using set_max_dist
@max_dist_id = nil
end

def setup_choices(parameters)
# Set Select Window to Active
$scene.message_window[@msgindex].active = true
# Set choice item count to choice_max
$game_temp.choice_max = parameters[0].size
# Set choice to message_text
for text in parameters[0]
# just add index for array
$game_temp.message_text[@msgindex] += text + "\n"
end
# Set cancel processing
$game_temp.choice_cancel_type = parameters[1]
# Set callback
current_indent = @list[@index].indent
$game_temp.choice_proc = Proc.new { |n| @branch[current_indent] = n }
end

# Not sure if this will be useful, leaving undocumented for now
def event_move_continue(event_id)
$game_map.events[event_id].event_move_continue(event_id, true)
end

def number_cancelled?
return $game_system.number_cancelled
end

def set_multi
# Setting these two variables causes the Next Message to be displayed.
@multi_message = true
@message_waiting = false
end

#--------------------------------------------------------------------------
# * Show Text
#--------------------------------------------------------------------------
def command_101
# If other text has been set to message_text
if $game_temp.message_text[@msgindex] != nil
if @multi_message
@msgindex += 1
$scene.new_message_window(@msgindex)
else
# End
return false
end
end
@msgindex = 0 if !@multi_message
@multi_message = false
# Set message end waiting flag and callback
@message_waiting = true
# just adding indexes
$game_temp.message_proc[@msgindex] = Proc.new { @message_waiting = false }
# Set message text on first line
$game_temp.message_text[@msgindex] = @list[@index].parameters[0] + "\n"
# Start Message on Line 1
line_count = 1
# Loop
loop do
# If next event command text is on the second line or after
if @list[@index+1].code == 401
# Add the second line or after to message_text
# just adding index
$game_temp.message_text[@msgindex]+=@list[@index+1].parameters[0]+"\n"
line_count += 1
# If event command is not on the second line or after
else
# If next event command is show choices
if @list[@index+1].code == 102
# If choices fit on screen
if @list[@index+1].parameters[0].size <= 4 - line_count
# Prevent the closure of a single window with multiple windows
$game_temp.input_in_window = true
# Flag this window as having choices displayed for multi
$scene.message_window[@msgindex].choice_window = @msgindex
# Advance index
@index += 1
# Choices setup
$game_temp.choice_start = line_count
setup_choices(@list[@index].parameters)
end
# If next event command is input number
elsif @list[@index+1].code == 103
# If number input window fits on screen
if line_count < 4
# Prevent the closure of a single window with multiple windows
$game_temp.input_in_window = true
# Flag this window as having choices displayed
$scene.message_window[@msgindex].choice_window = @msgindex
# Advance index
@index += 1
# Number input setup
$game_temp.num_input_start = line_count
$game_temp.num_input_variable_id = @list[@index].parameters[0]
$game_temp.num_input_digits_max = @list[@index].parameters[1]
$game_temp.num_input_variable_id_backup =
@list[@index].parameters[0]
end
# start multimessage if next line is "Show Text" starting with "\+"
elsif @list[@index+1].code == 101
if @list[@index+1].parameters[0][0..1]=="\\+"
@multi_message = true
@message_waiting = false
end
end
# Continue
return true
end
# Advance index
@index += 1
end
end

#--------------------------------------------------------------------------
# * Show Choices
#--------------------------------------------------------------------------
def command_102
# Prevent the closure of a single window with multiple windows
$game_temp.input_in_window = true
# Flag this window as having choices displayed for multi
$scene.message_window[@msgindex].choice_window = @msgindex
# If text has been set to message_text
# just adding index
if $game_temp.message_text[@msgindex] != nil
# End
return false
end
# Set message end waiting flag and callback
@message_waiting = true
# adding more indexes
$game_temp.message_proc[@msgindex] = Proc.new { @message_waiting = false }
# Choices setup
$game_temp.message_text[@msgindex] = ""
$game_temp.choice_start = 0
setup_choices(@parameters)
# Continue
return true
end

#--------------------------------------------------------------------------
# * Input Number
#--------------------------------------------------------------------------
def command_103
# Prevent the closure of a single window with multiple windows
$game_temp.input_in_window = true
# Flag this window as having choices displayed
$scene.message_window[@msgindex].choice_window = @msgindex
# If text has been set to message_text
# just adding index
if $game_temp.message_text[@msgindex] != nil
# End
return false
end
# Set message end waiting flag and callback
@message_waiting = true
# adding more indexes
$game_temp.message_proc[@msgindex] = Proc.new { @message_waiting = false }
# Number input setup
$game_temp.message_text[@msgindex] = ""
$game_temp.num_input_start = 0
$game_temp.num_input_variable_id = @parameters[0]
$game_temp.num_input_digits_max = @parameters[1]
$game_temp.num_input_variable_id_backup = @list[@index].parameters[0]
# Continue
return true
end

#--------------------------------------------------------------------------
# * Script
#--------------------------------------------------------------------------
# Fix for RMXP bug: call script boxes that return false hang the game
# See, e.g., http://rmxp.org/forums/showthread.php?p=106639
#--------------------------------------------------------------------------
def command_355
# Set first line to script
script = @list[@index].parameters[0] + "\n"
# Loop
loop do
# If next event command is second line of script or after
if @list[@index+1].code == 655
# Add second line or after to script
script += @list[@index+1].parameters[0] + "\n"
# If event command is not second line or after
else
# Abort loop
break
end
# Advance index
@index += 1
end
# Evaluation
result = eval(script)
# If return value is false
if result == false
# End
#return false
end
# Continue
return true
end

def message
$game_system.message
end

def within_range?(range = 4, id = @event_id)
e = $game_map.events[id]
radius = (Math.hypot((e.x - $game_player.x), (e.y - $game_player.y))).abs
return (radius <= range)
end

unless self.method_defined?('heretic_mmw_command_209')
alias heretic_mmw_command_202 command_202
alias heretic_mmw_command_209 command_209
end

#--------------------------------------------------------------------------
# * Set Event Location
#--------------------------------------------------------------------------
def command_202
# Run the Original
heretic_mmw_command_202
# Get character
character = get_character(@parameters[0])
# If no character exists, Player is still checked...
if character == nil
# Continue
return true
end
if @event_id != 0
$game_map.events[@event_id].allow_flip = false
$game_map.events[@event_id].preferred_loc = nil
end
# Return that the command has run...
return true
end
#--------------------------------------------------------------------------
# * Set Move Route
#--------------------------------------------------------------------------
def command_209
# Run the Original
heretic_mmw_command_209
# Get character
character = get_character(@parameters[0])
# If no character exists, Player is still checked...
if character == nil
# Continue
return true
end
if @parameters[1]
# Any Movement Related Commands, Turn Commands and Others are Ignored
codes = *[1..14]
# Scripts from Caterpillar that cause Movement in NPC's
commands = ['move_toward_event','move_away_from_event']
# Check the List of Move Commands to see if they are Movement Related...
for command in @parameters[1].list
if codes.include?(command.code) and @event_id != 0
$game_map.events[@event_id].allow_flip = false
$game_map.events[@event_id].preferred_loc = nil
# quit iterating
return true
elsif command.code == 45
script = command.parameters[0]
for string in commands
found = false
script.sub(string) {found = true}
if found and @event_id != 0
$game_map.events[@event_id].allow_flip = false if found
$game_map.events[@event_id].preferred_loc = nil if found
# quit iterating
return true
end
end
end
end
end
end

def set_max_dist(dist, save = true)
return if not $scene.is_a?(Scene_Map)
$game_map.events[@event_id].dist_kill = dist if dist.is_a?(Numeric)
# If Max Distance is 0 and Location is NOT Passable when triggered
if $game_map.events[@event_id].dist_kill == 0 and
(!$game_map.passable?($game_map.events[@event_id].x,
$game_map.events[@event_id].y,
0) or
($game_map.events[@event_id].character_name != "" and
!$game_map.events[@event_id].through))
# Bump it up to 1 because 0 doesnt work for non passable triggers
$game_map.events[@event_id].dist_kill = 1
end

# Prevent closing at a distance for other NPC's that might be speaking...
@max_dist_id = event_id
# Save MMW Configuration in case of a Walk Away...
save_mmw_vars if save
end

def clear_max_dist
return if not $scene.is_a?(Scene_Map)
# Leaves MMW Settings Intact and unsets Variable that causes End Commands
$game_map.events[@event_id].dist_kill = nil
end

def save_mmw_vars
# Window Skin
@windowskin_name_save = $game_system.windowskin_name
# MMW Variables
@mmw_vars_saved = true
@mmw_letter_by_letter = $game_system.message.letter_by_letter
@mmw_text_speed = $game_system.message.text_speed
@mmw_text_speed_player = $game_system.message.text_speed_player
@mmw_skippable = $game_system.message.skippable
@mmw_resize = $game_system.message.resize
@mmw_floating = $game_system.message.floating
@mmw_autocenter = $game_system.message.autocenter
@mmw_show_tail = $game_system.message.show_tail
@mmw_show_pause = $game_system.message.show_pause
@mmw_move_during = $game_system.message.move_during
@mmw_location = $game_system.message.location
@mmw_font_name = $game_system.message.font_name
@mmw_font_size = $game_system.message.font_size
@mmw_font_color = $game_system.message.font_color
@mmw_auto_comma_pause = $game_system.message.auto_comma_pause
@mmw_auto_comma_delay = $game_system.message.auto_comma_delay
@mmw_allow_cancel_numbers = $game_system.message.allow_cancel_numbers
@mmw_update_text_while_fading=$game_system.message.update_text_while_fading
@mmw_auto_ff_reset = $game_system.message.auto_ff_reset
@mmw_auto_move_continue = $game_system.message.auto_move_continue
@mmw_dist_exit = $game_system.message.dist_exit
@mmw_dist_max = $game_system.message.dist_max
@mmw_allow_offscreen = $game_system.message.allow_offscreen
@mmw_reposition_on_turn = $game_system.message.reposition_on_turn
@mmw_sticky = $game_system.message.sticky
# Sound Stuff
@mmw_sound = $game_system.message.sound
@mmw_sound_volume = $game_system.message.sound_volume
@mmw_sound_pitch = $game_system.message.sound_pitch
@mmw_sound_pitch_range = $game_system.message.sound_pitch_range
@mmw_sound_vary_pitch = $game_system.message.sound_vary_pitch
@mmw_sound_frequency = $game_system.message.sound_frequency
end

def restore_mmw_vars
if @mmw_vars_saved
# Windowskin - Used with Different Backgrounds on Signs
$game_system.windowskin_name = @windowskin_name_save
# MMW Variables
$game_system.message.letter_by_letter = @mmw_letter_by_letter
$game_system.message.text_speed = @mmw_text_speed
$game_system.message.text_speed_player = @mmw_text_speed_player
$game_system.message.skippable = @mmw_skippable
$game_system.message.resize = @mmw_resize
$game_system.message.floating = @mmw_floating
$game_system.message.autocenter = @mmw_autocenter
$game_system.message.show_tail = @mmw_show_tail
$game_system.message.show_pause = @mmw_show_pause
$game_system.message.move_during = @mmw_move_during
$game_system.message.location = @mmw_location
$game_system.message.font_name = @mmw_font_name
$game_system.message.font_size = @mmw_font_size
$game_system.message.font_color = @mmw_font_color
$game_system.message.auto_comma_pause = @mmw_auto_comma_pause
$game_system.message.auto_comma_delay = @mmw_auto_comma_delay
$game_system.message.allow_cancel_numbers = @mmw_allow_cancel_numbers
$game_system.message.update_text_while_fading=@mmw_update_text_while_fading
$game_system.message.auto_ff_reset = @mmw_auto_ff_reset
$game_system.message.auto_move_continue = @mmw_auto_move_continue
$game_system.message.dist_exit = @mmw_dist_exit
$game_system.message.dist_max = @mmw_dist_max
$game_system.message.allow_offscreen = @mmw_allow_offscreen
$game_system.message.reposition_on_turn = @mmw_reposition_on_turn
$game_system.message.sticky = @mmw_sticky
# Sound Stuff
$game_system.message.sound = @mmw_sound
$game_system.message.sound_volume = @mmw_sound_volume
$game_system.message.sound_pitch = @mmw_sound_pitch
$game_system.message.sound_pitch_range = @mmw_sound_pitch_range
$game_system.message.sound_vary_pitch=@mmw_sound_vary_pitch
$game_system.message.sound_frequency = @mmw_sound_frequency
end
end
end

#------------------------------------------------------------------------------

class Game_Map
attr_accessor :last_display_x # last display x-coord * 128
attr_accessor :last_display_y # last display y-coord * 128

alias wachunga_mmw_game_map_update update
def update
@last_display_x = @display_x
@last_display_y = @display_y
wachunga_mmw_game_map_update
end

# This was removed because it requires the SDK

#def name
# return load_data('Data/MapInfos.rxdata')[@map_id].name
#end

# Removes some of the need for the SDK

# NOTE: This is also defined in Caterpillar, which doesnt require the SDK

#----------------
# * Name
#----------------
@@map_info = load_data("Data/MapInfos.rxdata")

def name(id = @map_id)
return @@map_info[id].name
end

end

#------------------------------------------------------------------------------

# Note: I know this is a crappy way to do it, but I cant figure out another
# way to prevent the loss of data when showing a number input with multiple
# windows being displayed. It destroys the data before it can call the data
# so just creating a backup of that data. It works, thats all I care.

class Game_Temp
attr_accessor :num_input_variable_id_backup # prevents variable loss
attr_accessor :input_in_window # prevents window closures

#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
unless self.method_defined?('heretic_number_window_backup_initialize')
alias heretic_number_window_backup_initialize initialize
end

def initialize
# Call Original
heretic_number_window_backup_initialize
@num_input_variable_id_backup = 0
@input_in_window = false
end
end

#------------------------------------------------------------------------------

class Bitmap

attr_accessor :orientation

#--------------------------------------------------------------------------
# * Rotation Calculation
#--------------------------------------------------------------------------
def rotation(target)
return if not [0, 90, 180, 270].include?(target) # invalid orientation
if @rotation != target
degrees = target - @orientation
if degrees < 0
degrees += 360
end
rotate(degrees)
end
end

#--------------------------------------------------------------------------
# * Rotate Square (Clockwise)
#--------------------------------------------------------------------------
def rotate(degrees = 90)
# method originally by SephirothSpawn
# would just use Sprite.angle but its rotation is buggy
# (see http://www.rmxp.org/forums/showthread.php?t=12044)
return if not [90, 180, 270].include?(degrees)
copy = self.clone
if degrees == 90
# Passes Through all Pixels on Dummy Bitmap
for i in 0...self.height
for j in 0...self.width
self.set_pixel(width - i - 1, j, copy.get_pixel(j, i))
end
end
elsif degrees == 180
for i in 0...self.height
for j in 0...self.width
self.set_pixel(width - j - 1, height - i - 1, copy.get_pixel(j, i))
end
end
elsif degrees == 270
for i in 0...self.height
for j in 0...self.width
self.set_pixel(i, height - j - 1, copy.get_pixel(j, i))
end
end
end
@orientation = (@orientation + degrees) % 360
end

end

#------------------------------------------------------------------------------

class Window_Base

#--------------------------------------------------------------------------
# * Check Color
# color : color to check
#--------------------------------------------------------------------------
def check_color(color)
if color.is_a?(Color)
# already a Color object
return color
elsif color[0].chr == "#"
# specified as hexadecimal
r = color[1..2].hex
g = color[3..4].hex
b = color[5..6].hex
return Color.new(r,g,b)
else
# specified as integer (0-7)
color = color.to_i
if color >= 0 and color <= 7
return text_color(color)
end
end
return normal_color
end

end

#------------------------------------------------------------------------------

class Window_InputNumber < Window_Base

def set_font(fname, fsize, fcolor)
return if fname == nil and fsize == nil and fcolor == nil
# Calculate cursor width from number width
dummy_bitmap = Bitmap.new(32, 32)
dummy_bitmap.font.name = fname
dummy_bitmap.font.size = fsize
@cursor_width = dummy_bitmap.text_size("0").width + 8
dummy_bitmap.dispose
self.width = @cursor_width * @digits_max + 32
self.contents = Bitmap.new(width - 32, height - 32)
self.contents.font.name = fname
self.contents.font.size = fsize
self.contents.font.color = check_color(fcolor)
refresh
update_cursor_rect
end

def refresh
self.contents.clear
#self.contents.font.color = normal_color
s = sprintf("%0*d", @digits_max, @number)
for i in 0...@digits_max
self.contents.draw_text(i * @cursor_width + 4, 0, 32, 32, s[i,1])
end
end

end

#------------------------------------------------------------------------------
# * End SDK Enable Test
#------------------------------------------------------------------------------
#end

#==============================================================================
# ** Window_Base
#------------------------------------------------------------------------------
# This class is for all in-game windows.
#==============================================================================

class Window_Base < Window
#--------------------------------------------------------------------------
# * Frame Update - Redefinition - Added Aug 31st, 2013
#
# This fixes a Visual Bug where a Windowskin will change on you when
# a Non Floating Message Window is Fading Out. The NEXT Message will
# have the newly set Windowskin applied.
#--------------------------------------------------------------------------
def update
super
# Reset if windowskin was changed
if $game_system.windowskin_name != @windowskin_name
# Prevents changing Message Windowskin until Next Message
if not self.is_a?(Window_Message)
@windowskin_name = $game_system.windowskin_name
self.windowskin = RPG::Cache.windowskin(@windowskin_name)
end
end
end
end

# MMW SDK / Non-SDK Patch

# If SDK is not installed
if not Module.constants.include?('SDK')

# Use this script to disable Multiple Message Windows SDK Requirements

#=============================================================================
# ** Game_Multi_Message
#-----------------------------------------------------------------------------
# This class handles the actor array. Refer to "$game_actors" for each
# instance of this class.
#=============================================================================

class Game_Multi_Message
#--------------------------------------------------------------------------
# * Data
#--------------------------------------------------------------------------
def initialize() @data = [] end
def [](id) @data[id] end
def []=(id,val) @data[id] = val end
def update() @data.each {|s| s.respond_to?(:update) && s.update } end
def dispose() @data.each {|s| s.respond_to?(:dispose) && s.dispose } end
#--------------------------------------------------------------------------
# ● Method Missing
#--------------------------------------------------------------------------
def method_missing(val,*args,&block)
return @data.send(val.to_s,*args,&block) if @data.respond_to?(val.to_sym)
text = "Undefined method #{val} at #{self.inspect}"
raise(NoMethodError, text, caller(1))
end
end

#=============================================================================
# ** Scene_Map
#-----------------------------------------------------------------------------
# This class performs map screen processing.
#=============================================================================
class Scene_Map
#--------------------------------------------------------------------------
# ● Alias Listing
#--------------------------------------------------------------------------
$@ || alias_method(:mmw_sdk_patch_update, :update)
#--------------------------------------------------------------------------
# ● Main Dispose
#--------------------------------------------------------------------------
method_defined?(:main_dispose) or define_method(:main_dispose) {0}
#--------------------------------------------------------------------------
# ● Frame Update
#--------------------------------------------------------------------------
def update(*args)
unless @message_window.is_a?(Game_Multi_Message)
@message_window.respond_to?(:dispose) && @message_window.dispose
@message_window = Game_Multi_Message.new
@message_window[0] = Window_Message.new(0)
end
mmw_sdk_patch_update(*args)
end
end

#=============================================================================
# ** Scene_Battle
#-----------------------------------------------------------------------------
# This class performs battle screen processing.
#=============================================================================
class Scene_Battle
#--------------------------------------------------------------------------
# ● Alias Listing
#--------------------------------------------------------------------------
$@ || alias_method(:mmw_sdk_patch_update, :update)
#--------------------------------------------------------------------------
# ● Frame Update
#--------------------------------------------------------------------------
def update(*args)
unless @message_window.is_a?(Game_Multi_Message)
@message_window.respond_to?(:dispose) && @message_window.dispose
@message_window = Game_Multi_Message.new
@message_window[0] = Window_Message.new(0)
end
mmw_sdk_patch_update(*args)
end
end

#=============================================================================
# ** Game_Player
#-----------------------------------------------------------------------------
# This class handles the player. Its functions include event starting
# determinants and map scrolling. Refer to "$game_player" for the one
# instance of this class.
#=============================================================================
class Game_Player
#--------------------------------------------------------------------------
# * Player Movement Update
#--------------------------------------------------------------------------
unless method_defined?(:update_player_movement)
def update_player_movement
case Input.dir4
when 2 then move_down
when 4 then move_left
when 6 then move_right
when 8 then move_up
end
end
end
end

end # End SDK Not Installed

Das Problem: Das nutze ich nicht, da fehlt mir zu viel und ist zu viel drin, was ich nicht gebrauchen kann. Ich arbeite stattdessen mit Hermes 0.3c (Code als Zip-Datei (http://www.uglyhorst.de/rPG%20Maker/rGSS-Scripts/hermes/hermes03c.zip); sorry, aber der Code überschreitet die maximale Zeichenzahl). Neuere Versionen verursachen bei mir Kompabilitätsprobleme, bzw. sehe ich nicht ein, für den letter-by-letter speed zwei statt einen Buchstaben zu schreiben. ^^"

Ich habe nun bereits zwei Tools, die hier, wie ich meine, hilfreich sein könnten; das ist einmal der asynchronous-Tag bei Hermes, ein andermal das Script "Event Range Conditions" von ForeverZer0. Damit -- und mit etwas Variablen- und ID-Rumgeschiebe und einem PP-Event -- kriege ich das, was ich will, für genau eine einzige Message hin und auch das nur, wenn ich am Ende der Message einen close-tag anhänge.

Was mir jetzt also noch fehlt -- oder was insgesamt vielleicht völlig anders umgesetzt werden müsste, auch weil das Variablen-Rumgeschiebe und das PP-Event etwas aufwendig sind -- ist Folgendes:

Der Spieler kann sich also frei bewegen, während die Message über dem Event (geschwätziger NPC) angezeigt wird, muss aber am Ende der Message mit Enter die Message schließen, bevor die nächste beginnen kann. Er soll sich aber -- um's zusätzlich kompliziert zu machen -- weiterhin bewegen können, während die Message auf den Tastendruck wartet. Und der Spieler soll weiterhin die ganze Zeit einfach weglaufen können und nach z.B. zwei Tiles Entfernung zum Event soll die Message sich automatisch schließen und das Event in seinen Ausgangszustand zurückkehren.



Hat jemand eine Idee, wie sich das umsetzen ließe? Oder ist das ganz utopisch?
Ich kann mit MMW einfach nichts anfangen -- außer mit diesem einen sehr essentiellen Element davon.

Ghabry
09.12.2017, 16:19
Also da du ein Custom Script verwendest sinkt die Wahrscheinlichkeit stark, dass dir jemand helfen kann. Und das mit den "Nach 2 Tiles Entfernng schließen schließen" fällt mir spontan keine Funktion ein die das macht. Man muss vermutlich von Scene_Map aus @window_message.terminate aufrufen., aber das mit "2 Tiles entfernung" muss mal jmd. anderes liefern, zu viel Arbeit. Vermutlich Position des Events das die Message anzeigt ermitteln und dann einfach Distanz zwischen dem Event und dem Helden mit einer Metrik deiner Wahl (euklidisch oder Manhattan) berechnen.

Damit man noch laufen kann wenn eine Message angezeigt wird, würde bei nem Standard-Message-Script folgendes reichen:
Eventuell klappts auhc bei dem Custom script.

In Game_Player update ersetze die unless moving? Zeile mit


unless moving? or ($game_system.map_interpreter.running? and not $game_temp.message_window_showing) or
@move_route_forcing

Das "whitelisted" den Fall "interpreter läuft UND message window ist sichtbar".

Mordechaj
09.12.2017, 18:14
Erst einmal vielen Dank! Ich kann mir schon denken und kann auf alle Fälle verstehen, dass das die Wahrscheinlichkeit senkt; vor allem, weil man sich ja da erstmal anschauen muss, was dieses Script eigentlich so gut -- was ich übrigens selbst nur in sehr begrenztem Maße verstehe (wie begrenzt, wird sich gleich noch offenbaren ^^").

Die Entfernung kann ich beispielsweise mit Event-Scriptbefehlen aus ForeverZer0s Script (Code im Spoiler) abfragen.

class Interpreter

def range?(range = 4, id = @event_id)
e = $game_map.events[id]
radius = (Math.hypot((e.x - $game_player.x), (e.y - $game_player.y))).abs
return (radius <= range)
end

def on_screen?(id = @event_id)
x, y = $game_map.events[id].real_x, $game_map.events[id].real_y
return ((x - $game_map.display_x + 64) / 4).between?(0, 640) &&
((y - $game_map.display_y) / 4).between?(0, 480)
end

def x_dist?(distance = 0, id = @event_id)
x_dif = ($game_map.events[id].x - $game_player.x).abs
return (x_dif <= distance)
end

def y_dist?(distance = 0, id = @event_id)
y_dif = ($game_map.events[id].y - $game_player.y).abs
return (y_dif <= distance)
end

def player_above?(id = @event_id)
return ($game_map.events[id].y > $game_player.y)
end

def player_below?(id = @event_id)
return ($game_map.events[id].y < $game_player.y)
end

def player_right?(id = @event_id)
return ($game_map.events[id].x < $game_player.x)
end

def player_left?(id = @event_id)
return ($game_map.events[id].x > $game_player.x)
end
end


Was ich beispielsweise bisher gebastelt habe, sieht so aus:

Das ActionButton-Event:

# Variable 4 = ID dieses Events

Script: $game_variables[4] = @event_id

# Aktiviere den dazugehörigen Parallel Process
# (Befehl aus einem Utility Script)

Script: set_self_switch('A','On',3)

# Message Box über diesem Event, asynchronous
# (die Message wird angezeigt, ohne die Steuerung zu blockieren).
# Warte nach dem letzten Zeichen eine Sekunde (\|\|) bevor die Box
# geschlossen wird (\^)

Text: \p[,async]Tenny mucho mucho Deniro in su trucky-trailer?\|\|\^


Das dazugehörige Parallel Process Event macht Folgendes:

# Prüfe, ob Player noch in der Nähe ist
# (X-Achse: Distanz zu Event mit gespeicherter ID = 2?)
# Wenn nicht, zeige neue Message Box.
# Deaktiviere Parallel Process.

@>Conditional Branch: Script: x_dist?(2, $game_variables[4])
@>
: Else
@>Text: \p[kill,async]Lauf nicht weg!\|\|\^
@>Control Self Switch: A =OFF
: Branch End

# Prüfe, ob Player noch in der Nähe ist
# (Y-Achse: Distanz zu Event mit gespeicherter ID = 2?)
# Wenn nicht, zeige neue Message Box.
# Deaktiviere Parallel Process.

@>Conditional Branch: Script: y_dist?(2, $game_variables[4])
@>
: Else
@>Text: \p[kill,async]Lauf nicht weg!\|\|\^
@>Control Self Switch: A =OFF
: Branch End


Das Argument "kill" im \p-Tag ruft die Event ID aus Variable 4 ab, sodass die neue Message Box den aktuell über dem entsprechenden Event aktuell angezeigten Text abbricht und ersetzt. Wenn ich nur "\p[kill,async]" angebe, liest das Hermes-Script eine leere Message und löscht nur den über dem entsprechenden Event aktuell angezeigten Text.

Das läuft also im Prinzip genau so, wie ich es möchte (wobei meine Frage trotzdem noch ist, ob man das nicht galanter lösen könnte). Aber mit einer sehr entscheidenden Einschränkung:

Ich kann so nur eine einzige Message über dem Event ausgeben, weil der \p[,async]-Tag dazu führt, dass das Event automatisch die darauffolgende Nachricht ebenfalls ausliest, die dann automatisch ihren Vorgänger löscht. Außerdem muss ich die Messages so automatisch enden lassen, der Spieler kann die Message-Box also nicht durch Enter-Tastendruck schließen. Wenn es also bei dieser Lösung bleiben würde -- was nicht schlimm wär --, bräuchte ich die Möglichkeit, in einer async-Message am Ende einen Tastendruck zu verlangen, mit dem dann erst die nächste Message aufgerufen wird.


Damit man noch laufen kann wenn eine Message angezeigt wird, würde bei nem Standard-Message-Script folgendes reichen:
Eventuell klappts auhc bei dem Custom script.

In Game_Player update ersetze die unless moving? Zeile mit


unless moving? or ($game_system.map_interpreter.running? and not $game_temp.message_window_showing) or
@move_route_forcing

Das "whitelisted" den Fall "interpreter läuft UND message window ist sichtbar".
Das bedeutet also, ich würde für prinzipiell jede Message sagen, dass sie die Steuerung nicht blockieren soll? Kann ich das auch situativ, also bspw. mit einem Script-Befehl im Event machen?
Und: Der Effekt wäre dann, dass der Player noch bewegt werden kann; wie ist das mit dem Enter-Drücken am Ende der Nachricht? Könnte ich, als Spieler, rumlaufen und gleichzeitig durch Enterdrücken die Message Box schließen? Ich werde es bei Gelegenheit einfach mal ausprobieren, aber ich erwarte fast, dass das wie immer wird: Ich mach irgendwas kaputt und brauche Stunden, um herauszufinden, wie ich's wieder baue, sodass ich dann erst überhaupt testen kann.

Du merkst vielleicht, mein Scripting-Wissen ist massiv eingeschränkt; ich bin schon geschmeichelt, dass du mir zutraust zu wissen, was der Unterschied zwischen euklidisch und Manhattan ist. ^^"
Vor allem auch deshalb schonmal und nochmal: Vielen Dank!