Greetings,
I am using RPG Maker Ace, and it's very fun to use. I am trying to implement local two player capability. I've searched the web and it appears the only option right now is this script from Tsukihime:
http://www.rpgmakercentral.com/topic/4128-simple-2-player-script-development/ (http://www.rpgmakercentral.com/topic/4128-simple-2-player-script-development/)
I followed his instructions, and it works just as he described; However, it has limitations. It creates a copy of the player sprite and allows you to control that as a second player, but you can't make the two players have separate sprites (as far as I am aware!).
Now despite knowing practically nothing about script programming, I really wanted to try and solve this myself. So I spent a long while modifying things in the script editor, deleting and testing, modifying script (don't worry, I ensured to undo any of the damage I caused after I tested).
My tampering was not altogether useless however. I discovered the following:
In "Spriteset_Map" in the script editor, go to about line 60, and you'll see the "Create Character Sprite" section. At the bottom of that small section there is the following code:
@character_sprites.push(Sprite_Character.new(@viewport1, $game_player))
@map_id = $game_map.map_id
When I saw 'game_player' at the end, I decided to try and change it to 'game_player2' like in Tsukihime's script. The results were exciting. :)
The first actor of the initial party could be controlled with the multiplayer script (w,a,s,d keys), and second actor in the initial party could be controlled with the default keys.
In Database on the System tab you can change the sprite of both characters to whatever you wanted.
But there is one catch. The movement of the default keys player is now delayed. To change direction, you have to press the key 2-3 times, and the player will move in it's initial direction one tile before moving correctly. Very odd. It reminded me of followers.
My theory is that if the follower movement delay was gone, the movement of the default keys player would be normal.
But alas, I know nothing of scripting. So while I'm suspecting this to be the culprit:
Script Editor > Game_Follower, at about line 55 there is a section called "Pursue Preceding Character"
....I really have not the slightest idea on how to fix it. I could be way off base. Sorry for the lengthy description, it all seems so complicated. :???: Any help is appreciated!
I'm not sure I understand what you mean by your edit to Spriteset_Map; doing so just only shows one actor on the map: $game_player2. In fact, you would be drawing him twice because the 2-player script already adds $game_player2 in, as seen:
class Spriteset_Map
alias :th_multiplayer_create_characters :create_characters
def create_characters
th_multiplayer_create_characters
@character_sprites.push(Sprite_Character.new(@viewport1, $game_player2))
end
end
If all you want is to make the second party member be drawn for $game_player2, you can just add this method inside class Game_Multiplayer
def actor
$game_party.battle_members[1]
end
This was taken from the Game_Player class:
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
@character_name = actor ? actor.character_name : ""
@character_index = actor ? actor.character_index : 0
@followers.refresh
end
#--------------------------------------------------------------------------
# * Get Corresponding Actor
#--------------------------------------------------------------------------
def actor
$game_party.battle_members[0]
end
If you define the actor the player is supposed to represent, the game will set the graphic for you automatically in
refresh.
Quote from: KK20 on January 07, 2017, 02:08:12 am
If all you want is to make the second party member be drawn for $game_player2, you can just add this method inside class Game_Multiplayer
def actor
$game_party.battle_members[1]
end
Thank you KK20, you're a genius! :D That explanation makes total sense. I undid my modification to the Spriteset_Map, and followed your instructions. This mod to the script resolved the lag issue.
But there is another problem. Since the whole setup makes a follower become a second player, I went ahead and tested to see if I could gain a follower with both of the players. It appears this two player setup disables the ability to have followers at all. Is this script simply incompatible with the follower function?
If you have "Show Player Followers" enabled in the System tab, then only $game_player will have followers; $game_player2 will not. (If it's not doing this, you must have another script that's causing issues)
But I don't know why you would want to do that since your "party" must consist of two actors: one for $game_player and one for $game_player2. Followers are just party members that are not in the first slot. In this case, $game_player will have an actor that looks like $game_player2 follow them around.
(http://i.imgur.com/R9bkJMD.png)
If you can explain what it is that you want, I can probably point you in the right direction.
Show Player Followers was enabled, so it must be script like you said.
I started a fresh project and copied over the fullkeyboard and multiplayer scripts only. I added the other player in the system tab, and ran the game. It appeared just like your screenshot - Player1 and Player2 with another Player2 sprite following Player1. I must have forgot to undo some code adding/deleting during my initial haphazard 'troubleshooting'. :facepalm:
It makes sense. If "Show Player Followers" is disabled, then it shows up just like I want it but without the ability to see followers I actually want to add.
I obviously can't have another player 2 sprite following player 1 around.
To answer your question, I'm trying to make the game two player with the ability for a player to walk up to an NPC and trigger an event that adds that NPC to the party. I don't mind if it only can follow Player1.
I really appreciate your help, thank you!
I found this script that can help with making events follow the player: http://himeworks.com/2013/03/event-followers/
In order to make it work for two players, I had to do some slight edits.
module DataManager
class << self
alias :th_multiplayer_create_game_objects :create_game_objects
alias :th_multiplayer_make_save_contents :make_save_contents
alias :th_multiplayer_extract_save_contents :extract_save_contents
end
def self.create_game_objects
th_multiplayer_create_game_objects
$game_player2 = Game_Multiplayer.new
end
def self.make_save_contents
contents = th_multiplayer_make_save_contents
contents[:player2] = $game_player2
contents
end
def self.extract_save_contents(contents)
th_multiplayer_extract_save_contents(contents)
$game_player2 = contents[:player2]
end
def self.setup_new_game
create_game_objects
$game_party.setup_starting_members
$game_map.setup($data_system.start_map_id)
$game_player.moveto($data_system.start_x, $data_system.start_y)
$game_player.refresh
$game_player2.moveto($data_system.start_x, $data_system.start_y)
$game_player2.refresh
Graphics.frame_count = 0
end
end
class Game_Multiplayer < Game_Player
DOWN = Input::Y # S in Keyboard
LEFT = Input::X # A in Keyboard
RIGHT = Input::Z # D in Keyboard
UP = Input::R # W in Keyboard
ENTER = Input::L # Q in Keyboard
RUN = Input::A # Shift in Keyboard
#--------------------------------------------------------------------------
# * Get Corresponding Actor
#--------------------------------------------------------------------------
def actor
$game_party.battle_members[1]
end
def move_by_input
return unless movable?
return if $game_map.interpreter.running?
if Input.press?(DOWN)
move_straight(2)
elsif Input.press?(LEFT)
move_straight(4)
elsif Input.press?(RIGHT)
move_straight(6)
elsif Input.press?(UP)
move_straight(8)
end
end
def update_nonmoving(last_moving)
return if $game_map.interpreter.running?
if last_moving
$game_party.on_player_walk
return if check_touch_event
end
if movable? && Input.trigger?(ENTER)
return if get_on_off_vehicle
return if check_action_event
end
update_encounter if last_moving
end
#--------------------------------------------------------------------------
# * Trigger Map Event
# triggers : Trigger array
# normal : Is priority set to [Same as Characters] ?
#--------------------------------------------------------------------------
def start_map_event(x, y, triggers, normal)
return if $game_map.interpreter.running?
$game_map.events_xy(x, y).each do |event|
if event.trigger_in?(triggers) && event.normal_priority? == normal
event.start(true)
end
end
end
end
class Game_Event < Game_Character
#--------------------------------------------------------------------------
# * Start Event
#--------------------------------------------------------------------------
def start(player2=false)
return if empty?
@triggered_by = player2 ? $game_player2 : $game_player
@starting = true
lock if trigger_in?([0,1,2])
end
end
class Spriteset_Map
alias :th_multiplayer_create_characters :create_characters
def create_characters
th_multiplayer_create_characters
@character_sprites.push(Sprite_Character.new(@viewport1, $game_player2))
end
end
class Scene_Map < Scene_Base
alias :th_multiplayer_map_update :update
def update
th_multiplayer_map_update
$game_player2.update if $game_player2
end
end
=begin
#===============================================================================
Title: Event Followers
Author: Hime
Date: Feb 19, 2015
--------------------------------------------------------------------------------
** Change log
Fev 19, 2015
- event followers also move diagonally
Mar 31, 2014
- moving behind leader had the y-positions mixed up
Jan 9, 2014
- fixed bug where adding a follower to a leader was following the last
follower of the leader, not the leader itself
Jul 31, 2013
- added new following logic for more accurate following
Jul 25, 2013
- fixed bug where event follower speed wasn't updated to leader's speed
Mar 29, 2013
- Events following the player will now follow the last follower
- Initial release
--------------------------------------------------------------------------------
** Terms of Use
* Free to use in non-commercial projects
* Contact me for commercial use
* No real support. The script is provided as-is
* Will do bug fixes, but no compatibility patches
* Features may be requested but no guarantees, especially if it is non-trivial
* Credits to Hime Works in your project
* Preserve this header
--------------------------------------------------------------------------------
** Description
This script allows events to designate a "leader" that another character will
follow. This could be the player, the current event, or any other event.
Any characters following a leader will follow that leader.
--------------------------------------------------------------------------------
** Installation
Place this below Materials and above Main
--------------------------------------------------------------------------------
** Usage
The following method calls are available to Game_Character objects.
follow(event_id)
stop_follow
This can be called by any character object such as players or events.
If you make a script call and say
follow(event_id)
Then the event specified by the move route will follow that character.
You can also say things like
$game_player.follow(event_id)
$game_map.events[3].follow(event_id)
If the event_id is -1, then the character will follow the player.
otherwise, it will follow the specified event on the current map.
To stop following a character, make the script call
stop_follow
Again, remember from whose perspective the script call is being made from.
#===============================================================================
=end
$imported = {} if $imported.nil?
$imported["TH_EventFollowers"] = true
#===============================================================================
# ** Configuration
#===============================================================================
module TH
module Event_Followers
end
end
#===============================================================================
# ** Rest of Script
#===============================================================================
class Game_Character < Game_CharacterBase
attr_reader :event_followers
alias :th_event_followers_init_public_members :init_public_members
def init_public_members
th_event_followers_init_public_members
@event_followers = Game_EventFollowers.new(self)
@leader = nil
end
alias :th_event_followers_move_straight :move_straight
def move_straight(d, turn_ok = true)
@event_followers.move if passable?(@x, @y, d)
th_event_followers_move_straight(d, turn_ok)
end
alias :th_event_followers_update :update
def update
th_event_followers_update
update_following if following?
end
#-----------------------------------------------------------------------------
# New
#-----------------------------------------------------------------------------
def update_following
@move_speed = @leader.real_move_speed
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def following?
!@leader.nil?
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def last_follower
return @event_followers[-1] if @event_followers.size > 0
return self
end
#-----------------------------------------------------------------------------
# New. Backup this character's original settings
#-----------------------------------------------------------------------------
def store_original_settings
@old_through = @through
@old_move_speed = @move_speed
@old_real_move_speed = @real_move_speed
@old_transparent = @transparent
@old_walk_anime = @walk_anime
@old_step_anime = @step_anime
@old_direction_fix = @direction_fix
@old_opacity = @opacity
@old_blend_type = @blend_type
end
#-----------------------------------------------------------------------------
# New. Once we stop following another character, revert all original settings
#-----------------------------------------------------------------------------
def revert_original_settings
@through = @old_through
@move_speed = @old_move_speed
@real_move_speed = @old_real_move_speed
@transparent = @old_transparent
@walk_anime = @old_walk_anime
@step_anime = @old_step_anime
@direction_fix = @old_direction_fix
@opacity = @old_opacity
@blend_type = @old_blend_type
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def get_follow_leader(event_id) #KK20
# -1 is assumed to be the player
if event_id == 0
@triggered_by
elsif event_id == -1
$game_player
elsif event_id == -2
$game_player2
else
$game_map.events[event_id]
end
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def chase_preceding_character
unless moving?
sx = distance_x_from(@preceding_character.x)
sy = distance_y_from(@preceding_character.y)
if sx != 0 && sy != 0
move_diagonal(sx > 0 ? 4 : 6, sy > 0 ? 8 : 2)
elsif sx != 0
move_straight(sx > 0 ? 4 : 6)
elsif sy != 0
move_straight(sy > 0 ? 8 : 2)
end
end
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def move_behind_leader
x = @leader.x
y = @leader.y
case @leader.direction
when 2
y += 1
when 4
x += 1
when 6
x -= 1
when 8
y -= 1
end
x = [[1, x].max, $game_map.width-1].min
y = [[1, y].max, $game_map.height-1].min
moveto(x, y)
end
#-----------------------------------------------------------------------------
# New. Begin following the specified event.
#-----------------------------------------------------------------------------
def follow(event_id=0)
return if following?
@leader = get_follow_leader(event_id)
@preceding_character = @leader.last_follower
@leader.add_event_follower(self)
move_behind_leader
store_original_settings
@move_speed = @leader.move_speed
@transparent = @leader.transparent
@walk_anime = @leader.walk_anime
@step_anime = @leader.step_anime
@direction_fix = @leader.direction_fix
@opacity = @leader.opacity
@blend_type = @leader.blend_type
@through = true
end
#-----------------------------------------------------------------------------
# New. Stop following a leader
#-----------------------------------------------------------------------------
def stop_follow
@through = false
@leader.remove_event_follower(self)
@preceding_character = nil
@leader = nil
revert_original_settings
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def add_event_follower(char)
@event_followers.add(char)
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def remove_event_follower(char)
@event_followers.remove(char)
end
alias :th_event_followers_move_diagonal :move_diagonal
def move_diagonal(horz, vert)
@event_followers.move if diagonal_passable?(@x, @y, horz, vert)
th_event_followers_move_diagonal(horz, vert)
end
end
class Game_Event < Game_Character
#-----------------------------------------------------------------------------
# Ignore autonomous movement if following leader
#-----------------------------------------------------------------------------
alias :th_event_followers_update_self_movement :update_self_movement
def update_self_movement
return if following?
th_event_followers_update_self_movement
end
end
class Game_Player < Game_Character
#-----------------------------------------------------------------------------
# New. Since player happens to have different types of followers we have to
# check
#-----------------------------------------------------------------------------
def last_follower
return super if @event_followers.size > 0
follower_size = $game_player.followers.visible_folloers.size
return @followers[follower_size - 1] if follower_size > 0
return self
end
#-----------------------------------------------------------------------------
# Ignore player movement input if following leader
#-----------------------------------------------------------------------------
alias :th_event_followers_movable? :movable?
def movable?
return false if following?
th_event_followers_movable?
end
alias :th_event_followers_dash? :dash?
def dash?
return false if following?
th_event_followers_dash?
end
end
#-------------------------------------------------------------------------------
# Similar to player followers, except instead of pulling data from the party
# members it simply holds references to existing events
#-------------------------------------------------------------------------------
class Game_EventFollowers < Game_Followers
include Enumerable
def initialize(leader)
@data = []
end
def size
@data.size
end
def index(char)
@data.index(char)
end
def add(character)
@data.push(character)
end
def remove(character)
@data.delete(character)
end
end
class Game_Interpreter
def follow(id=0)
$game_map.events[@map_id].follow(id)
true
end
end
With the "Show Player Followers" disabled, you can create an event on the map with a Script command
and this will automatically follow the player that talked to it. To remove the event from following, the command is
$game_map.events[ID].stop_follow
where ID is the event ID that is following a player.
You can specify a specific player to follow using the following:
follow(-1) # Follows player 1
follow(-2) # Follows player 2
KK20,
This works great! :) I've had that "Event Followers" page open on my browser for a few days, but hadn't looked at. With your mods, it's perfect!
I went ahead and did another test involving transferring players from one map to the next. While the follower did not show up on the other map, I simply copied the event to the new map and ran it as a parallel process so he would automatically be following once they transferred. I read some of the comments at the bottom of the website link you sent me and it appears that events are not transferable, so my workaround will suffice quite well.
It did bring up another issue with the multiplayer script though - when you transfer the players to a new map, player2 shows up just a few tiles away. The big problem is if the location is really small, like a path only one map tile in width, then player 2 is not visible in the new location. I would like either to have player2 land on the same tile as player1, or maybe on a specified tile. I've looked at the multiplayer script, Scene_Map, Game_Follower, and Game_Party, but I don't see anything obvious.
Of course, I know hardly anything concerning script, so maybe the solution was right in front of me.
Also, when I set an event's move route to approach player, it goes toward player1. My idea for fixing that was to go to Script Editor > 'Game_Character' and add this:
def move_toward_player2
move_toward_character($game_player2)
end
Then, go to 'Game_Event' and modify the 'random' script in the "Move Type : Approach" section. I'm not sure if I'm on the right track, but I want an NPC to approach either of the two players (who ever is closest) and trigger with event touch.
Thanks again!
=begin
#===============================================================================
Title: Event Followers
Author: Hime
Date: Feb 19, 2015
--------------------------------------------------------------------------------
** Change log
Fev 19, 2015
- event followers also move diagonally
Mar 31, 2014
- moving behind leader had the y-positions mixed up
Jan 9, 2014
- fixed bug where adding a follower to a leader was following the last
follower of the leader, not the leader itself
Jul 31, 2013
- added new following logic for more accurate following
Jul 25, 2013
- fixed bug where event follower speed wasn't updated to leader's speed
Mar 29, 2013
- Events following the player will now follow the last follower
- Initial release
--------------------------------------------------------------------------------
** Terms of Use
* Free to use in non-commercial projects
* Contact me for commercial use
* No real support. The script is provided as-is
* Will do bug fixes, but no compatibility patches
* Features may be requested but no guarantees, especially if it is non-trivial
* Credits to Hime Works in your project
* Preserve this header
--------------------------------------------------------------------------------
** Description
This script allows events to designate a "leader" that another character will
follow. This could be the player, the current event, or any other event.
Any characters following a leader will follow that leader.
--------------------------------------------------------------------------------
** Installation
Place this below Materials and above Main
--------------------------------------------------------------------------------
** Usage
The following method calls are available to Game_Character objects.
follow(event_id)
stop_follow
This can be called by any character object such as players or events.
If you make a script call and say
follow(event_id)
Then the event specified by the move route will follow that character.
You can also say things like
$game_player.follow(event_id)
$game_map.events[3].follow(event_id)
If the event_id is -1, then the character will follow the player.
otherwise, it will follow the specified event on the current map.
To stop following a character, make the script call
stop_follow
Again, remember from whose perspective the script call is being made from.
#===============================================================================
=end
$imported = {} if $imported.nil?
$imported["TH_EventFollowers"] = true
#===============================================================================
# ** Configuration
#===============================================================================
module TH
module Event_Followers
end
end
#===============================================================================
# ** Rest of Script
#===============================================================================
class Game_Character < Game_CharacterBase
attr_reader :event_followers
alias :th_event_followers_init_public_members :init_public_members
def init_public_members
th_event_followers_init_public_members
@event_followers = Game_EventFollowers.new(self)
@leader = nil
end
alias :th_event_followers_move_straight :move_straight
def move_straight(d, turn_ok = true)
@event_followers.move if passable?(@x, @y, d)
th_event_followers_move_straight(d, turn_ok)
end
alias :th_event_followers_update :update
def update
th_event_followers_update
update_following if following?
end
#-----------------------------------------------------------------------------
# New
#-----------------------------------------------------------------------------
def update_following
@move_speed = @leader.real_move_speed
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def following?
!@leader.nil?
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def last_follower
return @event_followers[-1] if @event_followers.size > 0
return self
end
#-----------------------------------------------------------------------------
# New. Backup this character's original settings
#-----------------------------------------------------------------------------
def store_original_settings
@old_through = @through
@old_move_speed = @move_speed
@old_real_move_speed = @real_move_speed
@old_transparent = @transparent
@old_walk_anime = @walk_anime
@old_step_anime = @step_anime
@old_direction_fix = @direction_fix
@old_opacity = @opacity
@old_blend_type = @blend_type
end
#-----------------------------------------------------------------------------
# New. Once we stop following another character, revert all original settings
#-----------------------------------------------------------------------------
def revert_original_settings
@through = @old_through
@move_speed = @old_move_speed
@real_move_speed = @old_real_move_speed
@transparent = @old_transparent
@walk_anime = @old_walk_anime
@step_anime = @old_step_anime
@direction_fix = @old_direction_fix
@opacity = @old_opacity
@blend_type = @old_blend_type
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def get_follow_leader(event_id) #KK20
# -1 is assumed to be the player
if event_id == 0
@triggered_by
elsif event_id == -1
$game_player
elsif event_id == -2
$game_player2
else
$game_map.events[event_id]
end
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def chase_preceding_character
unless moving?
sx = distance_x_from(@preceding_character.x)
sy = distance_y_from(@preceding_character.y)
if sx != 0 && sy != 0
move_diagonal(sx > 0 ? 4 : 6, sy > 0 ? 8 : 2)
elsif sx != 0
move_straight(sx > 0 ? 4 : 6)
elsif sy != 0
move_straight(sy > 0 ? 8 : 2)
end
end
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def move_behind_leader
x = @leader.x
y = @leader.y
case @leader.direction
when 2
y += 1
when 4
x += 1
when 6
x -= 1
when 8
y -= 1
end
x = [[1, x].max, $game_map.width-1].min
y = [[1, y].max, $game_map.height-1].min
moveto(x, y)
end
#-----------------------------------------------------------------------------
# New. Begin following the specified event.
#-----------------------------------------------------------------------------
def follow(event_id=0)
return if following?
@leader = get_follow_leader(event_id)
@preceding_character = @leader.last_follower
@leader.add_event_follower(self)
move_behind_leader
store_original_settings
@move_speed = @leader.move_speed
@transparent = @leader.transparent
@walk_anime = @leader.walk_anime
@step_anime = @leader.step_anime
@direction_fix = @leader.direction_fix
@opacity = @leader.opacity
@blend_type = @leader.blend_type
@through = true
end
#-----------------------------------------------------------------------------
# New. Stop following a leader
#-----------------------------------------------------------------------------
def stop_follow
@through = false
@leader.remove_event_follower(self)
@preceding_character = nil
@leader = nil
revert_original_settings
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def add_event_follower(char)
@event_followers.add(char)
end
#-----------------------------------------------------------------------------
# New.
#-----------------------------------------------------------------------------
def remove_event_follower(char)
@event_followers.remove(char)
end
alias :th_event_followers_move_diagonal :move_diagonal
def move_diagonal(horz, vert)
@event_followers.move if diagonal_passable?(@x, @y, horz, vert)
th_event_followers_move_diagonal(horz, vert)
end
end
class Game_Event < Game_Character
#-----------------------------------------------------------------------------
# Ignore autonomous movement if following leader
#-----------------------------------------------------------------------------
alias :th_event_followers_update_self_movement :update_self_movement
def update_self_movement
return if following?
th_event_followers_update_self_movement
end
end
class Game_Player < Game_Character
#-----------------------------------------------------------------------------
# New. Since player happens to have different types of followers we have to
# check
#-----------------------------------------------------------------------------
def last_follower
return super if @event_followers.size > 0
follower_size = $game_player.followers.visible_folloers.size
return @followers[follower_size - 1] if follower_size > 0
return self
end
#-----------------------------------------------------------------------------
# Ignore player movement input if following leader
#-----------------------------------------------------------------------------
alias :th_event_followers_movable? :movable?
def movable?
return false if following?
th_event_followers_movable?
end
alias :th_event_followers_dash? :dash?
def dash?
return false if following?
th_event_followers_dash?
end
end
#-------------------------------------------------------------------------------
# Similar to player followers, except instead of pulling data from the party
# members it simply holds references to existing events
#-------------------------------------------------------------------------------
class Game_EventFollowers < Game_Followers
include Enumerable
def initialize(leader)
@data = []
end
def size
@data.size
end
def index(char)
@data.index(char)
end
def add(character)
@data.push(character)
end
def remove(character)
@data.delete(character)
end
end
class Game_Interpreter
def follow(id=0)
$game_map.events[@event_id].follow(id)
true
end
end
module DataManager
class << self
alias :th_multiplayer_create_game_objects :create_game_objects
alias :th_multiplayer_make_save_contents :make_save_contents
alias :th_multiplayer_extract_save_contents :extract_save_contents
end
def self.create_game_objects
th_multiplayer_create_game_objects
$game_player2 = Game_Multiplayer.new
end
def self.make_save_contents
contents = th_multiplayer_make_save_contents
contents[:player2] = $game_player2
contents
end
def self.extract_save_contents(contents)
th_multiplayer_extract_save_contents(contents)
$game_player2 = contents[:player2]
end
def self.setup_new_game
create_game_objects
$game_party.setup_starting_members
$game_map.setup($data_system.start_map_id)
$game_player.moveto($data_system.start_x, $data_system.start_y)
$game_player.refresh
$game_player2.moveto($data_system.start_x, $data_system.start_y)
$game_player2.refresh
Graphics.frame_count = 0
end
end
class Game_Multiplayer < Game_Player
DOWN = Input::Y # S in Keyboard
LEFT = Input::X # A in Keyboard
RIGHT = Input::Z # D in Keyboard
UP = Input::R # W in Keyboard
ENTER = Input::L # Q in Keyboard
RUN = Input::A # Shift in Keyboard
#--------------------------------------------------------------------------
# * Get Corresponding Actor
#--------------------------------------------------------------------------
def actor
$game_party.battle_members[1]
end
def move_by_input
return unless movable?
return if $game_map.interpreter.running?
if Input.press?(DOWN)
move_straight(2)
elsif Input.press?(LEFT)
move_straight(4)
elsif Input.press?(RIGHT)
move_straight(6)
elsif Input.press?(UP)
move_straight(8)
end
end
def update_nonmoving(last_moving)
return if $game_map.interpreter.running?
if last_moving
$game_party.on_player_walk
return if check_touch_event
end
if movable? && Input.trigger?(ENTER)
return if get_on_off_vehicle
return if check_action_event
end
update_encounter if last_moving
end
#--------------------------------------------------------------------------
# * Trigger Map Event
# triggers : Trigger array
# normal : Is priority set to [Same as Characters] ?
#--------------------------------------------------------------------------
def start_map_event(x, y, triggers, normal)
return if $game_map.interpreter.running?
$game_map.events_xy(x, y).each do |event|
if event.trigger_in?(triggers) && event.normal_priority? == normal
event.start(true)
end
end
end
end
class Game_Character
#--------------------------------------------------------------------------
# * Move toward Player
#--------------------------------------------------------------------------
def move_toward_player(player=$game_player)
move_toward_character(player)
end
end
class Game_Event < Game_Character
#--------------------------------------------------------------------------
# * Start Event
#--------------------------------------------------------------------------
def start(player2=false)
return if empty?
@triggered_by = player2 ? $game_player2 : $game_player
@starting = true
lock if trigger_in?([0,1,2])
end
#--------------------------------------------------------------------------
# * Move Type : Approach
#--------------------------------------------------------------------------
def move_type_toward_player
closest_player = near_the_player?
if closest_player
case rand(6)
when 0..3; move_toward_player(closest_player)
when 4; move_random
when 5; move_forward
end
else
move_random
end
end
#--------------------------------------------------------------------------
# * Determine if Near Player
#--------------------------------------------------------------------------
def near_the_player?
sx1 = distance_x_from($game_player.x).abs
sy1 = distance_y_from($game_player.y).abs
sx2 = distance_x_from($game_player2.x).abs
sy2 = distance_y_from($game_player2.y).abs
if sx1 + sy1 < 20 || sx2 + sy2 < 20
diff = (sx1 + sy1) - (sx2 + sy2)
return $game_player if diff < 0
return $game_player2 if diff > 0
return [$game_player, $game_player2][rand(2)]
end
return false
end
end
class Spriteset_Map
alias :th_multiplayer_create_characters :create_characters
def create_characters
th_multiplayer_create_characters
@character_sprites.push(Sprite_Character.new(@viewport1, $game_player2))
end
end
class Scene_Map < Scene_Base
alias :th_multiplayer_map_update :update
def update
th_multiplayer_map_update
$game_player2.update if $game_player2
end
#--------------------------------------------------------------------------
# * Player Transfer Processing
#--------------------------------------------------------------------------
def perform_transfer
pre_transfer
$game_player.perform_transfer
$game_player2.perform_transfer
post_transfer
end
end
class Game_Interpreter
#--------------------------------------------------------------------------
# * Transfer Player
#--------------------------------------------------------------------------
def command_201
return if $game_party.in_battle
Fiber.yield while $game_player.transfer? || $game_message.visible
if @params[0] == 0 # Direct designation
map_id = @params[1]
x = @params[2]
y = @params[3]
else # Designation with variables
map_id = $game_variables[@params[1]]
x = $game_variables[@params[2]]
y = $game_variables[@params[3]]
end
$game_player.reserve_transfer(map_id, x, y, @params[4])
$game_player2.reserve_transfer(map_id, x, y, @params[4])
$game_temp.fade_type = @params[5]
Fiber.yield while $game_player.transfer?
end
end
Noticed a bug in the script I posted yesterday; no idea how that passed by me before.
Transfer event will now put the second player in the specified teleport spot.
An event with an Autonomous Movement type Approach will generally move towards the closest player.
But you will soon see that event touch trigger won't work and will phase through the second player. There's a lot of other issues like this when you add another player entity that the game has no idea of. That's the reason why that script was only a Proof of Concept--there's just so much more that needs to be done.
This is pretty much the extent of all I can help you with. If you're still serious with this, I advise getting a full-time scripter who is willing to rewrite the default scripts for you.
The transfer now works flawlessly! KK20, you have gone above and beyond my expectations help-wise. I understand that rpg-maker wasn't designed to have 2 player ability to start with, but with Tsukihime's script and all your mods here, I think this is fantastic.
Thank you for spending your time and effort in getting this sorted out. I'm going to mark this topic as resolved as this final solution is at present satisfactory for me. As you said, this would need much more work in order to make it fully ingrained into the system.
If this little project gets to a reasonable size, I will do just as you suggest. :)