Hello everyone, some months after releasing my RubyENet online library some people asked me to make an example project using it, so they could see how things could be done and build a custom game on top of it. Today I finished filling the scripts with comments, so everything is easy to understand. So here it is:
RubyENet Game Template
This project shows how to integrate RubyENet into RPG Maker
This project is aimed to people who wants to add online functionality
to their games without to much trouble. This project includes the basic
structure to connect to a server, send and receive data.
It included:
- Methods to connect to a remote server
- Methods to receive and parse packets
- Other players in map
- Automatic global switches and variables
- Basic Chat
- A basic server for ruby 1.8.x and 1.9.x
Basic features to learn and build a solid and custom game on top of them
Explanation of what this project does:
- When clicked "New Game" the game connects to the remote server
- The server gives an unique ID to the game so it can be identified
- The game sends the player data to the server, who sends it to all the
other players, and returns the game the other players data.
- The players can interact throught switches and variables.
- Only players in the same map are updated and visibles.
- When another player disconnects, its deleted from the players list.
- If the game loses the connection to the server a warning appears.
All the new scripts are tagged as [Added]
All the edited default scripts are tagged ad [Edited]
Edited scripts and lines:
Downloads
Project:
RPG Maker XP Project
Scripts:
____Added Scripts_____
ENet Module:
Network Class:
Game_NetPlayer Class
Sprite_PlayerCharacter Class
Sprite_NetCharacter Class
Chat Class:
Window_ChatInput Class
Window_Chat Class
Keyboard Module by Hound
____Edited Scripts____
Game_Temp Class
Game_Player Class
Spriteset_Map Class
Interpreter 4 Class
Scene_Title Class
Scene_Map Class
Main
____Extra Script____
Server Example:
Additional Information and Notes
Servers can be done in C/C++, this can give a huge boost to your games
performance, also Server that doesnt display information (puts/print)
works faster.
This template connects to the server in Scene_Title when New Game is
selected.
The network is only updated in Scene_Map, if you are in another scene
the connection will be lost after 10 seconds or so. Update the network
in all the scenes you need.
The Chat input uses Hounds Keyboard Module,it uses this module because
it doesnt need external dlls, but its performance is pretty bad. Dont
think Chat is broken if you need to press the keys twice. It should be
rewritten using vgvgfs AInput module to get a perfect performance.
The RGSS Player stops updating the game when it doesnt have focus,
this is not a problem with TCP, where the stream just sleeps but ENet
uses UDP (which is a lot faster) and datagrams doesnt sleep. If the
game lose focus the connection will be lost after 10 seconds or so,
because the client isnt answering server petitions.
Workarounds:
- Use Win32API calls so the game has always the focus
- Make the game fullscreen so the player wont lose focus
- Hack the player so it updates without focus too
To fully understand how ENet works visit http://enet.bespin.org/
Comments, questions, petitions, fixes, etc are welcome.
This project shows how to integrate RubyENet into RPG Maker
This project is aimed to people who wants to add online functionality
to their games without to much trouble. This project includes the basic
structure to connect to a server, send and receive data.
It included:
- Methods to connect to a remote server
- Methods to receive and parse packets
- Other players in map
- Automatic global switches and variables
- Basic Chat
- A basic server for ruby 1.8.x and 1.9.x
Basic features to learn and build a solid and custom game on top of them
Explanation of what this project does:
- When clicked "New Game" the game connects to the remote server
- The server gives an unique ID to the game so it can be identified
- The game sends the player data to the server, who sends it to all the
other players, and returns the game the other players data.
- The players can interact throught switches and variables.
- Only players in the same map are updated and visibles.
- When another player disconnects, its deleted from the players list.
- If the game loses the connection to the server a warning appears.
All the new scripts are tagged as [Added]
All the edited default scripts are tagged ad [Edited]
Edited scripts and lines:
-- Game_Temp
-- 57
-- 58
- Game_player
-- 218
-- 219
-- 223
- -224
- -228
- -229
-- 233
-- 234
- Spriteset_Map
-- 40 to 49
-- 68 to 86
--107 to 109
-- 127- 128
-- 175 to 177
- Interpreter 4
--18
-- 174
- Scene_Title
-- 142
-- 143
-Scene_Map
-- 17
-- 18
-- 41
-- 42
-- 67 to 74
-- 139 to 41
-- 144
-- 300 to 305
-Main
--25 to 28
-- 57
-- 58
- Game_player
-- 218
-- 219
-- 223
- -224
- -228
- -229
-- 233
-- 234
- Spriteset_Map
-- 40 to 49
-- 68 to 86
--107 to 109
-- 127- 128
-- 175 to 177
- Interpreter 4
--18
-- 174
- Scene_Title
-- 142
-- 143
-Scene_Map
-- 17
-- 18
-- 41
-- 42
-- 67 to 74
-- 139 to 41
-- 144
-- 300 to 305
-Main
--25 to 28
Project:
RPG Maker XP Project
Scripts:
____Added Scripts_____
ENet Module:
Code:
################################################################################
#
# ###### # # ###### ##### ENet Ruby Bindings
# # ## # # #
# #### # # # #### # Last Update: 24/8/2010
# # # # # # #
# ###### # ## ###### # By Dahrkael
#
################################################################################
#
# ENet's purpose is to provide a relatively thin, simple and robust network
# communication layer on top of UDP (User Datagram Protocol).
# The primary feature it provides is optional reliable, in-order delivery
# of packets.
#
# ENet omits certain higher level networking features such as authentication,
# lobbying, server discovery, encryption, or other similar tasks that are
# particularly application specific so that the library remains flexible,
# portable, and easily embeddable.
#
# Copyright (c) 2002-2010 Lee Salzman
# [url=http://enet.bespin.org/]http://enet.bespin.org/[/url]
#===============================================================================
#
# TODO:
# - Error control
# - Add all missing internal functions
#
#===============================================================================
#
# This script is free to use and doesnt need any credits B U T enet library does
#
################################################################################
#==============================================================================
# * Module Enet
#
# Methods
# - initialize
# - deinitialize
# - destroy_event_packet
# - get_packet_data
# - get_packet_datalength
# - get_packet_from_event
# - get_channelid_from_event
# - get_peer_from_event
# - get_peer_host
# - get_peer_port
#
# SubModules
# - DLLs
# - Types
# - Constants
# - APIFunctions
#
# SubClasses (and methods)
# - ENetHost
# - initialize
# - create_host
# - destroy_host
# - connect
# - peers_list
# - send_packet
# - broadcast_packet
# - disconnect
# - service
# - on_packet_receive
# - on_connection
# - on_disconnect
#
# - ENetAddress
# - initialize
# - set_host
# - set_port
#
# - ENetEvent
# - initialize
# - update
# - peer
# - peer_host
# - peer_port
# - channel_id
# - packet
# - destroy_packet
#
# - ENetPacket
# - initialize
# - update
# - data_length
# - data
#
#==============================================================================
module Enet
#==============================================================================
# * M O D U L E S
#==============================================================================
#============================================================================
# ** DLLs
#----------------------------------------------------------------------------
# dlls containing needed functions
#============================================================================
module DLLs
Enet = "enet.dll" # enet itself
RubyEnet = "RubyENet.dll" # auxiliar functions
end
#============================================================================
# ** Types
#----------------------------------------------------------------------------
# Enet types converted to Win32API types
#============================================================================
module Types
ENetAddress = 'P'
ENetHost = 'L'
ENetEvent = 'L'
ENetPacket = 'L'
ENetPeer = 'L'
Enet_uint32 = 'L'
Enet_uint16 = 'L'
Enet_uint8 = 'I'
Size_t = 'L'
Int = 'I'
Void = 'V'
Const_void = 'P'
Const_char = 'P'
end
#============================================================================
# ** Constants
#----------------------------------------------------------------------------
# Enet constants, better than numbers
#============================================================================
module Constants
NULL = 0 # yes...
ENET_HOST_ANY = 0
ENET_HOST_BROADCAST = 0xFFFFFFFF
ENET_PORT_ANY = 0
ENET_EVENT_TYPE_NONE = 0
ENET_EVENT_TYPE_CONNECT = 1
ENET_EVENT_TYPE_DISCONNECT = 2
ENET_EVENT_TYPE_RECEIVE = 3
ENET_PACKET_FLAG_RELIABLE = 1 # (1 << 0)
ENET_PACKET_FLAG_UNSEQUENCED = 2 # (1 << 1)
ENET_PACKET_FLAG_NO_ALLOCATE = 4 # (1 << 2)
end
#============================================================================
# ** APIFunctions
#----------------------------------------------------------------------------
# DLL Functions, some secondary and/or no-vital functions are missing
#============================================================================
module APIFunctions
include Types
#--------------------------------------------------------------------------
# * Workaround Function (anyone help :3?)
#--------------------------------------------------------------------------
RubyEnet_CreateENetEvent = Win32API.new(DLLs::RubyEnet, "RubyEnet_CreateENetEvent", [''], ENetEvent)
#--------------------------------------------------------------------------
# * ENetEvent Auxiliar Functions
#--------------------------------------------------------------------------
RubyEnet_GetPeerFromEvent = Win32API.new(DLLs::RubyEnet, "RubyEnet_GetPeerFromEvent", [ENetEvent], ENetPeer)
RubyEnet_GetEventType = Win32API.new(DLLs::RubyEnet, "RubyEnet_GetEventType", [ENetEvent], Int)
RubyEnet_GetChannelIDFromEvent = Win32API.new(DLLs::RubyEnet, "RubyEnet_GetChannelIDFromEvent", [ENetEvent], Enet_uint8)
#--------------------------------------------------------------------------
# * ENetPacket Auxiliar Functions
#--------------------------------------------------------------------------
RubyEnet_GetPacketFromEvent = Win32API.new(DLLs::RubyEnet, "RubyEnet_GetPacketFromEvent", [ENetEvent], ENetPacket)
RubyEnet_GetPacket_DataLength = Win32API.new(DLLs::RubyEnet, "RubyEnet_GetPacket_DataLength", [ENetPacket], Size_t)
RubyEnet_GetPacket_Data = Win32API.new(DLLs::RubyEnet, "RubyEnet_GetPacket_Data", [ENetPacket], 'P')
#--------------------------------------------------------------------------
# * ENetPeer Auxiliar Functions
#--------------------------------------------------------------------------
RubyEnet_GetPeerHost = Win32API.new(DLLs::RubyEnet, "RubyEnet_GetPeerHost", [ENetPeer], Enet_uint32)
RubyEnet_GetPeerPort = Win32API.new(DLLs::RubyEnet, "RubyEnet_GetPeerPort", [ENetPeer], Enet_uint32)
#--------------------------------------------------------------------------
# * ENet Basic Functions
#--------------------------------------------------------------------------
Enet_initialize = Win32API.new(DLLs::Enet, "enet_initialize", [''], Int)
Enet_deinitialize = Win32API.new(DLLs::Enet, "enet_deinitialize", [''], Void)
#--------------------------------------------------------------------------
# * ENetHost Functions
#--------------------------------------------------------------------------
Enet_host_create = Win32API.new(DLLs::Enet, "enet_host_create", [ENetAddress, Size_t, Size_t, Enet_uint32, Enet_uint32], ENetHost)
Enet_host_destroy = Win32API.new(DLLs::Enet, "enet_host_destroy", [ENetHost], Void)
Enet_host_connect = Win32API.new(DLLs::Enet, "enet_host_connect", [ENetHost, ENetAddress, Size_t, Enet_uint32], ENetPeer)
Enet_host_service = Win32API.new(DLLs::Enet, "enet_host_service", [ENetHost, ENetEvent, Enet_uint32], Int)
Enet_host_broadcast = Win32API.new(DLLs::Enet, "enet_host_broadcast", [ENetHost, Enet_uint8, ENetPacket], Void)
Enet_host_flush = Win32API.new(DLLs::Enet, "enet_host_flush", [ENetHost], Void)
Enet_address_set_host = Win32API.new(DLLs::Enet, "enet_address_set_host", [ENetAddress, Const_char], Int)
#--------------------------------------------------------------------------
# * ENetpacket Functions
#--------------------------------------------------------------------------
Enet_packet_create = Win32API.new(DLLs::Enet, "enet_packet_create", [Const_void, Size_t, Enet_uint32], ENetPacket)
Enet_packet_destroy = Win32API.new(DLLs::Enet, "enet_packet_destroy", [ENetPacket], Void)
#--------------------------------------------------------------------------
# * ENetPeer Functions
#--------------------------------------------------------------------------
Enet_peer_send = Win32API.new(DLLs::Enet, "enet_peer_send", [ENetPeer, Enet_uint8, ENetPacket], Int)
Enet_peer_disconnect = Win32API.new(DLLs::Enet, "enet_peer_disconnect", [ENetPeer, Enet_uint32], Void)
Enet_peer_reset = Win32API.new(DLLs::Enet, "enet_peer_reset", [ENetPeer], Void)
end
#==============================================================================
# * M E T H O D S
#==============================================================================
#----------------------------------------------------------------------------
# * initialize
# Starts the library
#----------------------------------------------------------------------------
def self.initialize
APIFunctions::Enet_initialize.call()
end
#----------------------------------------------------------------------------
# * deinitialize
# Stops the library
#----------------------------------------------------------------------------
def self.deinitialize
APIFunctions::Enet_deinitialize.call()
end
#----------------------------------------------------------------------------
# * Destroy Event Packet
# Destroys the packet contained in the event
#----------------------------------------------------------------------------
def self.destroy_event_packet(event)
packet = self.get_packet_from_event(event)
APIFunctions::Enet_packet_destroy.call(packet)
end
#----------------------------------------------------------------------------
# * Get Packet Data
# Returns a string with the packet data
#----------------------------------------------------------------------------
def self.get_packet_data(packet)
length = APIFunctions::RubyEnet_GetPacket_DataLength.call(packet)
data = 0.chr * length
data = APIFunctions::RubyEnet_GetPacket_Data.call(packet)
return data
end
#----------------------------------------------------------------------------
# * Get Packet Datalength
# Returns the datalength from the packet (the data size)
#----------------------------------------------------------------------------
def self.get_packet_datalength(packet)
return APIFunctions::RubyEnet_GetPacket_DataLength.call(packet)
end
#----------------------------------------------------------------------------
# * Get Packet From Event
# Returns the packet pointer from the event
#----------------------------------------------------------------------------
def self.get_packet_from_event(event)
return APIFunctions::RubyEnet_GetPacketFromEvent.call(event)
end
#----------------------------------------------------------------------------
# * Get ChannelID From Event
# Returns the ChannelID used
#----------------------------------------------------------------------------
def self.get_channelid_from_event(event)
return APIFunctions::RubyEnet_GetChannelIDFromEvent.call(event)
end
#----------------------------------------------------------------------------
# * Get Peer From Event
# gets the peer pointer who generated the event
#----------------------------------------------------------------------------
def self.get_peer_from_event(event)
return APIFunctions::RubyEnet_GetPeerFromEvent.call(event)
end
#----------------------------------------------------------------------------
# * Get Peer Host
# Returns the hexadecimal peers address
#----------------------------------------------------------------------------
def self.get_peer_host(peer)
return APIFunctions::RubyEnet_GetPeerHost.call(peer)
end
#----------------------------------------------------------------------------
# * Get Peer Port
# Returns the peers port
#----------------------------------------------------------------------------
def self.get_peer_port(peer)
return APIFunctions::RubyEnet_GetPeerPort.call(peer)
end
#==============================================================================
# * C L A S S E S
#==============================================================================
#============================================================================
# ** ENetHost
#----------------------------------------------------------------------------
# Class that represents the computer networking and the connections
# associated
#============================================================================
class ENetHost
#----------------------------------------------------------------------------
# * Public Instance Variables
#----------------------------------------------------------------------------
attr_reader :connected # returns true if connected, all peers uses this var :/
#----------------------------------------------------------------------------
# * Object Initialization
#----------------------------------------------------------------------------
def initialize
@enet_host = nil
@peers = {}
@connections = 0
@channels = 0
@downstream = 0
@upstream = 0
@event = APIFunctions::RubyEnet_CreateENetEvent.call()
@external_event = ENetEvent.new(@event)
@connected = false
@on_packet_receive = nil
@on_disconnect = nil
@on_connection = nil
end
#----------------------------------------------------------------------------
# * Event
#----------------------------------------------------------------------------
def event
return @external_event
end
#----------------------------------------------------------------------------
# * Create Host
# type: Client or Server, NULL = Client, Pointer to ENetAddress = Server
# connections: Outgoing connections allowed (number)
# channels: Number of avaiable channels for connections (number)
# downstream: Downstream bandwidth in bytes (number)
# upstream: Upstream bandwidth in bytes (number)
#----------------------------------------------------------------------------
def create_host(type, connections, channels, downstream, upstream)
@enet_host = APIFunctions::Enet_host_create.call(type, connections, channels, downstream, upstream)
if @enet_host != 0
@connections = connections
@channels = channels
@downstream = downstream
@upstream = upstream
return true
else
return false
end
end
#----------------------------------------------------------------------------
# * Destroy Host
#----------------------------------------------------------------------------
def destroy_host
APIFunctions::Enet_host_destroy.call(@enet_host)
@enet_host = nil
@connections = 0
@channels = 0
@downstream = 0
@upstream = 0
end
#----------------------------------------------------------------------------
# * Connect
# address: ENetAddres instance with the remote host address and port (ENetAddress)
# channels: Number of channels allocated for this connection (number)
# extradata: Optional data to send with the connection petition (string)
#----------------------------------------------------------------------------
def connect(address, channels, extradata=0)
peer = APIFunctions::Enet_host_connect.call(@enet_host, address.enet_address, channels, extradata)
if peer != 0
address = APIFunctions::RubyEnet_GetPeerHost.call(peer)
port = APIFunctions::RubyEnet_GetPeerPort.call(peer)
@peers["server"] = {
"peer" => peer,
"address" => address,
"port" => port
}
return true
else
return false
end
end
#----------------------------------------------------------------------------
# * Peers List
#----------------------------------------------------------------------------
def peers_list
return @peers
end
#----------------------------------------------------------------------------
# * Send packet
# peer: peer to send the packet (pointer to peer)
# data: data to send in the packet, text, binary, anything (~string)
# datalength: data length + 1 (number)
# channelID: Channel to send the packet (number)
# flags: Optional flags for the packet, default is ENET_PACKET_FLAG_RELIABLE
#----------------------------------------------------------------------------
def send_packet(peer, data, datalength, channelID, flags=Constants::ENET_PACKET_FLAG_RELIABLE)
packet = APIFunctions::Enet_packet_create.call(data, datalength, flags)
if APIFunctions::Enet_peer_send.call(peer, channelID, packet) < 0
return false
else
return true
end
end
#----------------------------------------------------------------------------
# * Broadcast Packet
# data: data to send in the packet, text, binary, anything (~string)
# datalength: data length + 1 (number)
# channelID: Channel to send the packet (number)
# flags: Optional flags for the packet, default is ENET_PACKET_FLAG_RELIABLE
#----------------------------------------------------------------------------
def broadcast_packet(data, datalength, channelID, flags=Constants::ENET_PACKET_FLAG_RELIABLE)
packet = APIFunctions::Enet_packet_create.call(data, datalength, flags)
APIFunctions::Enet_host_broadcast.call(@enet_host, channelID, packet)
return true
end
#----------------------------------------------------------------------------
# * Disconnect
# peer: peer to disconnect (peer name string)
# data: extra data to send with the disconnection petition (~string)
# timeout: time in milliseconds to get answer, when over disconnection is forced (number)
#----------------------------------------------------------------------------
def disconnect(peer, data=0, timeout=3000)
APIFunctions::Enet_peer_disconnect.call(peer, data)
while APIFunctions::Enet_host_service.call(@enet_host, @event, timeout) > 0
case APIFunctions::RubyEnet_GetEventType.call(@event)
when Constants::ENET_EVENT_TYPE_RECEIVE
APIFunctions::Enet_packet_destroy(RubyEnet_GetPacketFromEvent.call(@event))
when Constants::ENET_EVENT_TYPE_DISCONNECT
@peers[peer] = nil
#print "Disconnected"
return true
end
end
Enet_peer_reset (@peers[peer][peer])
@peers[peer] = nil
return true
end
#----------------------------------------------------------------------------
# * Service
# milliseconds: time to wait for a packet (number)
#----------------------------------------------------------------------------
def service(milliseconds=1000)
while APIFunctions::Enet_host_service.call(@enet_host, @event, milliseconds) > 0
case APIFunctions::RubyEnet_GetEventType.call(@event)
when Constants::ENET_EVENT_TYPE_NONE
when Constants::ENET_EVENT_TYPE_CONNECT
#print "new client connected"
@external_event.update(@event)
on_connection
APIFunctions::Enet_host_flush.call(@enet_host)
@connected = true
when Constants::ENET_EVENT_TYPE_DISCONNECT
@connected = false
#print "Disconnected"
@external_event.update(@event)
on_disconnect
when Constants::ENET_EVENT_TYPE_RECEIVE
@external_event.update(@event)
on_packet_receive
end
end
end
#----------------------------------------------------------------------------
# * On Disconnection
# Method called when a disconnection event arrives
#----------------------------------------------------------------------------
def on_disconnect(&block)
if block
@on_disconnect = block
elsif @on_disconnect
@on_disconnect.call()
end
end
#----------------------------------------------------------------------------
# * On Connection
# Method called when a connection event arrives
#----------------------------------------------------------------------------
def on_connection(&block)
if block
@on_connection = block
elsif @on_connection
@on_connection.call()
end
end
#----------------------------------------------------------------------------
# * Packet Received
# Method called when an event containing a packet arrives
#----------------------------------------------------------------------------
def on_packet_receive(&block)
if block
@on_packet_receive = block
elsif @on_packet_receive
@on_packet_receive.call()
#destroy_event_packet(@event)
end
end
end
#============================================================================
# ** ENetAddress
#----------------------------------------------------------------------------
# Class to simplify C ENetAddress structs
#============================================================================
class ENetAddress
#----------------------------------------------------------------------------
# * Public Instance Variables
#----------------------------------------------------------------------------
attr_reader :address
attr_reader :port
attr_reader :enet_address
#----------------------------------------------------------------------------
# * Object Initialization
#----------------------------------------------------------------------------
def initialize
@address = ""
@port = 0
@enet_address = ""
end
#----------------------------------------------------------------------------
# * Set Host
# host: remote host to get address (string)
#----------------------------------------------------------------------------
def set_host(host)
@enet_address = [Constants::ENET_HOST_ANY, @port].pack("LS")
if APIFunctions::Enet_address_set_host.call(@enet_address, host) < 0
return false
end
@address = host
return true
end
#----------------------------------------------------------------------------
# * Set Port
# port: port to bind
#----------------------------------------------------------------------------
def set_port(port)
@port = port
@enet_address = [Constants::ENET_HOST_ANY, @port].pack("LS")
set_host(@address)
return true
end
end
#============================================================================
# ** ENetPacket
#----------------------------------------------------------------------------
# Class to simplify C ENetPacket structs
#============================================================================
class ENetPacket
#----------------------------------------------------------------------------
# * Object Initialization
# packet: packet to wrap
#----------------------------------------------------------------------------
def initialize(packet)
@packet = packet
@length = 0
@data = 0
end
#----------------------------------------------------------------------------
# * Update
# packet: packet to wrap
#----------------------------------------------------------------------------
def update(packet)
@packet = packet
@length = 0
@data = 0
end
#----------------------------------------------------------------------------
# * Data Length
#----------------------------------------------------------------------------
def data_length
@length = Enet.get_packet_datalength(@packet)
return @length
end
#----------------------------------------------------------------------------
# * Data
#----------------------------------------------------------------------------
def data
@data = Enet.get_packet_data(@packet)
return @data
end
end
#============================================================================
# ** ENetEvent
#----------------------------------------------------------------------------
# Class to simplify C ENetEvent structs
#============================================================================
class ENetEvent
#----------------------------------------------------------------------------
# * Object Initialization
# event: event to wrap
#----------------------------------------------------------------------------
def initialize(event)
@event = event
@peer = 0
@peer_host = 0
@peer_port = 0
@channel_id = 0
@packet = 0
end
#----------------------------------------------------------------------------
# * Update
# event: event to wrap
#----------------------------------------------------------------------------
def update(event)
@event = event
@peer = 0
@peer_host = 0
@peer_port = 0
@channel_id = 0
@packet = 0
end
#----------------------------------------------------------------------------
# * Peer
#----------------------------------------------------------------------------
def peer
@peer = Enet.get_peer_from_event(@event)
return @peer
end
#----------------------------------------------------------------------------
# * Peer Host
#----------------------------------------------------------------------------
def peer_host
if @peer == 0
@peer = Enet.get_peer_from_event(@event)
end
@host = Enet.get_peer_host(@peer)
return @host
end
#----------------------------------------------------------------------------
# * Peer Port
#----------------------------------------------------------------------------
def peer_port
if @peer == 0
@peer = Enet.get_peer_from_event(@event)
end
@port = Enet.get_peer_port(@peer)
return @port
end
#----------------------------------------------------------------------------
# * Channel ID
#----------------------------------------------------------------------------
def channel_id
@channel_id = Enet.get_channelid_from_event(@event)
end
#----------------------------------------------------------------------------
# * Packet
#----------------------------------------------------------------------------
def packet
if @packet == 0
packet = Enet.get_packet_from_event(@event)
@packet = ENetPacket.new(packet)
end
return @packet
end
#----------------------------------------------------------------------------
# * Destroy Packet
#----------------------------------------------------------------------------
def destroy_packet
Enet.destroy_event_packet(@event)
@packet = 0
end
end
end # Classes end
Network Class:
Code:
#==============================================================================
# ** Network
#------------------------------------------------------------------------------
# Handles the network.
#
# Basic demostration of RubyENet game integration
# To send additional data just add a new packet type and its logic
#==============================================================================
class Network
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_accessor :players # Other Players data
attr_reader :client # Underlying connections manager
attr_reader :chat # Chat manager
attr_reader :id # Unique-per-session Network ID
#--------------------------------------------------------------------------
# * Object Initialization
# server_adress : IP or Hostname where the server is running
# port : Port to connect in the server
# max_connections : outgoing connections to different hosts allowed
# channels : maximum channels allocated for the client
# upload_bw : upload bandwidth in bytes, 0 for unlimited
# download_bw : download bandwidth in bytes, 0 for unlimited
#--------------------------------------------------------------------------
def initialize
@players = {}
@server_address = "localhost"
@port = 8000
@max_connections = 1
@channels = 3
@upload_bw = 14400/8
@download_bw = 57600/8
@id = 0
@ready = false
@client = nil
@chat = Chat.new
end
#--------------------------------------------------------------------------
# * Connect and Start
# Initializes the network and connects to the server.
# Gets and ID, sends our initial data and retrieves the other players data.
#--------------------------------------------------------------------------
def connect_and_start
# Initialize the ENet library
if Enet.initialize != 0 # 0 = all ok
print "error initializing enet"
# exit if enet fails
exit
end
# New address object
@address = Enet::ENetAddress.new
@address.set_host(@server_address)
@address.set_port(@port)
# New host object as client
@client = Enet::ENetHost.new
@client.create_host(Enet::Constants::NULL,
@max_connections,
@channels,
@download_bw,
@upload_bw)
# What to do when a data packet arrives
@client.on_packet_receive do
parse_packet
end
# Connect to the server
@client.connect(@address, @channels, 0)
# Wait for the server accepting
@client.service
if @client.connected != true
print "connection aborted"
exit
end
# Select the server pointer
@server = @client.peers_list["server"]["peer"]
# Hang up until we have an ID
while @id == 0
Graphics.update
@client.service
end
# Send our character data
send_initial_data
# Retrieve other players data
while @ready == false
Graphics.update
@client.service
end
# Now we are connected!!
end
#--------------------------------------------------------------------------
# * Send initial data to the server
# Contains: ID, name, level, class, map, x, y, direction, graphics and speed
#--------------------------------------------------------------------------
def send_initial_data
data = ""
data += "0:"
data += @id.to_s
data += ";"
data += $game_actors[1].name
data += ";"
data += $game_actors[1].level.to_s
data += ";"
data += $game_actors[1].class_name
data += ";"
data += $game_map.map_id.to_s
data += ";"
data += $game_player.x.to_s
data += ";"
data += $game_player.y.to_s
data += ";"
data += $game_player.direction.to_s
data += ";"
data += $game_player.character_name
data += ";"
data += $game_player.character_hue.to_s
data += ";"
data += $game_player.opacity.to_s
data += ";"
data += $game_player.move_speed.to_s
@client.send_packet(@server, data, data.size+1, 1)
end
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
# * Functions to update our data
# * Format is: packet_id:player_id;value;etc
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#--------------------------------------------------------------------------
# * Sends our characters x position to the server
#--------------------------------------------------------------------------
def update_x
data = "1:#{@id};#{$game_player.x};#{$game_player.y}"
@client.send_packet(@server, data, data.size+1, 0)
end
#--------------------------------------------------------------------------
# * Sends our characters y position to the server
#--------------------------------------------------------------------------
def update_y
data = "1:#{@id};#{$game_player.x};#{$game_player.y}"
@client.send_packet(@server, data, data.size+1, 0)
end
#--------------------------------------------------------------------------
# * Sends our characters map id to the server
#--------------------------------------------------------------------------
def update_map_id
data = "2:#{@id};#{$game_map.map_id}"
@client.send_packet(@server, data, data.size+1, 0)
end
#--------------------------------------------------------------------------
# * Sends where is the characters facing to the server
#--------------------------------------------------------------------------
def update_direction
data = "3:#{@id};#{$game_player.direction}"
@client.send_packet(@server, data, data.size+1, 0)
end
#--------------------------------------------------------------------------
# * Sends our characters speed to the server
#--------------------------------------------------------------------------
def update_move_speed
data = "4:#{@id};#{$game_player.move_speed}"
@client.send_packet(@server, data, data.size+1, 0)
end
#--------------------------------------------------------------------------
# * Sends our characters graphic name to the server
#--------------------------------------------------------------------------
def update_character_name
data = "5:#{@id};#{$game_player.character_name}"
@client.send_packet(@server, data, data.size+1, 0)
end
#--------------------------------------------------------------------------
# * Sends our characters hue to the server
#--------------------------------------------------------------------------
def update_character_hue
data = "6:#{@id};#{$game_player.character_hue}"
@client.send_packet(@server, data, data.size+1, 0)
end
#--------------------------------------------------------------------------
# * Sends our characters opacity to the server
#--------------------------------------------------------------------------
def update_opacity
data = "7:#{@id};#{$game_player.opacity}"
@client.send_packet(@server, data, data.size+1, 0)
end
#--------------------------------------------------------------------------
# * Sends our characters name to the server
#--------------------------------------------------------------------------
def update_name
data = "10:#{@id};#{$game_actors[1].name}"
@client.send_packet(@server, data, data.size+1, 0)
end
#--------------------------------------------------------------------------
# * Sends our characters level to the server
#--------------------------------------------------------------------------
def update_level
data = "8:#{@id};#{$game_actors[1].level}"
@client.send_packet(@server, data, data.size+1, 0)
end
#--------------------------------------------------------------------------
# * Sends our characters class to the server
#--------------------------------------------------------------------------
def update_class_name
data = "9:#{@id};#{$game_actors[1].class_name}"
@client.send_packet(@server, data, data.size+1, 0)
end
#--------------------------------------------------------------------------
# * Sends a new state for the switch
#--------------------------------------------------------------------------
def update_switch(id)
data = "201:#{id};#{$game_switches[id]}"
@client.send_packet(@server, data, data.size+1, 0)
end
#--------------------------------------------------------------------------
# * Sends a new value for the variable
#--------------------------------------------------------------------------
def update_variable(id)
data = "200:#{id};#{$game_variables[id]}"
@client.send_packet(@server, data, data.size+1, 0)
end
#--------------------------------------------------------------------------
# * Network Update
# Receive packets for 10 milliseconds and update players in the same map
#--------------------------------------------------------------------------
def update
@client.service(10)
@players.each_value do |player|
if player.map_id == $game_map.map_id
player.update
end
end
end
#--------------------------------------------------------------------------
# * Parse the incoming packets and manipulate them correctly
# Each packet type has an unique ID number
# values[0] is the id of the player who sent the data
# values[1]+ are the actual data sent
#--------------------------------------------------------------------------
def parse_packet
# Retrieve the packet data
data = @client.event.packet.data.to_s
# Check if the data contains the correct format
# If not, the packet is ignored and destroyed
if data.match(/^([0-9]*):(.*)$/)
# Packet type
@part1 = $1
# Packet data
@part2 = $2
# Split the data in an array
values = @part2.split(";") if @part2.match(";")
# Check the packet type and do something in consequence
case @part1.to_i
when 0 # Other players initial data
# If its a new player, add it to the players hash
if @players[values[0]] == nil
@players[values[0]] = Game_NetPlayer.new(values)
# If the player is in the same map, add it to the map playrs array
$game_temp.new_map_players.push(@players[values[0]]) if values[4].to_i == $game_map.map_id
end
when 1 # Other players X and Y position
# X and Y from other players come at the same time
# Return if no players with that ID
return if @players[values[0]] == nil
# Update x and y values for this player
@players[values[0]].update_x(values[1])
@players[values[0]].update_y(values[2])
when 2 # Other players Map ID
# Return if no players with that ID
return if @players[values[0]] == nil
# If the actual map ID is the same as ours
if @players[values[0]].map_id == $game_map.map_id
# But the new one is another
if values[1].to_i != $game_map.map_id
# Delete this player from the map players array
$game_temp.old_map_players.push(@players[values[0]])
end
# If the actual map ID is different
elsif @players[values[0]].map_id != $game_map.map_id
# But the new one is ours
if values[1].to_i == $game_map.map_id
# Add this player to the map players array
$game_temp.new_map_players.push(@players[values[0]])
end
end
# Update this players map ID
@players[values[0]].update_map_id(values[1])
when 3 # Other players direction
# Return if no players with that ID
return if @players[values[0]] == nil
# Update this players direction
@players[values[0]].update_direction(values[1])
when 4 # Other players speed
# Return if no players with that ID
return if @players[values[0]] == nil
# Update this players speed
@players[values[0]].update_move_speed(values[1])
when 5 # Other players graphic
# Return if no players with that ID
return if @players[values[0]] == nil
# Update this players graphic
@players[values[0]].update_character_name(values[1])
when 6 # Other players hue
# Return if no players with that ID
return if @players[values[0]] == nil
# Update this players hue
@players[values[0]].update_character_hue(values[1])
when 7 # Other players opacity
# Return if no players with that ID
return if @players[values[0]] == nil
# Update this players opacity
@players[values[0]].update_opacity(values[1])
when 8 # Other players level
# Return if no players with that ID
return if @players[values[0]] == nil
# Update this players level
@players[values[0]].update_level(values[1])
when 9 # Other players class
# Return if no players with that ID
return if @players[values[0]] == nil
# Update this players class
@players[values[0]].update_class_name(values[1])
when 10 # Other players name
# Return if no players with that ID
return if @players[values[0]] == nil
# Update this players name
@players[values[0]].update_name(values[1])
when 11 # Other players disconnection
# Return if no players with that ID
return if @players[@part2] == nil
# If the player exists
if @players.has_key?(@part2)
# Delete it from the map if its in our same map
$game_temp.old_map_players.push(@players[@part2]) if @players[@part2].map_id == $game_map.map_id
# Delete it from the players list
@players.delete(@part2)
end
when 100 # Our ID arrived
return if @id != 0
@id = @part2.to_f
when 101 # Ready ACK
# This packet arrives when we already sent our initial data
# and we have the other players data
@ready = true
when 200 # New variable value
# Update the variable value
$game_variables[values[0].to_i] = eval(values[1])
# Refresh the map to see possible effects
$game_map.need_refresh = true
when 201 # New switch state
if values[1] == "true"
# Update the switch state
$game_switches[values[0].to_i] = true
else
# Update the switch state
$game_switches[values[0].to_i] = false
end
# Refresh the map to see possible effects
$game_map.need_refresh = true
when 202 # New Chat message
# Return if no players with that ID
return if @players[values[0]] == nil
# Compose the new chat text
line = "#{@players[values[0]].name}: #{values[1]}"
# Add the text to the chat
$network.chat.add_line(line)
end
end
# Finished with the packet, destroy it to free memory
@client.event.destroy_packet
end
end
Game_NetPlayer Class
Code:
#==============================================================================
# * Game_NetPlayer
#------------------------------------------------------------------------------
# Handles a network player's data.
#==============================================================================
class Game_NetPlayer < Game_Character
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_reader :id # Unique-per-session ID
attr_reader :name # Name
attr_reader :level # Level
attr_reader :class_name # Class name
attr_reader :map_id # Map ID
attr_reader :x # X Position
attr_reader :y # Y Position
attr_reader :direction # Direction
attr_reader :character_name # Graphic name
attr_reader :character_hue # Graphic hue
attr_reader :opacity # Graphic opacity
attr_reader :move_speed # Speed
#--------------------------------------------------------------------------
# * Initializes Network Player
#--------------------------------------------------------------------------
def initialize(values)
super()
id = values[0].to_f
@name = values[1]
@level = values[2].to_i
@class_name = values[3]
@map_id = values[4].to_i
@x = values[5].to_i
@y = values[6].to_i
@old_x = values[5].to_i
@old_y = values[6].to_i
@direction = values[7].to_i
@character_name = values[8]
@character_hue = values[9].to_i
@opacity = values[10].to_i
@move_speed = values[11].to_i
end
#--------------------------------------------------------------------------
# * Refreshes Network Player
#--------------------------------------------------------------------------
def move_to_actual_position
if @map_id == $game_map.map_id
moveto(@x, @y)
end
end
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
# * Update Attributes
# * Methods to update players attributes
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
def update_x(x)
@old_x = @x
@x = x.to_i
end
def update_y(y)
@old_y = @y
@y = y.to_i
end
def update_map_id(map_id)
@map_id = map_id.to_i
end
def update_direction(direction)
@direction = direction.to_i
end
def update_move_speed(move_speed)
@move_speed = move_speed.to_i
end
def update_character_name(character_name)
@character_name = character_name
end
def update_character_hue(character_hue)
@character_hue = character_hue.to_i
end
def update_opacity(opacity)
@opacity = opacity.to_i
end
def update_name(name)
@name = name
end
def update_level(level)
@level = level.to_i
end
def update_class_name(class_name)
@class_name = class_name
end
#--------------------------------------------------------------------------
# * Update Network Player
#--------------------------------------------------------------------------
def update
if moving?
update_move
else
straighten
end
if @anime_count > 18 - @move_speed * 2
if not @step_anime and @stop_count > 0
@pattern = @original_pattern
else
@pattern = (@pattern + 1) % 4
end
@anime_count = 0
end
if @wait_count > 0
@wait_count -= 1
return
end
end
#--------------------------------------------------------------------------
# * Update Walking Movement
#--------------------------------------------------------------------------
def update_move
distance = 2 ** @move_speed
if @y * 128 > @real_y
@real_y = [@real_y + distance, @y * 128].min
end
if @x * 128 < @real_x
@real_x = [@real_x - distance, @x * 128].max
end
if @x * 128 > @real_x
@real_x = [@real_x + distance, @x * 128].min
end
if @y * 128 < @real_y
@real_y = [@real_y - distance, @y * 128].max
end
@anime_count += 1.5
end
end
Sprite_PlayerCharacter Class
Code:
#==============================================================================
# ** Sprite_Character
#------------------------------------------------------------------------------
# This sprite is used to display the character.It observes the Game_Character
# class and automatically changes sprite conditions.
#==============================================================================
class Sprite_PlayerCharacter < RPG::Sprite
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_accessor :character # character
#--------------------------------------------------------------------------
# * Object Initialization
# viewport : viewport
# character : character (Game_Character)
#--------------------------------------------------------------------------
def initialize(viewport, character = nil)
super(viewport)
@character = character
update
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
super
# If tile ID, file name, or hue are different from current ones
if @tile_id != @character.tile_id or
@character_name != @character.character_name or
@character_hue != @character.character_hue
# Remember tile ID, file name, and hue
@tile_id = @character.tile_id
@character_name = @character.character_name
# Send the new graphic filename to the server
$network.update_character_name
@character_hue = @character.character_hue
# If tile ID value is valid
if @tile_id >= 384
self.bitmap = RPG::Cache.tile($game_map.tileset_name,
@tile_id, @character.character_hue)
self.src_rect.set(0, 0, 32, 32)
self.ox = 16
self.oy = 32
# If tile ID value is invalid
else
self.bitmap = RPG::Cache.character(@character.character_name,
@character.character_hue)
@cw = bitmap.width / 4
@ch = bitmap.height / 4
self.ox = @cw / 2
self.oy = @ch
end
end
# Set visible situation
self.visible = (not @character.transparent)
# If graphic is character
if @tile_id == 0
# Set rectangular transfer
sx = @character.pattern * @cw
sy = (@character.direction - 2) / 2 * @ch
self.src_rect.set(sx, sy, @cw, @ch)
end
# Set sprite coordinates
self.x = @character.screen_x
self.y = @character.screen_y
self.z = @character.screen_z(@ch)
# Set opacity level, blend method, and bush depth
self.opacity = @character.opacity
self.blend_type = @character.blend_type
self.bush_depth = @character.bush_depth
# Animation
if @character.animation_id != 0
animation = $data_animations[@character.animation_id]
animation(animation, true)
@character.animation_id = 0
end
end
end
Sprite_NetCharacter Class
Code:
#==============================================================================
# ** Sprite_Character
#------------------------------------------------------------------------------
# This sprite is used to display the character.It observes the Game_Character
# class and automatically changes sprite conditions.
#==============================================================================
class Sprite_NetCharacter < RPG::Sprite
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_accessor :character # character
#--------------------------------------------------------------------------
# * Object Initialization
# viewport : viewport
# character : character (Game_Character)
#--------------------------------------------------------------------------
def initialize(viewport, character = nil)
super(viewport)
@character = character
# Name over the character
@name_display = Sprite.new
@name_display.bitmap = Bitmap.new(120, 32)
@name_display.bitmap.font.size = 22
update
end
#--------------------------------------------------------------------------
# * Disposes sprite.
#--------------------------------------------------------------------------
def dispose
@name_display.bitmap.dispose
@name_display.dispose
super
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
super
# Clear&Draw the name
@name_display.bitmap.clear
@name_display.bitmap.draw_text(0, 0, 120, 32, @character.name, 1)
# If tile ID, file name, or hue are different from current ones
if @tile_id != @character.tile_id or
@character_name != @character.character_name or
@character_hue != @character.character_hue
# Remember tile ID, file name, and hue
@tile_id = @character.tile_id
@character_name = @character.character_name
@character_hue = @character.character_hue
# If tile ID value is valid
if @tile_id >= 384
self.bitmap = RPG::Cache.tile($game_map.tileset_name,
@tile_id, @character.character_hue)
self.src_rect.set(0, 0, 32, 32)
self.ox = 16
self.oy = 32
# If tile ID value is invalid
else
self.bitmap = RPG::Cache.character(@character.character_name,
@character.character_hue)
@cw = bitmap.width / 4
@ch = bitmap.height / 4
self.ox = @cw / 2
self.oy = @ch
end
end
# Set visible situation
self.visible = (not @character.transparent)
# If graphic is character
if @tile_id == 0
# Set rectangular transfer
sx = @character.pattern * @cw
sy = (@character.direction - 2) / 2 * @ch
self.src_rect.set(sx, sy, @cw, @ch)
end
# Set sprite coordinates
self.x = @character.screen_x
self.y = @character.screen_y
self.z = @character.screen_z(@ch)
# Set name coordinates
@name_display.x = self.x - 60
@name_display.y = self.y - 80
@name_display.z = self.z
# Set opacity level, blend method, and bush depth
self.opacity = @character.opacity
self.blend_type = @character.blend_type
self.bush_depth = @character.bush_depth
# Animation
if @character.animation_id != 0
animation = $data_animations[@character.animation_id]
animation(animation, true)
@character.animation_id = 0
end
end
end
Chat Class:
Code:
#===============================================================================
# ** Chat
#-------------------------------------------------------------------------------
# Contains the text and related methods to control the chat.
#===============================================================================
class Chat
#-----------------------------------------------------------------------------
# Public variables
#-----------------------------------------------------------------------------
attr_reader :text
attr_reader :visible_lines
attr_reader :width
#-----------------------------------------------------------------------------
# * Initialize
#-----------------------------------------------------------------------------
def initialize
@text = []
@visible_lines = 3
@width = 440
end
#-----------------------------------------------------------------------------
# * Size
# Returns the chat texts size
#-----------------------------------------------------------------------------
def size
return @text.size
end
#-----------------------------------------------------------------------------
# * Reset
# Resets the chat text
#-----------------------------------------------------------------------------
def reset
@text.clear
end
#-----------------------------------------------------------------------------
# * Add Line
# Adds a line to the end of chats text
#-----------------------------------------------------------------------------
def add_line(line)
@text << line
end
#-----------------------------------------------------------------------------
# * Add Line and Send
# Adds a line to the end of chats text and sends it to the server
#-----------------------------------------------------------------------------
def add_line_and_send(line)
line_to_send = "202:#{$network.id};#{line}"
$network.client.send_packet($network.client.peers_list["server"]["peer"],
line_to_send, line_to_send.size+1, 2)
@text << "#{$game_actors[1].name}: #{line}"
end
#-----------------------------------------------------------------------------
# * Delete Line
# Deletes the line at the given index
#-----------------------------------------------------------------------------
def delete_line(line_index)
return false if @text.size == 0
@text.slice!(line_index)
end
#-----------------------------------------------------------------------------
# * Delete First Lines
# Delete the first lines from 0 to quantity - 1
#-----------------------------------------------------------------------------
def delete_first_lines(quantity)
return false if @text.size == 0
for i in 0...(quantity - 1)
@text.slice!(i)
end
end
#-----------------------------------------------------------------------------
# * Last Line
# Returns the last text line
#-----------------------------------------------------------------------------
def last_line
return false if @text.size == 0
return @text[@text.size -1]
end
#-----------------------------------------------------------------------------
# * Lines
# Return a range of lines from the text
#-----------------------------------------------------------------------------
def lines(first, last)
return false if @text.size == 0
lines = []
for i in (first - 1)..(last - 1)
lines << @text[i]
end
return lines
end
#-----------------------------------------------------------------------------
# * Last Lines
# Return the last lines from the text
#-----------------------------------------------------------------------------
def last_lines(quantity)
return false if @text.size == 0
if quantity > @text.size
quantity = @text.size
end
j = @text.size - 1
lines = []
for i in 0..(quantity - 1)
lines << @text[j]
j -= 1
end
return lines
end
end
Window_ChatInput Class
Code:
#==============================================================================
# * Window_ChatInput
#------------------------------------------------------------------------------
# Captures typing and sends it
#==============================================================================
class Window_ChatInput < Window_Base
#--------------------------------------------------------------------------
# * Initialize
#--------------------------------------------------------------------------
def initialize
@x = 0
@y = 352 + 80
@width = $network.chat.width
@height = 48
super(@x, @y, @width, @height)
self.contents = Bitmap.new(width - 32, height - 32)
self.contents.font.size = 16
@text = []
self.visible = false
refresh
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
self.contents.clear
self.contents.draw_text(0, -16, 620, @height, @text.to_s + "_")
end
#--------------------------------------------------------------------------
# * Update
#--------------------------------------------------------------------------
def update
refresh
# Returns text
if Keyb.trigger($keys["Enter"])
if @text.size == 0
self.visible = false
else
$network.chat.add_line_and_send(@text.to_s)
@text.clear
end
end
# Remove last entry in text
if Keyb.trigger($keys["Back"])
@text.delete_at(-1) unless @text.size == 0
end
# Adds a pressed key
unless @text.size >= 50
@text.push(" ") if Keyb.trigger($keys["Space"])
if Keyb.mayus
@text.push("A") if Keyb.trigger($keys["A"])
@text.push("B") if Keyb.trigger($keys["B"])
@text.push("C") if Keyb.trigger($keys["C"])
@text.push("D") if Keyb.trigger($keys["D"])
@text.push("E") if Keyb.trigger($keys["E"])
@text.push("F") if Keyb.trigger($keys["F"])
@text.push("G") if Keyb.trigger($keys["G"])
@text.push("H") if Keyb.trigger($keys["H"])
@text.push("I") if Keyb.trigger($keys["I"])
@text.push("J") if Keyb.trigger($keys["J"])
@text.push("K") if Keyb.trigger($keys["K"])
@text.push("L") if Keyb.trigger($keys["L"])
@text.push("M") if Keyb.trigger($keys["M"])
@text.push("N") if Keyb.trigger($keys["N"])
@text.push("Ñ") if Keyb.trigger($keys["Ñ"])
@text.push("O") if Keyb.trigger($keys["O"])
@text.push("P") if Keyb.trigger($keys["P"])
@text.push("Q") if Keyb.trigger($keys["Q"])
@text.push("R") if Keyb.trigger($keys["R"])
@text.push("S") if Keyb.trigger($keys["S"])
@text.push("T") if Keyb.trigger($keys["T"])
@text.push("U") if Keyb.trigger($keys["U"])
@text.push("V") if Keyb.trigger($keys["V"])
@text.push("W") if Keyb.trigger($keys["W"])
@text.push("X") if Keyb.trigger($keys["X"])
@text.push("Y") if Keyb.trigger($keys["Y"])
@text.push("Z") if Keyb.trigger($keys["Z"])
@text.push("!") if Keyb.trigger($keys["1"])
@text.push("·") if Keyb.trigger($keys["3"])
@text.push("$") if Keyb.trigger($keys["4"])
@text.push("%") if Keyb.trigger($keys["5"])
@text.push("&") if Keyb.trigger($keys["6"])
@text.push("/") if Keyb.trigger($keys["7"])
@text.push("(") if Keyb.trigger($keys["8"])
@text.push(")") if Keyb.trigger($keys["9"])
@text.push("=") if Keyb.trigger($keys["0"])
@text.push("?") if Keyb.trigger($keys["Prg2"])
@text.push("¿") if Keyb.trigger($keys["Prg1"])
@text.push("^") if Keyb.trigger($keys["Ac2"])
@text.push("*") if Keyb.trigger($keys["Plus"])
@text.push("¨") if Keyb.trigger($keys["Ac1"])
@text.push("ç") if Keyb.trigger($keys["Ç"])
@text.push(";") if Keyb.trigger($keys["Sep"])
@text.push(":") if Keyb.trigger($keys["Dott"])
@text.push("_") if Keyb.trigger($keys["Dash"])
@text.push(">") if Keyb.trigger($keys["Cmp"])
@text.push("ª") if Keyb.trigger($keys["Ord"])
else
@text.push("a") if Keyb.trigger($keys["A"])
@text.push("b") if Keyb.trigger($keys["B"])
@text.push("c") if Keyb.trigger($keys["C"])
@text.push("d") if Keyb.trigger($keys["D"])
@text.push("e") if Keyb.trigger($keys["E"])
@text.push("f") if Keyb.trigger($keys["F"])
@text.push("g") if Keyb.trigger($keys["G"])
@text.push("h") if Keyb.trigger($keys["H"])
@text.push("i") if Keyb.trigger($keys["I"])
@text.push("j") if Keyb.trigger($keys["J"])
@text.push("k") if Keyb.trigger($keys["K"])
@text.push("l") if Keyb.trigger($keys["L"])
@text.push("m") if Keyb.trigger($keys["M"])
@text.push("n") if Keyb.trigger($keys["N"])
@text.push("ñ") if Keyb.trigger($keys["Ñ"])
@text.push("o") if Keyb.trigger($keys["O"])
@text.push("p") if Keyb.trigger($keys["P"])
@text.push("q") if Keyb.trigger($keys["Q"])
@text.push("r") if Keyb.trigger($keys["R"])
@text.push("s") if Keyb.trigger($keys["S"])
@text.push("t") if Keyb.trigger($keys["T"])
@text.push("u") if Keyb.trigger($keys["U"])
@text.push("v") if Keyb.trigger($keys["V"])
@text.push("w") if Keyb.trigger($keys["W"])
@text.push("x") if Keyb.trigger($keys["X"])
@text.push("y") if Keyb.trigger($keys["Y"])
@text.push("z") if Keyb.trigger($keys["Z"])
@text.push("0") if Keyb.trigger($keys["0"])
@text.push("1") if Keyb.trigger($keys["1"])
@text.push("2") if Keyb.trigger($keys["2"])
@text.push("3") if Keyb.trigger($keys["3"])
@text.push("4") if Keyb.trigger($keys["4"])
@text.push("5") if Keyb.trigger($keys["5"])
@text.push("6") if Keyb.trigger($keys["6"])
@text.push("7") if Keyb.trigger($keys["7"])
@text.push("8") if Keyb.trigger($keys["8"])
@text.push("9") if Keyb.trigger($keys["9"])
@text.push("`") if Keyb.trigger($keys["Ac2"])
@text.push("+") if Keyb.trigger($keys["Plus"])
@text.push("´") if Keyb.trigger($keys["Ac1"])
@text.push("ç") if Keyb.trigger($keys["Ç"])
@text.push(",") if Keyb.trigger($keys["Sep"])
@text.push(".") if Keyb.trigger($keys["Dott"])
@text.push("-") if Keyb.trigger($keys["Dash"])
@text.push("'") if Keyb.trigger($keys["Prg2"])
@text.push("¡") if Keyb.trigger($keys["Prg1"])
@text.push("<") if Keyb.trigger($keys["Cmp"])
@text.push("º") if Keyb.trigger($keys["Ord"])
end
@text.push("*") if Keyb.trigger($keys["Multiply"])
@text.push("+") if Keyb.trigger($keys["Add"])
@text.push("-") if Keyb.trigger($keys["Substract"])
@text.push("/") if Keyb.trigger($keys["Divide"])
@text.push(".") if Keyb.trigger($keys["Decimal"])
@text.push("0") if Keyb.trigger($keys["Pad0"])
@text.push("1") if Keyb.trigger($keys["Pad1"])
@text.push("2") if Keyb.trigger($keys["Pad2"])
@text.push("3") if Keyb.trigger($keys["Pad3"])
@text.push("4") if Keyb.trigger($keys["Pad4"])
@text.push("5") if Keyb.trigger($keys["Pad5"])
@text.push("6") if Keyb.trigger($keys["Pad6"])
@text.push("7") if Keyb.trigger($keys["Pad7"])
@text.push("8") if Keyb.trigger($keys["Pad8"])
@text.push("9") if Keyb.trigger($keys["Pad9"])
end
end
end
Window_Chat Class
Code:
#==============================================================================
# * Window_Chat
#------------------------------------------------------------------------------
# Displays chat messages
#==============================================================================
class Window_Chat < Window_Base
#--------------------------------------------------------------------------
# * Initialization
#--------------------------------------------------------------------------
def initialize
@x = 0
@y = 352
@width = $network.chat.width
@height = 80
super(@x, @y, @width, @height)
self.contents = Bitmap.new(width - 32, height - 32)
self.back_opacity = 50
self.visible = true
self.contents.font.size = 16
refresh
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
self.contents.clear
lines = $network.chat.last_lines($network.chat.visible_lines)
return if lines == false
for i in 1..lines.size
self.contents.draw_text(0, ($network.chat.visible_lines - i) * 16 - 8, @width, 32, lines[i-1])
end
end
#--------------------------------------------------------------------------
# * Update
#--------------------------------------------------------------------------
def update
super
#if Graphics.frame_count % Graphics.frame_rate == 0
refresh
#end
end
end
Keyboard Module by Hound
Code:
################################################################################
################################ KEYBOARD MODULE ###############################
################################################################################
#-------------------------------------------------------------------------------
# Basado en el Keyboard Script de Cybersam
# Script remodelado por Hound
#-------------------------------------------------------------------------------
# Explicación:
# Este script es un módulo para las condiciones de pulsado de teclas, que incluye
# TODAS las teclas del teclado español. Me basé en el famoso script de teclado
# de Cybersam para las funciones y teclas básicas del teclado inglés, pero con
# algunos cambios destacables, asi como las teclas especiales típicas del
# teclado español (Ñ, Ç, acentos, etc), cambios en las funciones y sintaxis, etc
# La mayoría de nombres para las teclas, están conservados en inglés.
#-------------------------------------------------------------------------------
# Instrucciones:
# El comando para la condición de tecla pulsada puedes ponerla desde el comando
# de evento "Condiciones y Efectos" desde la opción "Script" escribiendo:
# Keyb.trigger($keys["nombre de la tecla"]) # Para condición trigger/repeat
# Keyb.press($keys["nombre de la tecla"]) # Para condición mientras es pulsada
# Keyb.bloq($keys["nombre de la tecla"]) # Para condición de tecla bloqueada
# Keyb.mayus # Para condición de bloq mayus activado
# Keyb.empty # Para limpiar/arreglar el rastreo del teclado
# Es recomendable escribir Keyb.empty justo antes de una serie de condicione
# en las que se use este módulo, para limpiar el rastreo.
#-------------------------------------------------------------------------------
# Contacto:
# Para cualquier comentario, duda o sugerencia, mándalas por email
# a [email=houndninja@gmail.com]houndninja@gmail.com[/email]
# Espero que sirva de utilidad ;)
#-------------------------------------------------------------------------------
module Keyb
$keys = {}
$keys["MouseL"] = 0x01 # Botón Izquierdo
$keys["MouseR"] = 0x02 # Botón Derecho
$keys["MouseM"] = 0x04 # Botón medio
$keys["Mouse4"] = 0x05 # Cuarto Botón
$keys["Mouse5"] = 0x06 # Quinto Botón
# Teclas de Controles
$keys["Back"] = 0x08 # Tecla Retroceder/Borrar
$keys["Tab"] = 0x09 # Tecla Tab
$keys["Enter"] = 0x0D # Tecla Enter
$keys["Shift"] = 0x10 # Tecla Shift
$keys["Ctrl"] = 0x11 # Tecla Control
$keys["Alt"] = 0x12 # Tecla Alt
$keys["Pause"] = 0x13 # Tecla de Pausa
$keys["Caps"] = 0x14 # Tecla Bloq Mayus
$keys["Esc"] = 0x1B # Tecla Escape (ESC)
$keys["Space"] = 0x20 # Tecla Espaciadora
$keys["AvPag"] = 0x21 # Tecla Siguiente
$keys["RePag"] = 0x22 # Tecla Anterior
$keys["End"] = 0x23 # Tecla Fin
$keys["Home"] = 0x24 # Tecla Inicio
# Teclas de Direcciones
$keys["Left"] = 0x25 # Tecla Flecha Izquierda
$keys["Up"] = 0x26 # Tecla Flecha Arriba
$keys["Right"] = 0x27 # Tecla Flecha Derecha
$keys["Down"] = 0x28 # Tecla Flecha Abajo
$keys["Select"] = 0x29
# Otras teclas
$keys["Print"] = 0x2A # Tecla Imprimir
$keys["Snapshot"] = 0x2C # Tecla Capturar Pantalla
$keys["Ins"] = 0x2D # Tecla Insert
$keys["Del"] = 0x2E # Tecla Suprimir
# Teclas Numéricas Superiores
$keys["0"] = 0x30
$keys["1"] = 0x31
$keys["2"] = 0x32
$keys["3"] = 0x33
$keys["4"] = 0x34
$keys["5"] = 0x35
$keys["6"] = 0x36
$keys["7"] = 0x37
$keys["8"] = 0x38
$keys["9"] = 0x39
# Teclas de Windows
$keys["Lwin"] = 0x5B # Tecla Windows Izquierda
$keys["Rwin"] = 0x5C # Tecla Windows Derecha
$keys["Apps"] = 0x5D # Tecla Aplicaciones
# Teclas del Pad Numérico
$keys["Pad0"] = 0x60
$keys["Pad1"] = 0x61
$keys["Pad2"] = 0x62
$keys["Pad3"] = 0x63
$keys["Pad4"] = 0x64
$keys["Pad5"] = 0x65
$keys["Pad6"] = 0x66
$keys["Pad7"] = 0x67
$keys["Pad8"] = 0x68
$keys["Pad9"] = 0x69
$keys["Multiply"] = 0x6A # Tecla Multiplicar
$keys["Add"] = 0x6B # Tecla Sumar
$keys["Separator"] = 0x6C
$keys["Substract"] = 0x6D # Tecla Restar
$keys["Decimal"] = 0x6E
$keys["Divide"] = 0x6F # Tecla Dividir
# Teclas de Funciones
$keys["F1"] = 0x70
$keys["F2"] = 0x71
$keys["F3"] = 0x72
$keys["F4"] = 0x73
$keys["F5"] = 0x74
$keys["F6"] = 0x75
$keys["F7"] = 0x76
$keys["F8"] = 0x77
$keys["F9"] = 0x78
$keys["F10"] = 0x79
$keys["F11"] = 0x7A
$keys["F12"] = 0x7B
$keys["Numlock"] = 0x90
$keys["Scroll"] = 0x91 # Tecla Bloq Despl
# Teclas de cada letra
$keys["A"] = 0x41
$keys["B"] = 0x42
$keys["C"] = 0x43
$keys["D"] = 0x44
$keys["E"] = 0x45
$keys["F"] = 0x46
$keys["G"] = 0x47
$keys["H"] = 0x48
$keys["I"] = 0x49
$keys["J"] = 0x4A
$keys["K"] = 0x4B
$keys["L"] = 0x4C
$keys["M"] = 0x4D
$keys["N"] = 0x4E
$keys["O"] = 0x4F
$keys["P"] = 0x50
$keys["Q"] = 0x51
$keys["R"] = 0x52
$keys["S"] = 0x53
$keys["T"] = 0x54
$keys["U"] = 0x55
$keys["V"] = 0x56
$keys["W"] = 0x57
$keys["X"] = 0x58
$keys["Y"] = 0x59
$keys["Z"] = 0x5A
# Teclas de Signos de Puntuación
$keys["Sep"] = 0xBC # Tecla Coma , ;
$keys["Dash"] = 0xBD # Tecla Guión - _
$keys["Dott"] = 0xBE # Tecla Punto . :
# Teclas de carácteres especiales
$keys["Ç"] = 0xBF # ç Ç }
$keys["Ñ"] = 0xc0# ñ Ñ
$keys["Ac1"] = 0xde # Acento y Diéresis ´¨
$keys["Ac2"] = 0xBA # Acento al revés `^
$keys["Plus"] = 0xBB # + * ]
$keys["Prg2"] = 0xdb # ' ?
$keys["Ord"] = 0xdc # º ª \
$keys["Prg1"] = 0xdd # ¡ ¿
$keys["Cmp"] = 0xe2 # Comparación < >
# Teclas de Control Específicas
$keys["Lshift"] = 0xA0 # Shift izquierdo
$keys["Rshift"] = 0xA1 # Shift derecho
$keys["Lctrl"] = 0xA2 # Ctrl izquierdo
$keys["Rctrl"] = 0xA3 # Ctrl derecho
$keys["Lalt"] = 0xA4 # Alt izquierdo
$keys["Ralt"] = 0xA5 # Alt derecho
#--------------------------------------------------------------------------
# Creamos las variables de llamada Win32api
#--------------------------------------------------------------------------
GetKeyState = Win32API.new("user32","GetAsyncKeyState",['i'],'i')
GetKeyboardState = Win32API.new("user32","GetKeyState",['i'],'i')
GetSetKeyState = Win32API.new("user32","SetKeyboardState",['i'],'i')
#--------------------------------------------------------------------------
module_function #Ponemos los métodos agregados al nombre del módulo
#--------------------------------------------------------------------------
def trigger(rkey) # Condición de tecla pulsada repetitivamente
GetKeyState.call(rkey) & 0x01 == 1
end
#--------------------------------------------------------------------------
def press(key) # Condición de tecla pulsada
not GetKeyboardState.call(key).between?(0, 1)
end
def bloq(key) # Condición de tecla bloqueada
GetKeyboardState.call(key) == 1
end
def mayus # Condición del bloq mayus activado
GetKeyboardState.call(0x14) == 1
end
def empty # Método de arreglo para la condición de teclas
array = $keys.values
for i in 0...array.size
self.trigger(array[i])
end
end
end
____Edited Scripts____
Game_Temp Class
Code:
#==============================================================================
# ** Game_Temp
#------------------------------------------------------------------------------
# Esta clase almacena los datos temporales no incluidos en las partidas guardadas.
# Llama a "$game_temp" para acceder a las variables globales incluidas aquí.
#==============================================================================
class Game_Temp
#--------------------------------------------------------------------------
# * Variables Globales
#--------------------------------------------------------------------------
attr_accessor :map_bgm # Música de Mapa(Se devuelve al terminar batalla)
attr_accessor :message_text # Texto del Mensaje
attr_accessor :message_proc # Llamada de Mensaje (Proc)
attr_accessor :choice_start # Elecciones: Línea de Comienzo
attr_accessor :choice_max # Elecciones: Número de Opciones
attr_accessor :choice_cancel_type # Elecciones: Añadir Rama al Cancelar
attr_accessor :choice_proc # Elecciones: Llamada (Proc)
attr_accessor :num_input_start # Dígitos: Línea de Comienzo
attr_accessor :num_input_variable_id # Dígitos: Variable en que se guarda
attr_accessor :num_input_digits_max # input number: digit amount
attr_accessor :message_window_showing # Ejecutando Ventana de Mensaje
attr_accessor :common_event_id # ID de Evento Común
attr_accessor :in_battle # Indica si estás en la batalla
attr_accessor :battle_calling # Llamada a la Batalla
attr_accessor :battle_troop_id # ID de Grupo de Enemigos
attr_accessor :battle_can_escape # Posibilidad de Escapar
attr_accessor :battle_can_lose # Posibilidad de perder batalla
attr_accessor :battle_proc # Llamada a Batalla (Proc)
attr_accessor :battle_turn # Número de turnos en la batalla
attr_accessor :battle_event_flags # battle event flags: completed
attr_accessor :battle_abort # Llamada para finalizar batalla
attr_accessor :battle_main_phase # battle flag: main phase
attr_accessor :battleback_name # Nombre del fondo de batalla
attr_accessor :forcing_battler # Combatiente forzado a una acción
attr_accessor :shop_calling # Llamada a Tienda
attr_accessor :shop_goods # Lista de objetos para la tienda
attr_accessor :name_calling # Llamada a Escribir Nombre
attr_accessor :name_actor_id # ID de Héroe para Escribir Nombre
attr_accessor :name_max_char # Máximo de carácteres para Escribir Nombre
attr_accessor :menu_calling # Llamada al Menú
attr_accessor :menu_beep # Reproducir sonido del menú
attr_accessor :save_calling # Llamada a Pantalla de Guardar
attr_accessor :debug_calling # Llamada a Pantalla de Depuración
attr_accessor :player_transferring # Llamada a Teletransportar Héroe
attr_accessor :player_new_map_id # Destino del Héroe: ID de Mapa
attr_accessor :player_new_x # Destino del Héroe: Cordenada X
attr_accessor :player_new_y # Destino del Héroe: Cordenada Y
attr_accessor :player_new_direction # Destino del Héroe: direction
attr_accessor :transition_processing # Llamada a Proceso de Transición
attr_accessor :transition_name # Nombre del Archivo de Transición
attr_accessor :gameover # Llamada a GameOver
attr_accessor :to_title # Llamada a Volver a Título
attr_accessor :last_file_index # Número de la última partida guardada
attr_accessor :debug_top_row # Pantalla de Depuración: Fila Elegida
attr_accessor :debug_index # Pantalla de Depuración: Opción Elegida
attr_accessor :new_map_players
attr_accessor :old_map_players
#--------------------------------------------------------------------------
# * Inicio de Objetos (Aquí se agrega el valor incial a cada variable)
#--------------------------------------------------------------------------
def initialize
@map_bgm = nil
@message_text = nil
@message_proc = nil
@choice_start = 99
@choice_max = 0
@choice_cancel_type = 0
@choice_proc = nil
@num_input_start = 99
@num_input_variable_id = 0
@num_input_digits_max = 0
@message_window_showing = false
@common_event_id = 0
@in_battle = false
@battle_calling = false
@battle_troop_id = 0
@battle_can_escape = false
@battle_can_lose = false
@battle_proc = nil
@battle_turn = 0
@battle_event_flags = {}
@battle_abort = false
@battle_main_phase = false
@battleback_name = ''
@forcing_battler = nil
@shop_calling = false
@shop_id = 0
@name_calling = false
@name_actor_id = 0
@name_max_char = 0
@menu_calling = false
@menu_beep = false
@save_calling = false
@debug_calling = false
@player_transferring = false
@player_new_map_id = 0
@player_new_x = 0
@player_new_y = 0
@player_new_direction = 0
@transition_processing = false
@transition_name = ""
@gameover = false
@to_title = false
@last_file_index = 0
@debug_top_row = 0
@debug_index = 0
@new_map_players = []
@old_map_players = []
end
end
Game_Player Class
Code:
#==============================================================================
# ** 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 < Game_Character
#--------------------------------------------------------------------------
# * Invariables
#--------------------------------------------------------------------------
CENTER_X = (320 - 16) * 4 # Center screen x-coordinate * 4
CENTER_Y = (240 - 16) * 4 # Center screen y-coordinate * 4
#--------------------------------------------------------------------------
# * Passable Determinants
# x : x-coordinate
# y : y-coordinate
# d : direction (0,2,4,6,8)
# * 0 = Determines if all directions are impassable (for jumping)
#--------------------------------------------------------------------------
def passable?(x, y, d)
# Get new coordinates
new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
# If coordinates are outside of map
unless $game_map.valid?(new_x, new_y)
# Impassable
return false
end
# If debug mode is ON and ctrl key was pressed
if $DEBUG and Input.press?(Input::CTRL)
# Passable
return true
end
super
end
#--------------------------------------------------------------------------
# * Set Map Display Position to Center of Screen
#--------------------------------------------------------------------------
def center(x, y)
max_x = ($game_map.width - 20) * 128
max_y = ($game_map.height - 15) * 128
$game_map.display_x = [0, [x * 128 - CENTER_X, max_x].min].max
$game_map.display_y = [0, [y * 128 - CENTER_Y, max_y].min].max
end
#--------------------------------------------------------------------------
# * Move to Designated Position
# x : x-coordinate
# y : y-coordinate
#--------------------------------------------------------------------------
def moveto(x, y)
super
# Centering
center(x, y)
# Make encounter count
make_encounter_count
end
#--------------------------------------------------------------------------
# * Increaase Steps
#--------------------------------------------------------------------------
def increase_steps
super
# If move route is not forcing
unless @move_route_forcing
# Increase steps
$game_party.increase_steps
# Number of steps are an even number
if $game_party.steps % 2 == 0
# Slip damage check
$game_party.check_map_slip_damage
end
end
end
#--------------------------------------------------------------------------
# * Get Encounter Count
#--------------------------------------------------------------------------
def encounter_count
return @encounter_count
end
#--------------------------------------------------------------------------
# * Make Encounter Count
#--------------------------------------------------------------------------
def make_encounter_count
# Image of two dice rolling
if $game_map.map_id != 0
n = $game_map.encounter_step
@encounter_count = rand(n) + rand(n) + 1
end
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
# If party members = 0
if $game_party.actors.size == 0
# Clear character file name and hue
@character_name = ""
@character_hue = 0
# End method
return
end
# Get lead actor
actor = $game_party.actors[0]
# Set character file name and hue
@character_name = actor.character_name
@character_hue = actor.character_hue
# Initialize opacity level and blending method
@opacity = 255
@blend_type = 0
end
#--------------------------------------------------------------------------
# * Same Position Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_here(triggers)
result = false
# If event is running
if $game_system.map_interpreter.running?
return result
end
# All event loops
for event in $game_map.events.values
# If event coordinates and triggers are consistent
if event.x == @x and event.y == @y and triggers.include?(event.trigger)
# If starting determinant is same position event (other than jumping)
if not event.jumping? and event.over_trigger?
event.start
result = true
end
end
end
return result
end
#--------------------------------------------------------------------------
# * Front Envent Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_there(triggers)
result = false
# If event is running
if $game_system.map_interpreter.running?
return result
end
# 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 event coordinates and triggers are consistent
if event.x == new_x and event.y == new_y and
triggers.include?(event.trigger)
# If starting determinant is front event (other than jumping)
if not event.jumping? and not event.over_trigger?
event.start
result = true
end
end
end
# If fitting event is not found
if result == false
# 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 event coordinates and triggers are consistent
if event.x == new_x and event.y == new_y and
triggers.include?(event.trigger)
# If starting determinant is front event (other than jumping)
if not event.jumping? and not event.over_trigger?
event.start
result = true
end
end
end
end
end
return result
end
#--------------------------------------------------------------------------
# * Touch Event Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_touch(x, y)
result = false
# If event is running
if $game_system.map_interpreter.running?
return result
end
# All event loops
for event in $game_map.events.values
# If event coordinates and triggers are consistent
if event.x == x and event.y == y and [1,2].include?(event.trigger)
# If starting determinant is front event (other than jumping)
if not event.jumping? and not event.over_trigger?
event.start
result = true
end
end
end
return result
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
# 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 2
move_down
# Send our character x&y and direction to the server
$network.update_x
$network.update_direction
when 4
move_left
# Send our character x&y and direction to the server
$network.update_x
$network.update_direction
when 6
move_right
# Send our character x&y and direction to the server
$network.update_x
$network.update_direction
when 8
move_up
# Send our character x&y and direction to the server
$network.update_x
$network.update_direction
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
Spriteset_Map Class
Code:
#==============================================================================
# ** Spriteset_Map
#------------------------------------------------------------------------------
# This class brings together map screen sprites, tilemaps, etc.
# It's used within the Scene_Map class.
#==============================================================================
class Spriteset_Map
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
# Make viewports
@viewport1 = Viewport.new(0, 0, 640, 480)
@viewport2 = Viewport.new(0, 0, 640, 480)
@viewport3 = Viewport.new(0, 0, 640, 480)
@viewport2.z = 200
@viewport3.z = 5000
# Make tilemap
@tilemap = Tilemap.new(@viewport1)
@tilemap.tileset = RPG::Cache.tileset($game_map.tileset_name)
for i in 0..6
autotile_name = $game_map.autotile_names[i]
@tilemap.autotiles[i] = RPG::Cache.autotile(autotile_name)
end
@tilemap.map_data = $game_map.data
@tilemap.priorities = $game_map.priorities
# Make panorama plane
@panorama = Plane.new(@viewport1)
@panorama.z = -1000
# Make fog plane
@fog = Plane.new(@viewport1)
@fog.z = 3000
# Make character sprites
@character_sprites = []
for i in $game_map.events.keys.sort
sprite = Sprite_Character.new(@viewport1, $game_map.events[i])
@character_sprites.push(sprite)
end
@character_sprites.push(Sprite_PlayerCharacter.new(@viewport1, $game_player))
# Make network sprites
@network_sprites = []
for player in $network.players.values
player.move_to_actual_position
if player.map_id == $game_map.map_id
sprite = Sprite_NetCharacter.new(@viewport1, player)
@network_sprites.push(sprite)
end
end
# Make weather
@weather = RPG::Weather.new(@viewport1)
# Make picture sprites
@picture_sprites = []
for i in 1..50
@picture_sprites.push(Sprite_Picture.new(@viewport2,
$game_screen.pictures[i]))
end
# Make timer sprite
@timer_sprite = Sprite_Timer.new
# Frame update
update
end
#--------------------------------------------------------------------------
# * Refreshes the Network sprites
#--------------------------------------------------------------------------
def add_new_player_sprites
$game_temp.new_map_players.each do |player|
player.move_to_actual_position
sprite = Sprite_NetCharacter.new(@viewport1, player)
@network_sprites.push(sprite)
end
$game_temp.new_map_players.clear
end
def del_old_player_sprites
@network_sprites.each do |sprite|
$game_temp.old_map_players.each do |player|
if sprite.character == player
sprite.dispose
@network_sprites.delete(sprite)
end
end
end
$game_temp.old_map_players.clear
end
#--------------------------------------------------------------------------
# * Dispose
#--------------------------------------------------------------------------
def dispose
# Dispose of tilemap
@tilemap.tileset.dispose
for i in 0..6
@tilemap.autotiles[i].dispose
end
@tilemap.dispose
# Dispose of panorama plane
@panorama.dispose
# Dispose of fog plane
@fog.dispose
# Dispose of character sprites
for sprite in @character_sprites
sprite.dispose
end
# Dispose of network sprites
for sprite in @network_sprites
sprite.dispose
end
# Dispose of weather
@weather.dispose
# Dispose of picture sprites
for sprite in @picture_sprites
sprite.dispose
end
# Dispose of timer sprite
@timer_sprite.dispose
# Dispose of viewports
@viewport1.dispose
@viewport2.dispose
@viewport3.dispose
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
add_new_player_sprites if !($game_temp.new_map_players.empty?)
del_old_player_sprites if !($game_temp.old_map_players.empty?)
# If panorama is different from current one
if @panorama_name != $game_map.panorama_name or
@panorama_hue != $game_map.panorama_hue
@panorama_name = $game_map.panorama_name
@panorama_hue = $game_map.panorama_hue
if @panorama.bitmap != nil
@panorama.bitmap.dispose
@panorama.bitmap = nil
end
if @panorama_name != ""
@panorama.bitmap = RPG::Cache.panorama(@panorama_name, @panorama_hue)
end
Graphics.frame_reset
end
# If fog is different than current fog
if @fog_name != $game_map.fog_name or @fog_hue != $game_map.fog_hue
@fog_name = $game_map.fog_name
@fog_hue = $game_map.fog_hue
if @fog.bitmap != nil
@fog.bitmap.dispose
@fog.bitmap = nil
end
if @fog_name != ""
@fog.bitmap = RPG::Cache.fog(@fog_name, @fog_hue)
end
Graphics.frame_reset
end
# Update tilemap
@tilemap.ox = $game_map.display_x / 4
@tilemap.oy = $game_map.display_y / 4
@tilemap.update
# Update panorama plane
@panorama.ox = $game_map.display_x / 8
@panorama.oy = $game_map.display_y / 8
# Update fog plane
@fog.zoom_x = $game_map.fog_zoom / 100.0
@fog.zoom_y = $game_map.fog_zoom / 100.0
@fog.opacity = $game_map.fog_opacity
@fog.blend_type = $game_map.fog_blend_type
@fog.ox = $game_map.display_x / 4 + $game_map.fog_ox
@fog.oy = $game_map.display_y / 4 + $game_map.fog_oy
@fog.tone = $game_map.fog_tone
# Update character sprites
for sprite in @character_sprites
sprite.update
end
for sprite in @network_sprites
sprite.update
end
# Update weather graphic
@weather.type = $game_screen.weather_type
@weather.max = $game_screen.weather_max
@weather.ox = $game_map.display_x / 4
@weather.oy = $game_map.display_y / 4
@weather.update
# Update picture sprites
for sprite in @picture_sprites
sprite.update
end
# Update timer sprite
@timer_sprite.update
# Set screen color tone and shake position
@viewport1.tone = $game_screen.tone
@viewport1.ox = $game_screen.shake
# Set screen flash color
@viewport3.color = $game_screen.flash_color
# Update viewports
@viewport1.update
@viewport3.update
end
end
Interpreter 4 Class
Code:
#==============================================================================
# ** Interpreter (part 4)
#------------------------------------------------------------------------------
# This interpreter runs event commands. This class is used within the
# Game_System class and the Game_Event class.
#==============================================================================
class Interpreter
#--------------------------------------------------------------------------
# * Control Switches
#--------------------------------------------------------------------------
def command_121
# Loop for group control
for i in @parameters[0] .. @parameters[1]
# Change switch
$game_switches[i] = (@parameters[2] == 0)
# Send the new state to the server
$network.update_switch(i)
end
# Refresh map
$game_map.need_refresh = true
# Continue
return true
end
#--------------------------------------------------------------------------
# * Control Variables
#--------------------------------------------------------------------------
def command_122
# Initialize value
value = 0
# Branch with operand
case @parameters[3]
when 0 # invariable
value = @parameters[4]
when 1 # variable
value = $game_variables[@parameters[4]]
when 2 # random number
value = @parameters[4] + rand(@parameters[5] - @parameters[4] + 1)
when 3 # item
value = $game_party.item_number(@parameters[4])
when 4 # actor
actor = $game_actors[@parameters[4]]
if actor != nil
case @parameters[5]
when 0 # level
value = actor.level
when 1 # EXP
value = actor.exp
when 2 # HP
value = actor.hp
when 3 # SP
value = actor.sp
when 4 # MaxHP
value = actor.maxhp
when 5 # MaxSP
value = actor.maxsp
when 6 # strength
value = actor.str
when 7 # dexterity
value = actor.dex
when 8 # agility
value = actor.agi
when 9 # intelligence
value = actor.int
when 10 # attack power
value = actor.atk
when 11 # physical defense
value = actor.pdef
when 12 # magic defense
value = actor.mdef
when 13 # evasion
value = actor.eva
end
end
when 5 # enemy
enemy = $game_troop.enemies[@parameters[4]]
if enemy != nil
case @parameters[5]
when 0 # HP
value = enemy.hp
when 1 # SP
value = enemy.sp
when 2 # MaxHP
value = enemy.maxhp
when 3 # MaxSP
value = enemy.maxsp
when 4 # strength
value = enemy.str
when 5 # dexterity
value = enemy.dex
when 6 # agility
value = enemy.agi
when 7 # intelligence
value = enemy.int
when 8 # attack power
value = enemy.atk
when 9 # physical defense
value = enemy.pdef
when 10 # magic defense
value = enemy.mdef
when 11 # evasion correction
value = enemy.eva
end
end
when 6 # character
character = get_character(@parameters[4])
if character != nil
case @parameters[5]
when 0 # x-coordinate
value = character.x
when 1 # y-coordinate
value = character.y
when 2 # direction
value = character.direction
when 3 # screen x-coordinate
value = character.screen_x
when 4 # screen y-coordinate
value = character.screen_y
when 5 # terrain tag
value = character.terrain_tag
end
end
when 7 # other
case @parameters[4]
when 0 # map ID
value = $game_map.map_id
when 1 # number of party members
value = $game_party.actors.size
when 2 # gold
value = $game_party.gold
when 3 # steps
value = $game_party.steps
when 4 # play time
value = Graphics.frame_count / Graphics.frame_rate
when 5 # timer
value = $game_system.timer / Graphics.frame_rate
when 6 # save count
value = $game_system.save_count
end
end
# Loop for group control
for i in @parameters[0] .. @parameters[1]
# Branch with control
case @parameters[2]
when 0 # substitute
$game_variables[i] = value
when 1 # add
$game_variables[i] += value
when 2 # subtract
$game_variables[i] -= value
when 3 # multiply
$game_variables[i] *= value
when 4 # divide
if value != 0
$game_variables[i] /= value
end
when 5 # remainder
if value != 0
$game_variables[i] %= value
end
end
# Maximum limit check
if $game_variables[i] > 99999999
$game_variables[i] = 99999999
end
# Minimum limit check
if $game_variables[i] < -99999999
$game_variables[i] = -99999999
end
end
# Refresh map
$game_map.need_refresh = true
# Send the new value to the server
$network.update_variable(i)
# Continue
return true
end
#--------------------------------------------------------------------------
# * Control Self Switch
#--------------------------------------------------------------------------
def command_123
# If event ID is valid
if @event_id > 0
# Make a self switch key
key = [$game_map.map_id, @event_id, @parameters[0]]
# Change self switches
$game_self_switches[key] = (@parameters[1] == 0)
end
# Refresh map
$game_map.need_refresh = true
# Continue
return true
end
#--------------------------------------------------------------------------
# * Control Timer
#--------------------------------------------------------------------------
def command_124
# If started
if @parameters[0] == 0
$game_system.timer = @parameters[1] * Graphics.frame_rate
$game_system.timer_working = true
end
# If stopped
if @parameters[0] == 1
$game_system.timer_working = false
end
# Continue
return true
end
#--------------------------------------------------------------------------
# * Change Gold
#--------------------------------------------------------------------------
def command_125
# Get value to operate
value = operate_value(@parameters[0], @parameters[1], @parameters[2])
# Increase / decrease amount of gold
$game_party.gain_gold(value)
# Continue
return true
end
#--------------------------------------------------------------------------
# * Change Items
#--------------------------------------------------------------------------
def command_126
# Get value to operate
value = operate_value(@parameters[1], @parameters[2], @parameters[3])
# Increase / decrease items
$game_party.gain_item(@parameters[0], value)
# Continue
return true
end
#--------------------------------------------------------------------------
# * Change Weapons
#--------------------------------------------------------------------------
def command_127
# Get value to operate
value = operate_value(@parameters[1], @parameters[2], @parameters[3])
# Increase / decrease weapons
$game_party.gain_weapon(@parameters[0], value)
# Continue
return true
end
#--------------------------------------------------------------------------
# * Change Armor
#--------------------------------------------------------------------------
def command_128
# Get value to operate
value = operate_value(@parameters[1], @parameters[2], @parameters[3])
# Increase / decrease armor
$game_party.gain_armor(@parameters[0], value)
# Continue
return true
end
#--------------------------------------------------------------------------
# * Change Party Member
#--------------------------------------------------------------------------
def command_129
# Get actor
actor = $game_actors[@parameters[0]]
# If actor is valid
if actor != nil
# Branch with control
if @parameters[1] == 0
if @parameters[2] == 1
$game_actors[@parameters[0]].setup(@parameters[0])
end
$game_party.add_actor(@parameters[0])
else
$game_party.remove_actor(@parameters[0])
end
end
# Continue
return true
end
#--------------------------------------------------------------------------
# * Change Windowskin
#--------------------------------------------------------------------------
def command_131
# Change windowskin file name
$game_system.windowskin_name = @parameters[0]
# Continue
return true
end
#--------------------------------------------------------------------------
# * Change Battle BGM
#--------------------------------------------------------------------------
def command_132
# Change battle BGM
$game_system.battle_bgm = @parameters[0]
# Continue
return true
end
#--------------------------------------------------------------------------
# * Change Battle End ME
#--------------------------------------------------------------------------
def command_133
# Change battle end ME
$game_system.battle_end_me = @parameters[0]
# Continue
return true
end
#--------------------------------------------------------------------------
# * Change Save Access
#--------------------------------------------------------------------------
def command_134
# Change save access flag
$game_system.save_disabled = (@parameters[0] == 0)
# Continue
return true
end
#--------------------------------------------------------------------------
# * Change Menu Access
#--------------------------------------------------------------------------
def command_135
# Change menu access flag
$game_system.menu_disabled = (@parameters[0] == 0)
# Continue
return true
end
#--------------------------------------------------------------------------
# * Change Encounter
#--------------------------------------------------------------------------
def command_136
# Change encounter flag
$game_system.encounter_disabled = (@parameters[0] == 0)
# Make encounter count
$game_player.make_encounter_count
# Continue
return true
end
end
Scene_Title Class
Code:
#==============================================================================
# ** Scene_Title
#------------------------------------------------------------------------------
# This class performs title screen processing.
#==============================================================================
class Scene_Title
#--------------------------------------------------------------------------
# * Main Processing
#--------------------------------------------------------------------------
def main
# If battle test
if $BTEST
battle_test
return
end
# Load database
$data_actors = load_data("Data/Actors.rxdata")
$data_classes = load_data("Data/Classes.rxdata")
$data_skills = load_data("Data/Skills.rxdata")
$data_items = load_data("Data/Items.rxdata")
$data_weapons = load_data("Data/Weapons.rxdata")
$data_armors = load_data("Data/Armors.rxdata")
$data_enemies = load_data("Data/Enemies.rxdata")
$data_troops = load_data("Data/Troops.rxdata")
$data_states = load_data("Data/States.rxdata")
$data_animations = load_data("Data/Animations.rxdata")
$data_tilesets = load_data("Data/Tilesets.rxdata")
$data_common_events = load_data("Data/CommonEvents.rxdata")
$data_system = load_data("Data/System.rxdata")
# Make system object
$game_system = Game_System.new
# Make title graphic
@sprite = Sprite.new
@sprite.bitmap = RPG::Cache.title($data_system.title_name)
# Make command window
s1 = "Nuevo"
s2 = "Cargar"
s3 = "Salir"
@command_window = Window_Command.new(192, [s1, s2, s3])
@command_window.back_opacity = 160
@command_window.x = 320 - @command_window.width / 2
@command_window.y = 288
# Continue enabled determinant
# Check if at least one save file exists
# If enabled, make @continue_enabled true; if disabled, make it false
@continue_enabled = false
for i in 0..3
if FileTest.exist?("Save#{i+1}.rxdata")
@continue_enabled = true
end
end
# If continue is enabled, move cursor to "Continue"
# If disabled, display "Continue" text in gray
if @continue_enabled
@command_window.index = 1
else
@command_window.disable_item(1)
end
# Play title BGM
$game_system.bgm_play($data_system.title_bgm)
# Stop playing ME and BGS
Audio.me_stop
Audio.bgs_stop
# Execute transition
Graphics.transition
# Main loop
loop do
# Update game screen
Graphics.update
# Update input information
Input.update
# Frame update
update
# Abort loop if screen is changed
if $scene != self
break
end
end
# Prepare for transition
Graphics.freeze
# Dispose of command window
@command_window.dispose
# Dispose of title graphic
@sprite.bitmap.dispose
@sprite.dispose
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
# Update command window
@command_window.update
# If C button was pressed
if Input.trigger?(Input::C)
# Branch by command window cursor position
case @command_window.index
when 0 # New game
command_new_game
when 1 # Continue
command_continue
when 2 # Shutdown
command_shutdown
end
end
end
#--------------------------------------------------------------------------
# * Command: New Game
#--------------------------------------------------------------------------
def command_new_game
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Stop BGM
Audio.bgm_stop
# Reset frame count for measuring play time
Graphics.frame_count = 0
# Make each type of game object
$game_temp = Game_Temp.new
$game_system = Game_System.new
$game_switches = Game_Switches.new
$game_variables = Game_Variables.new
$game_self_switches = Game_SelfSwitches.new
$game_screen = Game_Screen.new
$game_actors = Game_Actors.new
$game_party = Game_Party.new
$game_troop = Game_Troop.new
$game_map = Game_Map.new
$game_player = Game_Player.new
# Set up initial party
$game_party.setup_starting_members
# Set up initial map position
$game_map.setup($data_system.start_map_id)
# Move player to initial position
$game_player.moveto($data_system.start_x, $data_system.start_y)
# Refresh player
$game_player.refresh
# Run automatic change for BGM and BGS set with map
$game_map.autoplay
# Update map (run parallel process event)
$game_map.update
# Initialize Network
$network = Network.new
$network.connect_and_start
# Switch to map screen
$scene = Scene_Map.new
end
#--------------------------------------------------------------------------
# * Command: Continue
#--------------------------------------------------------------------------
def command_continue
# If continue is disabled
unless @continue_enabled
# Play buzzer SE
$game_system.se_play($data_system.buzzer_se)
return
end
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Switch to load screen
$scene = Scene_Load.new
end
#--------------------------------------------------------------------------
# * Command: Shutdown
#--------------------------------------------------------------------------
def command_shutdown
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Fade out BGM, BGS, and ME
Audio.bgm_fade(800)
Audio.bgs_fade(800)
Audio.me_fade(800)
# Shutdown
$scene = nil
end
#--------------------------------------------------------------------------
# * Battle Test
#--------------------------------------------------------------------------
def battle_test
# Load database (for battle test)
$data_actors = load_data("Data/Actors.rxdata")
$data_classes = load_data("Data/Classes.rxdata")
$data_skills = load_data("Data/Skills.rxdata")
$data_items = load_data("Data/Items.rxdata")
$data_weapons = load_data("Data/Weapons.rxdata")
$data_armors = load_data("Data/Armors.rxdata")
$data_enemies = load_data("Data/Enemies.rxdata")
$data_troops = load_data("Data/Troops.rxdata")
$data_states = load_data("Data/States.rxdata")
$data_animations = load_data("Data/Animations.rxdata")
$data_tilesets = load_data("Data/Tilesets.rxdata")
$data_common_events = load_data("Data/CommonEvents.rxdata")
$data_system = load_data("Data/System.rxdata")
# Reset frame count for measuring play time
Graphics.frame_count = 0
# Make each game object
$game_temp = Game_Temp.new
$game_system = Game_System.new
$game_switches = Game_Switches.new
$game_variables = Game_Variables.new
$game_self_switches = Game_SelfSwitches.new
$game_screen = Game_Screen.new
$game_actors = Game_Actors.new
$game_party = Game_Party.new
$game_troop = Game_Troop.new
$game_map = Game_Map.new
$game_player = Game_Player.new
# Set up party for battle test
$game_party.setup_battle_test_members
# Set troop ID, can escape flag, and battleback
$game_temp.battle_troop_id = $data_system.test_troop_id
$game_temp.battle_can_escape = true
$game_map.battleback_name = $data_system.battleback_name
# Play battle start SE
$game_system.se_play($data_system.battle_start_se)
# Play battle BGM
$game_system.bgm_play($game_system.battle_bgm)
# Switch to battle screen
$scene = Scene_Battle.new
end
end
Scene_Map Class
Code:
#==============================================================================
# ** Scene_Map
#------------------------------------------------------------------------------
# This class performs map screen processing.
#==============================================================================
class Scene_Map
#--------------------------------------------------------------------------
# * Main Processing
#--------------------------------------------------------------------------
def main
# Make sprite set
@spriteset = Spriteset_Map.new
# Make message window
@message_window = Window_Message.new
# Chat Windows
@chat_window = Window_Chat.new
@chat_input_window = Window_ChatInput.new
# Transition run
Graphics.transition
# Main loop
loop do
# Update game screen
Graphics.update
# Update input information
Input.update
# Frame update
update
# Abort loop if screen is changed
if $scene != self
break
end
end
# Prepare for transition
Graphics.freeze
# Dispose of sprite set
@spriteset.dispose
# Dispose of message window
@message_window.dispose
# Dispose of chat windows
@chat_window.dispose
@chat_input_window.dispose
# If switching to title screen
if $scene.is_a?(Scene_Title)
# Fade out screen
Graphics.transition
Graphics.freeze
end
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
# Loop
loop do
# Update map, interpreter, and player order
# (this update order is important for when conditions are fulfilled
# to run any event, and the player isn't provided the opportunity to
# move in an instant)
$game_map.update
$game_system.map_interpreter.update
$game_player.update
# Update system (timer), screen
$game_system.update
$game_screen.update
# Update network
$network.update
if $network.client.connected == false
print "Disconnected from the server\nClosing..."
exit
end
# Update Chat
@chat_input_window.update if @chat_input_window.visible == true
@chat_window.update
# Abort loop if player isn't place moving
unless $game_temp.player_transferring
break
end
# Run place move
transfer_player
# Abort loop if transition processing
if $game_temp.transition_processing
break
end
end
# Update sprite set
@spriteset.update
# Update message window
@message_window.update
# If game over
if $game_temp.gameover
# Switch to game over screen
$scene = Scene_Gameover.new
return
end
# If returning to title screen
if $game_temp.to_title
# Change to title screen
$scene = Scene_Title.new
return
end
# If transition processing
if $game_temp.transition_processing
# Clear transition processing flag
$game_temp.transition_processing = false
# Execute transition
if $game_temp.transition_name == ""
Graphics.transition(20)
else
Graphics.transition(40, "Graphics/Transitions/" +
$game_temp.transition_name)
end
end
# If showing message window
if $game_temp.message_window_showing
return
end
# If encounter list isn't empty, and encounter count is 0
if $game_player.encounter_count == 0 and $game_map.encounter_list != []
# If event is running or encounter is not forbidden
unless $game_system.map_interpreter.running? or
$game_system.encounter_disabled
# Confirm troop
n = rand($game_map.encounter_list.size)
troop_id = $game_map.encounter_list[n]
# If troop is valid
if $data_troops[troop_id] != nil
# Set battle calling flag
$game_temp.battle_calling = true
$game_temp.battle_troop_id = troop_id
$game_temp.battle_can_escape = true
$game_temp.battle_can_lose = false
$game_temp.battle_proc = nil
end
end
end
# If F5 button was pressed
if Keyb.trigger($keys["F5"])
@chat_input_window.visible = true
end
# If B button was pressed
if Input.trigger?(Input::B) and @chat_input_window.visible == false
# If event is running, or menu is not forbidden
unless $game_system.map_interpreter.running? or
$game_system.menu_disabled
# Set menu calling flag or beep flag
$game_temp.menu_calling = true
$game_temp.menu_beep = true
end
end
# If debug mode is ON and F9 key was pressed
if $DEBUG and Input.press?(Input::F9)
# Set debug calling flag
$game_temp.debug_calling = true
end
# If player is not moving
unless $game_player.moving?
# Run calling of each screen
if $game_temp.battle_calling
call_battle
elsif $game_temp.shop_calling
call_shop
elsif $game_temp.name_calling
call_name
elsif $game_temp.menu_calling
call_menu
elsif $game_temp.save_calling
call_save
elsif $game_temp.debug_calling
call_debug
end
end
end
#--------------------------------------------------------------------------
# * Battle Call
#--------------------------------------------------------------------------
def call_battle
# Clear battle calling flag
$game_temp.battle_calling = false
# Clear menu calling flag
$game_temp.menu_calling = false
$game_temp.menu_beep = false
# Make encounter count
$game_player.make_encounter_count
# Memorize map BGM and stop BGM
$game_temp.map_bgm = $game_system.playing_bgm
$game_system.bgm_stop
# Play battle start SE
$game_system.se_play($data_system.battle_start_se)
# Play battle BGM
$game_system.bgm_play($game_system.battle_bgm)
# Straighten player position
$game_player.straighten
# Switch to battle screen
$scene = Scene_Battle.new
end
#--------------------------------------------------------------------------
# * Shop Call
#--------------------------------------------------------------------------
def call_shop
# Clear shop call flag
$game_temp.shop_calling = false
# Straighten player position
$game_player.straighten
# Switch to shop screen
$scene = Scene_Shop.new
end
#--------------------------------------------------------------------------
# * Name Input Call
#--------------------------------------------------------------------------
def call_name
# Clear name input call flag
$game_temp.name_calling = false
# Straighten player position
$game_player.straighten
# Switch to name input screen
$scene = Scene_Name.new
end
#--------------------------------------------------------------------------
# * Menu Call
#--------------------------------------------------------------------------
def call_menu
# Clear menu call flag
$game_temp.menu_calling = false
# If menu beep flag is set
if $game_temp.menu_beep
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Clear menu beep flag
$game_temp.menu_beep = false
end
# Straighten player position
$game_player.straighten
# Switch to menu screen
$scene = Scene_Menu.new
end
#--------------------------------------------------------------------------
# * Save Call
#--------------------------------------------------------------------------
def call_save
# Straighten player position
$game_player.straighten
# Switch to save screen
$scene = Scene_Save.new
end
#--------------------------------------------------------------------------
# * Debug Call
#--------------------------------------------------------------------------
def call_debug
# Clear debug call flag
$game_temp.debug_calling = false
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Straighten player position
$game_player.straighten
# Switch to debug screen
$scene = Scene_Debug.new
end
#--------------------------------------------------------------------------
# * Player Place Move
#--------------------------------------------------------------------------
def transfer_player
# Clear player place move call flag
$game_temp.player_transferring = false
# If move destination is different than current map
if $game_map.map_id != $game_temp.player_new_map_id
# Set up a new map
$game_map.setup($game_temp.player_new_map_id)
end
# Set up player position
$game_player.moveto($game_temp.player_new_x, $game_temp.player_new_y)
# Set player direction
case $game_temp.player_new_direction
when 2 # down
$game_player.turn_down
when 4 # left
$game_player.turn_left
when 6 # right
$game_player.turn_right
when 8 # up
$game_player.turn_up
end
# Straighten player position
$game_player.straighten
# Update map (run parallel process event)
$game_map.update
# Remake sprite set
@spriteset.dispose
@spriteset = Spriteset_Map.new
# If processing transition
if $game_temp.transition_processing
# Clear transition processing flag
$game_temp.transition_processing = false
# Execute transition
Graphics.transition(20)
end
# Update Player Information
$network.update_x
$network.update_y
$network.update_map_id
$network.update_direction
# Update network
$network.update
# Run automatic change for BGM and BGS set on the map
$game_map.autoplay
# Frame reset
Graphics.frame_reset
# Update input information
Input.update
end
end
Main
Code:
#==============================================================================
# ** Main
#------------------------------------------------------------------------------
# After defining each class, actual processing begins here.
#==============================================================================
begin
# Prepare for transition
Graphics.freeze
# Make scene object (title screen)
$scene = Scene_Title.new
# Call main method as long as $scene is effective
while $scene != nil
$scene.main
end
# Fade out
Graphics.transition(20)
rescue Errno::ENOENT
# Supplement Errno::ENOENT exception
# If unable to open file, display message and end
filename = $!.message.sub("No se encontó el archivo o directorio - ", "")
print("Error RGSS: #{filename}")
ensure
$network.client.disconnect($network.client.peers_list["server"]["peer"],
0,
1000)
end
____Extra Script____
Server Example:
Code:
#==============================================================================
# ** RubyENet Server
#------------------------------------------------------------------------------
# Server for the RubyENet Template
#
# Basic demostration of RubyENet game integration
# Tested with ruby 1.8.6 and ruby 1.9.1
#
# To send additional data just add a new packet type and its logic
# This applies to login/register too, for example:
#
# - server accepts the connection
# - waits for the client to send its login
# - if not a valid login or timeout, close the connection
# - if valid login, receive and send id&data
#
# Check [url=http://enet.bespin.org/]http://enet.bespin.org/[/url] to understand the ENet protocol
#
#==============================================================================
class Server
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
@players = {}
@address = 0
@port = 8000
@channels = 3
@max_number_of_players = 32
end
#--------------------------------------------------------------------------
# Run the server
# Initialize the library
# Bind the server to an addres and port
# Generate and send an ID when a players connects
# Warn all the players when a player disconnects and delete it
# Parse packets when they arrive
# Loop forever giving service
#--------------------------------------------------------------------------
def run
print "------------------------------------------------------------------\r\n\n"
print " RubyENet Template Server\r\n"
print " Version 1.0\r\n"
print "------------------------------------------------------------------\r\n\n"
print "Initializing ENetlibrary\r\n\n"
if Enet.initialize != 0
print "Error initializing ENet\r\n"
print "Press a key to exit\r\n"
gets.chomp
exit
end
print "Server will run in:\r\n"
print " Address: localhost\r\n" if @address == 0
print " Address: #{@address}\r\n" if @address != 0
print " Port: #{@port}\r\n\n"
address = [@address, @port].pack("LS")
print "Binding server\r\n"
@server = Enet::ENetHost.new
if @server.create_host(address, @max_number_of_players, @channels, 0, 0) == true
print "Server created\n"
else
print "Error binding the server\r\n"
print "Press a key to exit\r\n"
gets.chomp
exit
end
@server.on_connection do
print "New user connected: #{Enet.get_peer_host(@server.event.peer)}\r\n"
id = 0
for i in 0...5
id += rand() % 256
end
@players[id.to_s] = { "peer" => @server.event.peer }
data = "100:#{id}"
@server.send_packet(@server.event.peer, data, data.size+1, 1)
print "ID #{id} sent to the new player\r\n"
end
@server.on_disconnect do
print "User disconnected: #{Enet.get_peer_host(@server.event.peer)}\r\n"
@players.each_key { |id|
if @players[id]["peer"] == @server.event.peer
data = "11:#{id}"
@server.broadcast_packet(data, data.size+1, 1)
@players.delete(id) if @players.has_key?(id)
end
}
end
@server.on_packet_receive do
parse_packet
@server.event.destroy_packet
end
print "Server service started\r\n\n"
begin
loop do
@server.service
end
rescue
print "Deinitializing ENet library\r\n!"
Enet.deinitialize
print "Closing server\r\n"
print "Press a key to exit\r\n"
gets.chomp
exit
end
end
#--------------------------------------------------------------------------
# * Resend Data
# Sends throught the channel specified to all the players except
# to the player who sent the data
#--------------------------------------------------------------------------
def resend_data(channel_id)
@players.each_key { |id|
if @players[id]["peer"] != @server.event.peer
@server.send_packet( @players[id]["peer"], @server.event.packet.data, @server.event.packet.data_length, channel_id)
end
}
end
#--------------------------------------------------------------------------
# * Initial Data
# Generates the data of a player to send it when a new player arrives
#--------------------------------------------------------------------------
def initial_data(id)
data = ""
data += "0:"
data += id.to_s
data += ";"
data += @players[id]["name"]
data += ";"
data += @players[id]["level"]
data += ";"
data += @players[id]["class_name"]
data += ";"
data += @players[id]["map_id"]
data += ";"
data += @players[id]["x"]
data += ";"
data += @players[id]["y"]
data += ";"
data += @players[id]["direction"]
data += ";"
data += @players[id]["character_name"]
data += ";"
data += @players[id]["character_hue"]
data += ";"
data += @players[id]["opacity"]
data += ";"
data += @players[id]["move_speed"]
return data
end
#--------------------------------------------------------------------------
# * Parse Packet
# Parse the received packets and usually resend them to the rest
# of players
# This method is similar to the clients parse_data
# Check it if you have problems understanding this
#--------------------------------------------------------------------------
def parse_packet
data = @server.event.packet.data.to_s
print "Packet Arrived: "
print data +"\r\n"
if data.match(/^([0-9]*):(.*)$/)
@part1 = $1
@part2 = $2
values = @part2.split(";") if @part2.match(";")
case @part1.to_i
when 0 # Initial data
values[0] = values[0].to_s
if @players[values[0]] != nil
print "New player data. Creating information\n"
@players[values[0]]["name"] = values[1]
@players[values[0]]["level"] = values[2]
@players[values[0]]["class_name"] = values[3]
@players[values[0]]["map_id"] = values[4]
@players[values[0]]["x"] = values[5]
@players[values[0]]["y"] = values[6]
@players[values[0]]["direction"] = values[7]
@players[values[0]]["character_name"] = values[8]
@players[values[0]]["character_hue"] = values[9]
@players[values[0]]["opacity"] = values[10]
@players[values[0]]["move_speed"] = values[11]
@players.each_key { |id|
if @players[id]["peer"] != @server.event.peer
data = initial_data(id)
@server.send_packet(@server.event.peer, data, data.size+1, 1)
end
}
@server.send_packet(@server.event.peer, "101:ok", 7, 1)
print "Initial state finished, sent ACK\r\n"
resend_data(1)
print "Sent new player data to all the players\r\n"
end
when 1 # x / y
return if @players[values[0]] == nil
@players[values[0]]["x"] = values[1]
@players[values[0]]["y"] = values[2]
resend_data(0)
when 2 # map_id
return if @players[values[0]] == nil
@players[values[0]]["map_id"] = values[1]
resend_data(0)
when 3 # direction
return if @players[values[0]] == nil
@players[values[0]]["direction"] = values[1]
resend_data(0)
when 4 # move_speed
return if @players[values[0]] == nil
@players[values[0]]["move_speed"] = values[1]
resend_data(0)
when 5 # character_name
return if @players[values[0]] == nil
@players[values[0]]["character_name"] = values[1]
resend_data(0)
when 6 # character_hue
return if @players[values[0]] == nil
@players[values[0]]["character_hue"] = values[1]
resend_data(0)
when 7 # opacity
return if @players[values[0]] == nil
@players[values[0]]["opacity"] = values[1]
resend_data(0)
when 8 # level
return if @players[values[0]] == nil
@players[values[0]]["level"] = values[1]
resend_data(0)
when 9 # class_name
return if @players[values[0]] == nil
@players[values[0]]["class_name"] = values[1]
resend_data(0)
when 10 # name
return if @players[values[0]] == nil
@players[values[0]]["name"] = values[1]
resend_data(0)
when 11 # disconnection
@server.on_disconnect
when 200
resend_data(0)
when 201
resend_data(0)
when 202
resend_data(2)
end
end
end
end
Servers can be done in C/C++, this can give a huge boost to your games
performance, also Server that doesnt display information (puts/print)
works faster.
This template connects to the server in Scene_Title when New Game is
selected.
The network is only updated in Scene_Map, if you are in another scene
the connection will be lost after 10 seconds or so. Update the network
in all the scenes you need.
The Chat input uses Hounds Keyboard Module,it uses this module because
it doesnt need external dlls, but its performance is pretty bad. Dont
think Chat is broken if you need to press the keys twice. It should be
rewritten using vgvgfs AInput module to get a perfect performance.
The RGSS Player stops updating the game when it doesnt have focus,
this is not a problem with TCP, where the stream just sleeps but ENet
uses UDP (which is a lot faster) and datagrams doesnt sleep. If the
game lose focus the connection will be lost after 10 seconds or so,
because the client isnt answering server petitions.
Workarounds:
- Use Win32API calls so the game has always the focus
- Make the game fullscreen so the player wont lose focus
- Hack the player so it updates without focus too
To fully understand how ENet works visit http://enet.bespin.org/
Comments, questions, petitions, fixes, etc are welcome.