Code:
# Genocide_Movement 1.0 - 8 pixel precise movement for RPG Maker XP
#
# Author: derula
#
# This script is taken from the German RPGXP project "Genocide" and adjusted
# for standalone usage. Permission is granted by the author to freely use and
# edit it as long as the game "Genocide" and the code's original author remain
# credited in the code. Other means of crediting are voluntary, but appreciated.
module Genocide_Movement
# Hier: Konfiguration
# Um wie viele Viertelfelder soll sich ein Event standardmäßig bewegen?
# (um ein Event um weniger zu bewegen, muss ein Skript benutzt werden)
# Standard: 4, Minimum: 1, Maximum: 4
EVENT_DISTANCE = 4
# Um wie viele Viertelfelder soll sich der Spieler standardmäßig bewegen?
# (um den Spieler um weniger zu bewegen, muss ein Skript benutzt werden)
# Standard: 1, Minimum: 1, Maximum: 4
PLAYER_DISTANCE = 1
# Diagonallaufen aktivieren oder deaktivieren
# Standard: true, Deaktivieren: false
PLAYER_8_DIR = true
# Taste für Strafe: Während diese Taste gedrückt ist, dreht sich der Spieler
# nicht automatisch in die Richtung, in die er geht.
# Standard: Input::Shift, Deaktivieren: nil
STRAFE_KEY = Input::SHIFT
# Kosten für Diagonalgehen
# Standard: Math.sqrt(2), Deaktivieren: nil
DIAGONAL_COST = Math.sqrt(2)
class ::Numeric
# Mapfeldkoordinate berechnen aus Fließpunktkoordinate
def to_field
if (i = to_i) == self
i
else
(self-0.125).round
end
end
end
class :Game_Character
#--------------------------------------------------------------------------
# * Calculate new position
# x : x-coordinate
# y : y-coordinate
# d : direction (0,1,2,3,4,6,7,8,9)
# * 0 = no change
# s : steps (1..4)
#--------------------------------------------------------------------------
def get_new_coordinates(x, y, d, s = EVENT_DISTANCE)
# Get move distance
s *= 0.25
# Get new coordinates
if d != 0
dx = (d % 3 == 0 ? 1 : d % 3 == 1 ? -1 : 0)
dy = (d <= 3 ? 1 : d >= 7 ? -1 : 0)
new_x, new_y = x + dx * s, y + dy * s
else
dx = dy = 0
new_x, new_y = x, y
end
[new_x, new_y, dx, dy]
end
#--------------------------------------------------------------------------
# * Determine if Passable
# x : x-coordinate
# y : y-coordinate
# d : direction (0,1,2,3,4,6,7,8,9)
# * 0 = Determines if all directions are impassable (for jumping)
# s : steps (1..4)
# n : new coordinates as calculated by get_new_coordinates
# if not specified, they are calculated here
#--------------------------------------------------------------------------
def passable?(x, y, d, s = EVENT_DISTANCE, n = get_new_coordinates(x, y, d, s))
# Get new coordinates
new_x, new_y, dx, dy = *n
# If coordinates are outside of map: impassable
return false unless $game_map.valid?(new_x, new_y)
# If through is ON: passable
return true if @through
# Get move distance
s *= 0.25
# Standfeld berechnen
fx, fy = x.to_field, y.to_field
# Überprüfen, ob neues Feld betreten wird
cx = ((x - fx).abs < s and 0 < dx*(new_x - x))
cy = ((y - fy).abs < s and 0 < dy*(new_y - y))
if cx and cy
return false unless $game_map.passable?(fx, fy, d) and $game_map.passable?(fx + dx, fy + dy, 10 - d)
elsif cx
return false unless $game_map.passable?(fx, fy, 5 + dx) and $game_map.passable?(fx + dx, fy, 5 - dx)
# Wenn y-Koordinate *,5 ist, Feld daneben prüfen
unless y == fy or $game_map.passable?(fx, fy + (y <=> fy), 5 + dx) and
$game_map.passable?(fx + dx, fy + (y <=> fy), 5 - dx)
return false
end
elsif cy
return false unless $game_map.passable?(fx, fy, 5 - 3*dy) and $game_map.passable?(fx, fy + dy, 5 + 3*dy)
# Wenn x-Koordinate *,5 ist, Feld daneben prüfen
unless x == fx or $game_map.passable?(fx + (x <=> fx), fy, 5 - 3*dy) and
$game_map.passable?(fx + (x <=> fx), fy + dy, 5 + 3*dy)
return false
end
end
# Loop all events
for event in $game_map.events.values
next if event == self or event.through
# If through is OFF and (self is player => partner graphic as character)
# and event coordinates are consistent with move destination
if #not event.through and event.character_name != "" and
(self != $game_player or event.character_name != "") and
(event.x - new_x).abs < 1 and (event.y - new_y).abs < 1
# impassable
return false
end
end
# If self is not player, player through is OFF coordinates are consistent
# with move destination and your own graphic is the character
if self != $game_player and not $game_player.through and
@character_name != "" and ($game_player.x - new_x).abs < 1 and
($game_player.y - new_y).abs < 1
# impassable
return false
end
# passable
return true
end
#--------------------------------------------------------------------------
# * Move
# dir : direction (0,1,2,3,4,6,7,8,9)
# steps : number of steps to move (4 = 1 field)
# turn_enabled : a flag permits direction change on that spot
#--------------------------------------------------------------------------
def move(dir, steps = EVENT_DISTANCE, turn_enabled = true)
return if dir == 0
turned = false
# Turn to specified direction
if turn_enabled
turn(dir)
turned = true
end
# Calculate new coordinates
new_coords = get_new_coordinates(@x, @y, dir, steps)
# If passable and route free
if passable?(@x, @y, dir, steps, new_coords)
# Turn to specified direction
turn(dir) unless turned
# Update coordinates
@x, @y = new_coords
# Increase steps
increase_steps
# Slide if moving diagonally
elsif dir % 2 == 1 and
((m = dir % 6) == 1 and passable?(@x, @y, 4, steps, n = get_new_coordinates(@x, @y, 4, steps)) or
(m == 3 and passable?(@x, @y, 6, steps, n = get_new_coordinates(@x, @y, 6, steps))) or
(dir < 5 and passable?(@x, @y, 2, steps, n = get_new_coordinates(@x, @y, 2, steps))) or
(dir > 5 and passable?(@x, @y, 8, steps, n = get_new_coordinates(@x, @y, 8, steps))))
# Update coordinates
@x, @y = n#ew_coords
# Increase steps
increase_steps
# If impassable
else
# Determine if touch event is triggered
check_event_trigger_touch(new_coords[0], new_coords[1])
end
end
#--------------------------------------------------------------------------
# * Move Down
# turn_enabled : a flag permits direction change on that spot
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_down(turn_enabled = true, steps = EVENT_DISTANCE)
move(2, steps, turn_enabled)
end
#--------------------------------------------------------------------------
# * Move Left
# turn_enabled : a flag permits direction change on that spot
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_left(turn_enabled = true, steps = EVENT_DISTANCE)
move(4, steps, turn_enabled)
end
#--------------------------------------------------------------------------
# * Move Right
# turn_enabled : a flag permits direction change on that spot
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_right(turn_enabled = true, steps = EVENT_DISTANCE)
move(6, steps, turn_enabled)
end
#--------------------------------------------------------------------------
# * Move up
# turn_enabled : a flag permits direction change on that spot
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_up(turn_enabled = true, steps = EVENT_DISTANCE)
move(8, steps, turn_enabled)
end
#--------------------------------------------------------------------------
# * Move Lower Left
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_lower_left(steps = EVENT_DISTANCE)
move(1, steps)
end
#--------------------------------------------------------------------------
# * Move Lower Right
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_lower_right(steps = EVENT_DISTANCE)
move(3, steps)
end
#--------------------------------------------------------------------------
# * Move Upper Left
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_upper_left(steps = EVENT_DISTANCE)
move(7, steps)
end
#--------------------------------------------------------------------------
# * Move Upper Right
# steps : number of steps to move (4 = 1 field)
#--------------------------------------------------------------------------
def move_upper_right(steps = EVENT_DISTANCE)
move(9, steps)
end
#--------------------------------------------------------------------------
# * Turn
# d : direction (1,2,3,4,6,7,8,9)
#--------------------------------------------------------------------------
def turn(d)
# If no direction fix
unless @direction_fix
if d % 2 == 1
# If diagonal direction specified, replace it with good straight
# direction if the character is facing an opposite direction
if ((m = d % 6) == 1 and @direction == 6) or
(m == 3 and @direction == 4) or
(d < 5 and @direction == 8) or
(d > 5 and @direction == 2)
@direction = 10 - @direction
end
else
@direction = d
end
@stop_count = 0
end
end
#--------------------------------------------------------------------------
# * Update frame (move)
#--------------------------------------------------------------------------
def update_move
# Convert map coordinates from map move speed into move distance
distance = 2 ** @move_speed
# Apply cost for diagonal movement
if DIAGONAL_COST and @x * 128 != @real_x and @y * 128 != @real_y
distance = (distance / DIAGONAL_COST).round
end
# If logical coordinates are further down than real coordinates
if @y * 128 > @real_y
# Move down
@real_y = [@real_y + distance, @y * 128].min
end
# If logical coordinates are more to the left than real coordinates
if @x * 128 < @real_x
# Move left
@real_x = [@real_x - distance, @x * 128].max
end
# If logical coordinates are more to the right than real coordinates
if @x * 128 > @real_x
# Move right
@real_x = [@real_x + distance, @x * 128].min
end
# If logical coordinates are further up than real coordinates
if @y * 128 < @real_y
# Move up
@real_y = [@real_y - distance, @y * 128].max
end
# If move animation is ON
if @walk_anime
# Increase animation count by 1.5
@anime_count += 1.5
# If move animation is OFF, and stop animation is ON
elsif @step_anime
# Increase animation count by 1
@anime_count += 1
end
end
end
class :Game_Event
#--------------------------------------------------------------------------
# * Touch Event Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_touch(x, y)
# If event is running
if $game_system.map_interpreter.running?
return
end
# If starting determinant other than jumping is front event and
# trigger is [touch from event] and consistent with player coordinates
if @trigger == 2 and not over_trigger? and not jumping? and
($game_player.x - @x).abs < 1 and ($game_player.y - @y).abs < 1
start
end
end
#--------------------------------------------------------------------------
# * Automatic Event Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_auto
# If starting determinant other than jumping is same position event and
# trigger is [touch from event] and consistent with player coordinates
if @trigger == 2 and over_trigger? and not jumping? and
($game_player.x - @x).abs < 1 and ($game_player.y - @y).abs < 1
start
# If trigger is [auto run]
elsif @trigger == 3
start
end
end
end
# Schüsse/Treffer und Achtrichtungs- und Pixelmovement
class :Game_Player
def move(dir, steps = PLAYER_DISTANCE, turn_enabled = true)
super
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
# Remember whether or not moving in local variables
last_moving = moving?
# Richtung fixieren
if STRAFE_KEY
if Input.press?(STRAFE_KEY)
if @pre_fix == nil
@pre_fix = @direction_fix
@direction_fix = true
end
elsif @pre_fix != nil
@direction_fix = @pre_fix
@pre_fix = nil
end
end
# If moving, event running, move route forcing, and message window
# display are all not occurring
if not (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
move(PLAYER_8_DIR ? Input.dir8 : Input.dir4)
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
#--------------------------------------------------------------------------
# * Passable Determinants
# x : x-coordinate
# y : y-coordinate
# d : direction (0,2,4,6,8)
# * 0 = Determines if all directions are impassable (for jumping)
# s : steps (1..4)
#--------------------------------------------------------------------------
def passable?(x, y, d, s = 4, n = get_new_coordinates(x, y, d, s))
# If coordinates are outside of map: impassable
return false unless $game_map.valid?(n[0], n[1])
# If debug mode is ON and ctrl key was pressed: passable
return true if $DEBUG and Input.press?(Input::CTRL)
super
end
#--------------------------------------------------------------------------
# * Same Position Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_here(triggers)
# If no event is running
unless $game_system.map_interpreter.running?
# All event loops
for event in $game_map.events.values
# If triggers are consistent, starting determinant is same position event
# (other than jumping) and event coordinates are consistent
if event.over_trigger? and triggers.include?(event.trigger) and
(not event.jumping?) and (event.x - @x).abs < 1 and (event.y - @y).abs < 1
event.start
return true
end
end
end
return false
end
#--------------------------------------------------------------------------
# * Front Envent Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_there(triggers)
# If no event is running
unless $game_system.map_interpreter.running?
# Calculate front event coordinates
new_x = @x + (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
new_y = @y + (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
# All event loops
for event in $game_map.events.values
# If triggers are consistent, starting determinant is front event
# (other than jumping) and event coordinates are consistent
if not event.over_trigger? and triggers.include?(event.trigger) and
not event.jumping? and (event.x - new_x).abs < 1 and (event.y - new_y).abs < 1
event.start
return true
end
end
# If front tile is a counter
if $game_map.counter?(new_x, new_y)
# Calculate 1 tile inside coordinates
new_x += (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
new_y += (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
# All event loops
for event in $game_map.events.values
# If triggers are consistent, starting determinant is front event
# (other than jumping) and event coordinates are consistent
if not event.over_trigger? and triggers.include?(event.trigger) and
not event.jumping? and (event.x - new_x).abs < 1 and (event.y - new_y).abs < 1
event.start
return true
end
end
end
end
return false
end
#--------------------------------------------------------------------------
# * Touch Event Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_touch(x, y)
# If no event is running
unless $game_system.map_interpreter.running?
# All event loops
for event in $game_map.events.values
# If triggers are consistent, starting determinant is front event
# (other than jumping) and event coordinates are consistent
if not event.over_trigger? and not event.jumping? and
[1,2].include?(event.trigger) and (event.x - x).abs < 1 and (event.y - y).abs < 1
event.start
return true
end
end
end
return false
end
end
end