Advertisement
Guest User

Untitled

a guest
Apr 3rd, 2016
233
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 238.15 KB | None | 0 0
  1. #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
  2. # RPG Maker VX Ace Online System (RMX-OS)
  3. #------------------------------------------------------------------------------
  4. # Author: Blizzard (original)
  5. # Ported to VX Ace by Mason Wheeler
  6. #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
  7. #
  8. # This work is protected by the following license:
  9. # #----------------------------------------------------------------------------
  10. # #
  11. # # Creative Commons - Attribution-NonCommercial-ShareAlike 3.0 Unported
  12. # # ( http://creativecommons.org/licenses/by-nc-sa/3.0/ )
  13. # #
  14. # # You are free:
  15. # #
  16. # # to Share - to copy, distribute and transmit the work
  17. # # to Remix - to adapt the work
  18. # #
  19. # # Under the following conditions:
  20. # #
  21. # # Attribution. You must attribute the work in the manner specified by the
  22. # # author or licensor (but not in any way that suggests that they endorse you
  23. # # or your use of the work).
  24. # #
  25. # # Noncommercial. You may not use this work for commercial purposes.
  26. # #
  27. # # Share alike. If you alter, transform, or build upon this work, you may
  28. # # distribute the resulting work only under the same or similar license to
  29. # # this one.
  30. # #
  31. # # - For any reuse or distribution, you must make clear to others the license
  32. # # terms of this work. The best way to do this is with a link to this web
  33. # # page.
  34. # #
  35. # # - Any of the above conditions can be waived if you get permission from the
  36. # # copyright holder.
  37. # #
  38. # # - Nothing in this license impairs or restricts the author's moral rights.
  39. # #
  40. # #----------------------------------------------------------------------------
  41. #
  42. #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
  43. #
  44. # Information:
  45. #
  46. # There is a documentation for this system. Read it in order to learn how to
  47. # use this system. A server also comes with this system.
  48. #
  49. #
  50. # If you find any bugs, please report them here:
  51. # http://forum.chaos-project.com
  52. #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
  53.  
  54. module SceneManager
  55. def self.first_scene_class
  56. return $BTEST ? Scene_Battle : Scene_Servers
  57. end
  58. end
  59.  
  60. #==============================================================================
  61. # module RMXOS
  62. #------------------------------------------------------------------------------
  63. # Main module for all RMX-OS classes and procedures.
  64. #==============================================================================
  65.  
  66. module RMXOS
  67.  
  68. # RMX-OS version, should be changed only when server was changed to ensure
  69. # compatibility between server and client.
  70. VERSION = 2.05
  71.  
  72. # these values MUST correspond with the values specified in the server
  73. GROUP_ADMIN = 10
  74. GROUP_2NDADMIN = 9
  75. GROUP_MOD = 8
  76. GROUP_PLAYER = 0
  77.  
  78. # special permission group command sets
  79. COMMANDS = {}
  80. COMMANDS[GROUP_ADMIN] = ['admin']
  81. COMMANDS[GROUP_2NDADMIN] = ['kickall', 'mod', 'revoke', 'pass', 'gpass',
  82. 'eval', 'geval', 'seval', 'sql']
  83. COMMANDS[GROUP_MOD] = ['kick', 'ban', 'unban', 'global']
  84.  
  85. # login messages
  86. LOGIN_SUCCESS = 11
  87. LOGIN_NOUSER = 12
  88. LOGIN_NOPASS = 13
  89. LOGIN_BANNED = 14
  90. # register messages
  91. REGISTER_SUCCESS = 21
  92. REGISTER_EXIST = 22
  93. REGISTER_BANNED = 23
  94. # connection messages
  95. CONNECTION_SUCCESS = 31
  96. CONNECTION_DENIED = 32
  97. CONNECTION_CLIENT_VERSION = 33
  98. CONNECTION_GAME_VERSION = 34
  99. # loading messages
  100. LOADING_UPDATE = 41
  101. LOADING_END = 42
  102.  
  103. #============================================================================
  104. # module RMXOS::Data
  105. #----------------------------------------------------------------------------
  106. # Contains constants for all secondary configurable aspects in RMX-OS.
  107. #============================================================================
  108.  
  109. module Data
  110.  
  111. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  112. # Text constants
  113. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  114. AvailableCommands = 'Available Commands:'
  115. Banned = 'You are banned from this server.'
  116. BuddyAlreadyInList = 'Player already in buddy list.'
  117. BuddyNotInList = 'Player not in buddy list.'
  118. BuddySelfError = 'You cannot add yourself to your buddy list.'
  119. Cancel = 'Cancel'
  120. CancelingTradeAbort = 'Canceling... Press CANCEL again to abort trade.'
  121. Connecting = 'Connecting...'
  122. Disconnected = 'You have been disconnected.'
  123. EnterUserPass = 'Enter username and password.'
  124. ExecutingTrade = 'Executing trade...'
  125. Exit = 'Exit'
  126. HelpText = 'Use /help COMMAND for detailed explanations of a specific command.'
  127. GuildAlready = 'You are already in a guild.'
  128. GuildAlreadyLeader = 'You are already the guild leader.'
  129. GuildAlreadyMember = 'Player is already a member of your guild.'
  130. GuildCannotLeave = 'You are the guild leader. You cannot leave the guild unless you transfer leadership to another guild member first.'
  131. GuildNone = 'You are not in a guild.'
  132. GuildNotLeader = 'You are not the leader of your guild.'
  133. GuildNotMember = 'Player is not a member of your guild.'
  134. GuildNoTransfer = 'You have not been asked to take over leadership of your guild.'
  135. GuildReserved = 'You cannot use this name for a guild.'
  136. GuildTooLong = 'Guild name is too long.'
  137. Kicked = 'You have been kicked.'
  138. LoadingMessage = 'Loading...'
  139. LoggingIn = 'Logging in...'
  140. LoggedIn = 'Logged in.'
  141. Login = 'Login'
  142. LoginTimedOut = 'Login timed out.'
  143. NoResponse = 'Server did not respond.'
  144. NoPMsRetrieved = 'No PMs were retrieved.'
  145. NoUsername = 'Username does not exist.'
  146. OnlineTag = ' (ON)'
  147. PassChar = '*'
  148. PassTooShort = 'Password is too short.'
  149. PassNotRepeated = 'The confirmation password does not match!'
  150. Password = 'Password:'
  151. Register = 'Register'
  152. Registering = 'Registering...'
  153. RegisterUserPass = 'Register username and password.'
  154. Repeat = 'Repeat:'
  155. SelectServer = 'Select a server to connect to. Press F5 to refresh the list.'
  156. ServerOffline = 'Offline'
  157. ServerOnline = 'Online'
  158. ServerTesting = 'Testing...'
  159. Submit = 'Submit'
  160. TradeNoPlayer = 'Your trade partner is gone.'
  161. TradeSelfError = 'You cannot trade with yourself.'
  162. Username = 'Username:'
  163. UserRegistered = 'Username registered!'
  164. UserRegisteredAlready = 'Username already exists!'
  165. UserReserved = 'You cannot use this username.'
  166. UserTooShort = 'Username is too short.'
  167. Version = 'Version'
  168. WhisperNoLastName = 'You first have to use /w once before using /wr.'
  169. WrongPassword = 'Wrong password.'
  170. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  171. # Special constants
  172. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  173. BuddyList = 'Your buddies: BUDDIES'
  174. GuildInfo = 'Guild Name: GUILD; Leader: LEADER; Members: MEMBERS'
  175. PMTooLong = 'PM is COUNT characters too long.'
  176. PMInfo = 'ID:NUMBER by \'SENDER\' @ TIME'
  177. PMText = '\'SENDER\' @ TIME: MESSAGE'
  178. TradeWait = 'Waiting for \'PLAYER\'...'
  179. ReceivingMessage = 'Receiving data...'
  180. ReceivingMessageLegacy = 'Receiving: NOW / MAX'
  181. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  182. # Numeric constants
  183. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  184. CursorBlinkPeriod = 20
  185. ChatLogSize = 100
  186. ChatFontHeight = 16
  187. ChatLineEntries = 50
  188. ChatBubbleEntries = 8
  189. ChatBubbleMaxWidth = 192
  190. BubbleDisplayTime = 5
  191. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  192. # Array constants
  193. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  194. NoTradeItems = [23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
  195. TradeCommands = ['Select yours', 'View other', 'Confirm', 'Abort']
  196. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  197. # Chatbox color constants
  198. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  199. ColorAction = Color.new(0xBF, 0xFF, 0xBF)
  200. ColorError = Color.new(0xFF, 0xBF, 0x3F)
  201. ColorGlobal = Color.new(0x7F, 0xBF, 0xFF)
  202. ColorGuild = Color.new(0x1F, 0xFF, 0x7F)
  203. ColorInfo = Color.new(0xBF, 0xBF, 0xFF)
  204. ColorOk = Color.new(0x1F, 0xFF, 0x1F)
  205. ColorNo = Color.new(0x3F, 0x7F, 0xFF)
  206. ColorNormal = Color.new(0xFF, 0xFF, 0xFF)
  207. ColorServerError = Color.new(0xFF, 0xFF, 0x1F)
  208. ColorServerOffline = Color.new(0xFF, 0x1F, 0x1F)
  209. ColorServerOnline = Color.new(0x1F, 0xFF, 0x1F)
  210. ColorWhisper = Color.new(0xFF, 0xFF, 0x1F)
  211. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  212. # Other constants
  213. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  214. COLORS = {}
  215. COLORS['self'] = Color.new(0, 255, 0)
  216. COLORS[GROUP_ADMIN] = Color.new(64, 192, 255)
  217. COLORS[GROUP_2NDADMIN] = Color.new(128, 192, 255)
  218. COLORS[GROUP_MOD] = Color.new(255, 255, 0)
  219. COLORS[GROUP_PLAYER] = Color.new(255, 255, 255)
  220. COLORS['guild'] = Color.new(255, 192, 0)
  221.  
  222. end
  223.  
  224. #============================================================================
  225. # module RMXOS::Error
  226. #----------------------------------------------------------------------------
  227. # Contains constants and methods for RMX-OS specific errors.
  228. #============================================================================
  229.  
  230. module Error
  231.  
  232. # error message contants
  233. InvalidSyntax = 'Invalid Syntax!'
  234. # special error message contants
  235. Command = 'Error! Command \'CMD\' not used correctly. ' + RMXOS::Data::HelpText
  236. CommandPermission = 'Error! You do not have permission to use command \'CMD\'. Use /cmd for a list of available commands to you. ' + RMXOS::Data::HelpText
  237. CommandNotExist = 'Error! Command \'CMD\' does not exist. Use /cmd for a list of available commands to you. ' + RMXOS::Data::HelpText
  238. Save = 'Error! Saving for class CLASS undefined!'
  239. ServerFull = 'The server is full!'
  240. Version = 'Client outdated: VERSION'
  241. GameVersion = 'Game outdated: VERSION'
  242.  
  243. #--------------------------------------------------------------------------
  244. # Gets the client version error message.
  245. # Returns: Client version error message.
  246. #--------------------------------------------------------------------------
  247. def self.get_client_version_error
  248. return Version.sub('VERSION') {$network.version.to_s}
  249. end
  250. #--------------------------------------------------------------------------
  251. # Gets the game version error message.
  252. # Returns: Game version error message.
  253. #--------------------------------------------------------------------------
  254. def self.get_game_version_error
  255. return GameVersion.sub('VERSION') {$network.game_version.to_s}
  256. end
  257. #--------------------------------------------------------------------------
  258. # Gets the save error message.
  259. # object - any object that can't be saved
  260. # Returns: Save error message for the given class.
  261. #--------------------------------------------------------------------------
  262. def self.get_save_error(object)
  263. return Save.sub('CLASS') {object.class.name}
  264. end
  265. #--------------------------------------------------------------------------
  266. # Gets the chat command error message.
  267. # command - the used command
  268. # Returns: Command error message for the given command.
  269. #--------------------------------------------------------------------------
  270. def self.get_command_error(command)
  271. return Command.sub('CMD') {command}
  272. end
  273. #--------------------------------------------------------------------------
  274. # Gets the chat command error message.
  275. # command - the used command
  276. # Returns: Permission command error message for the given command.
  277. #--------------------------------------------------------------------------
  278. def self.get_permission_command_error(command)
  279. return CommandPermission.sub('CMD') {command}
  280. end
  281. #--------------------------------------------------------------------------
  282. # Gets the chat command error message.
  283. # command - the used command
  284. # Returns: No command error message for the given command.
  285. #--------------------------------------------------------------------------
  286. def self.get_no_command_error(command)
  287. return CommandNotExist.sub('CMD') {command}
  288. end
  289.  
  290. end
  291.  
  292. #============================================================================
  293. # module RMXOS::Documentation
  294. #----------------------------------------------------------------------------
  295. # Contains data for in-game information how to use RMX-OS. This should not
  296. # be edited but only extended in case of adding new functionality (i.e.
  297. # additional chat commands).
  298. #============================================================================
  299.  
  300. module Documentation
  301.  
  302. # permission group names
  303. GROUP_NAMES = {}
  304. GROUP_NAMES[GROUP_ADMIN] = 'Admin'
  305. GROUP_NAMES[GROUP_2NDADMIN] = 'Secondary Admin'
  306. GROUP_NAMES[GROUP_MOD] = 'Moderator'
  307.  
  308. PARAMETERS = {}
  309. # Admin commands
  310. PARAMETERS['admin'] = 'USERNAME'
  311. # Secondary Admin commands
  312. PARAMETERS['mod'] = 'USERNAME'
  313. PARAMETERS['revoke'] = 'USERNAME'
  314. PARAMETERS['kickall'] = 'none'
  315. PARAMETERS['pass'] = 'USERNAME NEWPASS'
  316. PARAMETERS['gpass'] = 'GUILDNAME NEWPASS'
  317. PARAMETERS['eval'] = 'SCRIPT'
  318. PARAMETERS['geval'] = 'SCRIPT'
  319. PARAMETERS['seval'] = 'SCRIPT'
  320. PARAMETERS['sql'] = 'SCRIPT'
  321. # Moderator commands
  322. PARAMETERS['kick'] = 'USERNAME'
  323. PARAMETERS['ban'] = 'USERNAME'
  324. PARAMETERS['unban'] = 'USERNAME'
  325. PARAMETERS['global'] = 'MESSAGE'
  326. # Normal commands
  327. PARAMETERS['w'] = 'USERNAME MESSAGE'
  328. PARAMETERS['wr'] = 'MESSAGE'
  329. PARAMETERS['me'] = 'MESSAGE'
  330. PARAMETERS['trade'] = 'USERNAME'
  331. PARAMETERS['newpass'] = 'OLDPASS NEWPASS'
  332. PARAMETERS['y'] = 'REQUEST_ID'
  333. PARAMETERS['n'] = 'REQUEST_ID'
  334. PARAMETERS['req'] = 'none'
  335. PARAMETERS['cancel'] = 'REQUEST_ID'
  336. PARAMETERS['cmd'] = 'none'
  337. PARAMETERS['help'] = 'none|COMMAND'
  338. # Buddy List commands
  339. PARAMETERS['badd'] = 'USERNAME'
  340. PARAMETERS['bremove'] = 'USERNAME'
  341. PARAMETERS['bshow'] = 'none'
  342. # PM commands#
  343. PARAMETERS['pmsend'] = 'USERNAME MESSAGE'
  344. PARAMETERS['pmunread'] = 'none'
  345. PARAMETERS['pmall'] = 'none'
  346. PARAMETERS['pmopen'] = 'MESSAGE_ID'
  347. PARAMETERS['pmdelete'] = 'MESSAGE_ID'
  348. PARAMETERS['pmdelall'] = 'none'
  349. PARAMETERS['pmstatus'] = 'none'
  350. # Guild commands
  351. PARAMETERS['gcreate'] = 'GUILDNAME PASSWORD'
  352. PARAMETERS['gnewpass'] = 'OLDGUILDPASS NEWGUILDPASS'
  353. PARAMETERS['gdisband'] = 'GUILDPASS'
  354. PARAMETERS['gtransfer'] = 'NEWLEADER GUILDPASS'
  355. PARAMETERS['ginvite'] = 'USERNAME'
  356. PARAMETERS['gremove'] = 'USERNAME GUILDPASS'
  357. PARAMETERS['gleave'] = 'PASSWORD'
  358. PARAMETERS['gmsg'] = 'MESSAGE'
  359. PARAMETERS['ginfo'] = 'none'
  360.  
  361. DESCRIPTIONS = {}
  362. # Admin commands
  363. DESCRIPTIONS['admin'] = 'Gives a player the permission group of a Secondary Admin.'
  364. # Secondary Admin commands
  365. DESCRIPTIONS['mod'] = 'Gives a player the permission group of a Moderator.'
  366. DESCRIPTIONS['revoke'] = 'Revokes all permissions from a player. This works only on players that have a lower permission group.'
  367. DESCRIPTIONS['kickall'] = 'Kicks all connected players with a lower permission group.'
  368. DESCRIPTIONS['pass'] = 'Changes the password of a player forcibly. This can be used to help players that have forgotten their password.'
  369. DESCRIPTIONS['gpass'] = 'Changes the password of a guild forcibly. This can be used to help players that have forgotten their guild\'s password.'
  370. DESCRIPTIONS['eval'] = 'Executes an RGSS script on your machine.'
  371. DESCRIPTIONS['geval'] = 'Executes an RGSS script on every connected player.'
  372. DESCRIPTIONS['seval'] = 'Executes an RGSS script on the server.'
  373. DESCRIPTIONS['sql'] = 'Executes an SQL command on the server.'
  374. # Moderator commands
  375. DESCRIPTIONS['kick'] = 'Kick a player. This works only on players that have a lower permission group.'
  376. DESCRIPTIONS['ban'] = 'Bans and kicks a player. This works only on players that have a lower permission group.'
  377. DESCRIPTIONS['unban'] = 'Unbans a player. This works only on players that have a lower permission group.'
  378. DESCRIPTIONS['global'] = 'Sends a global message to all currently connected players.'
  379. # Normal commands
  380. DESCRIPTIONS['w'] = 'Sends a whisper message to a player. Nobody else receives the message. The player does not have to be on the same map.'
  381. DESCRIPTIONS['wr'] = 'Sends a whisper message to the player lastly used with /w. See /w command for more information.'
  382. DESCRIPTIONS['me'] = 'Displays the message as action.'
  383. DESCRIPTIONS['trade'] = 'Sends a trade request to another player. Only one request can be sent at the time. Timeout for requests is 15 seconds.'
  384. DESCRIPTIONS['newpass'] = 'Changes your password.'
  385. DESCRIPTIONS['y'] = 'Answers YES to the action request with the given ID.'
  386. DESCRIPTIONS['n'] = 'Answers NO to the action request with the given ID.'
  387. DESCRIPTIONS['req'] = 'Displays a list of currently active action requests.'
  388. DESCRIPTIONS['cancel'] = 'Cancels the action request with the given ID. Works only requests that have been sent by you.'
  389. DESCRIPTIONS['cmd'] = 'Lists all available chat commands depending on your permission group.'
  390. DESCRIPTIONS['help'] = 'Explains a command. If no command is specified, it lists all available chat commands depending on your permission group.'
  391. # Buddy List commands
  392. DESCRIPTIONS['badd'] = 'Requests to adds a user for the Buddy List.'
  393. DESCRIPTIONS['bremove'] = 'Removes a player from the Buddy List and removes you from the other player\'s buddy list.'
  394. DESCRIPTIONS['bshow'] = 'Displays all players in your Buddy List. Their online status is also displayed.'
  395. # PM commands
  396. DESCRIPTIONS['pmsend'] = 'Sends a message to a player in the Buddy List.'
  397. DESCRIPTIONS['pmunread'] = 'Gets a list of all unread messages.'
  398. DESCRIPTIONS['pmall'] = 'Gets a list of all messages.'
  399. DESCRIPTIONS['pmopen'] = 'Displays a specific message and marks it as read.'
  400. DESCRIPTIONS['pmdelete'] = 'Deletes a specific message.'
  401. DESCRIPTIONS['pmdelall'] = 'Deletes all messages in the inbox.'
  402. DESCRIPTIONS['pmstatus'] = 'Gets the number of PMs and the number of maximum PMs allowed in the inbox.'
  403. # Guild commands
  404. DESCRIPTIONS['gcreate'] = 'Creates a new guild with you as leader.'
  405. DESCRIPTIONS['gnewpass'] = 'Changes the password of your guild.'
  406. DESCRIPTIONS['gdisband'] = 'Disbands your guild.'
  407. DESCRIPTIONS['gtransfer'] = 'Transfers leadership of your guild to another player. The other player must be a member of your guild.'
  408. DESCRIPTIONS['ginvite'] = 'Invites a player into your guild.'
  409. DESCRIPTIONS['gremove'] = 'Removes a player from your guild.'
  410. DESCRIPTIONS['gleave'] = 'Leaves the current guild.'
  411. DESCRIPTIONS['gmsg'] = 'Sends a message to all guild members that are currently online.'
  412. DESCRIPTIONS['ginfo'] = 'Displays information about your guild.'
  413.  
  414. # delete disabled commands
  415. RMXOS::Options::DISABLED_CHAT_COMMANDS.each {|command|
  416. PARAMETERS.delete(command)
  417. DESCRIPTIONS.delete(command)
  418. }
  419. #--------------------------------------------------------------------------
  420. # Gets the help text for a command.
  421. # command - the command
  422. # Returns: Help text for the given command.
  423. #--------------------------------------------------------------------------
  424. def self.get_command_help(command)
  425. # get all available commands
  426. commands = self.get_command_list
  427. # command is valid
  428. if commands.include?(command)
  429. message = "'/#{command}'"
  430. message += " Parameters: #{PARAMETERS[command]};"
  431. message += " Description: #{DESCRIPTIONS[command]}"
  432. # add permission requirement message if necessary
  433. COMMANDS.each_key {|key|
  434. if COMMANDS[key].include?(command)
  435. message += " Requires minimum #{GROUP_NAMES[key]} permission group."
  436. break
  437. end
  438. }
  439. return message
  440. # no permission to access this information
  441. elsif DESCRIPTIONS.has_key?(command)
  442. return "You do not have permission to access the command '#{command}'."
  443. end
  444. # command does not exist
  445. return "Command '#{command}' does not exist."
  446. end
  447. #--------------------------------------------------------------------------
  448. # Gets a list of all available commands.
  449. # Returns: List of all available commands.
  450. #--------------------------------------------------------------------------
  451. def self.get_command_list
  452. # get all commands
  453. commands = DESCRIPTIONS.keys.sort
  454. # remove all commands that require a higher permission group
  455. COMMANDS.each_key {|group|
  456. commands -= COMMANDS[group] if group > $network.usergroup
  457. }
  458. return commands
  459. end
  460.  
  461. end
  462.  
  463. #============================================================================
  464. # RMXOS::Result
  465. #----------------------------------------------------------------------------
  466. # Contains action result constants. It's a class only for consistency between
  467. # server and client and should not be used as a class on the client.
  468. #============================================================================
  469.  
  470. class Result
  471.  
  472. # these values MUST correspond with the values specified in the server
  473. SUCCESS = 0
  474. DENIED = 1
  475. SERVER_VERSION_MISMATCH = 3
  476. GAME_VERSION_MISMATCH = 4
  477.  
  478. PASSWORD_INCORRECT = 21
  479. ACCOUNT_ALREADY_EXIST = 22
  480.  
  481. PLAYER_NOT_EXIST = 31
  482.  
  483. end
  484.  
  485. #============================================================================
  486. # RMXOS::Server
  487. #----------------------------------------------------------------------------
  488. # Contains server connection data.
  489. #============================================================================
  490.  
  491. class Server
  492.  
  493. # setting all accessible variables
  494. attr_reader :name
  495. attr_reader :host
  496. attr_reader :port
  497. #--------------------------------------------------------------------------
  498. # Initialization
  499. # name - server display name
  500. # host - IP address or URL
  501. # port - port to connect to
  502. #--------------------------------------------------------------------------
  503. def initialize(name, host, port)
  504. @name = name
  505. @host = host
  506. @port = port
  507. end
  508.  
  509. end
  510.  
  511. #============================================================================
  512. # RMXOS::ChatMessage
  513. #----------------------------------------------------------------------------
  514. # Contains chat message data.
  515. #============================================================================
  516.  
  517. class ChatMessage
  518.  
  519. # setting all accessible variables
  520. attr_reader :text
  521. attr_reader :color
  522. #--------------------------------------------------------------------------
  523. # Initialization
  524. # text - chat message text
  525. # color - chat message color
  526. #--------------------------------------------------------------------------
  527. def initialize(text, color)
  528. @text = text
  529. @color = color
  530. end
  531.  
  532. end
  533.  
  534. #============================================================================
  535. # RMXOS::ChatBubbleMessage
  536. #----------------------------------------------------------------------------
  537. # Contains chat message data for chat bubbles.
  538. #============================================================================
  539.  
  540. class ChatBubbleMessage < ChatMessage
  541.  
  542. # setting all accessible variables
  543. attr_accessor :time
  544. #--------------------------------------------------------------------------
  545. # Initialization
  546. # text - chat message text
  547. # color - chat message color
  548. #--------------------------------------------------------------------------
  549. def initialize(text, color)
  550. super
  551. @time = RMXOS::Data::BubbleDisplayTime * Graphics.frame_rate
  552. end
  553. #--------------------------------------------------------------------------
  554. # Checks if the message display has expired.
  555. # Returns: True or False.
  556. #--------------------------------------------------------------------------
  557. def expired?
  558. return (@time <= 0)
  559. end
  560.  
  561. end
  562.  
  563. #============================================================================
  564. # module RMXOS::Options
  565. #============================================================================
  566.  
  567. module Options
  568.  
  569. SERVERS.each_index {|i|
  570. SERVERS[i] = Server.new(SERVERS[i][0], SERVERS[i][1], SERVERS[i][2])
  571. }
  572. RESERVED_USERNAMES.each {|name| name.downcase!}
  573.  
  574. end
  575.  
  576. #----------------------------------------------------------------------------
  577. # Creates a message for sending over the network to the server.
  578. # args - all arguments in an array
  579. # Returns: Message for sending over the network to the server.
  580. #----------------------------------------------------------------------------
  581. def self.make_message(*args)
  582. return args.map {|arg| arg = arg.to_s}.join("\t")
  583. end
  584. #----------------------------------------------------------------------------
  585. # Checks a username for reserved usernames.
  586. # username - the guild name that needs to be checked
  587. # Returns: Whether the username can be used or not.
  588. #----------------------------------------------------------------------------
  589. def self.reserved_username?(username)
  590. return self.string_match?(RMXOS::Options::RESERVED_USERNAMES, username)
  591. end
  592. #----------------------------------------------------------------------------
  593. # Checks a username for reserved guildnames.
  594. # guildname - the guild name that needs to be checked
  595. # Returns: Whether the guildname can be used or not.
  596. #----------------------------------------------------------------------------
  597. def self.reserved_guildname?(guildname)
  598. return self.string_match?(RMXOS::Options::RESERVED_GUILDNAMES, guildname)
  599. end
  600. #----------------------------------------------------------------------------
  601. # Checks a name against an array of strings.
  602. # strings - array of strings that are used for filtering
  603. # name - the name that needs to be checked.
  604. # Returns: Whether the name matches one of the other strings or not.
  605. #----------------------------------------------------------------------------
  606. def self.string_match?(strings, name)
  607. return strings.any? {|string| name.downcase.gsub!(string) {''} &&
  608. !name.downcase.gsub!(/([A-Za-z]+#{string})|(#{string}[A-Za-z]+)/i) {''}}
  609. end
  610. #----------------------------------------------------------------------------
  611. # Fixes strings for SQL queries and eval expressions.
  612. # string - string to be converted
  613. # Returns: Converted string.
  614. #----------------------------------------------------------------------------
  615. def self.fix_string(string)
  616. return string.gsub('\'') {'\\\''}
  617. end
  618. #----------------------------------------------------------------------------
  619. # Checks a chat message for being disabled.
  620. # message - the message to be checked
  621. # Returns: Whether this command is disabled or not.
  622. #----------------------------------------------------------------------------
  623. def self.chat_command_disabled?(message)
  624. if message =~ /\A\/(\S+)/
  625. return RMXOS::Options::DISABLED_CHAT_COMMANDS.include?($1)
  626. end
  627. return false
  628. end
  629. #----------------------------------------------------------------------------
  630. # Checks a chat message for usergroup permission.
  631. # message - the message to be checked
  632. # usergroup - usergroup
  633. # Returns: Whether this command can be used by this usergroup.
  634. #----------------------------------------------------------------------------
  635. def self.chat_command_permission?(message, usergroup)
  636. if message =~ /\A\/(\S+)/
  637. command = $1
  638. COMMANDS.each_key {|group|
  639. return (usergroup >= group) if COMMANDS[group].include?(command)
  640. }
  641. end
  642. return true
  643. end
  644.  
  645. end
  646.  
  647. #==============================================================================
  648. # module RMXOS
  649. #------------------------------------------------------------------------------
  650. # Main module for all RMX-OS classes and procedures.
  651. #==============================================================================
  652.  
  653. module RMXOS
  654.  
  655. #============================================================================
  656. # RMXOS::Network
  657. #----------------------------------------------------------------------------
  658. # This class handles network communication and basic processing of server
  659. # commands and messages.
  660. #============================================================================
  661.  
  662. class Network
  663.  
  664. # setting all accessible variables
  665. attr_reader :socket
  666. attr_reader :user_id
  667. attr_reader :username
  668. attr_reader :usergroup
  669. attr_reader :buddies
  670. attr_reader :guildname
  671. attr_reader :guildleader
  672. attr_reader :version
  673. attr_reader :game_version
  674. attr_reader :servername
  675. attr_reader :players
  676. attr_reader :map_players
  677. attr_reader :messages
  678. attr_reader :load_data
  679. attr_reader :load_size
  680. attr_reader :load_sizes
  681. attr_accessor :game_loaded
  682. #--------------------------------------------------------------------------
  683. # Initialization.
  684. #--------------------------------------------------------------------------
  685. def initialize
  686. # autosave timer
  687. @autosave_time = RMXOS::Options::AUTOSAVE_FREQUENCY * 40
  688. # ping timeout
  689. @ping_timeout = RMXOS::Options::PING_TIMEOUT * 40
  690. # reset general data
  691. self.reset
  692. end
  693. #--------------------------------------------------------------------------
  694. # Resets the network data.
  695. #--------------------------------------------------------------------------
  696. def reset
  697. # socket
  698. @socket = nil
  699. # database user ID
  700. @user_id = -1
  701. # database user name
  702. @username = ''
  703. # user group
  704. @usergroup = RMXOS::GROUP_PLAYER
  705. # currently logged in players
  706. @players = {}
  707. # players on the current map
  708. @map_players = {}
  709. # received messages in this frame
  710. @messages = []
  711. # saved game data loaded from the server
  712. @load_size = 0
  713. @load_sizes = []
  714. @load_data = {}
  715. # needed to prevent data corruption
  716. @game_loaded = false
  717. # buddy list
  718. @buddies = []
  719. # last whisper message username
  720. @last_whisper_name = ''
  721. # guild
  722. self.guild_reset
  723. end
  724. #--------------------------------------------------------------------------
  725. # Resets guild data.
  726. #--------------------------------------------------------------------------
  727. def guild_reset
  728. @guildname = ''
  729. @guildleader = ''
  730. @guildmembers = []
  731. end
  732. #--------------------------------------------------------------------------
  733. # Checks if this player is a admin.
  734. # Returns: Whether this player is an admin or not.
  735. #--------------------------------------------------------------------------
  736. def admin?
  737. return (@usergroup == RMXOS::GROUP_ADMIN ||
  738. @usergroup == RMXOS::GROUP_2NDADMIN)
  739. end
  740. #--------------------------------------------------------------------------
  741. # Checks if this player is a mod.
  742. # Returns: Whether this player is a mod or not.
  743. #--------------------------------------------------------------------------
  744. def mod?
  745. return (@usergroup == RMXOS::GROUP_MOD || self.admin?)
  746. end
  747. #--------------------------------------------------------------------------
  748. # Checks if this player is in a guild.
  749. # Returns: Whether this player is in a guild or not.
  750. #--------------------------------------------------------------------------
  751. def in_guild?
  752. return (@guildname != '')
  753. end
  754. #--------------------------------------------------------------------------
  755. # Checks if this player is the guild leader.
  756. # Returns: Whether this player is the guild leader or not.
  757. #--------------------------------------------------------------------------
  758. def guildleader?
  759. return (self.in_guild? && @guildleader == @username)
  760. end
  761. #--------------------------------------------------------------------------
  762. # Starts a connection.
  763. # host - IP address or URL (as string)
  764. # port - port for connection
  765. #--------------------------------------------------------------------------
  766. def start_connection(host, port)
  767. self.reset
  768. @socket = TCPSocket.new(host, port)
  769. end
  770. #--------------------------------------------------------------------------
  771. # Tests the connection capability to a host.
  772. # host - IP address or URL (as string)
  773. # port - port for connection
  774. # index - index for simultanous tests
  775. # Returns: Whether a connection could be astablished or not.
  776. #--------------------------------------------------------------------------
  777. def test_connection(host, port, index)
  778. begin
  779. # try to create a socket
  780. socket = TCPSocket.new(host, port)
  781. # try to send something
  782. socket.send("HAI\n")
  783. # try to close the socket
  784. socket.close
  785. # connection works
  786. return true
  787. rescue Hangup
  788. # cease further testing
  789. return nil
  790. rescue
  791. ensure
  792. # make sure socket is closed
  793. socket.close rescue nil
  794. end
  795. # connection failed
  796. return false
  797. end
  798. #--------------------------------------------------------------------------
  799. # Encapsulates the socket as connection between client and server for
  800. # message sending.
  801. # args - the message to be sent in form of arguments
  802. #--------------------------------------------------------------------------
  803. def send(*args)
  804. if self.connected?
  805. message = RMXOS.make_message(*args)
  806. @socket.send(message + "\n")
  807. end
  808. end
  809. #--------------------------------------------------------------------------
  810. # Disconnects this client from the server.
  811. #--------------------------------------------------------------------------
  812. def disconnect
  813. # if a connection actually exists
  814. if self.connected?
  815. # save the game first if saving is not disabled
  816. self.save if !$game_map.interpreter.running?
  817. # send disconnection message
  818. self.send('DCT')
  819. end
  820. # delete connection and reset data
  821. self.reset
  822. end
  823. #--------------------------------------------------------------------------
  824. # Disconnects this client from the server forcefully.
  825. #--------------------------------------------------------------------------
  826. def force_disconnect
  827. # delete connection and reset data
  828. self.reset
  829. end
  830. #--------------------------------------------------------------------------
  831. # Checks if an connection actually exists.
  832. # Returns: Whether this client is connected to a server or not.
  833. #--------------------------------------------------------------------------
  834. def connected?
  835. return (@socket != nil)
  836. end
  837. #--------------------------------------------------------------------------
  838. # Removes all players on the current map.
  839. #--------------------------------------------------------------------------
  840. def clear_map_players
  841. @map_players = {}
  842. end
  843. #--------------------------------------------------------------------------
  844. # Handles a player's server entry.
  845. # id - user ID of the player
  846. #--------------------------------------------------------------------------
  847. def player_entry(id)
  848. # create a new character for him if player just connected
  849. @players[id] = Game_OnlineCharacter.new if !@players.has_key?(id)
  850. end
  851. #--------------------------------------------------------------------------
  852. # Deletes a disconnected player.
  853. # id - user ID of the player that has disconnected
  854. #--------------------------------------------------------------------------
  855. def player_disconnect(id)
  856. # removes the player from the map
  857. @map_players.delete(id) if @map_players.has_key?(id)
  858. # deletes the player
  859. @players.delete(id) if @players.has_key?(id)
  860. end
  861. #--------------------------------------------------------------------------
  862. # Handles a player's map entry.
  863. # id - user ID of the player
  864. # map_id - map ID of the player
  865. #--------------------------------------------------------------------------
  866. def map_player_entry(id, map_id)
  867. # assign map ID
  868. @players[id].map_id = map_id
  869. # if player on the same map
  870. if @players[id].map_id == $game_map.map_id && !@map_players.has_key?(id)
  871. # assign the player to a map player
  872. @map_players[id] = @players[id]
  873. end
  874. end
  875. #--------------------------------------------------------------------------
  876. # Handles a player's map exit.
  877. # id - user ID of the player
  878. #--------------------------------------------------------------------------
  879. def map_player_exit(id)
  880. # reset map ID
  881. @players[id].map_id = 0
  882. # remove player from the map if still regarded as player on the map
  883. @map_players.delete(id) if @map_players.has_key?(id)
  884. end
  885. #--------------------------------------------------------------------------
  886. # Updates all players on the map.
  887. #--------------------------------------------------------------------------
  888. def update_map_players
  889. @map_players.each_value {|player| player.update}
  890. end
  891. #--------------------------------------------------------------------------
  892. # Saves the game automatically after a specifc amount of time.
  893. #--------------------------------------------------------------------------
  894. def update_autosave
  895. # decrease timer
  896. @autosave_time -= 1
  897. # abort if event is running
  898. return if $game_map.interpreter.running?
  899. # if timer expired
  900. if @autosave_time < 0
  901. # save all data
  902. self.save
  903. # reset timer
  904. @autosave_time = RMXOS::Options::AUTOSAVE_FREQUENCY * 40
  905. end
  906. end
  907. #--------------------------------------------------------------------------
  908. # Listens for incoming server messages.
  909. #--------------------------------------------------------------------------
  910. def listen
  911. @messages.clear
  912. # stop if socket is not ready
  913. return if !self.connected? || !@socket.ready?
  914. # get 0xFFFF bytes from a received message
  915. buffer = @socket.recv(0xFFFF)
  916. # split by \n without suppressing trailing empty strings
  917. buffer = buffer.split("\n", -1)
  918. # if chunk from previous incomplete message exists
  919. if @previous_chunk != nil
  920. # complete chunk with first new message
  921. buffer[0] = @previous_chunk + buffer[0]
  922. # delete chunk buffer
  923. @previous_chunk = nil
  924. end
  925. # remove last message in buffer
  926. last_chunk = buffer.pop
  927. # incomplete message if it exists (meaning last message has no \n)
  928. @previous_chunk = last_chunk if last_chunk != ''
  929. # check each message in the buffer
  930. buffer.each {|message|
  931. next if self.check_game(message)
  932. next if self.check_communication(message)
  933. next if self.check_connection(message)
  934. next if self.check_loading(message)
  935. }
  936. end
  937. #--------------------------------------------------------------------------
  938. # Checks general game messages.
  939. # message - the received message
  940. # Returns: True or false whether to stop checking this message.
  941. #--------------------------------------------------------------------------
  942. def check_game(message)
  943. case message
  944. when /\ACHT\t(.{6})\t(.+)\t(.+)/ # chat message
  945. # color encoded in hex
  946. c = [$1[0, 2].hex, $1[2, 2].hex, $1[4, 2].hex]
  947. self.add_message(eval($2), $3, Color.new(c[0], c[1], c[2]))
  948. return true
  949. when /\ACHA\t(.{6})\t(.+)\t(.+)/ # chat message
  950. # color encoded in hex
  951. c = [$1[0, 2].hex, $1[2, 2].hex, $1[4, 2].hex]
  952. self.add_message(eval($2), $3, Color.new(c[0], c[1], c[2]), true)
  953. return true
  954. when /\ADCS\Z/ # disconnected
  955. # disconnect
  956. $network.force_disconnect
  957. # show message
  958. p RMXOS::Data::Disconnected
  959. # return to server selection
  960. SceneManager.goto Scene_Servers
  961. return true
  962. when /\ADCL\Z/ # disconnected due to login timeout
  963. # disconnect
  964. $network.force_disconnect
  965. # show message
  966. p RMXOS::Data::LoginTimedOut
  967. # return to server selection
  968. SceneManager.goto Scene_Servers
  969. return true
  970. when /\ADCT\t(.+)/ # disconnection message for another player
  971. id = $1.to_i
  972. self.player_disconnect(id)
  973. $game_temp.trade_abort = true if id == $game_temp.trade_id
  974. return true
  975. when /\AENT\t(.+)\t(.+)\t(.+)\t(.+)/ # server entry message
  976. # get all necessary data from the message
  977. id = $1.to_i
  978. name = $2
  979. group = $3.to_i
  980. guild = eval($4)
  981. # handle player's server entry
  982. self.player_entry(id)
  983. # handle player's map data
  984. @players[id].set_user_data(id, name, group, guild)
  985. return true
  986. when /\APLA\t(.+)\t(.+)\t(.+)\t(.+)/ # connected player data
  987. # get all necessary data from the message
  988. id = $1.to_i
  989. name = $2
  990. group = $3.to_i
  991. guild = eval($4)
  992. # handle player's server entry
  993. self.player_entry(id)
  994. # handle player's map data
  995. @players[id].set_user_data(id, name, group, guild)
  996. return true
  997. when /\AMEN\t(.+)\t(.+)\t(.+)\t(.+)\t(.+)\t(.+)/ # map entry message
  998. # get all necessary data from the message
  999. map_id = $1.to_i
  1000. id = $2.to_i
  1001. name = $3
  1002. group = $4.to_i
  1003. guild = eval($5)
  1004. variables = eval($6)
  1005. # handle player's map entry
  1006. self.map_player_entry(id, map_id)
  1007. # handle player's map data
  1008. @players[id].set_user_data(id, name, group, guild)
  1009. # update player
  1010. @players[id].evaluate(variables)
  1011. # update player's position
  1012. @players[id].moveto(@players[id].x, @players[id].y)
  1013. return true
  1014. when /\AMEF/ # map entry finished
  1015. $game_temp.entering_map = false
  1016. return true
  1017. when /\AMEX\t(.+)/ # map exit message
  1018. # get all necessary data from the message
  1019. id = $1.to_i
  1020. # handle player's map exit
  1021. self.map_player_exit(id)
  1022. return true
  1023. when /\AMEV\t(.+)\t(.+)\t(.+)\t(.+)\t(.+)/ # exchange variable message
  1024. # get all necessary data from the message
  1025. id = $1.to_i
  1026. name = $2
  1027. group = $3.to_i
  1028. guild = eval($4)
  1029. variables = eval($5)
  1030. # handle player's map data
  1031. @players[id].set_user_data(id, name, group, guild)
  1032. # update player
  1033. @players[id].evaluate(variables)
  1034. return true
  1035. when /\ATRS\t(.+)\t(.+)/ # trade start
  1036. $game_temp.trade_active = true
  1037. $game_temp.trade_host = ($1 != '0')
  1038. $game_temp.trade_id = $2.to_i
  1039. $game_temp.chat_active = false
  1040. return true
  1041. when /\ATCO\Z/ # trade confirm
  1042. $game_temp.trade_confirmed = true
  1043. return true
  1044. when /\ATCA\Z/ # trade complete abort
  1045. $game_temp.trade_abort = true
  1046. return true
  1047. when /\ATRI\t(.*)/ # trade item list (can be empty, hence "(.*)")
  1048. data = $1.gsub('>') {'=>'}
  1049. $game_temp.trade_items = eval("{#{data}}")
  1050. return true
  1051. when /\ATRC\Z/ # trade cancel
  1052. $game_temp.trade_canceled = true
  1053. return true
  1054. when /\ATCC\Z/ # trade cancel confirmation
  1055. $game_temp.trade_cancel_confirmed = true
  1056. return true
  1057. when /\ATRF\Z/ # trade finalization
  1058. $game_temp.trade_finalized = true
  1059. return true
  1060. when /\AEVA\t(.+)/ # script to evaluate from server
  1061. begin
  1062. eval($1)
  1063. rescue SyntaxError
  1064. rescue
  1065. end
  1066. return true
  1067. end
  1068. return false
  1069. end
  1070. #--------------------------------------------------------------------------
  1071. # Checks server-client communication messages.
  1072. # message - the received message
  1073. # Returns: True or false whether to stop checking this message.
  1074. #--------------------------------------------------------------------------
  1075. def check_communication(message)
  1076. case message
  1077. when /\ABAD\t(.+)/ # new buddy
  1078. @buddies = (@buddies + [$1]).sort
  1079. return true
  1080. when /\ABRE\t(.+)/ # removed buddy
  1081. @buddies.delete($1)
  1082. return true
  1083. when /\AGJO\t(.+)/ # a new member joined the guild
  1084. @guildmembers = (@guildmembers + [$1]).sort
  1085. return true
  1086. when /\AGRE\t(.+)/ # removing a member from the guild
  1087. @guildmembers.delete($1)
  1088. return true
  1089. when /\AGRM\Z/ # removal from guild
  1090. self.guild_reset
  1091. return true
  1092. when /\AGLE\t(.+)/ # new guild leader
  1093. @guildleader = $1
  1094. return true
  1095. when /\APMA\t(.+)/ # retrieved PMs
  1096. # evaluate received data
  1097. data = eval("[#{$1}]")
  1098. # get PM data
  1099. pms = self.decode_pm_data(data)
  1100. # display each PM
  1101. pms.each {|pm| self.add_info(pm)}
  1102. return true
  1103. when /\APMO\t(.+)\t(.+)\t(.+)/ # opened PM
  1104. sender, time, message = $1, $2, $3
  1105. # get time
  1106. time = time.split(',')
  1107. time = Time.mktime(time[0], time[1], time[2], time[3], time[4], time[5])
  1108. time += Time.now.utc_offset
  1109. # create display string
  1110. string = RMXOS::Data::PMText.sub('SENDER') {sender}
  1111. string.sub!('TIME') {time.strftime('%Y-%m-%d %H:%M:%S')}
  1112. string.sub!('MESSAGE') {message}
  1113. # display PM
  1114. self.add_chat(string)
  1115. return true
  1116. end
  1117. return false
  1118. end
  1119. #--------------------------------------------------------------------------
  1120. # Checks connection and account related messages.
  1121. # message - the received message
  1122. # Returns: True or false whether to stop checking this message.
  1123. #--------------------------------------------------------------------------
  1124. def check_connection(message)
  1125. case message
  1126. when /\AUID\t(.+)\t(.+)\t(.+)\t(.+)/ # user data
  1127. @user_id = $1.to_i
  1128. @username = $2
  1129. @usergroup = $3.to_i
  1130. @buddies = eval("[#{$4}]").compact.sort
  1131. return true
  1132. when /\AGIN\t(.+)\t(.+)\t(.+)/ # guild info
  1133. @guildname = $1
  1134. @guildleader = $2
  1135. @guildmembers = eval("[#{$3}]").compact.sort
  1136. return true
  1137. when /\ACON\t(.+)\t(.+)\t(.+)/ # received connection message
  1138. # pass message to game about connection try
  1139. case $1.to_i
  1140. when RMXOS::Result::SUCCESS then @messages.push(RMXOS::CONNECTION_SUCCESS)
  1141. when RMXOS::Result::DENIED then @messages.push(RMXOS::CONNECTION_DENIED)
  1142. when RMXOS::Result::SERVER_VERSION_MISMATCH then @messages.push(RMXOS::CONNECTION_CLIENT_VERSION)
  1143. when RMXOS::Result::GAME_VERSION_MISMATCH then @messages.push(RMXOS::CONNECTION_GAME_VERSION)
  1144. end
  1145. # server version
  1146. @version = $2.to_f
  1147. # game version
  1148. @game_version = $3.to_f
  1149. return true
  1150. when /\ALIN\t(.+)/ # login result
  1151. # pass message to game about login try
  1152. case $1.to_i
  1153. when RMXOS::Result::SUCCESS then @messages.push(RMXOS::LOGIN_SUCCESS)
  1154. when RMXOS::Result::DENIED then @messages.push(RMXOS::LOGIN_BANNED)
  1155. when RMXOS::Result::PLAYER_NOT_EXIST then @messages.push(RMXOS::LOGIN_NOUSER)
  1156. when RMXOS::Result::PASSWORD_INCORRECT then @messages.push(RMXOS::LOGIN_NOPASS)
  1157. end
  1158. return true
  1159. when /\AREG\t(.+)/ # register result
  1160. # pass message to game about register try
  1161. case $1.to_i
  1162. when RMXOS::Result::SUCCESS then @messages.push(RMXOS::REGISTER_SUCCESS)
  1163. when RMXOS::Result::DENIED then @messages.push(RMXOS::REGISTER_BANNED)
  1164. when RMXOS::Result::ACCOUNT_ALREADY_EXIST then @messages.push(RMXOS::REGISTER_EXIST)
  1165. end
  1166. return true
  1167. when /\AKCK\Z/ # kicked
  1168. # disconnect
  1169. $network.force_disconnect
  1170. # show message
  1171. p RMXOS::Data::Kicked
  1172. # return to server selection
  1173. SceneManager.goto Scene_Servers
  1174. return true
  1175. end
  1176. return false
  1177. end
  1178. #--------------------------------------------------------------------------
  1179. # Checks messages related to loading of game data.
  1180. # message - the received message
  1181. # Returns: True or false whether to stop checking this message.
  1182. #--------------------------------------------------------------------------
  1183. def check_loading(message)
  1184. case message
  1185. when /\ALOA\t(.+)\t(.+)/ # game data message
  1186. # create data string entry
  1187. @load_data[$1] = $2
  1188. @load_sizes.push(@load_data.size)
  1189. @messages.push(RMXOS::LOADING_UPDATE)
  1190. return true
  1191. when /\ALOS\t(.+)/ # game data size
  1192. @load_size = $1.to_i
  1193. @load_sizes.push(0)
  1194. @messages.push(RMXOS::LOADING_UPDATE)
  1195. return true
  1196. when /\ALEN\Z/ # loading end
  1197. @load_sizes.push(@load_data.size)
  1198. self.load_game
  1199. # broadcasts server entry of new player
  1200. self.enter_server
  1201. # remove loading data
  1202. @load_data = {}
  1203. @messages.push(RMXOS::LOADING_END)
  1204. return true
  1205. end
  1206. return false
  1207. end
  1208. #--------------------------------------------------------------------------
  1209. # Adds a chat message to the queue to be drawn.
  1210. # data - raw data received from the server
  1211. # Returns: Array of PM data strings.
  1212. #--------------------------------------------------------------------------
  1213. def decode_pm_data(data)
  1214. # evaluate received data
  1215. pms = []
  1216. (0...(data.size / 8)).each {|i|
  1217. # split PM data
  1218. pm = data[i * 8, 8]
  1219. # get data fragments
  1220. message_id = pm.shift
  1221. sender = pm.shift
  1222. # get time
  1223. time = Time.mktime(pm[0], pm[1], pm[2], pm[3], pm[4], pm[5])
  1224. time += Time.now.utc_offset
  1225. # create display string
  1226. string = RMXOS::Data::PMInfo.sub('NUMBER') {message_id.to_s}
  1227. string.sub!('SENDER') {sender}
  1228. string.sub!('TIME') {time.strftime('%Y-%m-%d %H:%M:%S')}
  1229. # add string to final result
  1230. pms.push(string)}
  1231. return pms
  1232. end
  1233. #--------------------------------------------------------------------------
  1234. # Adds an error message to the queue to be drawn.
  1235. # message - the message to add
  1236. #--------------------------------------------------------------------------
  1237. def add_error(message)
  1238. self.add_message(nil, message, RMXOS::Data::ColorError)
  1239. end
  1240. #--------------------------------------------------------------------------
  1241. # Adds an info message to the queue to be drawn.
  1242. # message - the message to add
  1243. #--------------------------------------------------------------------------
  1244. def add_info(message)
  1245. self.add_message(0, message, RMXOS::Data::ColorInfo)
  1246. end
  1247. #--------------------------------------------------------------------------
  1248. # Adds an explicit chat message to the queue to be drawn.
  1249. # message - the message to add
  1250. #--------------------------------------------------------------------------
  1251. def add_chat(message)
  1252. self.add_message(nil, message, RMXOS::Data::ColorNormal)
  1253. end
  1254. #--------------------------------------------------------------------------
  1255. # Adds a chat message to the queue to be drawn.
  1256. # user_id - user ID of the sender
  1257. # message - the message to add
  1258. # color - message color
  1259. # action - action message flag
  1260. #--------------------------------------------------------------------------
  1261. def add_message(id, message, color, action = false)
  1262. # create a bitmap
  1263. bitmap = Bitmap.new(1, 1)
  1264. bitmap.font.size = RMXOS::Data::ChatFontHeight
  1265. # if not generic chat message
  1266. if id != nil
  1267. # if sent by a player
  1268. if id > 0
  1269. # message from this player
  1270. if @user_id == id
  1271. player = $game_player
  1272. username = @username
  1273. # message from other player
  1274. elsif @players.has_key?(id)
  1275. player = @players[id]
  1276. username = player.username
  1277. else
  1278. player = nil
  1279. username = nil
  1280. end
  1281. # if really sent by a player
  1282. if player != nil
  1283. # if chat bubbles active
  1284. if RMXOS::Options::CHAT_BUBBLES
  1285. # slice the text for chat bubbles
  1286. slices = bitmap.slice_text(action ? '* ' + message : message,
  1287. RMXOS::Data::ChatBubbleMaxWidth)
  1288. # add messages for bubble chat
  1289. player.add_chat_messages(slices, color)
  1290. end
  1291. # add username to message
  1292. if action
  1293. message = "* #{username} #{message}"
  1294. else
  1295. message = "#{username}: #{message}"
  1296. end
  1297. end
  1298. end
  1299. end
  1300. # slice the text if necessary
  1301. slices = bitmap.slice_text(message, RMXOS::Options::CHATBOX_WIDTH - 40)
  1302. bitmap.dispose
  1303. # add each text slice to chat display
  1304. slices.each {|slice| $game_temp.chat_messages.push(
  1305. RMXOS::ChatMessage.new(slice, color))
  1306. }
  1307. # if exceeding log size
  1308. if $game_temp.chat_messages.size > RMXOS::Data::ChatLineEntries
  1309. # remove a few messages from before
  1310. i = $game_temp.chat_messages.size
  1311. lines = RMXOS::Data::ChatLineEntries
  1312. $game_temp.chat_messages = $game_temp.chat_messages[i - lines, lines]
  1313. end
  1314. # chat box needs refreshing
  1315. $game_temp.chat_refresh = 0 if !$game_temp.chat_refresh
  1316. $game_temp.chat_refresh += slices.size
  1317. end
  1318. #--------------------------------------------------------------------------
  1319. # Requests a valid game connection from the server.
  1320. #--------------------------------------------------------------------------
  1321. def request_connection
  1322. self.send('CON', RMXOS::VERSION, RMXOS::Options::GAME_VERSION)
  1323. end
  1324. #--------------------------------------------------------------------------
  1325. # Requests a login. The server responds with whether the login has
  1326. # succeeded or failed.
  1327. # username - username of the player
  1328. # password - password of the player
  1329. #--------------------------------------------------------------------------
  1330. def try_login(username, password)
  1331. self.send('LIN', username, encrypt_password(password))
  1332. end
  1333. #--------------------------------------------------------------------------
  1334. # Requests the registering of an acocunt. The server responds with whether
  1335. # the login has succeeded or failed.
  1336. # username - username of the player
  1337. # password - password of the player
  1338. #--------------------------------------------------------------------------
  1339. def try_register(username, password)
  1340. self.send('REG', username, encrypt_password(password))
  1341. end
  1342. #--------------------------------------------------------------------------
  1343. # Broadcasts leaving of a map.
  1344. #--------------------------------------------------------------------------
  1345. def leave_map
  1346. self.send('MEX')
  1347. end
  1348. #--------------------------------------------------------------------------
  1349. # Broadcasts entering of a new map.
  1350. #--------------------------------------------------------------------------
  1351. def enter_map
  1352. mapid = $game_player.new_map_id
  1353. if mapid == 0
  1354. mapid = $game_map.map_id
  1355. end
  1356. self.send('MEN', mapid)
  1357. self.ping_server
  1358. end
  1359. #--------------------------------------------------------------------------
  1360. # Broadcasts entering of the server.
  1361. #--------------------------------------------------------------------------
  1362. def enter_server
  1363. self.send('ENT')
  1364. end
  1365. #--------------------------------------------------------------------------
  1366. # Waits for server to send all map data.
  1367. # Note: Do not call directly. This must go after an enter_map call.
  1368. #--------------------------------------------------------------------------
  1369. def wait_for_map_data
  1370. # set waiting flag
  1371. $game_temp.entering_map = true
  1372. # wait for server to reply
  1373. while $game_temp.entering_map
  1374. $network.update_server_ping
  1375. $network.listen
  1376. Graphics.update
  1377. end
  1378. end
  1379. #--------------------------------------------------------------------------
  1380. # Updates server ping timeout.
  1381. #--------------------------------------------------------------------------
  1382. def update_server_ping
  1383. @ping_timeout -= 1
  1384. self.ping_server if @ping_timeout <= 0
  1385. end
  1386. #--------------------------------------------------------------------------
  1387. # Pings the server (keep-alive).
  1388. #--------------------------------------------------------------------------
  1389. def ping_server
  1390. self.send('PNG')
  1391. @ping_timeout = RMXOS::Options::PING_TIMEOUT * 40
  1392. end
  1393. #--------------------------------------------------------------------------
  1394. # Sends a chatbox message.
  1395. # message - the message to be sent
  1396. # color - the message color
  1397. # prefix - message code with additional data
  1398. #--------------------------------------------------------------------------
  1399. def send_chat_message(message, color, prefix)
  1400. color = sprintf('%02X%02X%02X', color.red.to_i, color.green.to_i, color.blue.to_i)
  1401. self.send(prefix, color, @user_id, message)
  1402. end
  1403. #--------------------------------------------------------------------------
  1404. # Sends player exchange variables to the server.
  1405. # variables - player exchange variables
  1406. #--------------------------------------------------------------------------
  1407. def send_exchange_variables(variables = nil)
  1408. variables = $game_player.get_exchange_variables if variables == nil
  1409. self.send('MEV', variables.inspect)
  1410. end
  1411. #--------------------------------------------------------------------------
  1412. # Encrypts the password into an unsigned 32-bit hash value as string.
  1413. # password - original password
  1414. # Returns: Unsigned 32-bit hash of the given password as string.
  1415. #--------------------------------------------------------------------------
  1416. def encrypt_password(password)
  1417. # encrypting password
  1418. encrypted = password.crypt(RMXOS::Options::ENCRYPTION_SALT)
  1419. # removing first two characters which actually are the salt for safety
  1420. return encrypted[2, encrypted.size - 2]
  1421. end
  1422. #--------------------------------------------------------------------------
  1423. # Sends a trade confirmation message.
  1424. #--------------------------------------------------------------------------
  1425. def trade_confirm
  1426. self.send('TCO', $game_temp.trade_id)
  1427. end
  1428. #--------------------------------------------------------------------------
  1429. # Sends a message to abort the trade.
  1430. #--------------------------------------------------------------------------
  1431. def trade_abort
  1432. self.send('TCA', $game_temp.trade_id)
  1433. end
  1434. #--------------------------------------------------------------------------
  1435. # Sends a message with trade item data.
  1436. #--------------------------------------------------------------------------
  1437. def trade_send_items(items)
  1438. items = items.clone
  1439. items.keys.each {|key| items.delete(key) if items[key] == 0}
  1440. data = items.inspect.gsub(' '){''}.gsub('{'){''}.gsub('}'){''}.gsub('='){''}
  1441. self.send('TRI', $game_temp.trade_id, data)
  1442. end
  1443. #--------------------------------------------------------------------------
  1444. # Sends a trade cancelation message.
  1445. #--------------------------------------------------------------------------
  1446. def trade_cancel
  1447. self.send('TRC', $game_temp.trade_id)
  1448. end
  1449. #--------------------------------------------------------------------------
  1450. # Sends a trade cancel confirmation message.
  1451. #--------------------------------------------------------------------------
  1452. def trade_confirm_cancel
  1453. self.send('TCC', $game_temp.trade_id)
  1454. end
  1455. #--------------------------------------------------------------------------
  1456. # Sends a trade execution message.
  1457. #--------------------------------------------------------------------------
  1458. def trade_execute
  1459. self.send('TRX', $game_temp.trade_id)
  1460. end
  1461. #--------------------------------------------------------------------------
  1462. # Checks actions that require not to be in a guild.
  1463. # Returns: Whether the action can be executed or not.
  1464. #--------------------------------------------------------------------------
  1465. def check_no_guild_action
  1466. # if in a guild
  1467. if self.in_guild?
  1468. # show error message
  1469. self.add_error(RMXOS::Data::GuildAlready)
  1470. return false
  1471. end
  1472. return true
  1473. end
  1474. #--------------------------------------------------------------------------
  1475. # Checks actions that require to be in a guild.
  1476. # Returns: Whether the action can be executed or not.
  1477. #--------------------------------------------------------------------------
  1478. def check_guild_action
  1479. # if not in a guild
  1480. if !self.in_guild?
  1481. # show error message
  1482. self.add_error(RMXOS::Data::GuildNone)
  1483. return false
  1484. end
  1485. return true
  1486. end
  1487. #--------------------------------------------------------------------------
  1488. # Checks actions that require to be the guild leader.
  1489. # Returns: Whether the action can be executed or not.
  1490. #--------------------------------------------------------------------------
  1491. def check_guildleader_action
  1492. # if not guild leader
  1493. if !self.guildleader?
  1494. # show error message
  1495. self.add_error(RMXOS::Data::GuildNotLeader)
  1496. return false
  1497. end
  1498. return true
  1499. end
  1500. #--------------------------------------------------------------------------
  1501. # Checks a chat message for chat commands.
  1502. # message - the message to be checked
  1503. # Returns: Whether this message is a command or not.
  1504. #--------------------------------------------------------------------------
  1505. def check_chat_commands(message)
  1506. if !RMXOS.chat_command_disabled?(message) &&
  1507. RMXOS.chat_command_permission?(message, @usergroup)
  1508. return true if check_admin_commands(message)
  1509. return true if check_mod_commands(message)
  1510. return true if check_normal_commands(message)
  1511. return true if check_buddy_commands(message)
  1512. return true if check_pm_commands(message)
  1513. return true if check_guild_commands(message)
  1514. end
  1515. return true if check_command_error(message)
  1516. return false
  1517. end
  1518. #--------------------------------------------------------------------------
  1519. # Checks a chat message for admin commands.
  1520. # message - the message to be checked
  1521. # Returns: Whether this message is a command or not.
  1522. #--------------------------------------------------------------------------
  1523. def check_admin_commands(message)
  1524. case message
  1525. when /\A\/admin (\S+)\Z/ # giving secondary admin permission group
  1526. command_usergroup_change($1, RMXOS::GROUP_2NDADMIN)
  1527. return true
  1528. when /\A\/kickall\Z/ # kicking all players
  1529. command_kickall
  1530. return true
  1531. when /\A\/mod (\S+)\Z/ # giving mod permission group
  1532. command_usergroup_change($1, RMXOS::GROUP_MOD)
  1533. return true
  1534. when /\A\/revoke (\S+)\Z/ # revoking of all permission groups
  1535. command_usergroup_change($1, RMXOS::GROUP_PLAYER)
  1536. return true
  1537. when /\A\/pass (\S+) (\S+)\Z/ # forced user password change
  1538. command_forced_password_change($1, $2, 'APA')
  1539. return true
  1540. when /\A\/gpass (\S+) (\S+)\Z/ # forced guild password change
  1541. command_forced_password_change($1, $2, 'AGP')
  1542. return true
  1543. when /\A\/eval (\S{1}.*)/ # script evaluation on own machine
  1544. command_eval_script($1)
  1545. return true
  1546. when /\A\/geval (\S{1}.*)/ # script evaluation on every connected client
  1547. command_eval_script($1, true)
  1548. return true
  1549. when /\A\/seval (\S{1}.*)/ # script evaluation on server
  1550. command_server_script($1)
  1551. return true
  1552. when /\A\/sql (\S{1}.*)/ # SQL script evaluation on server
  1553. command_sql_script($1)
  1554. return true
  1555. end
  1556. return false
  1557. end
  1558. #--------------------------------------------------------------------------
  1559. # Checks a chat message for mod commands.
  1560. # message - the message to be checked
  1561. # Returns: Whether this message is a command or not.
  1562. #--------------------------------------------------------------------------
  1563. def check_mod_commands(message)
  1564. case message
  1565. when /\A\/kick (\S+)\Z/ # kick player
  1566. command_kick_player($1)
  1567. return true
  1568. when /\A\/ban (\S+)\Z/ # ban player
  1569. command_ban_player($1)
  1570. return true
  1571. when /\A\/unban (\S+)\Z/ # unban player
  1572. command_unban_player($1)
  1573. return true
  1574. when /\A\/global (\S{1}.*)/ # global message
  1575. command_global_chat($1)
  1576. return true
  1577. end
  1578. return false
  1579. end
  1580. #--------------------------------------------------------------------------
  1581. # Checks a chat message for normal commands.
  1582. # message - the message to be checked
  1583. # Returns: Whether this message is a command or not.
  1584. #--------------------------------------------------------------------------
  1585. def check_normal_commands(message)
  1586. case message
  1587. when /\A\/w (\S+) (\S{1}.*)/ # whisper chat
  1588. command_whisper_chat($2, $1)
  1589. return true
  1590. when /\A\/wr (\S{1}.*)/ # whisper chat
  1591. command_whisper_chat($1)
  1592. return true
  1593. when /\A\/me (\S{1}.*)/ # action chat
  1594. command_action_chat($1)
  1595. return true
  1596. when /\A\/trade (\S{1}.*)/ # trade request
  1597. command_trade_request($1)
  1598. return true
  1599. when /\A\/newpass (\S+) (\S+)\Z/ # password change
  1600. command_password_change($1, $2)
  1601. return true
  1602. when /\A\/y (\S+)\Z/ # answer YES to an action request
  1603. command_yes($1)
  1604. return true
  1605. when /\A\/n (\S+)\Z/ # answer NO to an action request
  1606. command_no($1)
  1607. return true
  1608. when /\A\/cancel (\S+)\Z/ # cancel action request
  1609. command_cancel($1)
  1610. return true
  1611. when /\A\/req\Z/ # display all action requests
  1612. command_req
  1613. return true
  1614. when /\A\/cmd\Z/, /\A\/help(\s*)\Z/ # listing of all commands
  1615. command_show_commands
  1616. return true
  1617. when /\A\/help (\S+)/ # display help for a command
  1618. command_help($1)
  1619. return true
  1620. end
  1621. return false
  1622. end
  1623. #--------------------------------------------------------------------------
  1624. # Checks a chat message for buddy list commands.
  1625. # message - the message to be checked
  1626. # Returns: Whether this message is a command or not.
  1627. #--------------------------------------------------------------------------
  1628. def check_buddy_commands(message)
  1629. case message
  1630. when /\A\/badd (\S+)\Z/ # adding a player to the buddy list
  1631. command_buddy_add($1)
  1632. return true
  1633. when /\A\/bremove (\S+)\Z/ # removing a player from the buddy list
  1634. command_buddy_remove($1)
  1635. return true
  1636. when /\A\/bshow\Z/ # displays the buddy list
  1637. command_buddy_show
  1638. return true
  1639. end
  1640. return false
  1641. end
  1642. #--------------------------------------------------------------------------
  1643. # Checks a chat message for normal commands.
  1644. # message - the message to be checked
  1645. # Returns: Whether this message is a command or not.
  1646. #--------------------------------------------------------------------------
  1647. def check_pm_commands(message)
  1648. case message
  1649. when /\A\/pmsend (\S+) (\S{1}.*)/ # sending a PM to a buddy
  1650. command_pm_send($1, $2)
  1651. return true
  1652. when /\A\/pmunread\Z/ # getting unread PMs
  1653. command_pm_get_unread
  1654. return true
  1655. when /\A\/pmall\Z/ # getting all PMs
  1656. command_pm_get_all
  1657. return true
  1658. when /\A\/pmopen (\d+)\Z/ # opening a PM
  1659. command_pm_open($1.to_i)
  1660. return true
  1661. when /\A\/pmdelete (\d+)\Z/ # deleting a PM
  1662. command_pm_delete($1.to_i)
  1663. return true
  1664. when /\A\/pmdelall\Z/ # deleting all PMs
  1665. command_pm_delete_all
  1666. return true
  1667. when /\A\/pmstatus\Z/ # inbox status
  1668. command_pm_status
  1669. return true
  1670. end
  1671. return false
  1672. end
  1673. #--------------------------------------------------------------------------
  1674. # Checks a chat message for normal commands.
  1675. # message - the message to be checked
  1676. # Returns: Whether this message is a command or not.
  1677. #--------------------------------------------------------------------------
  1678. def check_guild_commands(message)
  1679. case message
  1680. when /\A\/gcreate (\S+) (\S+)\Z/ # creating a guild
  1681. command_guild_create($1, $2)
  1682. return true
  1683. when /\A\/gnewpass (\S+) (\S+)\Z/ # changing the guild password
  1684. command_password_change($1, $2, 'GPS') if self.check_guildleader_action
  1685. return true
  1686. when /\A\/gdisband (\S+)\Z/ # disbanding the guild
  1687. command_guild_disband($1)
  1688. return true
  1689. when /\A\/gtransfer (\S+) (\S+)\Z/ # transferring leadership of guild
  1690. command_guild_transfer($1, $2)
  1691. return true
  1692. when /\A\/ginvite (\S+)\Z/ # inviting a player into the guild
  1693. command_guild_invite($1)
  1694. return true
  1695. when /\A\/gremove (\S+) (\S+)\Z/ # removing a player from the guild
  1696. command_guild_remove($1, $2)
  1697. return true
  1698. when /\A\/gleave (\S+)\Z/ # leaving the guild
  1699. command_guild_leave($1)
  1700. return true
  1701. when /\A\/gmsg (\S{1}.*)/ # message to all online guild members
  1702. command_guild_chat($1)
  1703. return true
  1704. when /\A\/ginfo\Z/ # guild information
  1705. command_guild_info
  1706. return true
  1707. end
  1708. return false
  1709. end
  1710. #--------------------------------------------------------------------------
  1711. # Checks a chat message for errorous commands.
  1712. # message - the message to be checked
  1713. # Returns: Whether this message is an invalid command or not.
  1714. #--------------------------------------------------------------------------
  1715. def check_command_error(message)
  1716. # if command usage
  1717. if message =~ /\A\/(\S+)/
  1718. used_command = $1
  1719. # get all commands
  1720. commands = RMXOS::Documentation.get_command_list
  1721. # get commands with no permission
  1722. other_commands = RMXOS::Documentation::DESCRIPTIONS.keys - commands
  1723. # check proper command syntax for available commands
  1724. commands.each {|command|
  1725. # command used wrongly
  1726. if message =~ /\A\/#{command}/
  1727. self.add_error(RMXOS::Error.get_command_error(command))
  1728. return true
  1729. end
  1730. }
  1731. # check for all commands without permission
  1732. other_commands.each {|command|
  1733. # no permission to use command
  1734. if message =~ /\A\/#{command}/
  1735. self.add_error(RMXOS::Error.get_permission_command_error(command))
  1736. return true
  1737. end
  1738. }
  1739. # command simply doesn't exist
  1740. self.add_error(RMXOS::Error.get_no_command_error(used_command))
  1741. return true
  1742. end
  1743. return false
  1744. end
  1745. #--------------------------------------------------------------------------
  1746. # Executes chat command for usergroup change.
  1747. # username - username of the player
  1748. # group - new usergroup
  1749. #--------------------------------------------------------------------------
  1750. def command_usergroup_change(username, group)
  1751. self.send('GRC', username, group)
  1752. end
  1753. #--------------------------------------------------------------------------
  1754. # Executes chat command for kicking all players.
  1755. #--------------------------------------------------------------------------
  1756. def command_kickall
  1757. self.send('AKA')
  1758. end
  1759. #--------------------------------------------------------------------------
  1760. # Executes chat command for forced password change.
  1761. # entity - name of the entity (player or guild)
  1762. # password - new password
  1763. # prefix - message prefix code
  1764. #--------------------------------------------------------------------------
  1765. def command_forced_password_change(entity, password, prefix)
  1766. self.send(prefix, entity, encrypt_password(password))
  1767. end
  1768. #--------------------------------------------------------------------------
  1769. # Executes chat command for executing a script.
  1770. # script - string containing Ruby script code
  1771. # global - execution on all connected clients.
  1772. #--------------------------------------------------------------------------
  1773. def command_eval_script(script, global = false)
  1774. begin
  1775. eval(script)
  1776. self.send('AEV', script) if global
  1777. rescue SyntaxError
  1778. self.add_error("#{RMXOS::Error::InvalidSyntax} #{script}")
  1779. rescue
  1780. self.add_error("#{$!.message} #{script}")
  1781. end
  1782. end
  1783. #--------------------------------------------------------------------------
  1784. # Executes chat command for executing a Ruby script on the server.
  1785. # script - string containing Ruby script code
  1786. #--------------------------------------------------------------------------
  1787. def command_server_script(script)
  1788. self.send('ASE', script)
  1789. end
  1790. #--------------------------------------------------------------------------
  1791. # Executes chat command for executing an SQL script on the server.
  1792. # script - string containing SQL script code
  1793. #--------------------------------------------------------------------------
  1794. def command_sql_script(script)
  1795. self.send('ASQ', script)
  1796. end
  1797. #--------------------------------------------------------------------------
  1798. # Executes chat command for kicking a player.
  1799. # username - username of the player
  1800. #--------------------------------------------------------------------------
  1801. def command_kick_player(username)
  1802. self.send('MKI', username)
  1803. end
  1804. #--------------------------------------------------------------------------
  1805. # Executes chat command for banning a player.
  1806. # username - username of the player
  1807. #--------------------------------------------------------------------------
  1808. def command_ban_player(username)
  1809. self.send('MBA', username)
  1810. end
  1811. #--------------------------------------------------------------------------
  1812. # Executes chat command for unbanning a player.
  1813. # username - username of the player
  1814. #--------------------------------------------------------------------------
  1815. def command_unban_player(username)
  1816. self.send('MUB', username)
  1817. end
  1818. #--------------------------------------------------------------------------
  1819. # Executes chat command for a normal chat message.
  1820. # message - the message to be sent
  1821. #--------------------------------------------------------------------------
  1822. def command_chat(message)
  1823. self.send_chat_message(message, RMXOS::Data::ColorNormal, 'CHT')
  1824. end
  1825. #--------------------------------------------------------------------------
  1826. # Executes chat command for a global chat message.
  1827. # message - the message to be sent
  1828. #--------------------------------------------------------------------------
  1829. def command_global_chat(message)
  1830. self.send_chat_message(message, RMXOS::Data::ColorGlobal, 'MGM')
  1831. end
  1832. #--------------------------------------------------------------------------
  1833. # Executes chat command for a whisper chat message.
  1834. # username - the target player for the message
  1835. # message - the message to be sent
  1836. #--------------------------------------------------------------------------
  1837. def command_whisper_chat(message, username = nil)
  1838. @last_whisper_name = username if username != nil
  1839. if @last_whisper_name != ''
  1840. self.send_chat_message(message, RMXOS::Data::ColorWhisper,
  1841. RMXOS.make_message('WCH', @last_whisper_name))
  1842. else
  1843. self.add_error(RMXOS::Data::WhisperNoLastName)
  1844. end
  1845. end
  1846. #--------------------------------------------------------------------------
  1847. # Executes chat command for a action chat message.
  1848. # message - the message to be sent
  1849. #--------------------------------------------------------------------------
  1850. def command_action_chat(message)
  1851. self.send_chat_message(message, RMXOS::Data::ColorAction, 'CHA')
  1852. end
  1853. #--------------------------------------------------------------------------
  1854. # Executes chat command for a guild chat message.
  1855. # message - the message to be sent
  1856. #--------------------------------------------------------------------------
  1857. def command_guild_chat(message)
  1858. if self.check_guild_action
  1859. self.send_chat_message(message, RMXOS::Data::ColorGuild, 'GME')
  1860. end
  1861. end
  1862. #--------------------------------------------------------------------------
  1863. # Executes chat command for trade request.
  1864. # username - the target player for the trade request
  1865. #--------------------------------------------------------------------------
  1866. def command_trade_request(username)
  1867. # if self
  1868. if @username == username
  1869. # show error message
  1870. self.add_error(RMXOS::Data::TradeSelfError)
  1871. else
  1872. # send request
  1873. self.send('TRQ', username)
  1874. end
  1875. end
  1876. #--------------------------------------------------------------------------
  1877. # Executes chat command for password change.
  1878. # old - old password
  1879. # new - new password
  1880. # prefix - message prefix code
  1881. #--------------------------------------------------------------------------
  1882. def command_password_change(old, new, prefix = 'NPS')
  1883. self.send(prefix, encrypt_password(old), encrypt_password(new))
  1884. end
  1885. #--------------------------------------------------------------------------
  1886. # Executes chat command for answering YES to an action request.
  1887. # request_id - the ID of the action request
  1888. #--------------------------------------------------------------------------
  1889. def command_yes(request_id)
  1890. self.send('YES', request_id)
  1891. end
  1892. #--------------------------------------------------------------------------
  1893. # Executes chat command for answering NO to an action request.
  1894. # request_id - the ID of the action request
  1895. #--------------------------------------------------------------------------
  1896. def command_no(request_id)
  1897. self.send('NOO', request_id)
  1898. end
  1899. #--------------------------------------------------------------------------
  1900. # Executes chat command for canceling an action request.
  1901. # request_id - the ID of the action request
  1902. #--------------------------------------------------------------------------
  1903. def command_cancel(request_id)
  1904. self.send('CAN', request_id)
  1905. end
  1906. #--------------------------------------------------------------------------
  1907. # Executes chat command for displaying all currently active action
  1908. # requests.
  1909. #--------------------------------------------------------------------------
  1910. def command_req
  1911. self.send('REQ')
  1912. end
  1913. #--------------------------------------------------------------------------
  1914. # Executes chat command for displaying all available commands.
  1915. #--------------------------------------------------------------------------
  1916. def command_show_commands
  1917. text = RMXOS::Data::HelpText + ' ' + RMXOS::Data::AvailableCommands
  1918. self.add_info(text + ' ' + RMXOS::Documentation.get_command_list.join(', '))
  1919. end
  1920. #--------------------------------------------------------------------------
  1921. # Executes chat command for displaying help text for a command.
  1922. # command - the command to be displayed
  1923. #--------------------------------------------------------------------------
  1924. def command_help(command)
  1925. self.add_info(RMXOS::Documentation.get_command_help(command))
  1926. end
  1927. #--------------------------------------------------------------------------
  1928. # Executes chat command for adding a player to the buddy list.
  1929. # username - username of the player
  1930. #--------------------------------------------------------------------------
  1931. def command_buddy_add(username)
  1932. # if already a buddy
  1933. if @buddies.include?(username)
  1934. # show error message
  1935. self.add_error(RMXOS::Data::BuddyAlreadyInList)
  1936. # if self
  1937. elsif @username == username
  1938. # show error message
  1939. self.add_error(RMXOS::Data::BuddySelfError)
  1940. else
  1941. # send request
  1942. self.send('BAD', username)
  1943. end
  1944. end
  1945. #--------------------------------------------------------------------------
  1946. # Executes chat command for removing a player from the buddy list.
  1947. # username - username of the player
  1948. #--------------------------------------------------------------------------
  1949. def command_buddy_remove(username)
  1950. # if not a buddy
  1951. if !@buddies.include?(username)
  1952. # show error message
  1953. self.add_error(RMXOS::Data::BuddyNotInList)
  1954. else
  1955. # send request
  1956. self.send('BRE', username)
  1957. end
  1958. end
  1959. #--------------------------------------------------------------------------
  1960. # Executes chat command for displaying the buddy list.
  1961. #--------------------------------------------------------------------------
  1962. def command_buddy_show
  1963. # show buddy list
  1964. if @buddies.size > 0
  1965. # add '(ON)' to buddies that are online right now
  1966. buddies = @buddies.map {|username|
  1967. if @players.any? {|key, value| value.username == username}
  1968. username += RMXOS::Data::OnlineTag
  1969. else
  1970. username = username
  1971. end
  1972. }
  1973. # create final display text
  1974. text = RMXOS::Data::BuddyList.sub('BUDDIES') {buddies.join(', ')}
  1975. else
  1976. # create display text, no buddies
  1977. text = RMXOS::Data::BuddyList.sub('BUDDIES') {'none'}
  1978. end
  1979. self.add_info(text)
  1980. end
  1981. #--------------------------------------------------------------------------
  1982. # Executes chat command for sending a PM.
  1983. # username - username of the player
  1984. # message - the message to be sent
  1985. #--------------------------------------------------------------------------
  1986. def command_pm_send(username, message)
  1987. # if not a buddy
  1988. if !@buddies.include?(username)
  1989. # show error message
  1990. self.add_error(RMXOS::Data::BuddyNotInList)
  1991. else
  1992. chars = message.scan(/./m)
  1993. # if PM is too long
  1994. if chars.size > RMXOS::Options::PM_MAX_LENGTH
  1995. # show error message
  1996. count = chars.size - RMXOS::Options::PM_MAX_LENGTH
  1997. error = RMXOS::Data::PMTooLong.sub('COUNT') {count}
  1998. self.add_error(error)
  1999. else
  2000. # send message
  2001. self.send('PMM', username, message)
  2002. end
  2003. end
  2004. end
  2005. #--------------------------------------------------------------------------
  2006. # Executes chat command for getting unread PMs.
  2007. #--------------------------------------------------------------------------
  2008. def command_pm_get_unread
  2009. self.send('PMU')
  2010. end
  2011. #--------------------------------------------------------------------------
  2012. # Executes chat command for getting all PMs.
  2013. #--------------------------------------------------------------------------
  2014. def command_pm_get_all
  2015. self.send('PMA')
  2016. end
  2017. #--------------------------------------------------------------------------
  2018. # Executes chat command for opening a PM.
  2019. # pm_id - ID of the PM
  2020. #--------------------------------------------------------------------------
  2021. def command_pm_open(pm_id)
  2022. self.send('PMO', pm_id)
  2023. end
  2024. #--------------------------------------------------------------------------
  2025. # Executes chat command for deleting a PM.
  2026. # pm_id - ID of the PM
  2027. #--------------------------------------------------------------------------
  2028. def command_pm_delete(pm_id)
  2029. self.send('PMD', pm_id)
  2030. end
  2031. #--------------------------------------------------------------------------
  2032. # Executes chat command for deleting all PMs.
  2033. #--------------------------------------------------------------------------
  2034. def command_pm_delete_all
  2035. self.send('PMC')
  2036. end
  2037. #--------------------------------------------------------------------------
  2038. # Executes chat command for getting the inbox status.
  2039. #--------------------------------------------------------------------------
  2040. def command_pm_status
  2041. self.send('PMS')
  2042. end
  2043. #--------------------------------------------------------------------------
  2044. # Executes chat command for creating a new guild.
  2045. # guildname - name of the new guild
  2046. # password - password of the new guild
  2047. #--------------------------------------------------------------------------
  2048. def command_guild_create(guildname, password)
  2049. # if allowed to execute action
  2050. if self.check_no_guild_action
  2051. # if guildname is reserved
  2052. if RMXOS.reserved_guildname?(guildname)
  2053. # show error message
  2054. self.add_error(RMXOS::Data::GuildReserved)
  2055. # if guildname is too long
  2056. elsif guildname.scan(/./m).size > RMXOS::Options::GUILDNAME_MAX_LENGTH
  2057. # show error message
  2058. self.add_error(RMXOS::Data::GuildTooLong)
  2059. else
  2060. # register the guild
  2061. self.send('GCR', guildname, encrypt_password(password))
  2062. end
  2063. end
  2064. end
  2065. #--------------------------------------------------------------------------
  2066. # Executes chat command for disbanding the guild.
  2067. # password - password of the guild
  2068. #--------------------------------------------------------------------------
  2069. def command_guild_disband(password)
  2070. # if allowed to execute action
  2071. if self.check_guildleader_action
  2072. # send password
  2073. self.send('GDI', encrypt_password(password))
  2074. end
  2075. end
  2076. #--------------------------------------------------------------------------
  2077. # Executes chat command for transferring guild leadership.
  2078. # username - username of the new guild leader
  2079. # password - password of the guild
  2080. #--------------------------------------------------------------------------
  2081. def command_guild_transfer(username, password)
  2082. # if allowed to execute action
  2083. if self.check_guildleader_action
  2084. # if username is self
  2085. if @username == username
  2086. # show error message
  2087. self.add_error(RMXOS::Data::GuildAlreadyLeader)
  2088. # if player is not a member of the guild
  2089. elsif !@guildmembers.include?(username)
  2090. # show error message
  2091. self.add_error(RMXOS::Data::GuildNotMember)
  2092. else
  2093. # send username and password
  2094. self.send('GTR', username, encrypt_password(password))
  2095. end
  2096. end
  2097. end
  2098. #--------------------------------------------------------------------------
  2099. # Executes chat command for inviting a new member into the guild.
  2100. # username - username of the new guild member
  2101. #--------------------------------------------------------------------------
  2102. def command_guild_invite(username)
  2103. # if allowed to execute action
  2104. if self.check_guildleader_action
  2105. # if already in the guild
  2106. if @guildmembers.include?(username)
  2107. # show error message
  2108. self.add_error(RMXOS::Data::GuildAlreadyMember)
  2109. else
  2110. # send invitation
  2111. self.send('GIN', username)
  2112. end
  2113. end
  2114. end
  2115. #--------------------------------------------------------------------------
  2116. # Executes chat command for removing a member from the guild.
  2117. # username - username of the guild member to be removed
  2118. # password - password of the guild
  2119. #--------------------------------------------------------------------------
  2120. def command_guild_remove(username, password)
  2121. # if allowed to execute action
  2122. if self.check_guildleader_action
  2123. # if already in the guild
  2124. if !@guildmembers.include?(username)
  2125. # show error message
  2126. self.add_error(RMXOS::Data::GuildAlreadyMember)
  2127. else
  2128. # send username and password
  2129. self.send('GRE', username, encrypt_password(password))
  2130. end
  2131. end
  2132. end
  2133. #--------------------------------------------------------------------------
  2134. # Executes chat command for leaving the guild.
  2135. # password - password of the player
  2136. #--------------------------------------------------------------------------
  2137. def command_guild_leave(password)
  2138. # if allowed to execute action
  2139. if self.guildleader?
  2140. # show error message
  2141. self.add_error(RMXOS::Data::GuildCannotLeave)
  2142. # if allowed to execute action
  2143. elsif self.check_guild_action
  2144. # send new password
  2145. self.send('GLE', encrypt_password(password))
  2146. end
  2147. end
  2148. #--------------------------------------------------------------------------
  2149. # Executes chat command for displaying guild information.
  2150. #--------------------------------------------------------------------------
  2151. def command_guild_info
  2152. # if allowed to execute action
  2153. if self.check_guild_action
  2154. # show guild info
  2155. text = RMXOS::Data::GuildInfo.sub('GUILD') {@guildname}
  2156. text = text.sub('LEADER') {@guildleader}
  2157. if @guildmembers.size > 1
  2158. # add '(ON)' to buddies that are online right now
  2159. members = (@guildmembers - [@guildleader]).map {|username|
  2160. if @players.any? {|key, value| value.username == username}
  2161. username += RMXOS::Data::OnlineTag
  2162. else
  2163. username = username
  2164. end
  2165. }
  2166. text = text.sub('MEMBERS') {members.join(', ')}
  2167. else
  2168. text = text.sub('MEMBERS') {'none'}
  2169. end
  2170. self.add_info(text)
  2171. end
  2172. end
  2173. #--------------------------------------------------------------------------
  2174. # Sends a load request server.
  2175. #--------------------------------------------------------------------------
  2176. def send_load_request
  2177. self.send('LRQ')
  2178. end
  2179. #--------------------------------------------------------------------------
  2180. # Sends save data to the server.
  2181. #--------------------------------------------------------------------------
  2182. def send_save_data
  2183. # marshal data
  2184. data = Marshal.dump(self.get_save_containers)
  2185. # create a hex stream
  2186. stream = data.unpack('H*').join('')
  2187. # send it to the server
  2188. self.send(RMXOS.make_message('SAV', 'no-legacy', stream))
  2189. end
  2190. #--------------------------------------------------------------------------
  2191. # Sends save data to the server.
  2192. #--------------------------------------------------------------------------
  2193. def send_save_data_legacy
  2194. serializations = []
  2195. # for each save container
  2196. self.get_save_containers.each {|container|
  2197. # if the container's class is on this saving list
  2198. if RMXOS::Options::SAVE_DATA[container.class] != nil
  2199. # recursively get save serializations
  2200. serializations += container.rmxos_serialize_legacy
  2201. end
  2202. }
  2203. # find all literals
  2204. literals = RMXOS::Options::SAVE_DATA.keys.find_all {|key|
  2205. !key.is_a?(Class)
  2206. }
  2207. # create serializations for literal saving data
  2208. literals.each {|key|
  2209. serializations.push(RMXOS.make_message('SAV', key, eval(key)))
  2210. }
  2211. # send all save serializations
  2212. serializations.each {|query| self.send(query)}
  2213. end
  2214. #--------------------------------------------------------------------------
  2215. # Saves the game. Only data from selected classes will be saved.
  2216. # classes - an array of classes which should be saved.
  2217. #--------------------------------------------------------------------------
  2218. def save
  2219. # abort if not logged in or not data exists (to prevent corruption)
  2220. return if @user_id <= 0 || !@game_loaded
  2221. # clear leftover data
  2222. self.send('SCL')
  2223. # send save data to server
  2224. if !RMXOS::Options::LEGACY_SAVE_METHOD
  2225. send_save_data
  2226. else
  2227. send_save_data_legacy
  2228. end
  2229. # send save end message to begin saving process
  2230. self.send('SEN')
  2231. # double autosave timer
  2232. @autosave_time *= 2
  2233. end
  2234. #--------------------------------------------------------------------------
  2235. # Gets the actual game data that can be saved.
  2236. # Returns: An array of all instances that can be saved.
  2237. #--------------------------------------------------------------------------
  2238. def get_save_containers
  2239. containers = []
  2240. RMXOS::Options::SAVE_CONTAINERS.each {|str| containers.push(eval(str))}
  2241. return containers
  2242. end
  2243. #--------------------------------------------------------------------------
  2244. # Loads the game from the data received from the server.
  2245. #--------------------------------------------------------------------------
  2246. def load_game_data
  2247. return if @load_data.size == 0
  2248. # get data
  2249. hex = @load_data['no-legacy']
  2250. # first reconstruct the original stream from the hex values
  2251. stream = hex.scan(/../).map {|h| ("0x" + h).hex.chr}.join('')
  2252. # unmarshal data
  2253. loaded = Marshal.load(stream)
  2254. # load data
  2255. RMXOS::Options::SAVE_CONTAINERS.each {|str|
  2256. break if loaded.size == 0
  2257. eval("#{str} = loaded.shift")
  2258. }
  2259. end
  2260. #--------------------------------------------------------------------------
  2261. # Loads the game from the data received from the server.
  2262. #--------------------------------------------------------------------------
  2263. def load_game_data_legacy
  2264. containers = self.get_save_containers
  2265. # get all loading data entries sorted ascending by string length
  2266. keys = @load_data.keys.sort {|a, b| a.size - b.size}
  2267. # filter out only high level entries
  2268. keys = keys.find_all {|key| key.split('/').size == 1}
  2269. # for each high level save data entry
  2270. keys.each {|name|
  2271. # evaluate the entry
  2272. data = eval(name)
  2273. # if entry is a class
  2274. if data.is_a?(Class)
  2275. # for each save container
  2276. containers.each {|container|
  2277. # if container class matches save data class
  2278. if container.class == data
  2279. # load this container's data with the entry's name
  2280. container.rmxos_deserialize_legacy(name)
  2281. break
  2282. end
  2283. }
  2284. else
  2285. # set the literal
  2286. eval("#{name} = #{data.inspect}")
  2287. end
  2288. }
  2289. end
  2290. #--------------------------------------------------------------------------
  2291. # Loads the game from the data received from the server.
  2292. #--------------------------------------------------------------------------
  2293. def load_game
  2294. # load received data
  2295. if !RMXOS::Options::LEGACY_SAVE_METHOD
  2296. load_game_data
  2297. else
  2298. load_game_data_legacy
  2299. end
  2300. end
  2301.  
  2302. end
  2303.  
  2304. end
  2305.  
  2306. #==============================================================================
  2307. # module PointerDerefence
  2308. #------------------------------------------------------------------------------
  2309. # Provides memory copying.
  2310. #==============================================================================
  2311.  
  2312. module PointerDerefence
  2313.  
  2314. #----------------------------------------------------------------------------
  2315. # Copies data from a pointer.
  2316. # length - number of bytes
  2317. # Returns: The copied data.
  2318. #----------------------------------------------------------------------------
  2319. def ref(length)
  2320. buffer = "\0" * length
  2321. Win32API.new('kernel32', 'RtlMoveMemory', 'ppl', '').call(buffer, self, length)
  2322. return buffer
  2323. end
  2324.  
  2325. end
  2326.  
  2327. class Numeric; include PointerDerefence; end;
  2328. class String; include PointerDerefence; end;
  2329.  
  2330. #==============================================================================
  2331. # module Winsock
  2332. #------------------------------------------------------------------------------
  2333. # Serves as wrapper for the used Win32API Socket functions.
  2334. #==============================================================================
  2335.  
  2336. module Winsock
  2337.  
  2338. DLL = 'ws2_32'
  2339.  
  2340. Win32API_bind = Win32API.new(DLL, 'bind', 'ppl', 'l')
  2341. Win32API_closesocket = Win32API.new(DLL, 'closesocket', 'p', 'l')
  2342. Win32API_setsockopt = Win32API.new(DLL, 'setsockopt', 'pllpl', 'l')
  2343. Win32API_connect = Win32API.new(DLL, 'connect', 'ppl', 'l')
  2344. Win32API_gethostbyname = Win32API.new(DLL, 'gethostbyname', 'p', 'l')
  2345. Win32API_recv = Win32API.new(DLL, 'recv', 'ppll', 'l')
  2346. Win32API_select = Win32API.new(DLL, 'select', 'lpppp', 'l')
  2347. Win32API_send = Win32API.new(DLL, 'send', 'ppll', 'l')
  2348. Win32API_socket = Win32API.new(DLL, 'socket', 'lll', 'l')
  2349. Win32API_WSAGetLastError = Win32API.new(DLL, 'WSAGetLastError', '', 'l')
  2350.  
  2351. def self.bind(*args); Win32API_bind.call(*args); end;
  2352. def self.closesocket(*args); Win32API_closesocket.call(*args); end;
  2353. def self.setsockopt(*args); Win32API_setsockopt.call(*args); end;
  2354. def self.connect(*args); Win32API_connect.call(*args); end;
  2355. def self.gethostbyname(*args); Win32API_gethostbyname.call(*args); end;
  2356. def self.recv(*args); Win32API_recv.call(*args); end;
  2357. def self.select(*args); Win32API_select.call(*args); end;
  2358. def self.send(*args); Win32API_send.call(*args); end;
  2359. def self.socket(*args); Win32API_socket.call(*args); end;
  2360. def self.WSAGetLastError(*args); Win32API_WSAGetLastError.call(*args); end;
  2361.  
  2362. end
  2363.  
  2364. #==============================================================================
  2365. # Socket
  2366. #------------------------------------------------------------------------------
  2367. # Creates and manages sockets.
  2368. #==============================================================================
  2369.  
  2370. class Socket
  2371.  
  2372. AF_INET = 2
  2373. SOCK_STREAM = 1
  2374. SOCK_DGRAM = 2
  2375. IPPROTO_TCP = 6
  2376. IPPROTO_UDP = 17
  2377.  
  2378. # set all accessible variables
  2379. attr_reader :host
  2380. attr_reader :port
  2381.  
  2382. #----------------------------------------------------------------------------
  2383. # Returns information about the given hostname.
  2384. #----------------------------------------------------------------------------
  2385. def self.gethostbyname(name)
  2386. data = Winsock.gethostbyname(name)
  2387. raise SocketError::ENOASSOCHOST if data == 0
  2388. host = data.ref(16).unpack('LLssL')
  2389. name = host[0].ref(256).unpack("c*").pack("c*").split("\0")[0]
  2390. address_type = host[2]
  2391. address_list = host[4].ref(4).unpack('L')[0].ref(4).unpack("c*").pack("c*")
  2392. return [name, [], address_type, address_list]
  2393. end
  2394. #----------------------------------------------------------------------------
  2395. # Creates an INET-sockaddr struct.
  2396. #----------------------------------------------------------------------------
  2397. def self.sockaddr_in(host, port)
  2398. begin
  2399. [AF_INET, port].pack('sn') + gethostbyname(host)[3] + [].pack('x8')
  2400. rescue
  2401. end
  2402. end
  2403. #----------------------------------------------------------------------------
  2404. # Creates a new socket and connects it to the given host and port.
  2405. #----------------------------------------------------------------------------
  2406. def self.open(*args)
  2407. socket = new(*args)
  2408. if block_given?
  2409. begin
  2410. yield socket
  2411. ensure
  2412. socket.close
  2413. end
  2414. end
  2415. return nil
  2416. end
  2417. #----------------------------------------------------------------------------
  2418. # Creates a new socket.
  2419. #----------------------------------------------------------------------------
  2420. def initialize(domain, type, protocol)
  2421. @descriptor = Winsock.socket(domain, type, protocol)
  2422. SocketError.check if @descriptor == -1
  2423. return @descriptor
  2424. end
  2425. #----------------------------------------------------------------------------
  2426. # Binds a socket to the given sockaddr.
  2427. #----------------------------------------------------------------------------
  2428. def bind(sockaddr)
  2429. result = Winsock.bind(@descriptor, sockaddr, sockaddr.size)
  2430. SocketError.check if result == -1
  2431. return result
  2432. end
  2433. #----------------------------------------------------------------------------
  2434. # Closes a socket.
  2435. #----------------------------------------------------------------------------
  2436. def close
  2437. result = Winsock.closesocket(@descriptor)
  2438. SocketError.check if result == -1
  2439. return result
  2440. end
  2441. #----------------------------------------------------------------------------
  2442. # Connects a socket to the given sockaddr.
  2443. #----------------------------------------------------------------------------
  2444. def connect(host, port)
  2445. @host, @port = host, port
  2446. sockaddr = Socket.sockaddr_in(@host, @port)
  2447. result = Winsock.connect(@descriptor, sockaddr, sockaddr.size)
  2448. SocketError.check if result == -1
  2449. return result
  2450. end
  2451. #----------------------------------------------------------------------------
  2452. # Checks waiting data's status.
  2453. #----------------------------------------------------------------------------
  2454. def select(timeout)
  2455. result = Winsock.select(1, [1, @descriptor].pack('ll'), 0, 0, [timeout, timeout * 1000000].pack('ll'))
  2456. SocketError.check if result == -1
  2457. return result
  2458. end
  2459. #----------------------------------------------------------------------------
  2460. # Checks if data is waiting.
  2461. #----------------------------------------------------------------------------
  2462. def ready?
  2463. return (self.select(0) != 0)
  2464. end
  2465. #----------------------------------------------------------------------------
  2466. # Returns recieved data.
  2467. #----------------------------------------------------------------------------
  2468. def recv(length, flags = 0)
  2469. buffer = "\0" * length
  2470. result = Winsock.recv(@descriptor, buffer, length, flags)
  2471. SocketError.check if result == -1
  2472. return '' if result == 0
  2473. return buffer[0, result].unpack("c*").pack("c*") # gets rid of a bunch of \0
  2474. end
  2475. #----------------------------------------------------------------------------
  2476. # Sends data to a host.
  2477. #----------------------------------------------------------------------------
  2478. def send(data, flags = 0)
  2479. result = Winsock.send(@descriptor, data, data.size, flags)
  2480. SocketError.check if result == -1
  2481. return result
  2482. end
  2483.  
  2484. end
  2485.  
  2486. #==============================================================================
  2487. # TCPSocket
  2488. #------------------------------------------------------------------------------
  2489. # Represents a TCP Socket Connection.
  2490. #==============================================================================
  2491.  
  2492. class TCPSocket < Socket
  2493.  
  2494. #----------------------------------------------------------------------------
  2495. # Initialization.
  2496. # host - IP or URL of the hots
  2497. # port - port number
  2498. #----------------------------------------------------------------------------
  2499. def initialize(host = nil, port = nil)
  2500. super(AF_INET, SOCK_STREAM, IPPROTO_TCP)
  2501. self.connect(host, port) if host != nil && port != nil
  2502. end
  2503.  
  2504. end
  2505.  
  2506. #==============================================================================
  2507. # SocketError
  2508. #------------------------------------------------------------------------------
  2509. # Default exception class for sockets.
  2510. #==============================================================================
  2511.  
  2512. class SocketError < StandardError
  2513.  
  2514. ENOASSOCHOST = 'getaddrinfo: no address associated with hostname.'
  2515.  
  2516. def self.check
  2517. errno = Winsock.WSAGetLastError
  2518. raise Errno.const_get(Errno.constants.detect {|c|
  2519. Errno.const_get(c).new.errno == errno}
  2520. )
  2521. end
  2522.  
  2523. end
  2524.  
  2525. class Hangup < Exception
  2526. end
  2527.  
  2528. #==============================================================================
  2529. # Object
  2530. #------------------------------------------------------------------------------
  2531. # Enhanced with methods for self-encoding of contained data and methods for
  2532. # decoding of saved game data that was received from the server.
  2533. #==============================================================================
  2534.  
  2535. class Object
  2536.  
  2537. #----------------------------------------------------------------------------
  2538. # Checks whether this object is actually a literal. (Literals are here
  2539. # defined as strings, numbers, ranges, true, false and nil.)
  2540. # Returns: True or false.
  2541. #----------------------------------------------------------------------------
  2542. def literal?
  2543. return (self.is_a?(String) || self.is_a?(Numeric) || self.is_a?(Range) ||
  2544. self.is_a?(TrueClass) || self.is_a?(FalseClass) || self.is_a?(NilClass))
  2545. end
  2546. #----------------------------------------------------------------------------
  2547. # Serializes the object and all contained objects for the RMX-OS SQL
  2548. # database.
  2549. # prefix - semantical prefix for the serializations
  2550. # Returns: Array of serialization strings.
  2551. #----------------------------------------------------------------------------
  2552. def rmxos_serialize_legacy(prefix = nil)
  2553. # add prefix extension if this isn't a top level class
  2554. (prefix == nil ? prefix = "SAV\t" : prefix += '/')
  2555. # add class name
  2556. prefix += self.class.name
  2557. # prepare result and data arrays
  2558. serializations, data = [], []
  2559. # for each variable that this class should save
  2560. RMXOS::Options::SAVE_DATA[self.class].each {|variable|
  2561. # get value of variable
  2562. value = self.instance_variable_get(variable)
  2563. # if value is of a class that should be saved as well
  2564. if RMXOS::Options::SAVE_DATA[value.class] != nil ||
  2565. value.is_a?(Array) || value.is_a?(Hash)
  2566. # get serializations from this value with this class as prefix
  2567. serializations += value.rmxos_serialize_legacy("#{prefix}/#{variable}")
  2568. data.push(value.class)
  2569. # if value is literal
  2570. elsif value.literal?
  2571. data.push(value)
  2572. else
  2573. # can't save this value
  2574. raise RMXOS::Error.get_save_error(value)
  2575. end
  2576. }
  2577. # if there is any data
  2578. if data.size > 0
  2579. # inspect and compress
  2580. data = data.inspect.gsub(', ') {','}
  2581. # add data array query
  2582. serializations.unshift("#{prefix}\t#{data}")
  2583. end
  2584. return serializations
  2585. end
  2586. #----------------------------------------------------------------------------
  2587. # Serializes array and hashes for the RMX-OS SQL database.
  2588. # prefix - semantical prefix for the serializations
  2589. # indices - array of indices (array) or keys (hash)
  2590. # all_literals - whether all elements are literals or not
  2591. # Returns: Array serialization strings.
  2592. #----------------------------------------------------------------------------
  2593. def rmxos_serialize_legacy_collection(prefix, indices, all_literals)
  2594. # prepare result
  2595. serializations = []
  2596. # if all array elements are literals
  2597. if all_literals
  2598. # get as string
  2599. data = self.inspect
  2600. else
  2601. # create new instance of this class
  2602. data = self.class.new
  2603. # for each index in enumerable
  2604. indices.each {|i|
  2605. # if element is literal
  2606. if self[i].literal?
  2607. # add it to the result
  2608. data[i] = self[i]
  2609. # if element is of a class that should be saved as well
  2610. elsif RMXOS::Options::SAVE_DATA[self[i].class] != nil ||
  2611. self[i].is_a?(Array) || self[i].is_a?(Hash)
  2612. # get serializations from this element with this class as prefix
  2613. serializations += self[i].rmxos_serialize_legacy("#{prefix}[#{i.inspect}]")
  2614. # add elements's class to data array
  2615. data[i] = self[i].class
  2616. else
  2617. # can't save this value
  2618. raise RMXOS::Error.get_save_error(self[i])
  2619. end
  2620. }
  2621. # inspect and compress
  2622. data = data.inspect
  2623. end
  2624. # add a little bit of compression :)
  2625. data.gsub!(', ') {','}
  2626. # add data array query
  2627. serializations.push("#{prefix}\t#{data}")
  2628. return serializations
  2629. end
  2630. #----------------------------------------------------------------------------
  2631. # Deserializes data retrieved from the server into this object.
  2632. # name - the key for the hash data retrieved from the server
  2633. #----------------------------------------------------------------------------
  2634. def rmxos_deserialize_legacy(name)
  2635. # evaluate the data for this class which turns into an array
  2636. data = eval($network.load_data[name])
  2637. # iterate through all indices of variables that are to be saved
  2638. RMXOS::Options::SAVE_DATA[self.class].each_index {|i|
  2639. # get variable name
  2640. variable = RMXOS::Options::SAVE_DATA[self.class][i]
  2641. # if this variable's loaded value is a class
  2642. if data[i].is_a?(Class)
  2643. # access key for loaded data
  2644. key = "#{name}/#{variable}"
  2645. # if it's an array
  2646. if data[i] == Array
  2647. # evaluate and get the loaded array
  2648. data[i] = eval($network.load_data[key])
  2649. # load all classes contained in this array
  2650. rmxos_deserialize_legacy_collection(name, variable, data[i],
  2651. (0...data[i].size).to_a)
  2652. elsif data[i] == Hash
  2653. # evaluate and get the loaded hash
  2654. data[i] = eval($network.load_data[key])
  2655. # load all classes contained in this hash
  2656. rmxos_deserialize_legacy_collection(name, variable, data[i], data[i].keys)
  2657. else
  2658. # load this class
  2659. data[i] = rmxos_deserialize_legacy_object(key, data[i])
  2660. end
  2661. end
  2662. # set the variable to this value
  2663. self.instance_variable_set(variable, data[i])
  2664. }
  2665. end
  2666. #----------------------------------------------------------------------------
  2667. # Deserializes data retrieved from an array or a hash.
  2668. # name - the key for the hash data retrieved from the server
  2669. # variable - name of the variable containing the array
  2670. # data - actual array or hash
  2671. # indices - array of indices (array) or keys (hash)
  2672. #----------------------------------------------------------------------------
  2673. def rmxos_deserialize_legacy_collection(name, variable, data, indices)
  2674. # iterate through all indices
  2675. indices.each {|i|
  2676. # if data is a class
  2677. if data[i].is_a?(Class)
  2678. # access key for loaded data
  2679. key = "#{name}/#{variable}[#{i.inspect}]"
  2680. # if it's an array
  2681. if data[i] == Array
  2682. # evaluate and get the loaded array
  2683. data[i] = eval($network.load_data[key])
  2684. # load all classes contained in this array
  2685. rmxos_deserialize_legacy_collection(name, "#{variable}[#{i.inspect}]",
  2686. data[i], (0...data[i].size).to_a)
  2687. elsif data[i] == Hash
  2688. # evaluate and get the loaded hash
  2689. data[i] = eval($network.load_data[key])
  2690. # load all classes contained in this hash
  2691. rmxos_deserialize_legacy_collection(name, "#{variable}[#{i.inspect}]",
  2692. data[i], data[i].keys)
  2693. else
  2694. # load this class
  2695. data[i] = rmxos_deserialize_legacy_object(key, data[i])
  2696. end
  2697. end
  2698. }
  2699. end
  2700. #----------------------------------------------------------------------------
  2701. # Deserializes data retrieved from the server into this object.
  2702. # prefix - semantical prefix for loaded data access
  2703. # classe - class that needs to be instantiated
  2704. # Returns: New instance of a class after loading.
  2705. #----------------------------------------------------------------------------
  2706. def rmxos_deserialize_legacy_object(prefix, classe)
  2707. # if classe requires additional creation arguments
  2708. if RMXOS::Options::CREATION_DATA.has_key?(classe)
  2709. # get the arguments
  2710. args = RMXOS::Options::CREATION_DATA[classe]
  2711. # create an instance with those arguments
  2712. new = eval("#{classe.name}.new(#{args})")
  2713. else
  2714. # simply instantiate the class
  2715. new = classe.new
  2716. end
  2717. # load data for this class
  2718. new.rmxos_deserialize_legacy("#{prefix}/#{classe.name}")
  2719. return new
  2720. end
  2721.  
  2722. end
  2723.  
  2724. #==============================================================================
  2725. # Array
  2726. #------------------------------------------------------------------------------
  2727. # Arrays need to be encoded and decoded differently than other obejcts.
  2728. #==============================================================================
  2729.  
  2730. class Array
  2731.  
  2732. #----------------------------------------------------------------------------
  2733. # Serializes the object and all contained objects for the RMX-OS SQL
  2734. # database.
  2735. # prefix - semantical prefix for the serializations
  2736. # Returns: Array of serialization strings.
  2737. #----------------------------------------------------------------------------
  2738. def rmxos_serialize_legacy(prefix)
  2739. # all indices
  2740. indices = (0...self.size).to_a
  2741. # are all elements literals
  2742. all_literals = !self.any? {|val| !val.literal?}
  2743. # return serializations from this array
  2744. return self.rmxos_serialize_legacy_collection(prefix, indices, all_literals)
  2745. end
  2746.  
  2747. end
  2748.  
  2749. #==============================================================================
  2750. # Hash
  2751. #------------------------------------------------------------------------------
  2752. # Hashes need to be encoded and decoded differently than other obejcts.
  2753. #==============================================================================
  2754.  
  2755. class Hash
  2756.  
  2757. #----------------------------------------------------------------------------
  2758. # Serializes the object and all contained objects for the RMX-OS SQL
  2759. # database.
  2760. # prefix - semantical prefix for the serializations
  2761. # Returns: Array of serialization strings.
  2762. #----------------------------------------------------------------------------
  2763. def rmxos_serialize_legacy(prefix)
  2764. # all keys
  2765. indices = self.keys
  2766. # are all elements literals
  2767. all_literals = !self.any? {|key, val| !val.literal?}
  2768. # return serializations from this hash
  2769. return self.rmxos_serialize_legacy_collection(prefix, indices, all_literals)
  2770. end
  2771.  
  2772. end
  2773.  
  2774. #==============================================================================
  2775. # Bitmap
  2776. #------------------------------------------------------------------------------
  2777. # Extended with text handling methods.
  2778. #==============================================================================
  2779.  
  2780. class Bitmap
  2781.  
  2782. #----------------------------------------------------------------------------
  2783. # Uses an aliased version of draw_text to draw outlined text.
  2784. # x2 - x-coordinate
  2785. # y2 - y-coordinate
  2786. # w2 - width
  2787. # h2 - height
  2788. # text2 - text
  2789. # a2 - align
  2790. #----------------------------------------------------------------------------
  2791. # if method not aliased already
  2792. if $tons_version == nil || $tons_version < 1.6
  2793. # alias original method
  2794. alias draw_text_shaded_later draw_text
  2795. end
  2796. def draw_text_full(x2, y2, w2 = 0, h2 = 0, text2 = '', a2 = 0)
  2797. # if x2 is a rectangle
  2798. if x2.is_a?(Rect)
  2799. # set temporary variables
  2800. x, y, w, h, text, a = x2.x, x2.y, x2.width, x2.height, y2, w2
  2801. else
  2802. # set temporary variables
  2803. x, y, w, h, text, a = x2, y2, w2, h2, text2, a2
  2804. end
  2805. # save old font color
  2806. save_color = self.font.color.clone
  2807. # set new font color (black)
  2808. self.font.color = Color.new(0, 0, 0)
  2809. # draw text with offsets in all directions
  2810. [x - 1, x + 1].each {|xx|
  2811. [y - 1, y + 1].each {|yy|
  2812. draw_text_shaded_later(xx, yy, w, h, text, a)
  2813. }
  2814. }
  2815. # restore original color
  2816. self.font.color = save_color
  2817. # drw text at normal postion
  2818. draw_text_shaded_later(x, y, w, h, text, a)
  2819. end
  2820. #----------------------------------------------------------------------------
  2821. # Slices text to fit a specific width.
  2822. # text - text to slice
  2823. # width - max width of the text
  2824. # Returns: Array of text slices
  2825. #----------------------------------------------------------------------------
  2826. def slice_text(text, width)
  2827. # split string by words
  2828. words = text.split(' ')
  2829. # only one word, no need to split
  2830. return words if words.size == 1
  2831. # initialize
  2832. result, current_text = [], words.shift
  2833. # check each word
  2834. words.each_index {|i|
  2835. # if too long
  2836. if self.text_size("#{current_text} #{words[i]}").width > width
  2837. # save the text from before
  2838. result.push(current_text)
  2839. # next word
  2840. current_text = words[i]
  2841. else
  2842. # add to text from before
  2843. current_text = "#{current_text} #{words[i]}"
  2844. end
  2845. # add last word
  2846. result.push(current_text) if i >= words.size - 1
  2847. }
  2848. return result
  2849. end
  2850.  
  2851. end
  2852.  
  2853. #==============================================================================
  2854. # Game_Temp
  2855. #==============================================================================
  2856.  
  2857. class Game_Temp
  2858.  
  2859. # setting all accessible variables
  2860. attr_accessor :chat_calling
  2861. attr_accessor :chat_visible
  2862. attr_accessor :chat_active
  2863. attr_accessor :chat_messages
  2864. attr_accessor :chat_logs
  2865. attr_accessor :chat_refresh
  2866. attr_accessor :chat_sprites
  2867. attr_accessor :name_sprites
  2868. attr_accessor :entering_map
  2869. attr_accessor :trade_active
  2870. attr_accessor :trade_host
  2871. attr_accessor :trade_id
  2872. attr_accessor :trade_items
  2873. attr_accessor :trade_abort
  2874. attr_accessor :trade_confirmed
  2875. attr_accessor :trade_canceled
  2876. attr_accessor :trade_cancel_confirmed
  2877. attr_accessor :trade_finalized
  2878. #----------------------------------------------------------------------------
  2879. # Altered to instantiate new variables.
  2880. #----------------------------------------------------------------------------
  2881. alias initialize_rmxos_later initialize
  2882. def initialize
  2883. initialize_rmxos_later
  2884. @chat_calling = false
  2885. @chat_visible = true
  2886. @chat_active = false
  2887. @chat_messages = []
  2888. @chat_logs = []
  2889. @chat_refresh = false
  2890. @chat_sprites = true
  2891. @name_sprites = true
  2892. @entering_map = false
  2893. self.trade_reset
  2894. end
  2895. #----------------------------------------------------------------------------
  2896. # Resets all variables for trading.
  2897. #----------------------------------------------------------------------------
  2898. def trade_reset
  2899. @trade_active = false
  2900. @trade_host = false
  2901. @trade_id = -1
  2902. @trade_items = {}
  2903. @trade_abort = false
  2904. @trade_confirmed = false
  2905. @trade_canceled = false
  2906. @trade_cancel_confirmed = false
  2907. @trade_finalized = nil
  2908. end
  2909.  
  2910. end
  2911.  
  2912. #==============================================================================
  2913. # Game_Character
  2914. #==============================================================================
  2915. class Game_Map
  2916.  
  2917. alias setup_rmxos_later setup
  2918. def setup(map_id)
  2919. setup_rmxos_later (map_id)
  2920. end
  2921.  
  2922. #----------------------------------------------------------------------------
  2923. # Altered for map change execution.
  2924. #----------------------------------------------------------------------------
  2925. alias update_rmxos_later update
  2926. def update(main = false)
  2927. update_rmxos_later(main)
  2928. if $game_temp.entering_map
  2929. # remove all current players from this map
  2930. $network.clear_map_players
  2931. $network.send_exchange_variables
  2932. # enter new map
  2933. $network.enter_map
  2934. $network.wait_for_map_data
  2935. end
  2936. end
  2937.  
  2938. end
  2939.  
  2940. #==============================================================================
  2941. # Game_Character
  2942. #==============================================================================
  2943.  
  2944. class Game_Character
  2945.  
  2946. # setting all accessible variables
  2947. attr_reader :anime_count
  2948. attr_reader :chat_messages
  2949. #----------------------------------------------------------------------------
  2950. # Altered to updates chat message bubbles.
  2951. #----------------------------------------------------------------------------
  2952. alias update_rmxos_later update
  2953. def update
  2954. update_rmxos_later
  2955. update_chat_messages
  2956. update_exchange_variables
  2957. end
  2958. #----------------------------------------------------------------------------
  2959. # Updates all chat message bubbles and removes the one that have expired.
  2960. #----------------------------------------------------------------------------
  2961. def update_chat_messages
  2962. @chat_messages = [] if @chat_messages == nil
  2963. @chat_messages.clone.each {|chat_message|
  2964. if chat_message.expired?
  2965. @chat_messages.delete(chat_message)
  2966. else
  2967. chat_message.time -= 1
  2968. end
  2969. }
  2970. end
  2971. #----------------------------------------------------------------------------
  2972. # Adds chat messages to bubble chat display queue.
  2973. # messages - array of messages
  2974. # color - text display color
  2975. #----------------------------------------------------------------------------
  2976. def add_chat_messages(messages, color)
  2977. @chat_messages = [] if @chat_messages == nil
  2978. messages.each {|text|
  2979. @chat_messages.push(RMXOS::ChatBubbleMessage.new(text, color))
  2980. }
  2981. while @chat_messages.size > RMXOS::Data::ChatBubbleEntries
  2982. @chat_messages.shift
  2983. end
  2984. end
  2985. #----------------------------------------------------------------------------
  2986. # Gets the used exchange variable names.
  2987. # Returns: Array with variable names.
  2988. #----------------------------------------------------------------------------
  2989. def get_exchange_variable_names
  2990. return []
  2991. end
  2992. #----------------------------------------------------------------------------
  2993. # Stores exchange variables.
  2994. # variables - the exchange variables
  2995. #----------------------------------------------------------------------------
  2996. def store_exchange_variables(variables)
  2997. # update the exchange variable records
  2998. @exchange_variables = {} if @exchange_variables == nil
  2999. variables.each_key {|key| @exchange_variables[key] = variables[key]}
  3000. end
  3001. #----------------------------------------------------------------------------
  3002. # Sends a hash of exchange variables to the server.
  3003. # variables - the exchange variables the will be sent
  3004. # Returns: The variables that were actually sent.
  3005. #----------------------------------------------------------------------------
  3006. def send_exchange_variables(variables = nil)
  3007. return (variables != nil ? variables : self.get_exchange_variables)
  3008. end
  3009. #----------------------------------------------------------------------------
  3010. # Gets a hash with the current values of the exchange variables.
  3011. # names - names of the exchange variables
  3012. # Returns: Hash with values of variables.
  3013. #----------------------------------------------------------------------------
  3014. def get_exchange_variables(names = nil)
  3015. # get all exchange variables if none were specified
  3016. names = get_exchange_variable_names if names == nil
  3017. variables = {}
  3018. # for each exchange variable name
  3019. names.each {|name|
  3020. keys = name.split('|')
  3021. current = self
  3022. # recursively get the value
  3023. while keys.size > 0 && current != nil
  3024. current = current.instance_variable_get(keys.shift)
  3025. end
  3026. variables[name] = current if keys.size == 0
  3027. }
  3028. return variables
  3029. end
  3030. #----------------------------------------------------------------------------
  3031. # Gets a hash with exchange variable values that have changed.
  3032. # Returns: Hash with changed variables.
  3033. #----------------------------------------------------------------------------
  3034. def get_exchange_variables_changes
  3035. @exchange_variables = {} if @exchange_variables == nil
  3036. # get all variables
  3037. variables = self.get_exchange_variables
  3038. changed = {}
  3039. # find new keys
  3040. new_keys = variables.keys - @exchange_variables.keys
  3041. # new variables need to be updated
  3042. new_keys.each {|key| changed[key] = variables[key]}
  3043. # get changed variables
  3044. (@exchange_variables.keys - new_keys).each {|key|
  3045. if @exchange_variables[key] != variables[key]
  3046. changed[key] = variables[key]
  3047. end
  3048. }
  3049. return changed
  3050. end
  3051. #----------------------------------------------------------------------------
  3052. # Updates exchange variable values and sends them to server if necessary.
  3053. #----------------------------------------------------------------------------
  3054. def update_exchange_variables
  3055. end
  3056. #----------------------------------------------------------------------------
  3057. # Evaluates player exchange variables received from the server.
  3058. # variables - hash of exchange_variables
  3059. #----------------------------------------------------------------------------
  3060. def evaluate(variables)
  3061. # for each variable
  3062. variables.each_key {|key|
  3063. current = self
  3064. keys = key.split('|')
  3065. name = keys.pop
  3066. # recursively get object
  3067. while keys.size > 0 && current != nil
  3068. current = current.instance_variable_get(keys.shift)
  3069. end
  3070. # set variable
  3071. current.instance_variable_set(name, variables[key]) if current != nil
  3072. }
  3073. end
  3074.  
  3075. end
  3076.  
  3077. #==============================================================================
  3078. # Game_Player
  3079. #==============================================================================
  3080.  
  3081. class Game_Player
  3082.  
  3083. # setting all accessible variables
  3084. attr_reader :move_speed
  3085. attr_reader :new_map_id
  3086. #----------------------------------------------------------------------------
  3087. # Altered to send player coordinates to the server when there is a change
  3088. # in positioning or other related attributes.
  3089. #----------------------------------------------------------------------------
  3090. alias update_network_later update
  3091. def update
  3092. # no freezing condition
  3093. if !$game_temp.chat_active
  3094. # call original method
  3095. update_network_later
  3096. else
  3097. super
  3098. end
  3099. end
  3100. #----------------------------------------------------------------------------
  3101. # Gets the used exchange variable names.
  3102. # Returns: Array with variable names.
  3103. #----------------------------------------------------------------------------
  3104. def get_exchange_variable_names
  3105. return RMXOS::Options::EXCHANGE_VARIABLES.clone
  3106. end
  3107. #----------------------------------------------------------------------------
  3108. # Updates exchange variable values and sends them to server if necessary.
  3109. #----------------------------------------------------------------------------
  3110. def update_exchange_variables
  3111. changed = self.get_exchange_variables_changes
  3112. if changed.size > 0
  3113. self.send_exchange_variables(changed)
  3114. self.store_exchange_variables(changed)
  3115. end
  3116. end
  3117. #----------------------------------------------------------------------------
  3118. # Sends a hash of exchange variables to the server.
  3119. # variables - the exchange variables the will be sent
  3120. # Returns: The variables that were actually sent.
  3121. #----------------------------------------------------------------------------
  3122. def send_exchange_variables(variables = nil)
  3123. variables = super(variables)
  3124. # send variables over network
  3125. $network.send_exchange_variables(variables)
  3126. return variables
  3127. end
  3128.  
  3129. end
  3130.  
  3131. #==============================================================================
  3132. # Sprite_Character
  3133. #==============================================================================
  3134.  
  3135. class Sprite_Character
  3136.  
  3137. #--------------------------------------------------------------------------
  3138. # Altered to update the name sprite as well.
  3139. #--------------------------------------------------------------------------
  3140. alias update_rmxos_later update
  3141. def update
  3142. # call original method
  3143. update_rmxos_later
  3144. # if name sprites are on
  3145. if $game_temp.name_sprites
  3146. # update name sprites
  3147. update_name_sprite
  3148. # if name sprite exists
  3149. elsif @name_sprite != nil
  3150. # delete it
  3151. @name_sprite.dispose
  3152. @name_sprite = nil
  3153. end
  3154. # if chat sprites are on
  3155. if $game_temp.chat_sprites
  3156. # update chat sprites if chat bubbles are active
  3157. update_chat_sprite if RMXOS::Options::CHAT_BUBBLES
  3158. # if chat sprite exists
  3159. elsif @chat_sprite != nil
  3160. # delete it
  3161. @chat_sprite.dispose
  3162. @chat_sprite = nil
  3163. end
  3164. end
  3165. #--------------------------------------------------------------------------
  3166. # Updates the name sprite.
  3167. #--------------------------------------------------------------------------
  3168. def update_name_sprite
  3169. username = nil
  3170. usergroup = nil
  3171. guildname = nil
  3172. # if player
  3173. if @character == $game_player
  3174. # get name
  3175. username = $network.username
  3176. guildname = $network.guildname
  3177. # if any other player
  3178. elsif @character.is_a?(Game_OnlineCharacter)
  3179. # get name and group
  3180. username = @character.username
  3181. usergroup = @character.usergroup
  3182. guildname = @character.guildname
  3183. end
  3184. # if name exists and either sprite doesn't exist or name wasn't set yet
  3185. if username != nil && (@name_sprite == nil || @username != username ||
  3186. @usergroup != usergroup || @guildname != guildname)
  3187. # set username
  3188. @username = username
  3189. # set usergroup
  3190. @usergroup = usergroup
  3191. # set guildname
  3192. @guildname = guildname
  3193. # remove old sprite if one exists
  3194. @name_sprite.dispose if @name_sprite != nil
  3195. # create new sprite
  3196. @name_sprite = Sprite.new
  3197. @name_sprite.bitmap = Bitmap.new(1, 1)
  3198. @name_sprite.bitmap.font.size = 21
  3199. # calculate width of name
  3200. has_guild = (RMXOS::Options::GUILD_NAME_SPRITES && guildname != '')
  3201. text = username
  3202. w = @name_sprite.bitmap.text_size(text).width + 2
  3203. # coordinates offsets
  3204. y = 0
  3205. h = 24
  3206. guild_text = "[#{guildname}]"
  3207. # if has guild text
  3208. if has_guild
  3209. # modify coordinates
  3210. y += 22
  3211. h += 22
  3212. guild_w = @name_sprite.bitmap.text_size(guild_text).width + 2
  3213. w = guild_w if w < guild_w
  3214. end
  3215. # create bitmap
  3216. @name_sprite.bitmap = Bitmap.new(w, h)
  3217. @name_sprite.bitmap.font.size = 21
  3218. # set coordinates
  3219. @name_sprite.ox = w / 2
  3220. @name_sprite.oy = self.bitmap.height / 4 + h
  3221. # draw guild text
  3222. if has_guild
  3223. @name_sprite.bitmap.font.color = RMXOS::Data::COLORS['guild']
  3224. @name_sprite.bitmap.draw_text_full(1, 1, w, 24, guild_text, 1)
  3225. end
  3226. # if this player
  3227. if usergroup == nil
  3228. # self color
  3229. @name_sprite.bitmap.font.color = RMXOS::Data::COLORS['self']
  3230. # if group color exists
  3231. elsif RMXOS::Data::COLORS.has_key?(usergroup)
  3232. # get group color
  3233. @name_sprite.bitmap.font.color = RMXOS::Data::COLORS[usergroup]
  3234. else
  3235. # white
  3236. @name_sprite.bitmap.font.color = RMXOS::Data::COLORS[GROUP_PLAYER]
  3237. end
  3238. # draw name
  3239. @name_sprite.bitmap.draw_text_full(1, y + 1, w, 24, username, 1)
  3240. end
  3241. # if sprite exists
  3242. if @name_sprite != nil
  3243. # make sure name sprite is at the proper position
  3244. @name_sprite.x, @name_sprite.y, @name_sprite.z = self.x, self.y, self.z
  3245. end
  3246. end
  3247. #--------------------------------------------------------------------------
  3248. # Updates the chat sprite.
  3249. #--------------------------------------------------------------------------
  3250. def update_chat_sprite
  3251. # if this player or any other player
  3252. if @character == $game_player || @character.is_a?(Game_OnlineCharacter)
  3253. # get messages
  3254. chat_messages = @character.chat_messages
  3255. else
  3256. chat_messages = nil
  3257. end
  3258. # if chat messages have changed
  3259. if chat_messages != nil && @chat_messages != chat_messages
  3260. @chat_messages = chat_messages.clone
  3261. # if sprite exists
  3262. if @chat_sprite != nil
  3263. # remove old bitmap and sprite
  3264. @chat_sprite.bitmap.dispose
  3265. @chat_sprite.dispose
  3266. end
  3267. # if there are no chat messages
  3268. if @chat_messages.size == 0
  3269. @chat_sprite = nil
  3270. else
  3271. # create new sprite
  3272. @chat_sprite = Sprite.new
  3273. @chat_sprite.bitmap = Bitmap.new(1, 1)
  3274. @chat_sprite.bitmap.font.size = RMXOS::Data::ChatFontHeight
  3275. # calculate width of maximum message
  3276. w = 0
  3277. @chat_messages.each {|message|
  3278. width = @chat_sprite.bitmap.text_size(message.text).width + 4
  3279. w = width if width > w
  3280. }
  3281. h = 24
  3282. h += 24 if (RMXOS::Options::GUILD_NAME_SPRITES && @guildname != '')
  3283. # set offsets
  3284. @chat_sprite.ox = w / 2
  3285. @chat_sprite.oy = self.bitmap.height / 4 + h + @chat_messages.size *
  3286. RMXOS::Data::ChatFontHeight
  3287. @chat_sprite.bitmap.dispose
  3288. @chat_sprite.bitmap = Bitmap.new(w, @chat_messages.size *
  3289. RMXOS::Data::ChatFontHeight)
  3290. @chat_sprite.bitmap.font.size = RMXOS::Data::ChatFontHeight
  3291. @chat_sprite.bitmap.fill_rect(0, 0, w, @chat_sprite.bitmap.height,
  3292. Frame::BACK_COLOR)
  3293. # font height
  3294. h = RMXOS::Data::ChatFontHeight
  3295. # if using Tons of Add-ons that has Simple Shaded Text
  3296. if $tons_version != nil && $tons_version >= 1.6
  3297. # skip shadow drawing
  3298. @chat_messages.each_index {|i|
  3299. # draw message
  3300. @chat_sprite.bitmap.font.color = @chat_messages[i].color
  3301. @chat_sprite.bitmap.draw_text_shaded_later(2, i * h - 1, w, h,
  3302. @chat_messages[i].text)
  3303. }
  3304. else
  3305. # draw normally
  3306. @chat_messages.each_index {|i|
  3307. # draw message
  3308. @chat_sprite.bitmap.font.color = @chat_messages[i].color
  3309. @chat_sprite.bitmap.draw_text(2, i * h - 1, w, h,
  3310. @chat_messages[i].text)
  3311. }
  3312. end
  3313. end
  3314. end
  3315. # if sprite exists
  3316. if @chat_sprite != nil
  3317. # make sure name sprite is at the proper position
  3318. @chat_sprite.x, @chat_sprite.y, @chat_sprite.z = self.x, self.y, self.z
  3319. end
  3320. end
  3321. #--------------------------------------------------------------------------
  3322. # Altered to dispose the additional name sprite.
  3323. #--------------------------------------------------------------------------
  3324. alias dispose_rmxos_later dispose
  3325. def dispose
  3326. @name_sprite.dispose if @name_sprite != nil
  3327. @chat_sprite.dispose if @chat_sprite != nil
  3328. dispose_rmxos_later
  3329. end
  3330.  
  3331. end
  3332.  
  3333. #==============================================================================
  3334. # Spriteset_Map
  3335. #==============================================================================
  3336.  
  3337. class Spriteset_Map
  3338.  
  3339. #----------------------------------------------------------------------------
  3340. # Altered to include a hash of other's player characters so they can be
  3341. # checked for changes in the actual hash for players in Network.
  3342. #----------------------------------------------------------------------------
  3343. alias initialize_rmxos_later initialize
  3344. def initialize
  3345. @players = {}
  3346. # call original method
  3347. initialize_rmxos_later
  3348. update
  3349. end
  3350. #----------------------------------------------------------------------------
  3351. # Altered to include the creation and disposal of characters that enter/leave
  3352. # the map or connect/disconnect.
  3353. #----------------------------------------------------------------------------
  3354. alias update_rmxos_later update
  3355. def update
  3356. # call original method
  3357. update_rmxos_later
  3358. # for each removed player
  3359. (@players.keys - $network.map_players.keys).each {|id|
  3360. # dispose sprite
  3361. dispose_character_sprite(@players[id])
  3362. # remove nil values from sprites
  3363. @character_sprites.compact!
  3364. }
  3365. # for each new player
  3366. ($network.map_players.keys - @players.keys).each {|id|
  3367. # create a sprite
  3368. create_character_sprite($network.map_players[id])
  3369. }
  3370. # store current players on the map
  3371. @players = $network.map_players.clone
  3372. end
  3373. #----------------------------------------------------------------------------
  3374. # Creates a sprite for the given character.
  3375. # character - character that needs a sprite
  3376. #----------------------------------------------------------------------------
  3377. def create_character_sprite(character)
  3378. @character_sprites.push(Sprite_Character.new(@viewport1, character))
  3379. end
  3380. #----------------------------------------------------------------------------
  3381. # Disposes the sprite of a character.
  3382. # character - character that is being removed
  3383. #----------------------------------------------------------------------------
  3384. def dispose_character_sprite(character)
  3385. # iterate through all character sprites
  3386. @character_sprites.each_index {|i|
  3387. # if sprite's character matches
  3388. if @character_sprites[i].character == character
  3389. # dispose the sprite
  3390. @character_sprites[i].dispose
  3391. # remove the disposed sprite
  3392. @character_sprites[i] = nil
  3393. break
  3394. end
  3395. }
  3396. end
  3397.  
  3398. end
  3399.  
  3400. #==============================================================================
  3401. # Window_Command
  3402. #==============================================================================
  3403.  
  3404. class Window_Command
  3405.  
  3406. # setting all accessible variables
  3407. attr_reader :commands
  3408. #----------------------------------------------------------------------------
  3409. # Changes commands used in a window rather than instantiating a new window.
  3410. # commands - new array of commands
  3411. #----------------------------------------------------------------------------
  3412. def set_commands(commands)
  3413. # store new commands
  3414. @commands = commands
  3415. @item_max = @commands.size
  3416. # delete old bitmap
  3417. self.contents.dispose if self.contents != nil
  3418. # if there are any commands
  3419. if @item_max > 0
  3420. # create a new display
  3421. self.contents = Bitmap.new(width - 32, @item_max * 32)
  3422. refresh
  3423. else
  3424. # remove the disposed bitmap
  3425. self.contents = nil
  3426. end
  3427. end
  3428.  
  3429. end
  3430.  
  3431. #==============================================================================
  3432. # Scene_Title
  3433. #------------------------------------------------------------------------------
  3434. # Altered to switch to RMX-OS Server selection scene instead.
  3435. #==============================================================================
  3436.  
  3437. class Scene_Title
  3438.  
  3439. #----------------------------------------------------------------------------
  3440. # Overriden to disconnect and change the scene immediately.
  3441. #----------------------------------------------------------------------------
  3442. def main
  3443. $network.disconnect
  3444. SceneManager.goto Scene_Servers
  3445. end
  3446.  
  3447. end
  3448.  
  3449. #==============================================================================
  3450. # Scene_Map
  3451. #==============================================================================
  3452.  
  3453. class Scene_Map
  3454.  
  3455. #----------------------------------------------------------------------------
  3456. # Altered to create a chat window.
  3457. #----------------------------------------------------------------------------
  3458. alias main_rmxos_later main
  3459. def main
  3460. create_chat_window if $game_temp.chat_visible
  3461. $game_temp.chat_active = false
  3462. # call original method
  3463. main_rmxos_later
  3464. dispose_chat_window
  3465. dispose_trade_windows if @trade_command_window != nil
  3466. end
  3467. #----------------------------------------------------------------------------
  3468. # Altered to accept server messages and update all player characters on the
  3469. # map.
  3470. #----------------------------------------------------------------------------
  3471. alias update_rmxos_later update
  3472. def update
  3473. $network.update_server_ping
  3474. $network.update_autosave if !$game_temp.trade_active
  3475. $network.listen
  3476. $network.update_map_players
  3477. # update chat
  3478. update_chat
  3479. # update trade or call original method
  3480. $game_temp.trade_active ? update_trade : update_rmxos_later
  3481. end
  3482. #----------------------------------------------------------------------------
  3483. # Altered to update player data on the server when changing maps.
  3484. #----------------------------------------------------------------------------
  3485. alias transfer_player_rmxos_later perform_transfer
  3486. def perform_transfer
  3487. # if map has changed
  3488. if $game_player.new_map_id != $game_map.map_id
  3489. # make clear that player is changing the map
  3490. $network.leave_map
  3491. # setup flag for map entering
  3492. $game_temp.entering_map = true
  3493. end
  3494. # call original method
  3495. transfer_player_rmxos_later
  3496. # save game after map change
  3497. $network.save
  3498. end
  3499. #----------------------------------------------------------------------------
  3500. # Creates the chat windows.
  3501. #----------------------------------------------------------------------------
  3502. def create_chat_window
  3503. @chatinput_window = Frame_ChatInput.new
  3504. @chat_window = Frame_Chat.new
  3505. end
  3506. #----------------------------------------------------------------------------
  3507. # Disposes the chat windows.
  3508. #----------------------------------------------------------------------------
  3509. def dispose_chat_window
  3510. if @chatinput_window != nil
  3511. @chatinput_window.dispose
  3512. @chatinput_window = nil
  3513. @chat_window.dispose
  3514. @chat_window = nil
  3515. end
  3516. end
  3517. #----------------------------------------------------------------------------
  3518. # Updates everything related to chat.
  3519. #----------------------------------------------------------------------------
  3520. def update_chat
  3521. if self.special_update?
  3522. # Ff triggers the chat window
  3523. if Input.trigger?(Input::Key['F5'])
  3524. $game_temp.chat_visible = !$game_temp.chat_visible
  3525. $game_temp.chat_active = false if !$game_temp.chat_visible
  3526. # F6 shows the chat window as well if it's not visible
  3527. elsif Input.trigger?(Input::Key['F6'])
  3528. $game_temp.chat_visible = true
  3529. if $game_temp.chat_active
  3530. $game_temp.chat_active = false
  3531. else
  3532. # prepare calling chat
  3533. $game_temp.chat_calling = true
  3534. end
  3535. end
  3536. end
  3537. # if chat window doesn't exist yet
  3538. if @chatinput_window == nil
  3539. # create if display is active
  3540. create_chat_window if $game_temp.chat_visible
  3541. # if display not active
  3542. elsif !$game_temp.chat_visible
  3543. dispose_chat_window
  3544. else
  3545. # apply chat active mode if the mode has changed
  3546. if @chatinput_window.active != $game_temp.chat_active
  3547. @chatinput_window.active = $game_temp.chat_active
  3548. @chat_window.active = @chatinput_window.active
  3549. end
  3550. # update chat windows
  3551. @chatinput_window.update
  3552. @chat_window.update
  3553. end
  3554. # if not moving and calling chat mode
  3555. if !$game_player.moving? && $game_temp.chat_calling
  3556. # activate chat mode
  3557. $game_temp.chat_calling = false
  3558. $game_temp.chat_active = true
  3559. end
  3560. end
  3561. #----------------------------------------------------------------------------
  3562. # Checks if specific code fragments should be updated.
  3563. # Returns: Whether to execute special updates or not.
  3564. #----------------------------------------------------------------------------
  3565. def special_update?
  3566. return !($game_player.moving? || $game_map.interpreter.running? ||
  3567. $game_player.move_route_forcing || $game_message.visible)
  3568. end
  3569. #----------------------------------------------------------------------------
  3570. # Updates trade execution.
  3571. #----------------------------------------------------------------------------
  3572. def update_trade
  3573. # create all windows if there are none yet
  3574. create_trade_windows if @trade_command_window == nil
  3575. # part of normal map update
  3576. $game_map.update
  3577. $game_map.interpreter.update
  3578. $game_system.update
  3579. $game_screen.update
  3580. @spriteset.update
  3581. @message_window.update
  3582. $game_player.update_chat_messages
  3583. # trade abortion
  3584. if $game_temp.trade_abort
  3585. dispose_trade_windows
  3586. return
  3587. end
  3588. # abort if chat is active
  3589. return if $game_temp.chat_active
  3590. # if cancel attempt from a non-host
  3591. if $game_temp.trade_host && $game_temp.trade_canceled
  3592. $network.trade_confirm_cancel
  3593. $game_temp.trade_confirmed = false
  3594. $game_temp.trade_canceled = false
  3595. end
  3596. @trade_partner_window.update
  3597. # update proper submenu
  3598. if @trade_command_window.active
  3599. update_trade_command
  3600. elsif @trade_player_window.active
  3601. update_trade_player
  3602. elsif @trade_partner_window.active
  3603. update_trade_partner
  3604. else
  3605. update_trade_wait
  3606. end
  3607. # cancel confirmation needs to be cleared
  3608. $game_temp.trade_cancel_confirmed = false
  3609. end
  3610. #----------------------------------------------------------------------------
  3611. # Creates all windows needed for trade.
  3612. #----------------------------------------------------------------------------
  3613. def create_trade_windows
  3614. # trade command window
  3615. @trade_command_window = Window_CommandHorizontal.new(152,
  3616. RMXOS::Data::TradeCommands)
  3617. @trade_command_window.active = true
  3618. @trade_command_window.opacity = 160
  3619. @trade_command_window.z = 10000
  3620. # own item selection
  3621. @trade_player_window = Window_TradePlayer.new
  3622. @trade_player_window.z = 10000
  3623. @trade_player_window.opacity = 160
  3624. # other's item selection
  3625. @trade_partner_window = Window_TradePartner.new
  3626. @trade_partner_window.z = 10000
  3627. @trade_partner_window.opacity = 160
  3628. # wait message
  3629. @trade_wait_window = Window_Button.new(0, 256, 640, RMXOS::Data::TradeWait)
  3630. @trade_wait_window.z = 10000
  3631. @trade_wait_window.opacity = 160
  3632. @trade_wait_window.visible = false
  3633. end
  3634. #----------------------------------------------------------------------------
  3635. # Dispose all trade windows.
  3636. #----------------------------------------------------------------------------
  3637. def dispose_trade_windows
  3638. @trade_command_window.dispose
  3639. @trade_command_window = nil
  3640. @trade_partner_window.dispose
  3641. @trade_partner_window = nil
  3642. @trade_player_window.dispose
  3643. @trade_player_window = nil
  3644. @trade_wait_window.dispose
  3645. @trade_wait_window = nil
  3646. $game_temp.trade_reset
  3647. end
  3648. #----------------------------------------------------------------------------
  3649. # Updates trade command window execution.
  3650. #----------------------------------------------------------------------------
  3651. def update_trade_command
  3652. @trade_command_window.update
  3653. # if pressed cancel
  3654. if Input.trigger?(Input::B)
  3655. Sound.play_cancel
  3656. # abort trade
  3657. $network.trade_abort
  3658. dispose_trade_windows
  3659. # if pressed confirm
  3660. elsif Input.trigger?(Input::C)
  3661. Sound.play_ok
  3662. case @trade_command_window.index
  3663. when 0
  3664. # activate your window
  3665. @trade_command_window.active = false
  3666. @trade_player_window.active = true
  3667. @trade_player_window.index = 0
  3668. when 1
  3669. # activate other window
  3670. @trade_command_window.active = false
  3671. @trade_partner_window.active = true
  3672. @trade_partner_window.index = 0
  3673. when 2
  3674. # confirm
  3675. @trade_command_window.active = false
  3676. # if player exists
  3677. if $network.players[$game_temp.trade_id] != nil
  3678. # get wait text
  3679. text = RMXOS::Data::TradeWait.gsub('PLAYER') {
  3680. $network.players[$game_temp.trade_id].username
  3681. }
  3682. # show it
  3683. @trade_wait_window.set_command(text)
  3684. else
  3685. # other player is gone
  3686. @trade_wait_window.set_command(RMXOS::Data::TradeNoPlayer)
  3687. end
  3688. @trade_wait_window.visible = true
  3689. # if host
  3690. if $game_temp.trade_host
  3691. # if already confirmed by other
  3692. if $game_temp.trade_confirmed
  3693. # execute the trade
  3694. $network.trade_confirm
  3695. execute_trade
  3696. end
  3697. else
  3698. # wait for other
  3699. $network.trade_confirm
  3700. end
  3701. when 3
  3702. # abort completely
  3703. $network.trade_abort
  3704. dispose_trade_windows
  3705. end
  3706. end
  3707. end
  3708. #----------------------------------------------------------------------------
  3709. # Updates execution of trade window with own items.
  3710. #----------------------------------------------------------------------------
  3711. def update_trade_player
  3712. @trade_player_window.update
  3713. value = 1
  3714. value *= 10 if Input.press?(Input::X)
  3715. value *= 100 if Input.press?(Input::Y)
  3716. value *= 1000 if Input.press?(Input::Z)
  3717. # if pressed cancel
  3718. if Input.trigger?(Input::B)
  3719. Sound.play_cancel
  3720. @trade_player_window.active = false
  3721. @trade_player_window.index = -1
  3722. @trade_command_window.active = true
  3723. # if pressed confirm
  3724. elsif Input.trigger?(Input::C)
  3725. Sound.play_ok
  3726. @trade_player_window.active = false
  3727. @trade_player_window.index = -1
  3728. @trade_command_window.active = true
  3729. # if pressed left
  3730. elsif Input.repeat?(Input::LEFT)
  3731. # if quantity has changed
  3732. if @trade_player_window.decrease_quantity(value)
  3733. Sound.play_cursor
  3734. # send new data to other
  3735. $network.trade_send_items(@trade_player_window.items)
  3736. # cancel other's trade confirmation
  3737. $network.trade_confirm_cancel
  3738. else
  3739. Sound.play_buzzer
  3740. end
  3741. # if pressed right
  3742. elsif Input.repeat?(Input::RIGHT)
  3743. # if quantity has changed
  3744. if @trade_player_window.increase_quantity(value)
  3745. Sound.play_cursor
  3746. # send new data to other
  3747. $network.trade_send_items(@trade_player_window.items)
  3748. # cancel other's trade confirmation
  3749. $network.trade_confirm_cancel
  3750. else
  3751. Sound.play_buzzer
  3752. end
  3753. end
  3754. end
  3755. #----------------------------------------------------------------------------
  3756. # Updates execution of trade window with other's items.
  3757. #----------------------------------------------------------------------------
  3758. def update_trade_partner
  3759. # if pressed cancel
  3760. if Input.trigger?(Input::B)
  3761. Sound.play_cancel
  3762. # deactivate other window
  3763. @trade_partner_window.active = false
  3764. @trade_partner_window.index = -1
  3765. @trade_command_window.active = true
  3766. # if pressed confirm
  3767. elsif Input.trigger?(Input::C)
  3768. Sound.play_ok
  3769. # deactivate other window
  3770. @trade_partner_window.active = false
  3771. @trade_partner_window.index = -1
  3772. @trade_command_window.active = true
  3773. end
  3774. end
  3775. #----------------------------------------------------------------------------
  3776. # Updates execution of waiting for trade confirmation.
  3777. #----------------------------------------------------------------------------
  3778. def update_trade_wait
  3779. # if trade is in finalizing stage
  3780. if $game_temp.trade_finalized != nil
  3781. # finish if finalization is done
  3782. dispose_trade_windows if $game_temp.trade_finalized
  3783. # if trade cancel confirmed
  3784. elsif $game_temp.trade_cancel_confirmed
  3785. Sound.play_cancel
  3786. # cancel confirmed trade
  3787. @trade_command_window.active = true
  3788. @trade_wait_window.visible = false
  3789. $game_temp.trade_canceled = false
  3790. $game_temp.trade_cancel_confirmed = false
  3791. # if not host and trade canceled
  3792. elsif !$game_temp.trade_host && $game_temp.trade_canceled
  3793. # if pressed cancel during cancelation process
  3794. if Input.trigger?(Input::B)
  3795. Sound.play_cancel
  3796. # other player might got stuck, abort trade completely
  3797. $network.trade_abort
  3798. dispose_trade_windows
  3799. end
  3800. # if confirmed trade
  3801. elsif $game_temp.trade_confirmed
  3802. Sound.play_ok
  3803. # execute trade
  3804. execute_trade
  3805. # send confirmation if host
  3806. $network.trade_confirm if $game_temp.trade_host
  3807. # if pressed cancel
  3808. elsif Input.trigger?(Input::B)
  3809. # if host
  3810. if $game_temp.trade_host
  3811. # cancel trade
  3812. Sound.play_cancel
  3813. @trade_command_window.active = true
  3814. @trade_wait_window.visible = false
  3815. else
  3816. # request cancel trade
  3817. $network.trade_cancel
  3818. # waiting for host to confirm the cancelation
  3819. @trade_wait_window.set_command(RMXOS::Data::CancelingTradeAbort)
  3820. $game_temp.trade_canceled = true
  3821. end
  3822. end
  3823. end
  3824. #----------------------------------------------------------------------------
  3825. # Updates execution of waiting for trade confirmation.
  3826. #----------------------------------------------------------------------------
  3827. def execute_trade
  3828. # execute item/gold exchange
  3829. @trade_player_window.items.each {|id, value|
  3830. if id != 0
  3831. $game_party.lose_item(id, value)
  3832. else
  3833. $game_party.lose_gold(value)
  3834. end
  3835. }
  3836. @trade_partner_window.items.each {|id, value|
  3837. if id != 0
  3838. $game_party.gain_item(id, value)
  3839. else
  3840. $game_party.gain_gold(value)
  3841. end
  3842. }
  3843. # send data for saving the game
  3844. if !RMXOS::Options::LEGACY_SAVE_METHOD
  3845. $network.send_save_data
  3846. else
  3847. $network.send_save_data_legacy
  3848. end
  3849. # request server to execute the final trade confirmation
  3850. $network.trade_execute
  3851. # waiting for server to finalize the trade
  3852. $game_temp.trade_finalized = false
  3853. # waiting for server to execute trade message
  3854. @trade_wait_window.set_command(RMXOS::Data::ExecutingTrade)
  3855. end
  3856.  
  3857. end
  3858.  
  3859. #==============================================================================
  3860. # Game_OnlineCharacter
  3861. #------------------------------------------------------------------------------
  3862. # Represents other players on the map.
  3863. #==============================================================================
  3864.  
  3865. class Game_OnlineCharacter < Game_Character
  3866.  
  3867. # setting all accessible variables
  3868. attr_reader :user_id
  3869. attr_reader :username
  3870. attr_reader :usergroup
  3871. attr_reader :guildname
  3872. attr_accessor :map_id
  3873. #----------------------------------------------------------------------------
  3874. # Sets player data.
  3875. # user_id - user ID
  3876. # username - username
  3877. # usergroup - usergroup
  3878. # guildname - guildname
  3879. #----------------------------------------------------------------------------
  3880. def set_user_data(user_id, username, usergroup, guildname)
  3881. @user_id = user_id
  3882. @username = username
  3883. @usergroup = usergroup
  3884. @guildname = guildname
  3885. end
  3886.  
  3887. end
  3888.  
  3889. #==============================================================================
  3890. # Frame
  3891. #------------------------------------------------------------------------------
  3892. # Represents an advanced sprite class. It is lighter than a window and avoids
  3893. # usage of window specific additions that cannot be turned off. This class is
  3894. # abstract and should not be instantiated as such.
  3895. #==============================================================================
  3896.  
  3897. class Frame < Sprite
  3898.  
  3899. # constants
  3900. BORDER_COLOR = Color.new(255, 255, 255, 160)
  3901. BACK_COLOR = Color.new(0, 0, 0, 160)
  3902. # setting all accessible variables
  3903. attr_accessor :active
  3904. attr_reader :width
  3905. attr_reader :height
  3906. #----------------------------------------------------------------------------
  3907. # Initialization.
  3908. # x - x coordinate
  3909. # y - y coordinate
  3910. # width - width of the sprite
  3911. # height - height of the sprite
  3912. #----------------------------------------------------------------------------
  3913. def initialize(x, y, width, height)
  3914. # create the actual sprite
  3915. super()
  3916. # set dimensions
  3917. @width = width
  3918. @height = height
  3919. # create background sprite
  3920. create_background_sprite
  3921. # set position
  3922. self.x, self.y, self.z = x, y, 1000
  3923. # store variables
  3924. @active = true
  3925. end
  3926. #----------------------------------------------------------------------------
  3927. # Creates a background sprite.
  3928. #----------------------------------------------------------------------------
  3929. def create_background_sprite
  3930. # create background sprite
  3931. @background = Sprite.new
  3932. create_background_bitmap
  3933. end
  3934. #----------------------------------------------------------------------------
  3935. # Creates the background bitmap.
  3936. #----------------------------------------------------------------------------
  3937. def create_background_bitmap
  3938. @background.bitmap = Bitmap.new(@width, @height)
  3939. @background.bitmap.fill_rect(0, 0, @width, @height, BORDER_COLOR)
  3940. @background.bitmap.fill_rect(1, 1, @width - 2, @height - 2, BACK_COLOR)
  3941. end
  3942. #----------------------------------------------------------------------------
  3943. # Updates the background sprite.
  3944. #----------------------------------------------------------------------------
  3945. def update_background
  3946. @background.x, @background.y, @background.z = self.x, self.y, self.z - 1
  3947. end
  3948. #----------------------------------------------------------------------------
  3949. # Changes the sprite width.
  3950. # value - new width
  3951. #----------------------------------------------------------------------------
  3952. def width=(value)
  3953. # if width had changed
  3954. if @width != value
  3955. # delete old bitmap
  3956. @background.bitmap.dispose if @background.bitmap != nil
  3957. @width = value
  3958. # create new background bitmap
  3959. create_background_bitmap
  3960. end
  3961. end
  3962. #----------------------------------------------------------------------------
  3963. # Changes the sprite height.
  3964. # value - new height
  3965. #----------------------------------------------------------------------------
  3966. def height=(value)
  3967. # if width had changed
  3968. if @height != value
  3969. # delete old bitmap
  3970. @background.bitmap.dispose if @background.bitmap != nil
  3971. @height = value
  3972. # create new background bitmap
  3973. create_background_bitmap
  3974. end
  3975. end
  3976. #----------------------------------------------------------------------------
  3977. # Changes sprite x.
  3978. # value - new x coordinate
  3979. #----------------------------------------------------------------------------
  3980. def x=(value)
  3981. super
  3982. update_background
  3983. end
  3984. #----------------------------------------------------------------------------
  3985. # Changes sprite y.
  3986. # value - new y coordinate
  3987. #----------------------------------------------------------------------------
  3988. def y=(value)
  3989. super
  3990. update_background
  3991. end
  3992. #----------------------------------------------------------------------------
  3993. # Changes sprite z.
  3994. # value - new z coordinate
  3995. #----------------------------------------------------------------------------
  3996. def z=(value)
  3997. super
  3998. update_background
  3999. end
  4000. #----------------------------------------------------------------------------
  4001. # Refreshes the display. Abstract method.
  4002. #----------------------------------------------------------------------------
  4003. def refresh
  4004. end
  4005. #----------------------------------------------------------------------------
  4006. # Disposes the additional background sprite.
  4007. #----------------------------------------------------------------------------
  4008. def dispose
  4009. if @background.bitmap != nil
  4010. @background.bitmap.dispose
  4011. @background.bitmap = nil
  4012. end
  4013. @background.dispose
  4014. super
  4015. end
  4016.  
  4017. end
  4018.  
  4019. #==============================================================================
  4020. # Frame_Text
  4021. #------------------------------------------------------------------------------
  4022. # Handles basic user input from the keyboard for text related entries. This
  4023. # class is abstract and should not be instantiated as such.
  4024. #==============================================================================
  4025.  
  4026. class Frame_Text < Frame
  4027.  
  4028. # constants
  4029. CURSOR_COLOR = Color.new(255, 255, 255)
  4030. # setting all accessible variables
  4031. attr_reader :text
  4032. attr_reader :password_char
  4033. #----------------------------------------------------------------------------
  4034. # Initialization.
  4035. # x - x coordinate
  4036. # y - y coordinate
  4037. # width - width of the sprite
  4038. # height - height of the sprite
  4039. # caption - title text displayed
  4040. # text - default text entered
  4041. # password_char - password character used to hide text (no hiding if empty)
  4042. #----------------------------------------------------------------------------
  4043. def initialize(x, y, width, height, text = '', password_char = '')
  4044. # store variables
  4045. @frame = 0
  4046. @text = text
  4047. @password_char = password_char
  4048. # set cursor position at the end
  4049. @cursor_position = text.scan(/./m).size
  4050. # maximum text length
  4051. self.max_length = RMXOS::Options::CHATINPUT_MAX_LENGTH
  4052. # create the actual sprite
  4053. super(x, y, width, height)
  4054. # filter for input, allows all printable characters
  4055. @input_filter = //
  4056. end
  4057. #----------------------------------------------------------------------------
  4058. # Changes sprite x.
  4059. # value - new x coordinate
  4060. #----------------------------------------------------------------------------
  4061. def x=(value)
  4062. super
  4063. update_cursor
  4064. end
  4065. #----------------------------------------------------------------------------
  4066. # Changes sprite y.
  4067. # value - new y coordinate
  4068. #----------------------------------------------------------------------------
  4069. def y=(value)
  4070. super
  4071. update_cursor
  4072. end
  4073. #----------------------------------------------------------------------------
  4074. # Changes sprite z.
  4075. # value - new z coordinate
  4076. #----------------------------------------------------------------------------
  4077. def z=(value)
  4078. super
  4079. update_cursor
  4080. end
  4081. #----------------------------------------------------------------------------
  4082. # Sets displayed text. Refreshes the display immediately.
  4083. # new_text - new text to be displayed
  4084. #----------------------------------------------------------------------------
  4085. def text=(new_text)
  4086. @text = new_text
  4087. refresh
  4088. update_cursor
  4089. end
  4090. #----------------------------------------------------------------------------
  4091. # Sets password character. Refreshes the display immediately.
  4092. # new_password_char - new password character to be used
  4093. #----------------------------------------------------------------------------
  4094. def password_char=(new_password_char)
  4095. @password_char = new_password_char
  4096. refresh
  4097. update_cursor
  4098. end
  4099. #----------------------------------------------------------------------------
  4100. # Changes maximum length of allowed text and truncates text if too long.
  4101. # new_max_length - new_max_length
  4102. #----------------------------------------------------------------------------
  4103. def max_length=(new_max_length)
  4104. @max_length = new_max_length
  4105. chars = @text.scan(/./m)
  4106. @text = chars[0, @max_length].join if chars.size > @max_length
  4107. self.cursor_move_to_end if @cursor_position > chars.size
  4108. end
  4109. #----------------------------------------------------------------------------
  4110. # Gets the text that should be displayed. This method is needed so when using
  4111. # a password character the original text can stay unchanged while it's
  4112. # actually being displayed in password characters.
  4113. # Returns: The text that should be displayed.
  4114. #----------------------------------------------------------------------------
  4115. def get_display_text
  4116. return (@password_char == '' ? @text : @text.gsub(/./m) {@password_char})
  4117. end
  4118. #----------------------------------------------------------------------------
  4119. # Moves the cursor to the left if possible.
  4120. #----------------------------------------------------------------------------
  4121. def cursor_move_left
  4122. @cursor_position -= 1 if self.cursor_can_move_left?
  4123. self.reset_cursor_blinking
  4124. end
  4125. #----------------------------------------------------------------------------
  4126. # Moves the cursor to the right if possible.
  4127. #----------------------------------------------------------------------------
  4128. def cursor_move_right
  4129. @cursor_position += 1 if self.cursor_can_move_right?
  4130. self.reset_cursor_blinking
  4131. end
  4132. #----------------------------------------------------------------------------
  4133. # Moves the cursor to the left end of a word.
  4134. #----------------------------------------------------------------------------
  4135. def cursor_move_left_word
  4136. chars = @text.scan(/./m)
  4137. # skip all whitespaces first
  4138. while @cursor_position > 0 && chars[@cursor_position - 1] == ' '
  4139. @cursor_position -= 1
  4140. end
  4141. # skip all non-whitespaces
  4142. while @cursor_position > 0 && chars[@cursor_position - 1] != ' '
  4143. @cursor_position -= 1
  4144. end
  4145. self.reset_cursor_blinking
  4146. end
  4147. #----------------------------------------------------------------------------
  4148. # Moves the cursor to the right end of a word.
  4149. #----------------------------------------------------------------------------
  4150. def cursor_move_right_word
  4151. chars = @text.scan(/./m)
  4152. # skip all non-whitespaces first
  4153. while @cursor_position < chars.size && chars[@cursor_position] != ' '
  4154. @cursor_position += 1
  4155. end
  4156. # skip all whitespaces
  4157. while @cursor_position < chars.size && chars[@cursor_position] == ' '
  4158. @cursor_position += 1
  4159. end
  4160. self.reset_cursor_blinking
  4161. end
  4162. #----------------------------------------------------------------------------
  4163. # Moves the cursor to the beginning.
  4164. #----------------------------------------------------------------------------
  4165. def cursor_move_to_beginning
  4166. @cursor_position = 0
  4167. self.reset_cursor_blinking
  4168. end
  4169. #----------------------------------------------------------------------------
  4170. # Moves the cursor to the end.
  4171. #----------------------------------------------------------------------------
  4172. def cursor_move_to_end
  4173. @cursor_position = @text.scan(/./m).size
  4174. self.reset_cursor_blinking
  4175. end
  4176. #----------------------------------------------------------------------------
  4177. # Checks if the cursor can move further left.
  4178. # Returns: True of false.
  4179. #----------------------------------------------------------------------------
  4180. def cursor_can_move_left?
  4181. return (@cursor_position > 0)
  4182. end
  4183. #----------------------------------------------------------------------------
  4184. # Checks if the cursor can move further right.
  4185. # Returns: True of false.
  4186. #----------------------------------------------------------------------------
  4187. def cursor_can_move_right?
  4188. return (@cursor_position < @text.scan(/./m).size)
  4189. end
  4190. #----------------------------------------------------------------------------
  4191. # Deletes the character left of the cursor if there is one.
  4192. # count - how many characters should be deleted
  4193. #----------------------------------------------------------------------------
  4194. def delete_left(count = 1)
  4195. if self.cursor_can_move_left?
  4196. # limiting character count
  4197. count = @cursor_position if count > @cursor_position
  4198. # split text at cursor with one character removed left from the cursor
  4199. chars = @text.scan(/./m)
  4200. left = (@cursor_position > count ? chars[0, @cursor_position - count] : [])
  4201. if @cursor_position < chars.size
  4202. right = chars[@cursor_position, chars.size - @cursor_position]
  4203. else
  4204. right = []
  4205. end
  4206. # set cursor at right position
  4207. @cursor_position -= count
  4208. # put together the split halves
  4209. self.text = (left + right).join
  4210. self.reset_cursor_blinking
  4211. end
  4212. end
  4213. #----------------------------------------------------------------------------
  4214. # Deletes the character right of the cursor if there is one.
  4215. # count - how many characters should be deleted
  4216. #----------------------------------------------------------------------------
  4217. def delete_right(count = 1)
  4218. if self.cursor_can_move_right?
  4219. # limiting character count
  4220. chars = @text.scan(/./m)
  4221. if count > chars.size - @cursor_position
  4222. count = chars.size - @cursor_position
  4223. end
  4224. # moving cursor to the right
  4225. @cursor_position += count
  4226. # deleting everything left from cursor
  4227. self.delete_left(count)
  4228. self.reset_cursor_blinking
  4229. end
  4230. end
  4231. #----------------------------------------------------------------------------
  4232. # Deletes the word left of the cursor.
  4233. #----------------------------------------------------------------------------
  4234. def delete_left_word
  4235. chars = @text.scan(/./m)
  4236. position = @cursor_position
  4237. # skip all whitespaces first
  4238. while position > 0 && chars[position - 1] == ' '
  4239. position -= 1
  4240. end
  4241. # skip all non-whitespaces
  4242. while position > 0 && chars[position - 1] != ' '
  4243. position -= 1
  4244. end
  4245. delete_left(@cursor_position - position) if @cursor_position > position
  4246. self.reset_cursor_blinking
  4247. end
  4248. #----------------------------------------------------------------------------
  4249. # Deletes the word right of the cursor.
  4250. #----------------------------------------------------------------------------
  4251. def delete_right_word
  4252. chars = @text.scan(/./m)
  4253. position = @cursor_position
  4254. # skip all non-whitespaces first
  4255. while position < chars.size && chars[position] != ' '
  4256. position += 1
  4257. end
  4258. # skip all whitespaces
  4259. while position < chars.size && chars[position] == ' '
  4260. position += 1
  4261. end
  4262. delete_right(position - @cursor_position) if position > @cursor_position
  4263. self.reset_cursor_blinking
  4264. end
  4265. #----------------------------------------------------------------------------
  4266. # Inserts a character into the text right from the current cursor position
  4267. # and moves the cursor positions.
  4268. # text - text that will be inserted into the current text
  4269. #----------------------------------------------------------------------------
  4270. def insert(text)
  4271. chars = @text.scan(/./m)
  4272. return if chars.size >= @max_length
  4273. # limiting characters
  4274. new_chars = text.scan(/./m)
  4275. if chars.size + new_chars.size > @max_length
  4276. new_chars = new_chars[0, @max_length - chars.size]
  4277. end
  4278. # it's possible that text contains tab characters which are forbidden
  4279. while new_chars.include?("\t")
  4280. new_chars.delete("\t")
  4281. end
  4282. return if new_chars.size == 0
  4283. # split text at cursor position
  4284. left = (@cursor_position > 0 ? chars[0, @cursor_position] : [])
  4285. if @cursor_position < chars.size
  4286. right = chars[@cursor_position, chars.size - @cursor_position]
  4287. else
  4288. right = []
  4289. end
  4290. # move cursor
  4291. @cursor_position += new_chars.size
  4292. # put together the split halves with the new text inbetween
  4293. self.text = (left + new_chars + right).join
  4294. self.reset_cursor_blinking
  4295. end
  4296. #----------------------------------------------------------------------------
  4297. # Resets cursor blinking.
  4298. #----------------------------------------------------------------------------
  4299. def reset_cursor_blinking
  4300. @frame = 0
  4301. end
  4302. #----------------------------------------------------------------------------
  4303. # Shows/hides the cursor when activating/deactivating the window.
  4304. # value - true or false
  4305. #----------------------------------------------------------------------------
  4306. def active=(value)
  4307. super
  4308. self.reset_cursor_blinking
  4309. update_cursor
  4310. end
  4311. #----------------------------------------------------------------------------
  4312. # Updates the window behavior.
  4313. #----------------------------------------------------------------------------
  4314. def update
  4315. super
  4316. # blinking period of 1 second
  4317. @frame = (@frame + 1) % RMXOS::Data::CursorBlinkPeriod
  4318. update_input
  4319. update_cursor
  4320. end
  4321. #----------------------------------------------------------------------------
  4322. # Updates user input (moving cursor, deleting characters).
  4323. # Returns: Whether to stop updating or not.
  4324. #----------------------------------------------------------------------------
  4325. def update_input
  4326. # left key moves the cursor to the left
  4327. if Input.repeat?(Input::LEFT)
  4328. if Input.press?(Input::CTRL)
  4329. self.cursor_move_left_word
  4330. else
  4331. self.cursor_move_left
  4332. end
  4333. return true
  4334. end
  4335. # right key moves the cursor to the left
  4336. if Input.repeat?(Input::RIGHT)
  4337. if Input.press?(Input::CTRL)
  4338. self.cursor_move_right_word
  4339. else
  4340. self.cursor_move_right
  4341. end
  4342. return true
  4343. end
  4344. # home moves to the beginning
  4345. if Input.trigger?(Input::Key['Home'])
  4346. self.cursor_move_to_beginning
  4347. return true
  4348. end
  4349. # end moves to the end
  4350. if Input.trigger?(Input::Key['End'])
  4351. self.cursor_move_to_end
  4352. return true
  4353. end
  4354. # backspace deletes to the left
  4355. if Input.repeat?(Input::Key['Backspace'])
  4356. if Input.press?(Input::CTRL)
  4357. self.delete_left_word
  4358. else
  4359. self.delete_left
  4360. end
  4361. return true
  4362. end
  4363. # backspace deletes to the right
  4364. if Input.repeat?(Input::Key['Delete'])
  4365. if Input.press?(Input::CTRL)
  4366. self.delete_right_word
  4367. else
  4368. self.delete_right
  4369. end
  4370. return true
  4371. end
  4372. # get text
  4373. text = Input.get_input_string
  4374. # put text through input filter
  4375. text.gsub!(@input_filter) {''}
  4376. # if text is not empty
  4377. if text != ''
  4378. # insert it in the text
  4379. self.insert(text)
  4380. return true
  4381. end
  4382. return false
  4383. end
  4384. #----------------------------------------------------------------------------
  4385. # Gets the x offset of the cursor.
  4386. # Returns: X offset for the cursor.
  4387. #----------------------------------------------------------------------------
  4388. def cursor_x
  4389. # x is "0" if cursor position at 0
  4390. return -self.src_rect.x if !self.cursor_can_move_left?
  4391. # find cursor position from text left from it
  4392. display_text = get_display_text.scan(/./m)[0, @cursor_position].join
  4393. return self.bitmap.text_size(display_text).width - self.src_rect.x
  4394. end
  4395. #----------------------------------------------------------------------------
  4396. # Gets the y offset of the cursor.
  4397. # Returns: Y offset for the cursor.
  4398. #----------------------------------------------------------------------------
  4399. def cursor_y
  4400. return 2
  4401. end
  4402. #----------------------------------------------------------------------------
  4403. # Gets the height of the cursor.
  4404. # Returns: Height for the cursor.
  4405. #----------------------------------------------------------------------------
  4406. def cursor_height
  4407. return 28
  4408. end
  4409. #----------------------------------------------------------------------------
  4410. # Updates the cursor display.
  4411. #----------------------------------------------------------------------------
  4412. def update_cursor
  4413. # if not active or blinking timer has exceeded value
  4414. if !self.active || @frame >= RMXOS::Data::CursorBlinkPeriod / 2
  4415. # if cursor exists
  4416. if @cursor != nil
  4417. # delete cursor
  4418. @cursor.dispose
  4419. @cursor = nil
  4420. end
  4421. else
  4422. # if cursor does not exist
  4423. @cursor = Sprite.new if @cursor == nil
  4424. if @cursor.bitmap != nil && @cursor.bitmap.height != cursor_height
  4425. @cursor.bitmap.dispose
  4426. @cursor.bitmap = nil
  4427. end
  4428. if @cursor.bitmap == nil
  4429. # create bitmap
  4430. @cursor.bitmap = Bitmap.new(1, cursor_height)
  4431. @cursor.bitmap.fill_rect(0, 0, 1, cursor_height, CURSOR_COLOR)
  4432. end
  4433. # position the cursor
  4434. @cursor.x, @cursor.y = self.x + cursor_x, self.y + cursor_y
  4435. @cursor.z = self.z + 1
  4436. end
  4437. end
  4438. #----------------------------------------------------------------------------
  4439. # Disposes the additional cursor sprite.
  4440. #----------------------------------------------------------------------------
  4441. def dispose
  4442. if @cursor != nil
  4443. @cursor.bitmap.dispose if @cursor.bitmap != nil
  4444. @cursor.dispose
  4445. @cursor = nil
  4446. end
  4447. super
  4448. end
  4449.  
  4450. end
  4451.  
  4452. #==============================================================================
  4453. # Frame_Caption
  4454. #------------------------------------------------------------------------------
  4455. # Displays a text entry window with a caption. It allows the entry of usernames
  4456. # and passwords with a limited characterset of alphanumeric characters
  4457. # inluding "-" (minus) and "_" (underscore).
  4458. #==============================================================================
  4459.  
  4460. class Frame_Caption < Frame_Text
  4461.  
  4462. #----------------------------------------------------------------------------
  4463. # Initialization.
  4464. # x - x coordinate
  4465. # y - y coordinate
  4466. # width - width of the window
  4467. # caption - title text displayed
  4468. # text - default text entered
  4469. # password_char - password character used to hide text (no hiding if empty)
  4470. #----------------------------------------------------------------------------
  4471. def initialize(x, y, width, caption, text = '', password_char = '')
  4472. # create the actual window
  4473. super(x, y, width, 32, text, password_char)
  4474. # store variables
  4475. @caption = caption
  4476. # change max length
  4477. self.max_length = RMXOS::Options::USERPASS_MAX_LENGTH
  4478. # create display
  4479. self.bitmap = Bitmap.new(@width, @height)
  4480. # filter for input, allows all characters except white-space and apostrophe
  4481. @input_filter = /([^\S])/
  4482. refresh
  4483. end
  4484. #----------------------------------------------------------------------------
  4485. # Refreshes the display.
  4486. #----------------------------------------------------------------------------
  4487. def refresh
  4488. self.bitmap.clear
  4489. # draw caption
  4490. self.bitmap.draw_text(4, 0, 160, 32, @caption, 2)
  4491. # draw text
  4492. self.bitmap.draw_text(172, 0, @width - 8 - 168, 32, get_display_text)
  4493. end
  4494. #----------------------------------------------------------------------------
  4495. # Gets the x offset of the cursor.
  4496. # Returns: X offset for the cursor.
  4497. #----------------------------------------------------------------------------
  4498. def cursor_x
  4499. return (super + 172)
  4500. end
  4501.  
  4502. end
  4503.  
  4504. #==============================================================================
  4505. # Frame_ChatInput
  4506. #------------------------------------------------------------------------------
  4507. # Allows the entry of text for chatting and includes sending history.
  4508. #==============================================================================
  4509.  
  4510. class Frame_ChatInput < Frame_Text
  4511.  
  4512. #----------------------------------------------------------------------------
  4513. # Initialization.
  4514. #----------------------------------------------------------------------------
  4515. def initialize
  4516. # create the actual window
  4517. h = RMXOS::Data::ChatFontHeight
  4518. super(0, Graphics.height - h, RMXOS::Options::CHATINPUT_WIDTH, h)
  4519. self.z = 10000
  4520. @log_index = $game_temp.chat_logs.size
  4521. self.active = false
  4522. # create display
  4523. self.bitmap = Bitmap.new(1, 1)
  4524. refresh
  4525. end
  4526. #----------------------------------------------------------------------------
  4527. # Refreshes the display.
  4528. #----------------------------------------------------------------------------
  4529. def refresh
  4530. width = self.bitmap.text_size(@text).width + 8
  4531. self.bitmap.dispose
  4532. # create new bitmap
  4533. x = self.src_rect.x
  4534. self.bitmap = Bitmap.new(width + 4, @height)
  4535. self.bitmap.font.size = RMXOS::Data::ChatFontHeight
  4536. self.src_rect.x = x
  4537. self.src_rect.width = @width
  4538. # if using Tons of Add-ons that has Simple Shaded Text
  4539. if $tons_version != nil && $tons_version >= 1.6
  4540. # draw text
  4541. self.bitmap.draw_text_shaded_later(2, -1, width - 4,
  4542. RMXOS::Data::ChatFontHeight, @text)
  4543. else
  4544. # draw text
  4545. self.bitmap.draw_text(2, -1, width - 4,
  4546. RMXOS::Data::ChatFontHeight, @text)
  4547. end
  4548. end
  4549. #----------------------------------------------------------------------------
  4550. # Gets the x offset of the cursor.
  4551. # Returns: X offset for the cursor.
  4552. #----------------------------------------------------------------------------
  4553. def cursor_x
  4554. return (super + 2)
  4555. end
  4556. #----------------------------------------------------------------------------
  4557. # Gets the height of the cursor.
  4558. # Returns: Height for the cursor.
  4559. #----------------------------------------------------------------------------
  4560. def cursor_height
  4561. return (RMXOS::Data::ChatFontHeight - 4)
  4562. end
  4563. #----------------------------------------------------------------------------
  4564. # Updates user input (moving cursor, deleting characters).
  4565. # Returns: Whether to stop updating or not.
  4566. #----------------------------------------------------------------------------
  4567. def update_input
  4568. # abort if not active
  4569. return false if !self.active
  4570. # if holding CTRL
  4571. if Input.press?(Input::CTRL)
  4572. # if pressed UP
  4573. if Input.repeat?(Input::UP)
  4574. # if not at beginning of history
  4575. if @log_index > 0
  4576. @log_index -= 1
  4577. # get current entry
  4578. self.text = $game_temp.chat_logs[@log_index].clone
  4579. self.cursor_move_to_end
  4580. end
  4581. return true
  4582. # if pressed DOWN
  4583. elsif Input.repeat?(Input::DOWN)
  4584. # if there are still logs in the history
  4585. if @log_index < $game_temp.chat_logs.size
  4586. @log_index += 1
  4587. # get current entry
  4588. if @log_index < $game_temp.chat_logs.size
  4589. self.text = $game_temp.chat_logs[@log_index].clone
  4590. else
  4591. self.text = ''
  4592. end
  4593. self.cursor_move_to_end
  4594. end
  4595. return true
  4596. end
  4597. end
  4598. # if pressed enter
  4599. if Input.repeat?(Input::Key['Enter'])
  4600. # if any text entered
  4601. if @text.size > 0
  4602. Sound.play_ok
  4603. # if not a special command
  4604. if !$network.check_chat_commands(@text)
  4605. # send this text per chat
  4606. $network.command_chat(@text)
  4607. end
  4608. # save this message in chat log
  4609. $game_temp.chat_logs.push(@text)
  4610. if $game_temp.chat_logs.size > RMXOS::Data::ChatLogSize
  4611. $game_temp.chat_logs.shift
  4612. end
  4613. # reset
  4614. @log_index = $game_temp.chat_logs.size
  4615. self.text = ''
  4616. self.cursor_move_to_beginning
  4617. end
  4618. return true
  4619. end
  4620. # call superclass method
  4621. return super
  4622. end
  4623. #----------------------------------------------------------------------------
  4624. # Updates the cursor display.
  4625. #----------------------------------------------------------------------------
  4626. def update_cursor
  4627. x = cursor_x
  4628. if x < 2
  4629. self.src_rect.x += x - 2
  4630. elsif x >= @width - 2
  4631. self.src_rect.x += x - (@width - 2) + 1
  4632. end
  4633. super
  4634. end
  4635.  
  4636. end
  4637.  
  4638. #==============================================================================
  4639. # Frame_Chat
  4640. #------------------------------------------------------------------------------
  4641. # Displays a chat log.
  4642. #==============================================================================
  4643.  
  4644. class Frame_Chat < Frame
  4645.  
  4646. #----------------------------------------------------------------------------
  4647. # Initialization.
  4648. #----------------------------------------------------------------------------
  4649. def initialize
  4650. # create the actual window
  4651. height = RMXOS::Options::CHATBOX_LINES * RMXOS::Data::ChatFontHeight
  4652. super(0, Graphics.height - height - RMXOS::Data::ChatFontHeight,
  4653. RMXOS::Options::CHATBOX_WIDTH, height)
  4654. self.z = 10000
  4655. self.active = false
  4656. # create display
  4657. refresh
  4658. if self.bitmap != nil && self.bitmap.height > @height
  4659. self.src_rect.y = self.bitmap.height - @height
  4660. end
  4661. end
  4662. #----------------------------------------------------------------------------
  4663. # Refreshes the display.
  4664. #----------------------------------------------------------------------------
  4665. def refresh
  4666. if self.bitmap != nil
  4667. # remove old bitmap
  4668. self.bitmap.dispose
  4669. self.bitmap = nil
  4670. end
  4671. # abort if no messages
  4672. return if $game_temp.chat_messages.size == 0
  4673. # create new bitmap
  4674. h = $game_temp.chat_messages.size * RMXOS::Data::ChatFontHeight
  4675. self.bitmap = Bitmap.new(@width, h)
  4676. self.bitmap.font.size = RMXOS::Data::ChatFontHeight
  4677. self.src_rect.height = @height
  4678. self.draw_messages
  4679. end
  4680. #----------------------------------------------------------------------------
  4681. # Refreshes part of the display.
  4682. #----------------------------------------------------------------------------
  4683. def refresh_chat
  4684. new_lines = $game_temp.chat_refresh
  4685. $game_temp.chat_refresh = false
  4686. # abort if no messages
  4687. return if $game_temp.chat_messages.size == 0
  4688. # if no messages are being displayed yet
  4689. if self.bitmap == nil
  4690. # just draw them all
  4691. refresh
  4692. return
  4693. end
  4694. # store current display
  4695. bitmap = self.bitmap
  4696. h = $game_temp.chat_messages.size * RMXOS::Data::ChatFontHeight
  4697. # scrolling down if at bottom
  4698. if self.src_rect.y >= bitmap.height - @height && h > @height
  4699. src_y = h - @height
  4700. else
  4701. src_y = self.src_rect.y
  4702. end
  4703. # creating a new bitmap
  4704. self.bitmap = Bitmap.new(@width, h)
  4705. self.bitmap.font.size = RMXOS::Data::ChatFontHeight
  4706. self.src_rect.y = src_y
  4707. self.src_rect.height = @height
  4708. # y offset for drawing
  4709. if bitmap.height == h
  4710. y = new_lines * RMXOS::Data::ChatFontHeight
  4711. else
  4712. y = 0
  4713. end
  4714. self.bitmap.blt(0, 0, bitmap, Rect.new(0, y, @width, bitmap.height - y))
  4715. # delete old bitmap
  4716. bitmap.dispose
  4717. # draw new messages
  4718. self.draw_messages($game_temp.chat_messages.size - new_lines)
  4719. end
  4720. #----------------------------------------------------------------------------
  4721. # Draws specific messages onto the display.
  4722. # start - starting message index
  4723. #----------------------------------------------------------------------------
  4724. def draw_messages(start = 0)
  4725. h = RMXOS::Data::ChatFontHeight
  4726. # if using Tons of Add-ons that has Simple Shaded Text
  4727. if $tons_version != nil && $tons_version >= 1.6
  4728. # skip shadow drawing
  4729. (start...$game_temp.chat_messages.size).each {|i|
  4730. # draw message
  4731. self.bitmap.font.color = $game_temp.chat_messages[i].color
  4732. self.bitmap.draw_text_shaded_later(2, i * h - 1, @width - 4, h,
  4733. $game_temp.chat_messages[i].text)
  4734. }
  4735. else
  4736. # draw normally
  4737. (start...$game_temp.chat_messages.size).each {|i|
  4738. # draw message
  4739. self.bitmap.font.color = $game_temp.chat_messages[i].color
  4740. self.bitmap.draw_text(2, i * h - 1, @width - 4, h,
  4741. $game_temp.chat_messages[i].text)
  4742. }
  4743. end
  4744. end
  4745. #----------------------------------------------------------------------------
  4746. # Updates the window.
  4747. #----------------------------------------------------------------------------
  4748. def update
  4749. super
  4750. refresh_chat if $game_temp.chat_refresh
  4751. # if active and not holding CTRL
  4752. if self.active && !Input.press?(Input::CTRL)
  4753. # if pressed UP
  4754. if Input.repeat?(Input::UP)
  4755. # scroll up if possible
  4756. self.src_rect.y -= RMXOS::Data::ChatFontHeight if self.src_rect.y > 0
  4757. return true
  4758. # if pressed DOWN
  4759. elsif Input.repeat?(Input::DOWN)
  4760. if self.bitmap != nil && self.src_rect.y < self.bitmap.height - @height
  4761. self.src_rect.y += RMXOS::Data::ChatFontHeight
  4762. end
  4763. # scroll down if possible
  4764. return true
  4765. end
  4766. end
  4767. end
  4768.  
  4769. end
  4770.  
  4771. #==============================================================================
  4772. # Window_Button
  4773. #------------------------------------------------------------------------------
  4774. # Wraps the command window into a button-like appearance.
  4775. #==============================================================================
  4776.  
  4777. class Window_Button < Window_Selectable
  4778.  
  4779. #----------------------------------------------------------------------------
  4780. # Initialization.
  4781. # x - x coordinate
  4782. # y - y coordinate
  4783. # width - window width
  4784. # command - command to be displayed
  4785. #----------------------------------------------------------------------------
  4786. def initialize(x, y, width, command)
  4787. super(x, y, width, 64)
  4788. self.x, self.y = x, y
  4789. self.index = -1
  4790. @command = command
  4791. self.contents = Bitmap.new(width - 32, 32)
  4792. refresh
  4793. end
  4794. #----------------------------------------------------------------------------
  4795. # Refreshes the display.
  4796. #----------------------------------------------------------------------------
  4797. def refresh
  4798. self.contents.clear
  4799. self.contents.font.color = normal_color
  4800. self.contents.draw_text(0, 0, width - 32, 32, @command, 1)
  4801. end
  4802. #----------------------------------------------------------------------------
  4803. # Changes the command that is displayed.
  4804. #----------------------------------------------------------------------------
  4805. def set_command(command)
  4806. @command = command
  4807. refresh
  4808. end
  4809.  
  4810. end
  4811.  
  4812. class Window_RMXOSCommand < Window_Command
  4813.  
  4814. def initialize(width, commands)
  4815. # Compute window height from command quantity
  4816. @rmxos_width = width
  4817. @commands = commands
  4818. super(0, 0)
  4819. end
  4820.  
  4821. def make_command_list
  4822. @commands.each do |cmd|
  4823. add_command(cmd, cmd)
  4824. end
  4825. end
  4826.  
  4827. def window_width
  4828. return @rmxos_width
  4829. end
  4830.  
  4831. end
  4832.  
  4833. #==============================================================================
  4834. # Window_ServerCommand
  4835. #------------------------------------------------------------------------------
  4836. # Allows quick change of displayed commands.
  4837. #==============================================================================
  4838.  
  4839. class Window_ServerCommand < Window_RMXOSCommand
  4840.  
  4841. #----------------------------------------------------------------------------
  4842. # Overrides the drawing of a command once.
  4843. # i - item index
  4844. # command - command to draw
  4845. # color - text color
  4846. #----------------------------------------------------------------------------
  4847. def draw_command(i, command, color = normal_color)
  4848. commands = @commands.clone
  4849. @commands[i] = command
  4850. self.draw_item(i)
  4851. @commands = commands
  4852. end
  4853.  
  4854. #----------------------------------------------------------------------------
  4855. # Overrides the drawing of a command to use specific colors for certain
  4856. # words.
  4857. # i - item index
  4858. #----------------------------------------------------------------------------
  4859. def draw_item(index)
  4860. if @commands[index] == RMXOS::Data::ServerOnline
  4861. color = RMXOS::Data::ColorServerOnline
  4862. elsif @commands[index] == RMXOS::Data::ServerOffline
  4863. color = RMXOS::Data::ColorServerOffline
  4864. else
  4865. color = normal_color
  4866. end
  4867. change_color(color, command_enabled?(index))
  4868. draw_text(item_rect_for_text(index), command_name(index), alignment)
  4869. end
  4870.  
  4871. #----------------------------------------------------------------------------
  4872. # Updats cursor rectangle.
  4873. #----------------------------------------------------------------------------
  4874. def page_row_max
  4875. result = super
  4876. result += 1 if self.active && self.index >= 0 && self.index < @commands.length - 1
  4877. return result
  4878. end
  4879.  
  4880. end
  4881.  
  4882. #==============================================================================
  4883. # Window_CommandHorizontal
  4884. #------------------------------------------------------------------------------
  4885. # This window deals with general command choices, but the display is
  4886. # horizontal.
  4887. #==============================================================================
  4888.  
  4889. class Window_CommandHorizontal < Window_RMXOSCommand
  4890.  
  4891. #----------------------------------------------------------------------------
  4892. # Initialization.
  4893. #----------------------------------------------------------------------------
  4894. def initialize(width, commands)
  4895. super
  4896. self.width, self.height = commands.size * width + 32, 64
  4897. @column_max = commands.size
  4898. self.contents.dispose
  4899. self.contents = Bitmap.new(self.width - 32, self.height - 32)
  4900. refresh
  4901. update_cursor_rect
  4902. end
  4903. #----------------------------------------------------------------------------
  4904. # Draws one item.
  4905. # i - item index
  4906. # color - text color
  4907. #----------------------------------------------------------------------------
  4908. def draw_item(i, color)
  4909. self.contents.font.color = color
  4910. w = (self.width - 32) / @column_max
  4911. x = i % @column_max * w
  4912. rect = Rect.new(x, 0, self.contents.width / @column_max, 32)
  4913. self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
  4914. self.contents.draw_text(rect, @commands[i], 1)
  4915. end
  4916. #----------------------------------------------------------------------------
  4917. # Updates the cursor rectangle.
  4918. #----------------------------------------------------------------------------
  4919. def update_cursor_rect
  4920. # if no cursor position
  4921. if @index < 0
  4922. self.cursor_rect.empty
  4923. return
  4924. end
  4925. # match rows
  4926. row = @index / @column_max
  4927. self.top_row = row if row < self.top_row
  4928. if row > self.top_row + (self.page_row_max - 1)
  4929. self.top_row = row - (self.page_row_max - 1)
  4930. end
  4931. # set cursor position
  4932. cursor_width = (self.width - 32) / @column_max
  4933. x = @index % @column_max * cursor_width
  4934. self.cursor_rect.set(x, 0, cursor_width, 32)
  4935. end
  4936.  
  4937. end
  4938.  
  4939. #==============================================================================
  4940. # Window_TradeItem
  4941. #------------------------------------------------------------------------------
  4942. # Displays items for trading.
  4943. #==============================================================================
  4944.  
  4945. class Window_TradeItem < Window_ItemList
  4946.  
  4947. # setting all accessible variables
  4948. attr_reader :item_max
  4949. attr_reader :items
  4950. #----------------------------------------------------------------------------
  4951. # Initialization
  4952. #----------------------------------------------------------------------------
  4953. def initialize
  4954. super
  4955. # setup dimensions
  4956. self.y, self.z = 64, 11000
  4957. self.width, self.height = 320, 192
  4958. # initialize
  4959. @column_max = 1
  4960. self.active = false
  4961. self.cursor_rect.empty
  4962. # refresh display
  4963. refresh
  4964. end
  4965. #----------------------------------------------------------------------------
  4966. # Draws the data on the window.
  4967. #----------------------------------------------------------------------------
  4968. def refresh
  4969. # if bitmap exists
  4970. if self.contents != nil
  4971. # delete bitmap
  4972. self.contents.dispose
  4973. self.contents = nil
  4974. end
  4975. # set up all items for display
  4976. setup_items
  4977. # if there are any items
  4978. if @item_max > 0
  4979. # create bitmap
  4980. self.contents = Bitmap.new(width - 32, @item_max * 32)
  4981. # if using Dyna Edition scripts
  4982. if $fontface != nil
  4983. # set font name and size
  4984. self.contents.font.name = $fontface
  4985. self.contents.font.size = $fontsize
  4986. # if using PK Edition 2
  4987. elsif $defaultfonttype != nil
  4988. # set font name and size
  4989. self.contents.font.name = $defaultfonttype
  4990. self.contents.font.size = $defaultfontsize
  4991. end
  4992. # draws all items
  4993. draw_items
  4994. end
  4995. end
  4996. #----------------------------------------------------------------------------
  4997. # Sets up all items displayed.
  4998. #----------------------------------------------------------------------------
  4999. def setup_items
  5000. # empty data
  5001. @data = [0] # this is gold!
  5002. @items = {}
  5003. # iterate through all items without the no-trade items
  5004. ((1...$data_items.size).to_a - RMXOS::Data::NoTradeItems).each {|i|
  5005. # add item
  5006. @data.push($data_items[i])
  5007. }
  5008. # set size
  5009. @item_max = @data.size
  5010. end
  5011. #----------------------------------------------------------------------------
  5012. # Draws all items.
  5013. #----------------------------------------------------------------------------
  5014. def draw_items
  5015. (0...@item_max).each {|i| draw_item(i)}
  5016. end
  5017. #----------------------------------------------------------------------------
  5018. # Draws one item completely.
  5019. # i - item index
  5020. #----------------------------------------------------------------------------
  5021. def draw_item(i)
  5022. y = i * 32
  5023. # clear the display for the item
  5024. self.contents.fill_rect(Rect.new(4, y, 288, 32), Color.new(0, 0, 0, 0))
  5025. # draw icon bitmap if not gold
  5026. if @data[i] != 0
  5027. bitmap = RPG::Cache.icon(@data[i].icon_name)
  5028. opacity = self.contents.font.color == normal_color ? 255 : 128
  5029. self.contents.blt(4, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
  5030. end
  5031. self.contents.font.color = normal_color
  5032. # draw item/gold name
  5033. name = (@data[i] != 0 ? @data[i].name : $data_system.words.gold)
  5034. self.contents.draw_text(32, y, 212, 32, name)
  5035. self.draw_item_remaining(i)
  5036. end
  5037. #----------------------------------------------------------------------------
  5038. # Draws the remaining number of an item.
  5039. # i - item index
  5040. #----------------------------------------------------------------------------
  5041. def draw_item_remaining(i)
  5042. y = i * 32
  5043. # if not gold
  5044. if @data[i] != 0
  5045. # draw number of items left
  5046. self.contents.draw_text(244, y, 16, 32, ':', 1)
  5047. number = $game_party.item_number(@data[i].id)
  5048. self.contents.draw_text(260, y, 24, 32, number.to_s, 2)
  5049. else
  5050. # draw gold left
  5051. self.contents.draw_text(188, y, 96, 96, $game_party.gold.to_s, 2)
  5052. end
  5053. end
  5054.  
  5055. end
  5056.  
  5057. #==============================================================================
  5058. # Window_TradePlayer
  5059. #------------------------------------------------------------------------------
  5060. # Displays items selected for trading.
  5061. #==============================================================================
  5062.  
  5063. class Window_TradePlayer < Window_TradeItem
  5064.  
  5065. #----------------------------------------------------------------------------
  5066. # Adds a selection counter for items.
  5067. #----------------------------------------------------------------------------
  5068. def setup_items
  5069. super
  5070. # for each item
  5071. @data.each_index {|i|
  5072. # if not gold
  5073. if @data[i] != 0
  5074. # set up values
  5075. id = @data[i].id
  5076. number = $game_party.item_number(@data[i].id)
  5077. else
  5078. # set up gold values
  5079. id = 0
  5080. number = $game_party.gold
  5081. end
  5082. # if in possession
  5083. if number > 0
  5084. # initialize number of that item
  5085. @items[id] = 0
  5086. else
  5087. # delete item
  5088. @data[i] = nil
  5089. end
  5090. }
  5091. # remove all nil values
  5092. @data.compact!
  5093. # set size and autocorrect index
  5094. @item_max = @data.size
  5095. @index = @item_max - 1 if @index >= @item_max
  5096. end
  5097. #----------------------------------------------------------------------------
  5098. # Increases the quantity of an item to trade.
  5099. # value - by how much
  5100. # Returns: Whether the quantity was changed or not.
  5101. #----------------------------------------------------------------------------
  5102. def increase_quantity(value)
  5103. # if not gold
  5104. if @data[@index] != 0
  5105. # set up values
  5106. id = @data[@index].id
  5107. number = $game_party.item_number(@data[@index].id)
  5108. else
  5109. # set up gold values
  5110. id = 0
  5111. number = $game_party.gold
  5112. end
  5113. value = number - @items[id] if value > number - @items[id]
  5114. # increase
  5115. if @items[id] < number
  5116. @items[id] += value
  5117. self.draw_item(@index)
  5118. return true
  5119. end
  5120. return false
  5121. end
  5122. #----------------------------------------------------------------------------
  5123. # Decreases the quantity of an item to trade.
  5124. # value - by how much
  5125. # Returns: Whether the quantity was changed or not.
  5126. #----------------------------------------------------------------------------
  5127. def decrease_quantity(value)
  5128. # if not gold
  5129. if @data[@index] != 0
  5130. # set up values
  5131. id = @data[@index].id
  5132. number = $game_party.item_number(@data[@index].id)
  5133. else
  5134. # set up gold values
  5135. id = 0
  5136. number = $game_party.gold
  5137. end
  5138. value = @items[id] if value > @items[id]
  5139. # decrease
  5140. if @items[id] > 0
  5141. @items[id] -= value
  5142. self.draw_item(@index)
  5143. return true
  5144. end
  5145. return false
  5146. end
  5147. #----------------------------------------------------------------------------
  5148. # Draws the remaining number of an item.
  5149. # i - item index
  5150. #----------------------------------------------------------------------------
  5151. def draw_item_remaining(i)
  5152. y = i * 32
  5153. # if not gold
  5154. if @data[i] != 0
  5155. # draw number of items left
  5156. self.contents.draw_text(220, y, 24, 32, @items[@data[i].id].to_s, 2)
  5157. self.contents.draw_text(244, y, 16, 32, '/', 1)
  5158. number = $game_party.item_number(@data[i].id)
  5159. self.contents.draw_text(260, y, 24, 32, number.to_s, 2)
  5160. else
  5161. # draw number of items left
  5162. self.contents.draw_text(100, y, 84, 32, @items[0].to_s, 2)
  5163. self.contents.draw_text(184, y, 16, 32, '/', 1)
  5164. self.contents.draw_text(200, y, 84, 32, $game_party.gold.to_s, 2)
  5165. end
  5166. end
  5167.  
  5168. end
  5169.  
  5170. #==============================================================================
  5171. # Window_TradePartner
  5172. #------------------------------------------------------------------------------
  5173. # Displays items from the other player selected for trading.
  5174. #==============================================================================
  5175.  
  5176. class Window_TradePartner < Window_TradeItem
  5177.  
  5178. #----------------------------------------------------------------------------
  5179. # Initialization
  5180. #----------------------------------------------------------------------------
  5181. def initialize
  5182. super
  5183. self.x = 320
  5184. end
  5185. #----------------------------------------------------------------------------
  5186. # Refreshes the display upon item change.
  5187. #----------------------------------------------------------------------------
  5188. def update
  5189. super if self.active
  5190. if @items != $game_temp.trade_items
  5191. # remove 0 count items
  5192. $game_temp.trade_items.keys.each {|i|
  5193. $game_temp.trade_items.delete(i) if $game_temp.trade_items[i] == 0
  5194. }
  5195. # refresh the display
  5196. setup_items
  5197. refresh
  5198. end
  5199. end
  5200. #----------------------------------------------------------------------------
  5201. # Adds a selection counter for items.
  5202. #----------------------------------------------------------------------------
  5203. def setup_items
  5204. super
  5205. # for each item
  5206. @data.each_index {|i|
  5207. # that is not in the list
  5208. id = (@data[i] != 0 ? @data[i].id : 0)
  5209. if $game_temp.trade_items[id] == nil
  5210. # delete it
  5211. @data[i] = nil
  5212. end
  5213. }
  5214. # remove all nil values
  5215. @data.compact!
  5216. # set number of that item
  5217. @items = $game_temp.trade_items
  5218. # set size and autocorrect index
  5219. @item_max = @data.size
  5220. @index = @item_max - 1 if @index >= @item_max
  5221. end
  5222. #----------------------------------------------------------------------------
  5223. # Draws the remaining number of an item.
  5224. # i - item index
  5225. #----------------------------------------------------------------------------
  5226. def draw_item_remaining(i)
  5227. y = i * 32
  5228. # if not gold
  5229. if @data[i] != 0
  5230. # draw number of items
  5231. self.contents.draw_text(244, y, 16, 32, ':', 1)
  5232. self.contents.draw_text(260, y, 24, 32, @items[@data[i].id].to_s, 2)
  5233. else
  5234. # draw number of gold
  5235. self.contents.draw_text(200, y, 84, 32, @items[0].to_s, 2)
  5236. end
  5237. end
  5238.  
  5239. end
  5240.  
  5241. #==============================================================================
  5242. # Scene_BaseRMXOS
  5243. #------------------------------------------------------------------------------
  5244. # Serves as superclass for special scenes used in RMX-OS. This class is used
  5245. # for consistency, a stable framework and reusability to minimize the amount
  5246. # of coding that needs to be done. It is an abstract class and should not be
  5247. # instantiated as such.
  5248. #==============================================================================
  5249.  
  5250. class Scene_BaseRMXOS
  5251.  
  5252. #----------------------------------------------------------------------------
  5253. # Main loop for RMX-OS scenes.
  5254. #----------------------------------------------------------------------------
  5255. def main
  5256. setup_scene
  5257. create_scene
  5258. start_scene
  5259. loop do
  5260. Graphics.update
  5261. Input.update
  5262. update
  5263. break if SceneManager.scene != self
  5264. end
  5265. finish_scene
  5266. finalize_scene
  5267. dispose_scene
  5268. end
  5269. #----------------------------------------------------------------------------
  5270. # Sets up different parameters used in the scene. Abstract method.
  5271. #----------------------------------------------------------------------------
  5272. def setup_scene
  5273. end
  5274. #----------------------------------------------------------------------------
  5275. # Sets up visual elements of a scene. Abstract method.
  5276. #----------------------------------------------------------------------------
  5277. def create_scene
  5278. end
  5279. #----------------------------------------------------------------------------
  5280. # Starts the scene.
  5281. #----------------------------------------------------------------------------
  5282. def start_scene
  5283. Graphics.transition(10)
  5284. end
  5285. #----------------------------------------------------------------------------
  5286. # Finishes the scene.
  5287. #----------------------------------------------------------------------------
  5288. def finish_scene
  5289. Graphics.freeze
  5290. end
  5291. #----------------------------------------------------------------------------
  5292. # Finalizes all non-visual data in the scene. Abstract method.
  5293. #----------------------------------------------------------------------------
  5294. def finalize_scene
  5295. end
  5296. #----------------------------------------------------------------------------
  5297. # Disposes all visual elements of the scene. Abstract method.
  5298. #----------------------------------------------------------------------------
  5299. def dispose_scene
  5300. end
  5301. #----------------------------------------------------------------------------
  5302. # Updates the scene's behavior.
  5303. #----------------------------------------------------------------------------
  5304. def update
  5305. SceneManager.exit if Input.trigger?(Input::B)
  5306. end
  5307.  
  5308. end
  5309.  
  5310. #==============================================================================
  5311. # Scene_Network
  5312. #------------------------------------------------------------------------------
  5313. # Serves as superclass for all network based scenes during the connection to
  5314. # the server.
  5315. #==============================================================================
  5316.  
  5317. class Scene_Network < Scene_BaseRMXOS
  5318.  
  5319. #----------------------------------------------------------------------------
  5320. # Initialization.
  5321. # helptext - the text displayed initially in the help window.
  5322. #----------------------------------------------------------------------------
  5323. def initialize(helptext)
  5324. @helptext = helptext
  5325. end
  5326. #----------------------------------------------------------------------------
  5327. # Adds a wait count.
  5328. #----------------------------------------------------------------------------
  5329. def setup_scene
  5330. super
  5331. @wait_count = 0
  5332. end
  5333.  
  5334. #--------------------------------------------------------------------------
  5335. # * Move Sprite to Screen Center
  5336. #--------------------------------------------------------------------------
  5337. def center_sprite(sprite)
  5338. sprite.ox = sprite.bitmap.width / 2
  5339. sprite.oy = sprite.bitmap.height / 2
  5340. sprite.x = Graphics.width / 2
  5341. sprite.y = Graphics.height / 2
  5342. end
  5343.  
  5344. #--------------------------------------------------------------------------
  5345. # * Create Background
  5346. #--------------------------------------------------------------------------
  5347. def create_background
  5348. @sprite1 = Sprite.new
  5349. @sprite1.bitmap = Cache.title1($data_system.title1_name)
  5350. @sprite2 = Sprite.new
  5351. @sprite2.bitmap = Cache.title2($data_system.title2_name)
  5352. center_sprite(@sprite1)
  5353. center_sprite(@sprite2)
  5354. end
  5355.  
  5356. #----------------------------------------------------------------------------
  5357. # Creates a title screen background, a version display and a help window.
  5358. #----------------------------------------------------------------------------
  5359. def create_scene
  5360. # play the title music
  5361. $data_system.title_bgm.play
  5362. # stop playing ME and BGS
  5363. Audio.me_stop
  5364. Audio.bgs_stop
  5365. # load the title screen
  5366. create_background
  5367. # create a sprite displaying the version of RMX-OS
  5368. @version = Sprite.new
  5369. @version.x, @version.y = 4, Graphics.height - 32
  5370. @version.bitmap = Bitmap.new(160, 32)
  5371. # if using Dyna Edition scripts
  5372. if $fontface != nil
  5373. # set font name and size
  5374. @version.bitmap.font.name = $fontface
  5375. # if using PK Edition 2
  5376. elsif $defaultfonttype != nil
  5377. # set font name and size
  5378. @version.bitmap.font.name = $defaultfonttype
  5379. end
  5380. @version.bitmap.font.name = 'Arial'
  5381. @version.bitmap.font.size = 24
  5382. @version.bitmap.draw_text(4, 0, 152, 32,
  5383. "#{RMXOS::Data::Version}: #{RMXOS::Options::GAME_VERSION}")
  5384. # create help window
  5385. @help_window = Window_Help.new
  5386. @help_window.set_text(@helptext)
  5387. end
  5388. #----------------------------------------------------------------------------
  5389. # Disposes title screen background and a version display.
  5390. #----------------------------------------------------------------------------
  5391. def dispose_scene
  5392. super
  5393. @sprite1.bitmap.dispose
  5394. @sprite2.bitmap.dispose
  5395. @sprite1.dispose
  5396. @sprite2.dispose
  5397. @version.dispose
  5398. @help_window.dispose
  5399. end
  5400. #----------------------------------------------------------------------------
  5401. # Wait for the server to respond to a request. Abstract method.
  5402. # Returns: True or false.
  5403. #----------------------------------------------------------------------------
  5404. def waiting_for_server
  5405. return false
  5406. end
  5407. #----------------------------------------------------------------------------
  5408. # Wait for the server to respond to a request. Abstract method.
  5409. # Returns: True or false.
  5410. #----------------------------------------------------------------------------
  5411. def waiting?
  5412. # if waiting timer active
  5413. if @wait_count > 0
  5414. @wait_count -= 1
  5415. # if timer expired
  5416. if @wait_count == 0
  5417. # server did not respond
  5418. p RMXOS::Data::NoResponse
  5419. return true
  5420. end
  5421. # skip update if waiting for server
  5422. return true if waiting_for_server
  5423. @wait_count = 0
  5424. end
  5425. return false
  5426. end
  5427.  
  5428. end
  5429.  
  5430. #==============================================================================
  5431. # Scene_Servers
  5432. #------------------------------------------------------------------------------
  5433. # Displays a connection dialog to connect to an existing server.
  5434. #==============================================================================
  5435.  
  5436. class Scene_Servers < Scene_Network
  5437.  
  5438. #----------------------------------------------------------------------------
  5439. # Initialization.
  5440. #----------------------------------------------------------------------------
  5441. def initialize
  5442. super(RMXOS::Data::SelectServer)
  5443. end
  5444. #----------------------------------------------------------------------------
  5445. # Adds several variables used in this scene.
  5446. #----------------------------------------------------------------------------
  5447. def setup_scene
  5448. super
  5449. @refresh_count = 1
  5450. @server_states = []
  5451. # for each server add a server state and test state text
  5452. RMXOS::Options::SERVERS.size.times {@server_states.push(false)}
  5453. end
  5454.  
  5455. def exit_handler
  5456. Sound.play_ok
  5457. SceneManager.exit
  5458. end
  5459.  
  5460. def server_handler
  5461. # if selected server is tested to be online
  5462. if @server_states[@server_window.index]
  5463. Sound.play_ok
  5464. @online_window.draw_command(@server_window.index, RMXOS::Data::Connecting)
  5465. Graphics.update
  5466. # get data
  5467. server = RMXOS::Options::SERVERS[@server_window.index]
  5468. $network.start_connection(server.host, server.port)
  5469. $network.request_connection
  5470. # set waiting timer for server answer
  5471. @wait_count = RMXOS::Options::SERVER_TIMEOUT
  5472. @refresh_count = RMXOS::Options::SERVER_REFRESH
  5473. else
  5474. Sound.play_buzzer
  5475. end
  5476. end
  5477.  
  5478. #----------------------------------------------------------------------------
  5479. # Creates a display for available servers and whether they are online or not.
  5480. #----------------------------------------------------------------------------
  5481. def create_scene
  5482. super
  5483. # get all server names
  5484. server_names = []
  5485. RMXOS::Options::SERVERS.each {|server| server_names.push(server.name)}
  5486. server_names.push(RMXOS::Data::Exit)
  5487. # create server selection window
  5488. @server_window = Window_ServerCommand.new(224, server_names)
  5489. @server_window.x = 32
  5490. @server_window.y = (Graphics.height - @server_window.height) / 2
  5491. @server_window.y = 96 if @server_window.y < 96
  5492. if @server_window.height > Graphics.height - 128
  5493. @server_window.height = Graphics.height - 128
  5494. end
  5495. server_names.each do |name|
  5496. next if name == RMXOS::Data::Exit
  5497. @server_window.set_handler(name, method(:server_handler))
  5498. end
  5499. @server_window.set_handler(RMXOS::Data::Exit, method(:exit_handler))
  5500.  
  5501. @server_window.active = true
  5502. @server_window.index = 0
  5503. # create server states window
  5504. states = []
  5505. @server_states.size.times {states.push(RMXOS::Data::ServerOffline)}
  5506. @online_window = Window_ServerCommand.new(
  5507. Graphics.width - 320, states)
  5508. @online_window.x, @online_window.y = 288, @server_window.y
  5509. if @online_window.height > Graphics.height - 160
  5510. @online_window.height = Graphics.height - 160
  5511. end
  5512. @online_window.active = false
  5513. @online_window.index = -1
  5514. end
  5515. #----------------------------------------------------------------------------
  5516. # Refreshes the online status of the servers.
  5517. #----------------------------------------------------------------------------
  5518. def refresh_server_states
  5519. states = self.make_server_states
  5520. @online_window.set_commands(states)
  5521. Graphics.update
  5522. end
  5523. #----------------------------------------------------------------------------
  5524. # Refreshes the online status of the servers.
  5525. #----------------------------------------------------------------------------
  5526. def make_server_states
  5527. states = []
  5528. RMXOS::Options::SERVERS.each_index {|i|
  5529. # add online/offline text
  5530. states.push(@server_states[i] ? RMXOS::Data::ServerOnline :
  5531. RMXOS::Data::ServerOffline)
  5532. }
  5533. # for each server
  5534. RMXOS::Options::SERVERS.each_index {|i|
  5535. # this server is being tested now
  5536. states[i] = RMXOS::Data::ServerTesting
  5537. # refresh server display
  5538. @online_window.set_commands(states)
  5539. Graphics.update
  5540. # if server is actually available
  5541. if @server_states[i] != nil
  5542. # get connection data
  5543. server = RMXOS::Options::SERVERS[i]
  5544. # test connection to server and store the result
  5545. @server_states[i] = $network.test_connection(server.host, server.port, i)
  5546. # add online/offline text
  5547. if @server_states[i]
  5548. states[i] = RMXOS::Data::ServerOnline
  5549. else
  5550. states[i] = RMXOS::Data::ServerOffline
  5551. end
  5552. else
  5553. states[i] = RMXOS::Data::ServerOffline
  5554. end
  5555. }
  5556. return states
  5557. end
  5558. #----------------------------------------------------------------------------
  5559. # Disposes the windows.
  5560. #----------------------------------------------------------------------------
  5561. def dispose_scene
  5562. super
  5563. @server_window.dispose
  5564. @online_window.dispose
  5565. end
  5566. #----------------------------------------------------------------------------
  5567. # Updates the scene's behavior.
  5568. #----------------------------------------------------------------------------
  5569. def update
  5570. return if waiting?
  5571. # check for server connections
  5572. check_server_states
  5573. @server_window.update
  5574. @online_window.oy = @server_window.oy
  5575. # if pressed cancel
  5576. if Input.trigger?(Input::B)
  5577. # exit
  5578. Sound.play_cancel
  5579. SceneManager.exit
  5580. end
  5581. end
  5582. #----------------------------------------------------------------------------
  5583. # Checks for server connections when necessary.
  5584. #----------------------------------------------------------------------------
  5585. def check_server_states
  5586. # decrease timer
  5587. @refresh_count -= 1
  5588. # if timer expired
  5589. if @refresh_count <= 0 || Input.trigger?(Input::F5)
  5590. refresh_server_states
  5591. # renew timer
  5592. @refresh_count = RMXOS::Options::SERVER_REFRESH
  5593. end
  5594. end
  5595. #----------------------------------------------------------------------------
  5596. # Wait for server to answer to the requested data.
  5597. # Returns: Whether to skip the rest of the update or not.
  5598. #----------------------------------------------------------------------------
  5599. def waiting_for_server
  5600. $network.listen
  5601. # check each message
  5602. $network.messages.each {|message|
  5603. case message
  5604. when RMXOS::CONNECTION_SUCCESS # connection granted
  5605. # proceed to login
  5606. SceneManager.goto Scene_Login
  5607. return false
  5608. when RMXOS::CONNECTION_DENIED # server is full
  5609. # disconnect from server
  5610. $network.disconnect
  5611. # show error
  5612. @online_window.draw_command(@server_window.index,
  5613. RMXOS::Error::ServerFull, RMXOS::Data::ColorServerError)
  5614. return false
  5615. when RMXOS::CONNECTION_CLIENT_VERSION # client version does not match
  5616. # disconnect from server
  5617. $network.disconnect
  5618. # show error
  5619. @online_window.draw_command(@server_window.index,
  5620. RMXOS::Error.get_client_version_error, RMXOS::Data::ColorServerError)
  5621. return false
  5622. when RMXOS::CONNECTION_GAME_VERSION # game version does not match
  5623. # disconnect from server
  5624. $network.disconnect
  5625. # show error
  5626. @online_window.draw_command(@server_window.index,
  5627. RMXOS::Error.get_game_version_error, RMXOS::Data::ColorServerError)
  5628. return false
  5629. end
  5630. }
  5631. return true
  5632. end
  5633.  
  5634. end
  5635.  
  5636. #==============================================================================
  5637. # Scene_UserPass
  5638. #------------------------------------------------------------------------------
  5639. # Handles scenes where the player is prompted for a username and password.
  5640. # This class is abstract and should not be instantiated as such.
  5641. #==============================================================================
  5642.  
  5643. class Scene_UserPass < Scene_Network
  5644.  
  5645. #----------------------------------------------------------------------------
  5646. # Creates all necessary visuals.
  5647. #----------------------------------------------------------------------------
  5648. def create_scene
  5649. super
  5650. create_windows
  5651. create_buttons
  5652. end
  5653. #----------------------------------------------------------------------------
  5654. # Creates all windows.
  5655. #----------------------------------------------------------------------------
  5656. def create_windows
  5657. @input_frames = []
  5658. y, h1, h2 = self._get_window_ys
  5659. # create username and password windows
  5660. @username_window = Frame_Caption.new(32, y,
  5661. Graphics.width - 64, RMXOS::Data::Username)
  5662. @password_window = Frame_Caption.new(32, y + 32 + h1,
  5663. Graphics.width - 64, RMXOS::Data::Password)
  5664. @password_window.password_char = RMXOS::Data::PassChar
  5665. @password_window.active = false
  5666. @input_frames.push(@username_window)
  5667. @input_frames.push(@password_window)
  5668. end
  5669. #----------------------------------------------------------------------------
  5670. # Prepares button array.
  5671. #----------------------------------------------------------------------------
  5672. def create_buttons
  5673. @buttons = []
  5674. end
  5675. #----------------------------------------------------------------------------
  5676. # Removes all visuals.
  5677. #----------------------------------------------------------------------------
  5678. def dispose_scene
  5679. super
  5680. @input_frames.each {|window| window.dispose}
  5681. @buttons.each {|button| button.dispose}
  5682. end
  5683. #----------------------------------------------------------------------------
  5684. # Calculates the GUI element positions depending on screen height
  5685. # Returns: Y coordinate of first window, offset height between frames and
  5686. # additional offset height for buttons.
  5687. #----------------------------------------------------------------------------
  5688. def _get_window_ys
  5689. y, h1, h2 = 128, 32, 32
  5690. if Graphics.height < 480
  5691. y -= (480 - Graphics.height) / 2
  5692. y = 96 if y < 96
  5693. h2 = 0
  5694. if Graphics.height < 384
  5695. h1 = (Graphics.height - 288) / 3
  5696. end
  5697. end
  5698. return [y, h1, h2]
  5699. end
  5700. #----------------------------------------------------------------------------
  5701. # Updates the scene's behavior.
  5702. #----------------------------------------------------------------------------
  5703. def update
  5704. $network.listen
  5705. return if waiting?
  5706. # update username window and password window if they are active
  5707. @input_frames.each {|window| window.update if window.active}
  5708. @buttons.each {|button| button.update}
  5709. # if pressed cancel
  5710. if Input.trigger?(Input::B)
  5711. Sound.play_cancel
  5712. command_cancel
  5713. # if pressed confirm
  5714. elsif Input.trigger?(Input::C)
  5715. command_confirm
  5716. # if pressed down
  5717. elsif Input.repeat?(Input::DOWN)
  5718. command_down
  5719. # if pressed up
  5720. elsif Input.repeat?(Input::UP)
  5721. command_up
  5722. # if pressed left
  5723. elsif Input.repeat?(Input::LEFT)
  5724. command_left
  5725. # if pressed right
  5726. elsif Input.repeat?(Input::RIGHT)
  5727. command_right
  5728. end
  5729. end
  5730. #----------------------------------------------------------------------------
  5731. # Executed upon choosing the "cancel" choice. Abstract method.
  5732. #----------------------------------------------------------------------------
  5733. def command_cancel
  5734. end
  5735. #----------------------------------------------------------------------------
  5736. # Executed upon choosing the "confirm" choice.
  5737. #----------------------------------------------------------------------------
  5738. def command_confirm
  5739. # if confirm button active
  5740. if @buttons[0].index == 0
  5741. Sound.play_ok
  5742. submit_to_server
  5743. # if cancel button active
  5744. elsif @buttons[@buttons.size - 1].index == 0
  5745. Sound.play_ok
  5746. command_cancel
  5747. # if bottom input frame is active
  5748. elsif @input_frames[@input_frames.size - 1].active
  5749. Sound.play_ok
  5750. submit_to_server
  5751. # if username window active
  5752. else
  5753. # switch to next input frame if possible
  5754. window = @input_frames.find {|w| w.active}
  5755. if window != nil
  5756. Sound.play_ok
  5757. window.active = false
  5758. @input_frames[@input_frames.index(window) + 1].active = true
  5759. end
  5760. end
  5761. end
  5762. #----------------------------------------------------------------------------
  5763. # Submits data to the server.
  5764. #----------------------------------------------------------------------------
  5765. def submit_to_server
  5766. @wait_count = RMXOS::Options::SERVER_TIMEOUT
  5767. end
  5768. #----------------------------------------------------------------------------
  5769. # Saves current username and password.
  5770. #----------------------------------------------------------------------------
  5771. def save_user_pass
  5772. # if login remember option is on
  5773. if RMXOS::Options::REMEMBER_LOGIN
  5774. # create data stream
  5775. stream = "#{@username_window.text}\t#{@password_window.text}"
  5776. # zip stream
  5777. rawdata = Zlib::Deflate.deflate(stream, 9)
  5778. # save stream into file
  5779. file = File.open('account.dat', 'wb')
  5780. file.write(rawdata)
  5781. file.close
  5782. end
  5783. end
  5784. #----------------------------------------------------------------------------
  5785. # Executed upon pressing "down".
  5786. #----------------------------------------------------------------------------
  5787. def command_down
  5788. Sound.play_cursor
  5789. # if last frame active
  5790. if @input_frames[@input_frames.size - 1].active
  5791. @input_frames[@input_frames.size - 1].active = false
  5792. @buttons[0].index = 0
  5793. else
  5794. # switch to next input frame if possible
  5795. window = @input_frames.find {|w| w.active}
  5796. if window != nil
  5797. window.active = false
  5798. @input_frames[@input_frames.index(window) + 1].active = true
  5799. else
  5800. # switch to username window
  5801. @buttons.each {|button| button.index = -1}
  5802. @input_frames[0].active = true
  5803. end
  5804. end
  5805. end
  5806. #----------------------------------------------------------------------------
  5807. # Executed upon pressing "up".
  5808. #----------------------------------------------------------------------------
  5809. def command_up
  5810. Sound.play_cursor
  5811. # if last frame active
  5812. if @input_frames[0].active
  5813. @input_frames[0].active = false
  5814. @buttons[0].index = 0
  5815. else
  5816. # switch to next input frame if possible
  5817. window = @input_frames.find {|w| w.active}
  5818. if window != nil
  5819. window.active = false
  5820. @input_frames[@input_frames.index(window) - 1].active = true
  5821. else
  5822. # switch to username window
  5823. @buttons.each {|button| button.index = -1}
  5824. @input_frames[@input_frames.size - 1].active = true
  5825. end
  5826. end
  5827. end
  5828. #----------------------------------------------------------------------------
  5829. # Executed upon pressing "left".
  5830. #----------------------------------------------------------------------------
  5831. def command_left
  5832. # check each button
  5833. @buttons.each_index {|i|
  5834. # if active
  5835. if @buttons[i].index == 0
  5836. Sound.play_cursor
  5837. # circularry switch to the left button
  5838. @buttons[i].index = -1
  5839. @buttons[(i + @buttons.size - 1) % @buttons.size].index = 0
  5840. return
  5841. end
  5842. }
  5843. end
  5844. #----------------------------------------------------------------------------
  5845. # Executed upon pressing "right".
  5846. #----------------------------------------------------------------------------
  5847. def command_right
  5848. # check each button
  5849. @buttons.each_index {|i|
  5850. # if active
  5851. if @buttons[i].index == 0
  5852. Sound.play_cursor
  5853. # circularry switch to the right button
  5854. @buttons[i].index = -1
  5855. @buttons[(i + 1) % @buttons.size].index = 0
  5856. return
  5857. end
  5858. }
  5859. end
  5860.  
  5861. end
  5862.  
  5863. #==============================================================================
  5864. # Scene_Login
  5865. #------------------------------------------------------------------------------
  5866. # Handles logging in of a player.
  5867. #==============================================================================
  5868.  
  5869. class Scene_Login < Scene_UserPass
  5870.  
  5871. #----------------------------------------------------------------------------
  5872. # Initialization.
  5873. #----------------------------------------------------------------------------
  5874. def initialize
  5875. super(RMXOS::Data::EnterUserPass)
  5876. end
  5877. #----------------------------------------------------------------------------
  5878. # Makes the password characters disappear and loads account.dat.
  5879. #----------------------------------------------------------------------------
  5880. def create_windows
  5881. super
  5882. # stop if not active or file doesn't exist
  5883. return if !RMXOS::Options::REMEMBER_LOGIN || !FileTest.exist?('account.dat')
  5884. # read data from file
  5885. file = File.open('account.dat', 'rb')
  5886. rawdata = file.read
  5887. file.close
  5888. # stop if file was empty
  5889. return if rawdata.size == 0
  5890. begin
  5891. # unzip data from file
  5892. lines = Zlib::Inflate.inflate(rawdata).split("\t")
  5893. # if file data is valid
  5894. if lines.size == 2
  5895. # set read username and password
  5896. @username_window.text, @password_window.text = lines
  5897. @username_window.cursor_move_to_end
  5898. @username_window.update_cursor
  5899. @password_window.cursor_move_to_end
  5900. end
  5901. rescue
  5902. end
  5903. end
  5904. #----------------------------------------------------------------------------
  5905. # Creates all buttons.
  5906. #----------------------------------------------------------------------------
  5907. def create_buttons
  5908. super
  5909. y, h1, h2 = self._get_window_ys
  5910. y += 96 + h1 * 3 + h2
  5911. w = (Graphics.width - 64) / 3
  5912. # create Login button
  5913. @buttons.push(Window_Button.new(32, y, w, RMXOS::Data::Login))
  5914. # create Register button
  5915. @buttons.push(Window_Button.new(32 + w, y, w, RMXOS::Data::Register))
  5916. # create Cancel button
  5917. @buttons.push(Window_Button.new(32 + w * 2, y, w, RMXOS::Data::Cancel))
  5918. end
  5919. #----------------------------------------------------------------------------
  5920. # Executed upon choosing the "cancel" choice.
  5921. #----------------------------------------------------------------------------
  5922. def command_cancel
  5923. # disconnect
  5924. $network.disconnect
  5925. # return to server selection
  5926. SceneManager.goto Scene_Servers
  5927. end
  5928. #----------------------------------------------------------------------------
  5929. # Executed upon choosing the "confirm" choice.
  5930. #----------------------------------------------------------------------------
  5931. def command_confirm
  5932. # if register button is active
  5933. if @buttons[1].index == 0
  5934. # proceed to registering
  5935. Sound.play_ok
  5936. SceneManager.goto Scene_Register
  5937. else
  5938. super
  5939. end
  5940. end
  5941. #----------------------------------------------------------------------------
  5942. # Submits the player login request to the server.
  5943. #----------------------------------------------------------------------------
  5944. def submit_to_server
  5945. # try to login
  5946. $network.try_login(@username_window.text, @password_window.text)
  5947. # show waiting message
  5948. @help_window.set_text(RMXOS::Data::LoggingIn)
  5949. super
  5950. end
  5951. #----------------------------------------------------------------------------
  5952. # Wait for server to answer to the requested data.
  5953. # Returns: Whether to skip the rest of the update or not.
  5954. #----------------------------------------------------------------------------
  5955. def waiting_for_server
  5956. # check each message
  5957. $network.messages.each {|message|
  5958. case message
  5959. when RMXOS::LOGIN_SUCCESS # login was a success
  5960. # display messsage
  5961. @help_window.set_text(RMXOS::Data::LoggedIn)
  5962. # save username and password
  5963. save_user_pass
  5964. # proceed to game
  5965. SceneManager.goto Scene_Loading
  5966. return false
  5967. when RMXOS::LOGIN_NOUSER # username does not exist
  5968. # display messsage
  5969. @help_window.set_text(RMXOS::Data::NoUsername)
  5970. return false
  5971. when RMXOS::LOGIN_NOPASS # wrong password
  5972. # display messsage
  5973. @help_window.set_text(RMXOS::Data::WrongPassword)
  5974. return false
  5975. when RMXOS::LOGIN_BANNED # banned
  5976. # display messsage
  5977. @help_window.set_text(RMXOS::Data::Banned)
  5978. return false
  5979. end
  5980. }
  5981. return true
  5982. end
  5983.  
  5984. end
  5985.  
  5986. #==============================================================================
  5987. # Scene_Register
  5988. #------------------------------------------------------------------------------
  5989. # Handles registering of a player.
  5990. #==============================================================================
  5991.  
  5992. class Scene_Register < Scene_UserPass
  5993.  
  5994. #----------------------------------------------------------------------------
  5995. # Initialization.
  5996. #----------------------------------------------------------------------------
  5997. def initialize
  5998. super(RMXOS::Data::RegisterUserPass)
  5999. end
  6000. #----------------------------------------------------------------------------
  6001. # Creates all windows.
  6002. #----------------------------------------------------------------------------
  6003. def create_windows
  6004. super
  6005. @confirm_window = Frame_Caption.new(
  6006. @password_window.x, @password_window.y * 2 - @username_window.y,
  6007. @password_window.width, RMXOS::Data::Repeat)
  6008. @confirm_window.password_char = RMXOS::Data::PassChar
  6009. @confirm_window.active = false
  6010. @input_frames.push(@confirm_window)
  6011. end
  6012. #----------------------------------------------------------------------------
  6013. # Creates all buttons.
  6014. #----------------------------------------------------------------------------
  6015. def create_buttons
  6016. super
  6017. y, h1, h2 = self._get_window_ys
  6018. y += 96 + h1 * 3 + h2
  6019. w = (Graphics.width - 64) / 2
  6020. # create Submit button
  6021. @buttons.push(Window_Button.new(32, y, w, RMXOS::Data::Submit))
  6022. # create Cancel button
  6023. @buttons.push(Window_Button.new(32 + w, y, w, RMXOS::Data::Cancel))
  6024. end
  6025. #----------------------------------------------------------------------------
  6026. # Executed upon choosing the "cancel" choice.
  6027. #----------------------------------------------------------------------------
  6028. def command_cancel
  6029. SceneManager.goto Scene_Login
  6030. end
  6031. #----------------------------------------------------------------------------
  6032. # Submits the player register request to the server.
  6033. #----------------------------------------------------------------------------
  6034. def submit_to_server
  6035. # if username too short
  6036. if @username_window.text.size < RMXOS::Options::USERPASS_MIN_LENGTH
  6037. @help_window.set_text(RMXOS::Data::UserTooShort)
  6038. # if username is reserved
  6039. elsif RMXOS.reserved_username?(@username_window.text)
  6040. @help_window.set_text(RMXOS::Data::UserReserved)
  6041. # if password too short
  6042. elsif @password_window.text.size < RMXOS::Options::USERPASS_MIN_LENGTH
  6043. @help_window.set_text(RMXOS::Data::PassTooShort)
  6044. # if password not repeated properly
  6045. elsif @password_window.text != @confirm_window.text
  6046. @help_window.set_text(RMXOS::Data::PassNotRepeated)
  6047. else
  6048. # try to register
  6049. $network.try_register(@username_window.text, @password_window.text)
  6050. # show waiting message
  6051. @help_window.set_text(RMXOS::Data::Registering)
  6052. super
  6053. end
  6054. end
  6055. #----------------------------------------------------------------------------
  6056. # Wait for server to answer to the requested data.
  6057. # Returns: Whether to skip the rest of the update or not.
  6058. #----------------------------------------------------------------------------
  6059. def waiting_for_server
  6060. # check each message
  6061. $network.messages.each {|message|
  6062. case message
  6063. when RMXOS::REGISTER_SUCCESS # register was a success
  6064. # display messsage
  6065. @help_window.set_text(RMXOS::Data::UserRegistered)
  6066. # save username and password
  6067. save_user_pass
  6068. # proceed to game
  6069. SceneManager.goto Scene_Loading
  6070. return false
  6071. when RMXOS::REGISTER_BANNED # banned
  6072. # display messsage
  6073. @help_window.set_text(RMXOS::Data::Banned)
  6074. return false
  6075. when RMXOS::REGISTER_EXIST # username already exists
  6076. # display messsage
  6077. @help_window.set_text(RMXOS::Data::UserRegisteredAlready)
  6078. return false
  6079. end
  6080. }
  6081. return true
  6082. end
  6083.  
  6084. end
  6085.  
  6086. #==============================================================================
  6087. # Scene_Loading
  6088. #------------------------------------------------------------------------------
  6089. # Waits for the server to send all saved game data.
  6090. #==============================================================================
  6091.  
  6092. class Scene_Loading < Scene_Network
  6093.  
  6094. #----------------------------------------------------------------------------
  6095. # Initialization.
  6096. #----------------------------------------------------------------------------
  6097. def initialize
  6098. # send a loading request to the server pre-emptively
  6099. $network.send_load_request
  6100. if RMXOS::Options::LEGACY_SAVE_METHOD
  6101. super(RMXOS::Data::ReceivingMessageLegacy.sub('NOW', '0').sub('MAX', '???'))
  6102. else
  6103. super(RMXOS::Data::ReceivingMessage)
  6104. end
  6105. end
  6106. #----------------------------------------------------------------------------
  6107. # Waits for server to send all loading data to be able to load the game.
  6108. #----------------------------------------------------------------------------
  6109. def update
  6110. $network.listen
  6111. loading_end = false
  6112. # check each message
  6113. $network.messages.each {|message|
  6114. case message
  6115. when RMXOS::LOADING_UPDATE
  6116. size = $network.load_sizes.shift
  6117. if RMXOS::Options::LEGACY_SAVE_METHOD
  6118. text = RMXOS::Data::ReceivingMessageLegacy.sub(
  6119. 'NOW', size.to_s).sub('MAX', $network.load_size.to_s)
  6120. @help_window.set_text(text)
  6121. 5.times {Graphics.update} if size == $network.load_size
  6122. end
  6123. when RMXOS::LOADING_END # game has been loaded
  6124. @help_window.set_text(RMXOS::Data::LoadingMessage)
  6125. 5.times {Graphics.update}
  6126. loading_end = true
  6127. end
  6128. }
  6129. if loading_end
  6130. # load game and proceed to map
  6131. self.load_game
  6132. SceneManager.goto Scene_Map
  6133. end
  6134. end
  6135. #----------------------------------------------------------------------------
  6136. # Sets up the map data for a loaded game. In case the game of a newly
  6137. # registered user, a new game will be started.
  6138. #----------------------------------------------------------------------------
  6139. def load_game
  6140. # if game was loaded
  6141. if $game_map.map_id != 0
  6142. # setup map and player
  6143. $game_map.setup($game_map.map_id)
  6144. $game_player.center($game_player.x, $game_player.y)
  6145. else
  6146. # start a new game
  6147. $game_party.setup_starting_members
  6148. $game_map.setup($data_system.start_map_id)
  6149. $game_player.moveto($data_system.start_x, $data_system.start_y)
  6150. end
  6151. # prepare everything for starting the game
  6152. $game_player.refresh
  6153. $game_map.autoplay
  6154. $game_temp.entering_map = true
  6155. $game_map.update
  6156. $network.game_loaded = true
  6157. end
  6158.  
  6159. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement