Advertisement
Guest User

Untitled

a guest
Mar 28th, 2016
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 238.65 KB | None | 0 0
  1. #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
  2. # RPG Maker XP Online System (RMX-OS) VX Ace Port
  3. #------------------------------------------------------------------------------
  4. # Author: Blizzard
  5. #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
  6. #
  7. # This work is protected by the following license:
  8. # #----------------------------------------------------------------------------
  9. # #
  10. # # Creative Commons - Attribution-NonCommercial-ShareAlike 3.0 Unported
  11. # # ( http://creativecommons.org/licenses/by-nc-sa/3.0/ )
  12. # #
  13. # # You are free:
  14. # #
  15. # # to Share - to copy, distribute and transmit the work
  16. # # to Remix - to adapt the work
  17. # #
  18. # # Under the following conditions:
  19. # #
  20. # # Attribution. You must attribute the work in the manner specified by the
  21. # # author or licensor (but not in any way that suggests that they endorse you
  22. # # or your use of the work).
  23. # #
  24. # # Noncommercial. You may not use this work for commercial purposes.
  25. # #
  26. # # Share alike. If you alter, transform, or build upon this work, you may
  27. # # distribute the resulting work only under the same or similar license to
  28. # # this one.
  29. # #
  30. # # - For any reuse or distribution, you must make clear to others the license
  31. # # terms of this work. The best way to do this is with a link to this web
  32. # # page.
  33. # #
  34. # # - Any of the above conditions can be waived if you get permission from the
  35. # # copyright holder.
  36. # #
  37. # # - Nothing in this license impairs or restricts the author's moral rights.
  38. # #
  39. # #----------------------------------------------------------------------------
  40. #
  41. #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
  42. #
  43. # Information:
  44. #
  45. # There is a documentation for this system. Read it in order to learn how to
  46. # use this system. A server also comes with this system.
  47. #
  48. #
  49. # If you find any bugs, please report them here:
  50. # http://forum.chaos-project.com
  51. #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
  52.  
  53. module SceneManager
  54. def self.first_scene_class
  55. return $BTEST ? Scene_Battle : Scene_Servers
  56. end
  57. end
  58.  
  59. #==============================================================================
  60. # module RMXOS
  61. #------------------------------------------------------------------------------
  62. # Main module for all RMX-OS classes and procedures.
  63. #==============================================================================
  64.  
  65. module RMXOS
  66.  
  67. # RMX-OS version, should be changed only when server was changed to ensure
  68. # compatibility between server and client.
  69. VERSION = 2.05
  70.  
  71. # these values MUST correspond with the values specified in the server
  72. GROUP_ADMIN = 10
  73. GROUP_2NDADMIN = 9
  74. GROUP_MOD = 8
  75. GROUP_PLAYER = 0
  76.  
  77. # special permission group command sets
  78. COMMANDS = {}
  79. COMMANDS[GROUP_ADMIN] = ['admin']
  80. COMMANDS[GROUP_2NDADMIN] = ['kickall', 'mod', 'revoke', 'pass', 'gpass',
  81. 'eval', 'geval', 'seval', 'sql']
  82. COMMANDS[GROUP_MOD] = ['kick', 'ban', 'unban', 'global']
  83.  
  84. # login messages
  85. LOGIN_SUCCESS = 11
  86. LOGIN_NOUSER = 12
  87. LOGIN_NOPASS = 13
  88. LOGIN_BANNED = 14
  89. # register messages
  90. REGISTER_SUCCESS = 21
  91. REGISTER_EXIST = 22
  92. REGISTER_BANNED = 23
  93. # connection messages
  94. CONNECTION_SUCCESS = 31
  95. CONNECTION_DENIED = 32
  96. CONNECTION_CLIENT_VERSION = 33
  97. CONNECTION_GAME_VERSION = 34
  98. # loading messages
  99. LOADING_UPDATE = 41
  100. LOADING_END = 42
  101.  
  102. #============================================================================
  103. # module RMXOS::Data
  104. #----------------------------------------------------------------------------
  105. # Contains constants for all secondary configurable aspects in RMX-OS.
  106. #============================================================================
  107.  
  108. module Data
  109.  
  110. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  111. # Text constants
  112. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  113. AvailableCommands = 'Available Commands:'
  114. Banned = 'You are banned from this server.'
  115. BuddyAlreadyInList = 'Player already in buddy list.'
  116. BuddyNotInList = 'Player not in buddy list.'
  117. BuddySelfError = 'You cannot add yourself to your buddy list.'
  118. Cancel = 'Cancel'
  119. CancelingTradeAbort = 'Canceling... Press CANCEL again to abort trade.'
  120. Connecting = 'Connecting...'
  121. Disconnected = 'You have been disconnected.'
  122. EnterUserPass = 'Enter username and password.'
  123. ExecutingTrade = 'Executing trade...'
  124. Exit = 'Exit'
  125. HelpText = 'Use /help COMMAND for detailed explanations of a specific command.'
  126. GuildAlready = 'You are already in a guild.'
  127. GuildAlreadyLeader = 'You are already the guild leader.'
  128. GuildAlreadyMember = 'Player is already a member of your guild.'
  129. GuildCannotLeave = 'You are the guild leader. You cannot leave the guild unless you transfer leadership to another guild member first.'
  130. GuildNone = 'You are not in a guild.'
  131. GuildNotLeader = 'You are not the leader of your guild.'
  132. GuildNotMember = 'Player is not a member of your guild.'
  133. GuildNoTransfer = 'You have not been asked to take over leadership of your guild.'
  134. GuildReserved = 'You cannot use this name for a guild.'
  135. GuildTooLong = 'Guild name is too long.'
  136. Kicked = 'You have been kicked.'
  137. LoadingMessage = 'Loading...'
  138. LoggingIn = 'Logging in...'
  139. LoggedIn = 'Logged in.'
  140. Login = 'Login'
  141. LoginTimedOut = 'Login timed out.'
  142. NoResponse = 'Server did not respond.'
  143. NoPMsRetrieved = 'No PMs were retrieved.'
  144. NoUsername = 'Username does not exist.'
  145. OnlineTag = ' (ON)'
  146. PassChar = '*'
  147. PassTooShort = 'Password is too short.'
  148. PassNotRepeated = 'The confirmation password does not match!'
  149. Password = 'Password:'
  150. Register = 'Register'
  151. Registering = 'Registering...'
  152. RegisterUserPass = 'Register username and password.'
  153. Repeat = 'Repeat:'
  154. SelectServer = 'Select a server to connect to. Press F5 to refresh the list.'
  155. ServerOffline = 'Offline'
  156. ServerOnline = 'Online'
  157. ServerTesting = 'Testing...'
  158. Submit = 'Submit'
  159. TradeNoPlayer = 'Your trade partner is gone.'
  160. TradeSelfError = 'You cannot trade with yourself.'
  161. Username = 'Username:'
  162. UserRegistered = 'Username registered!'
  163. UserRegisteredAlready = 'Username already exists!'
  164. UserReserved = 'You cannot use this username.'
  165. UserTooShort = 'Username is too short.'
  166. Version = 'Version'
  167. WhisperNoLastName = 'You first have to use /w once before using /wr.'
  168. WrongPassword = 'Wrong password.'
  169. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  170. # Special constants
  171. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  172. BuddyList = 'Your buddies: BUDDIES'
  173. GuildInfo = 'Guild Name: GUILD; Leader: LEADER; Members: MEMBERS'
  174. PMTooLong = 'PM is COUNT characters too long.'
  175. PMInfo = 'ID:NUMBER by \'SENDER\' @ TIME'
  176. PMText = '\'SENDER\' @ TIME: MESSAGE'
  177. TradeWait = 'Waiting for \'PLAYER\'...'
  178. ReceivingMessage = 'Receiving data...'
  179. ReceivingMessageLegacy = 'Receiving: NOW / MAX'
  180. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  181. # Numeric constants
  182. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  183. CursorBlinkPeriod = 20
  184. ChatLogSize = 100
  185. ChatFontHeight = 16
  186. ChatLineEntries = 50
  187. ChatBubbleEntries = 8
  188. ChatBubbleMaxWidth = 192
  189. BubbleDisplayTime = 5
  190. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  191. # Array constants
  192. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  193. NoTradeItems = [23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
  194. TradeCommands = ['Select yours', 'View other', 'Confirm', 'Abort']
  195. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  196. # Chatbox color constants
  197. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  198. ColorAction = Color.new(0xBF, 0xFF, 0xBF)
  199. ColorError = Color.new(0xFF, 0xBF, 0x3F)
  200. ColorGlobal = Color.new(0x7F, 0xBF, 0xFF)
  201. ColorGuild = Color.new(0x1F, 0xFF, 0x7F)
  202. ColorInfo = Color.new(0xBF, 0xBF, 0xFF)
  203. ColorOk = Color.new(0x1F, 0xFF, 0x1F)
  204. ColorNo = Color.new(0x3F, 0x7F, 0xFF)
  205. ColorNormal = Color.new(0xFF, 0xFF, 0xFF)
  206. ColorServerError = Color.new(0xFF, 0xFF, 0x1F)
  207. ColorServerOffline = Color.new(0xFF, 0x1F, 0x1F)
  208. ColorServerOnline = Color.new(0x1F, 0xFF, 0x1F)
  209. ColorWhisper = Color.new(0xFF, 0xFF, 0x1F)
  210. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  211. # Other constants
  212. #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  213. COLORS = {}
  214. COLORS['self'] = Color.new(0, 255, 0)
  215. COLORS[GROUP_ADMIN] = Color.new(64, 192, 255)
  216. COLORS[GROUP_2NDADMIN] = Color.new(128, 192, 255)
  217. COLORS[GROUP_MOD] = Color.new(255, 255, 0)
  218. COLORS[GROUP_PLAYER] = Color.new(255, 255, 255)
  219. COLORS['guild'] = Color.new(255, 192, 0)
  220.  
  221. end
  222.  
  223. #============================================================================
  224. # module RMXOS::Error
  225. #----------------------------------------------------------------------------
  226. # Contains constants and methods for RMX-OS specific errors.
  227. #============================================================================
  228.  
  229. module Error
  230.  
  231. # error message contants
  232. InvalidSyntax = 'Invalid Syntax!'
  233. # special error message contants
  234. Command = 'Error! Command \'CMD\' not used correctly. ' + RMXOS::Data::HelpText
  235. CommandPermission = 'Error! You do not have permission to use command \'CMD\'. Use /cmd for a list of available commands to you. ' + RMXOS::Data::HelpText
  236. CommandNotExist = 'Error! Command \'CMD\' does not exist. Use /cmd for a list of available commands to you. ' + RMXOS::Data::HelpText
  237. Save = 'Error! Saving for class CLASS undefined!'
  238. ServerFull = 'The server is full!'
  239. Version = 'Client outdated: VERSION'
  240. GameVersion = 'Game outdated: VERSION'
  241.  
  242. #--------------------------------------------------------------------------
  243. # Gets the client version error message.
  244. # Returns: Client version error message.
  245. #--------------------------------------------------------------------------
  246. def self.get_client_version_error
  247. return Version.sub('VERSION') {$network.version.to_s}
  248. end
  249. #--------------------------------------------------------------------------
  250. # Gets the game version error message.
  251. # Returns: Game version error message.
  252. #--------------------------------------------------------------------------
  253. def self.get_game_version_error
  254. return GameVersion.sub('VERSION') {$network.game_version.to_s}
  255. end
  256. #--------------------------------------------------------------------------
  257. # Gets the save error message.
  258. # object - any object that can't be saved
  259. # Returns: Save error message for the given class.
  260. #--------------------------------------------------------------------------
  261. def self.get_save_error(object)
  262. return Save.sub('CLASS') {object.class.name}
  263. end
  264. #--------------------------------------------------------------------------
  265. # Gets the chat command error message.
  266. # command - the used command
  267. # Returns: Command error message for the given command.
  268. #--------------------------------------------------------------------------
  269. def self.get_command_error(command)
  270. return Command.sub('CMD') {command}
  271. end
  272. #--------------------------------------------------------------------------
  273. # Gets the chat command error message.
  274. # command - the used command
  275. # Returns: Permission command error message for the given command.
  276. #--------------------------------------------------------------------------
  277. def self.get_permission_command_error(command)
  278. return CommandPermission.sub('CMD') {command}
  279. end
  280. #--------------------------------------------------------------------------
  281. # Gets the chat command error message.
  282. # command - the used command
  283. # Returns: No command error message for the given command.
  284. #--------------------------------------------------------------------------
  285. def self.get_no_command_error(command)
  286. return CommandNotExist.sub('CMD') {command}
  287. end
  288.  
  289. end
  290.  
  291. #============================================================================
  292. # module RMXOS::Documentation
  293. #----------------------------------------------------------------------------
  294. # Contains data for in-game information how to use RMX-OS. This should not
  295. # be edited but only extended in case of adding new functionality (i.e.
  296. # additional chat commands).
  297. #============================================================================
  298.  
  299. module Documentation
  300.  
  301. # permission group names
  302. GROUP_NAMES = {}
  303. GROUP_NAMES[GROUP_ADMIN] = 'Admin'
  304. GROUP_NAMES[GROUP_2NDADMIN] = 'Secondary Admin'
  305. GROUP_NAMES[GROUP_MOD] = 'Moderator'
  306.  
  307. PARAMETERS = {}
  308. # Admin commands
  309. PARAMETERS['admin'] = 'USERNAME'
  310. # Secondary Admin commands
  311. PARAMETERS['mod'] = 'USERNAME'
  312. PARAMETERS['revoke'] = 'USERNAME'
  313. PARAMETERS['kickall'] = 'none'
  314. PARAMETERS['pass'] = 'USERNAME NEWPASS'
  315. PARAMETERS['gpass'] = 'GUILDNAME NEWPASS'
  316. PARAMETERS['eval'] = 'SCRIPT'
  317. PARAMETERS['geval'] = 'SCRIPT'
  318. PARAMETERS['seval'] = 'SCRIPT'
  319. PARAMETERS['sql'] = 'SCRIPT'
  320. # Moderator commands
  321. PARAMETERS['kick'] = 'USERNAME'
  322. PARAMETERS['ban'] = 'USERNAME'
  323. PARAMETERS['unban'] = 'USERNAME'
  324. PARAMETERS['global'] = 'MESSAGE'
  325. # Normal commands
  326. PARAMETERS['w'] = 'USERNAME MESSAGE'
  327. PARAMETERS['wr'] = 'MESSAGE'
  328. PARAMETERS['me'] = 'MESSAGE'
  329. PARAMETERS['trade'] = 'USERNAME'
  330. PARAMETERS['newpass'] = 'OLDPASS NEWPASS'
  331. PARAMETERS['y'] = 'REQUEST_ID'
  332. PARAMETERS['n'] = 'REQUEST_ID'
  333. PARAMETERS['req'] = 'none'
  334. PARAMETERS['cancel'] = 'REQUEST_ID'
  335. PARAMETERS['cmd'] = 'none'
  336. PARAMETERS['help'] = 'none|COMMAND'
  337. # Buddy List commands
  338. PARAMETERS['badd'] = 'USERNAME'
  339. PARAMETERS['bremove'] = 'USERNAME'
  340. PARAMETERS['bshow'] = 'none'
  341. # PM commands#
  342. PARAMETERS['pmsend'] = 'USERNAME MESSAGE'
  343. PARAMETERS['pmunread'] = 'none'
  344. PARAMETERS['pmall'] = 'none'
  345. PARAMETERS['pmopen'] = 'MESSAGE_ID'
  346. PARAMETERS['pmdelete'] = 'MESSAGE_ID'
  347. PARAMETERS['pmdelall'] = 'none'
  348. PARAMETERS['pmstatus'] = 'none'
  349. # Guild commands
  350. PARAMETERS['gcreate'] = 'GUILDNAME PASSWORD'
  351. PARAMETERS['gnewpass'] = 'OLDGUILDPASS NEWGUILDPASS'
  352. PARAMETERS['gdisband'] = 'GUILDPASS'
  353. PARAMETERS['gtransfer'] = 'NEWLEADER GUILDPASS'
  354. PARAMETERS['ginvite'] = 'USERNAME'
  355. PARAMETERS['gremove'] = 'USERNAME GUILDPASS'
  356. PARAMETERS['gleave'] = 'PASSWORD'
  357. PARAMETERS['gmsg'] = 'MESSAGE'
  358. PARAMETERS['ginfo'] = 'none'
  359.  
  360. DESCRIPTIONS = {}
  361. # Admin commands
  362. DESCRIPTIONS['admin'] = 'Gives a player the permission group of a Secondary Admin.'
  363. # Secondary Admin commands
  364. DESCRIPTIONS['mod'] = 'Gives a player the permission group of a Moderator.'
  365. DESCRIPTIONS['revoke'] = 'Revokes all permissions from a player. This works only on players that have a lower permission group.'
  366. DESCRIPTIONS['kickall'] = 'Kicks all connected players with a lower permission group.'
  367. DESCRIPTIONS['pass'] = 'Changes the password of a player forcibly. This can be used to help players that have forgotten their password.'
  368. DESCRIPTIONS['gpass'] = 'Changes the password of a guild forcibly. This can be used to help players that have forgotten their guild\'s password.'
  369. DESCRIPTIONS['eval'] = 'Executes an RGSS script on your machine.'
  370. DESCRIPTIONS['geval'] = 'Executes an RGSS script on every connected player.'
  371. DESCRIPTIONS['seval'] = 'Executes an RGSS script on the server.'
  372. DESCRIPTIONS['sql'] = 'Executes an SQL command on the server.'
  373. # Moderator commands
  374. DESCRIPTIONS['kick'] = 'Kick a player. This works only on players that have a lower permission group.'
  375. DESCRIPTIONS['ban'] = 'Bans and kicks a player. This works only on players that have a lower permission group.'
  376. DESCRIPTIONS['unban'] = 'Unbans a player. This works only on players that have a lower permission group.'
  377. DESCRIPTIONS['global'] = 'Sends a global message to all currently connected players.'
  378. # Normal commands
  379. 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.'
  380. DESCRIPTIONS['wr'] = 'Sends a whisper message to the player lastly used with /w. See /w command for more information.'
  381. DESCRIPTIONS['me'] = 'Displays the message as action.'
  382. DESCRIPTIONS['trade'] = 'Sends a trade request to another player. Only one request can be sent at the time. Timeout for requests is 15 seconds.'
  383. DESCRIPTIONS['newpass'] = 'Changes your password.'
  384. DESCRIPTIONS['y'] = 'Answers YES to the action request with the given ID.'
  385. DESCRIPTIONS['n'] = 'Answers NO to the action request with the given ID.'
  386. DESCRIPTIONS['req'] = 'Displays a list of currently active action requests.'
  387. DESCRIPTIONS['cancel'] = 'Cancels the action request with the given ID. Works only requests that have been sent by you.'
  388. DESCRIPTIONS['cmd'] = 'Lists all available chat commands depending on your permission group.'
  389. DESCRIPTIONS['help'] = 'Explains a command. If no command is specified, it lists all available chat commands depending on your permission group.'
  390. # Buddy List commands
  391. DESCRIPTIONS['badd'] = 'Requests to adds a user for the Buddy List.'
  392. DESCRIPTIONS['bremove'] = 'Removes a player from the Buddy List and removes you from the other player\'s buddy list.'
  393. DESCRIPTIONS['bshow'] = 'Displays all players in your Buddy List. Their online status is also displayed.'
  394. # PM commands
  395. DESCRIPTIONS['pmsend'] = 'Sends a message to a player in the Buddy List.'
  396. DESCRIPTIONS['pmunread'] = 'Gets a list of all unread messages.'
  397. DESCRIPTIONS['pmall'] = 'Gets a list of all messages.'
  398. DESCRIPTIONS['pmopen'] = 'Displays a specific message and marks it as read.'
  399. DESCRIPTIONS['pmdelete'] = 'Deletes a specific message.'
  400. DESCRIPTIONS['pmdelall'] = 'Deletes all messages in the inbox.'
  401. DESCRIPTIONS['pmstatus'] = 'Gets the number of PMs and the number of maximum PMs allowed in the inbox.'
  402. # Guild commands
  403. DESCRIPTIONS['gcreate'] = 'Creates a new guild with you as leader.'
  404. DESCRIPTIONS['gnewpass'] = 'Changes the password of your guild.'
  405. DESCRIPTIONS['gdisband'] = 'Disbands your guild.'
  406. DESCRIPTIONS['gtransfer'] = 'Transfers leadership of your guild to another player. The other player must be a member of your guild.'
  407. DESCRIPTIONS['ginvite'] = 'Invites a player into your guild.'
  408. DESCRIPTIONS['gremove'] = 'Removes a player from your guild.'
  409. DESCRIPTIONS['gleave'] = 'Leaves the current guild.'
  410. DESCRIPTIONS['gmsg'] = 'Sends a message to all guild members that are currently online.'
  411. DESCRIPTIONS['ginfo'] = 'Displays information about your guild.'
  412.  
  413. # delete disabled commands
  414. RMXOS::Options::DISABLED_CHAT_COMMANDS.each {|command|
  415. PARAMETERS.delete(command)
  416. DESCRIPTIONS.delete(command)
  417. }
  418. #--------------------------------------------------------------------------
  419. # Gets the help text for a command.
  420. # command - the command
  421. # Returns: Help text for the given command.
  422. #--------------------------------------------------------------------------
  423. def self.get_command_help(command)
  424. # get all available commands
  425. commands = self.get_command_list
  426. # command is valid
  427. if commands.include?(command)
  428. message = "'/#{command}'"
  429. message += " Parameters: #{PARAMETERS[command]};"
  430. message += " Description: #{DESCRIPTIONS[command]}"
  431. # add permission requirement message if necessary
  432. COMMANDS.each_key {|key|
  433. if COMMANDS[key].include?(command)
  434. message += " Requires minimum #{GROUP_NAMES[key]} permission group."
  435. break
  436. end
  437. }
  438. return message
  439. # no permission to access this information
  440. elsif DESCRIPTIONS.has_key?(command)
  441. return "You do not have permission to access the command '#{command}'."
  442. end
  443. # command does not exist
  444. return "Command '#{command}' does not exist."
  445. end
  446. #--------------------------------------------------------------------------
  447. # Gets a list of all available commands.
  448. # Returns: List of all available commands.
  449. #--------------------------------------------------------------------------
  450. def self.get_command_list
  451. # get all commands
  452. commands = DESCRIPTIONS.keys.sort
  453. # remove all commands that require a higher permission group
  454. COMMANDS.each_key {|group|
  455. commands -= COMMANDS[group] if group > $network.usergroup
  456. }
  457. return commands
  458. end
  459.  
  460. end
  461.  
  462. #============================================================================
  463. # RMXOS::Result
  464. #----------------------------------------------------------------------------
  465. # Contains action result constants. It's a class only for consistency between
  466. # server and client and should not be used as a class on the client.
  467. #============================================================================
  468.  
  469. class Result
  470.  
  471. # these values MUST correspond with the values specified in the server
  472. SUCCESS = 0
  473. DENIED = 1
  474. SERVER_VERSION_MISMATCH = 3
  475. GAME_VERSION_MISMATCH = 4
  476.  
  477. PASSWORD_INCORRECT = 21
  478. ACCOUNT_ALREADY_EXIST = 22
  479.  
  480. PLAYER_NOT_EXIST = 31
  481.  
  482. end
  483.  
  484. #============================================================================
  485. # RMXOS::Server
  486. #----------------------------------------------------------------------------
  487. # Contains server connection data.
  488. #============================================================================
  489.  
  490. class Server
  491.  
  492. # setting all accessible variables
  493. attr_reader :name
  494. attr_reader :host
  495. attr_reader :port
  496. #--------------------------------------------------------------------------
  497. # Initialization
  498. # name - server display name
  499. # host - IP address or URL
  500. # port - port to connect to
  501. #--------------------------------------------------------------------------
  502. def initialize(name, host, port)
  503. @name = name
  504. @host = host
  505. @port = port
  506. end
  507.  
  508. end
  509.  
  510. #============================================================================
  511. # RMXOS::ChatMessage
  512. #----------------------------------------------------------------------------
  513. # Contains chat message data.
  514. #============================================================================
  515.  
  516. class ChatMessage
  517.  
  518. # setting all accessible variables
  519. attr_reader :text
  520. attr_reader :color
  521. #--------------------------------------------------------------------------
  522. # Initialization
  523. # text - chat message text
  524. # color - chat message color
  525. #--------------------------------------------------------------------------
  526. def initialize(text, color)
  527. @text = text
  528. @color = color
  529. end
  530.  
  531. end
  532.  
  533. #============================================================================
  534. # RMXOS::ChatBubbleMessage
  535. #----------------------------------------------------------------------------
  536. # Contains chat message data for chat bubbles.
  537. #============================================================================
  538.  
  539. class ChatBubbleMessage < ChatMessage
  540.  
  541. # setting all accessible variables
  542. attr_accessor :time
  543. #--------------------------------------------------------------------------
  544. # Initialization
  545. # text - chat message text
  546. # color - chat message color
  547. #--------------------------------------------------------------------------
  548. def initialize(text, color)
  549. super
  550. @time = RMXOS::Data::BubbleDisplayTime * Graphics.frame_rate
  551. end
  552. #--------------------------------------------------------------------------
  553. # Checks if the message display has expired.
  554. # Returns: True or False.
  555. #--------------------------------------------------------------------------
  556. def expired?
  557. return (@time <= 0)
  558. end
  559.  
  560. end
  561.  
  562. #============================================================================
  563. # module RMXOS::Options
  564. #============================================================================
  565.  
  566. module Options
  567.  
  568. SERVERS.each_index {|i|
  569. SERVERS[i] = Server.new(SERVERS[i][0], SERVERS[i][1], SERVERS[i][2])
  570. }
  571. RESERVED_USERNAMES.each {|name| name.downcase!}
  572.  
  573. end
  574.  
  575. #----------------------------------------------------------------------------
  576. # Creates a message for sending over the network to the server.
  577. # args - all arguments in an array
  578. # Returns: Message for sending over the network to the server.
  579. #----------------------------------------------------------------------------
  580. def self.make_message(*args)
  581. return args.map {|arg| arg = arg.to_s}.join("\t")
  582. end
  583. #----------------------------------------------------------------------------
  584. # Checks a username for reserved usernames.
  585. # username - the guild name that needs to be checked
  586. # Returns: Whether the username can be used or not.
  587. #----------------------------------------------------------------------------
  588. def self.reserved_username?(username)
  589. return self.string_match?(RMXOS::Options::RESERVED_USERNAMES, username)
  590. end
  591. #----------------------------------------------------------------------------
  592. # Checks a username for reserved guildnames.
  593. # guildname - the guild name that needs to be checked
  594. # Returns: Whether the guildname can be used or not.
  595. #----------------------------------------------------------------------------
  596. def self.reserved_guildname?(guildname)
  597. return self.string_match?(RMXOS::Options::RESERVED_GUILDNAMES, guildname)
  598. end
  599. #----------------------------------------------------------------------------
  600. # Checks a name against an array of strings.
  601. # strings - array of strings that are used for filtering
  602. # name - the name that needs to be checked.
  603. # Returns: Whether the name matches one of the other strings or not.
  604. #----------------------------------------------------------------------------
  605. def self.string_match?(strings, name)
  606. return strings.any? {|string| name.downcase.gsub!(string) {''} &&
  607. !name.downcase.gsub!(/([A-Za-z]+#{string})|(#{string}[A-Za-z]+)/i) {''}}
  608. end
  609. #----------------------------------------------------------------------------
  610. # Fixes strings for SQL queries and eval expressions.
  611. # string - string to be converted
  612. # Returns: Converted string.
  613. #----------------------------------------------------------------------------
  614. def self.fix_string(string)
  615. return string.gsub('\'') {'\\\''}
  616. end
  617. #----------------------------------------------------------------------------
  618. # Checks a chat message for being disabled.
  619. # message - the message to be checked
  620. # Returns: Whether this command is disabled or not.
  621. #----------------------------------------------------------------------------
  622. def self.chat_command_disabled?(message)
  623. if message =~ /\A\/(\S+)/
  624. return RMXOS::Options::DISABLED_CHAT_COMMANDS.include?($1)
  625. end
  626. return false
  627. end
  628. #----------------------------------------------------------------------------
  629. # Checks a chat message for usergroup permission.
  630. # message - the message to be checked
  631. # usergroup - usergroup
  632. # Returns: Whether this command can be used by this usergroup.
  633. #----------------------------------------------------------------------------
  634. def self.chat_command_permission?(message, usergroup)
  635. if message =~ /\A\/(\S+)/
  636. command = $1
  637. COMMANDS.each_key {|group|
  638. return (usergroup >= group) if COMMANDS[group].include?(command)
  639. }
  640. end
  641. return true
  642. end
  643.  
  644. end
  645.  
  646. #==============================================================================
  647. # module RMXOS
  648. #------------------------------------------------------------------------------
  649. # Main module for all RMX-OS classes and procedures.
  650. #==============================================================================
  651.  
  652. module RMXOS
  653.  
  654. #============================================================================
  655. # RMXOS::Network
  656. #----------------------------------------------------------------------------
  657. # This class handles network communication and basic processing of server
  658. # commands and messages.
  659. #============================================================================
  660.  
  661. class Network
  662.  
  663. # setting all accessible variables
  664. attr_reader :socket
  665. attr_reader :user_id
  666. attr_reader :username
  667. attr_reader :usergroup
  668. attr_reader :buddies
  669. attr_reader :guildname
  670. attr_reader :guildleader
  671. attr_reader :version
  672. attr_reader :game_version
  673. attr_reader :servername
  674. attr_reader :players
  675. attr_reader :map_players
  676. attr_reader :messages
  677. attr_reader :load_data
  678. attr_reader :load_size
  679. attr_reader :load_sizes
  680. attr_accessor :game_loaded
  681. #--------------------------------------------------------------------------
  682. # Initialization.
  683. #--------------------------------------------------------------------------
  684. def initialize
  685. # autosave timer
  686. @autosave_time = RMXOS::Options::AUTOSAVE_FREQUENCY * 40
  687. # ping timeout
  688. @ping_timeout = RMXOS::Options::PING_TIMEOUT * 40
  689. # reset general data
  690. self.reset
  691. end
  692. #--------------------------------------------------------------------------
  693. # Resets the network data.
  694. #--------------------------------------------------------------------------
  695. def reset
  696. # socket
  697. @socket = nil
  698. # database user ID
  699. @user_id = -1
  700. # database user name
  701. @username = ''
  702. # user group
  703. @usergroup = RMXOS::GROUP_PLAYER
  704. # currently logged in players
  705. @players = {}
  706. # players on the current map
  707. @map_players = {}
  708. # received messages in this frame
  709. @messages = []
  710. # saved game data loaded from the server
  711. @load_size = 0
  712. @load_sizes = []
  713. @load_data = {}
  714. # needed to prevent data corruption
  715. @game_loaded = false
  716. # buddy list
  717. @buddies = []
  718. # last whisper message username
  719. @last_whisper_name = ''
  720. # guild
  721. self.guild_reset
  722. end
  723. #--------------------------------------------------------------------------
  724. # Resets guild data.
  725. #--------------------------------------------------------------------------
  726. def guild_reset
  727. @guildname = ''
  728. @guildleader = ''
  729. @guildmembers = []
  730. end
  731. #--------------------------------------------------------------------------
  732. # Checks if this player is a admin.
  733. # Returns: Whether this player is an admin or not.
  734. #--------------------------------------------------------------------------
  735. def admin?
  736. return (@usergroup == RMXOS::GROUP_ADMIN ||
  737. @usergroup == RMXOS::GROUP_2NDADMIN)
  738. end
  739. #--------------------------------------------------------------------------
  740. # Checks if this player is a mod.
  741. # Returns: Whether this player is a mod or not.
  742. #--------------------------------------------------------------------------
  743. def mod?
  744. return (@usergroup == RMXOS::GROUP_MOD || self.admin?)
  745. end
  746. #--------------------------------------------------------------------------
  747. # Checks if this player is in a guild.
  748. # Returns: Whether this player is in a guild or not.
  749. #--------------------------------------------------------------------------
  750. def in_guild?
  751. return (@guildname != '')
  752. end
  753. #--------------------------------------------------------------------------
  754. # Checks if this player is the guild leader.
  755. # Returns: Whether this player is the guild leader or not.
  756. #--------------------------------------------------------------------------
  757. def guildleader?
  758. return (self.in_guild? && @guildleader == @username)
  759. end
  760. #--------------------------------------------------------------------------
  761. # Starts a connection.
  762. # host - IP address or URL (as string)
  763. # port - port for connection
  764. #--------------------------------------------------------------------------
  765. def start_connection(host, port)
  766. self.reset
  767. @socket = TCPSocket.new(host, port)
  768. end
  769. #--------------------------------------------------------------------------
  770. # Tests the connection capability to a host.
  771. # host - IP address or URL (as string)
  772. # port - port for connection
  773. # index - index for simultanous tests
  774. # Returns: Whether a connection could be astablished or not.
  775. #--------------------------------------------------------------------------
  776. def test_connection(host, port, index)
  777. begin
  778. # try to create a socket
  779. socket = TCPSocket.new(host, port)
  780. # try to send something
  781. socket.send("HAI\n")
  782. # try to close the socket
  783. socket.close
  784. # connection works
  785. return true
  786. rescue Hangup
  787. # cease further testing
  788. return nil
  789. rescue
  790. ensure
  791. # make sure socket is closed
  792. socket.close rescue nil
  793. end
  794. # connection failed
  795. return false
  796. end
  797. #--------------------------------------------------------------------------
  798. # Encapsulates the socket as connection between client and server for
  799. # message sending.
  800. # args - the message to be sent in form of arguments
  801. #--------------------------------------------------------------------------
  802. def send(*args)
  803. if self.connected?
  804. message = RMXOS.make_message(*args)
  805. @socket.send(message + "\n")
  806. end
  807. end
  808. #--------------------------------------------------------------------------
  809. # Disconnects this client from the server.
  810. #--------------------------------------------------------------------------
  811. def disconnect
  812. # if a connection actually exists
  813. if self.connected?
  814. # save the game first if saving is not disabled
  815. self.save if !$game_map.interpreter.running?
  816. # send disconnection message
  817. self.send('DCT')
  818. end
  819. # delete connection and reset data
  820. self.reset
  821. end
  822. #--------------------------------------------------------------------------
  823. # Disconnects this client from the server forcefully.
  824. #--------------------------------------------------------------------------
  825. def force_disconnect
  826. # delete connection and reset data
  827. self.reset
  828. end
  829. #--------------------------------------------------------------------------
  830. # Checks if an connection actually exists.
  831. # Returns: Whether this client is connected to a server or not.
  832. #--------------------------------------------------------------------------
  833. def connected?
  834. return (@socket != nil)
  835. end
  836. #--------------------------------------------------------------------------
  837. # Removes all players on the current map.
  838. #--------------------------------------------------------------------------
  839. def clear_map_players
  840. @map_players = {}
  841. end
  842. #--------------------------------------------------------------------------
  843. # Handles a player's server entry.
  844. # id - user ID of the player
  845. #--------------------------------------------------------------------------
  846. def player_entry(id)
  847. # create a new character for him if player just connected
  848. @players[id] = Game_OnlineCharacter.new if !@players.has_key?(id)
  849. end
  850. #--------------------------------------------------------------------------
  851. # Deletes a disconnected player.
  852. # id - user ID of the player that has disconnected
  853. #--------------------------------------------------------------------------
  854. def player_disconnect(id)
  855. # removes the player from the map
  856. @map_players.delete(id) if @map_players.has_key?(id)
  857. # deletes the player
  858. @players.delete(id) if @players.has_key?(id)
  859. end
  860. #--------------------------------------------------------------------------
  861. # Handles a player's map entry.
  862. # id - user ID of the player
  863. # map_id - map ID of the player
  864. #--------------------------------------------------------------------------
  865. def map_player_entry(id, map_id)
  866. # assign map ID
  867. @players[id].map_id = map_id
  868. # if player on the same map
  869. if @players[id].map_id == $game_map.map_id && !@map_players.has_key?(id)
  870. # assign the player to a map player
  871. @map_players[id] = @players[id]
  872. end
  873. end
  874. #--------------------------------------------------------------------------
  875. # Handles a player's map exit.
  876. # id - user ID of the player
  877. #--------------------------------------------------------------------------
  878. def map_player_exit(id)
  879. # reset map ID
  880. @players[id].map_id = 0
  881. # remove player from the map if still regarded as player on the map
  882. @map_players.delete(id) if @map_players.has_key?(id)
  883. end
  884. #--------------------------------------------------------------------------
  885. # Updates all players on the map.
  886. #--------------------------------------------------------------------------
  887. def update_map_players
  888. @map_players.each_value {|player| player.update}
  889. end
  890. #--------------------------------------------------------------------------
  891. # Saves the game automatically after a specifc amount of time.
  892. #--------------------------------------------------------------------------
  893. def update_autosave
  894. # decrease timer
  895. @autosave_time -= 1
  896. # abort if event is running
  897. return if $game_map.interpreter.running?
  898. # if timer expired
  899. if @autosave_time < 0
  900. # save all data
  901. self.save
  902. # reset timer
  903. @autosave_time = RMXOS::Options::AUTOSAVE_FREQUENCY * 40
  904. end
  905. end
  906. #--------------------------------------------------------------------------
  907. # Listens for incoming server messages.
  908. #--------------------------------------------------------------------------
  909. def listen
  910. @messages.clear
  911. # stop if socket is not ready
  912. return if !self.connected? || !@socket.ready?
  913. # get 0xFFFF bytes from a received message
  914. buffer = @socket.recv(0xFFFF)
  915. # split by \n without suppressing trailing empty strings
  916. buffer = buffer.split("\n", -1)
  917. # if chunk from previous incomplete message exists
  918. if @previous_chunk != nil
  919. # complete chunk with first new message
  920. buffer[0] = @previous_chunk + buffer[0]
  921. # delete chunk buffer
  922. @previous_chunk = nil
  923. end
  924. # remove last message in buffer
  925. last_chunk = buffer.pop
  926. # incomplete message if it exists (meaning last message has no \n)
  927. @previous_chunk = last_chunk if last_chunk != ''
  928. # check each message in the buffer
  929. buffer.each {|message|
  930. next if self.check_game(message)
  931. next if self.check_communication(message)
  932. next if self.check_connection(message)
  933. next if self.check_loading(message)
  934. }
  935. end
  936. #--------------------------------------------------------------------------
  937. # Checks general game messages.
  938. # message - the received message
  939. # Returns: True or false whether to stop checking this message.
  940. #--------------------------------------------------------------------------
  941. def check_game(message)
  942. case message
  943. when /\ACHT\t(.{6})\t(.+)\t(.+)/ # chat message
  944. # color encoded in hex
  945. c = [$1[0, 2].hex, $1[2, 2].hex, $1[4, 2].hex]
  946. self.add_message(eval($2), $3, Color.new(c[0], c[1], c[2]))
  947. return true
  948. when /\ACHA\t(.{6})\t(.+)\t(.+)/ # chat message
  949. # color encoded in hex
  950. c = [$1[0, 2].hex, $1[2, 2].hex, $1[4, 2].hex]
  951. self.add_message(eval($2), $3, Color.new(c[0], c[1], c[2]), true)
  952. return true
  953. when /\ADCS\Z/ # disconnected
  954. # disconnect
  955. $network.force_disconnect
  956. # show message
  957. p RMXOS::Data::Disconnected
  958. # return to server selection
  959. SceneManager.goto Scene_Servers
  960. return true
  961. when /\ADCL\Z/ # disconnected due to login timeout
  962. # disconnect
  963. $network.force_disconnect
  964. # show message
  965. p RMXOS::Data::LoginTimedOut
  966. # return to server selection
  967. SceneManager.goto Scene_Servers
  968. return true
  969. when /\ADCT\t(.+)/ # disconnection message for another player
  970. id = $1.to_i
  971. self.player_disconnect(id)
  972. $game_temp.trade_abort = true if id == $game_temp.trade_id
  973. return true
  974. when /\AENT\t(.+)\t(.+)\t(.+)\t(.+)/ # server entry message
  975. # get all necessary data from the message
  976. id = $1.to_i
  977. name = $2
  978. group = $3.to_i
  979. guild = eval($4)
  980. # handle player's server entry
  981. self.player_entry(id)
  982. # handle player's map data
  983. @players[id].set_user_data(id, name, group, guild)
  984. return true
  985. when /\APLA\t(.+)\t(.+)\t(.+)\t(.+)/ # connected player data
  986. # get all necessary data from the message
  987. id = $1.to_i
  988. name = $2
  989. group = $3.to_i
  990. guild = eval($4)
  991. # handle player's server entry
  992. self.player_entry(id)
  993. # handle player's map data
  994. @players[id].set_user_data(id, name, group, guild)
  995. return true
  996. when /\AMEN\t(.+)\t(.+)\t(.+)\t(.+)\t(.+)\t(.+)/ # map entry message
  997. # get all necessary data from the message
  998. map_id = $1.to_i
  999. id = $2.to_i
  1000. name = $3
  1001. group = $4.to_i
  1002. guild = eval($5)
  1003. variables = eval($6)
  1004. # handle player's map entry
  1005. self.map_player_entry(id, map_id)
  1006. # handle player's map data
  1007. @players[id].set_user_data(id, name, group, guild)
  1008. # update player
  1009. @players[id].evaluate(variables)
  1010. # update player's position
  1011. @players[id].moveto(@players[id].x, @players[id].y)
  1012. return true
  1013. when /\AMEF/ # map entry finished
  1014. $game_temp.entering_map = false
  1015. return true
  1016. when /\AMEX\t(.+)/ # map exit message
  1017. # get all necessary data from the message
  1018. id = $1.to_i
  1019. # handle player's map exit
  1020. self.map_player_exit(id)
  1021. return true
  1022. when /\AMEV\t(.+)\t(.+)\t(.+)\t(.+)\t(.+)/ # exchange variable message
  1023. # get all necessary data from the message
  1024. id = $1.to_i
  1025. name = $2
  1026. group = $3.to_i
  1027. guild = eval($4)
  1028. variables = eval($5)
  1029. # handle player's map data
  1030. @players[id].set_user_data(id, name, group, guild)
  1031. # update player
  1032. @players[id].evaluate(variables)
  1033. return true
  1034. when /\ATRS\t(.+)\t(.+)/ # trade start
  1035. $game_temp.trade_active = true
  1036. $game_temp.trade_host = ($1 != '0')
  1037. $game_temp.trade_id = $2.to_i
  1038. $game_temp.chat_active = false
  1039. return true
  1040. when /\ATCO\Z/ # trade confirm
  1041. $game_temp.trade_confirmed = true
  1042. return true
  1043. when /\ATCA\Z/ # trade complete abort
  1044. $game_temp.trade_abort = true
  1045. return true
  1046. when /\ATRI\t(.*)/ # trade item list (can be empty, hence "(.*)")
  1047. data = $1.gsub('>') {'=>'}
  1048. $game_temp.trade_items = eval("{#{data}}")
  1049. return true
  1050. when /\ATRC\Z/ # trade cancel
  1051. $game_temp.trade_canceled = true
  1052. return true
  1053. when /\ATCC\Z/ # trade cancel confirmation
  1054. $game_temp.trade_cancel_confirmed = true
  1055. return true
  1056. when /\ATRF\Z/ # trade finalization
  1057. $game_temp.trade_finalized = true
  1058. return true
  1059. when /\AEVA\t(.+)/ # script to evaluate from server
  1060. begin
  1061. eval($1)
  1062. rescue SyntaxError
  1063. rescue
  1064. end
  1065. return true
  1066. end
  1067. return false
  1068. end
  1069. #--------------------------------------------------------------------------
  1070. # Checks server-client communication messages.
  1071. # message - the received message
  1072. # Returns: True or false whether to stop checking this message.
  1073. #--------------------------------------------------------------------------
  1074. def check_communication(message)
  1075. case message
  1076. when /\ABAD\t(.+)/ # new buddy
  1077. @buddies = (@buddies + [$1]).sort
  1078. return true
  1079. when /\ABRE\t(.+)/ # removed buddy
  1080. @buddies.delete($1)
  1081. return true
  1082. when /\AGJO\t(.+)/ # a new member joined the guild
  1083. @guildmembers = (@guildmembers + [$1]).sort
  1084. return true
  1085. when /\AGRE\t(.+)/ # removing a member from the guild
  1086. @guildmembers.delete($1)
  1087. return true
  1088. when /\AGRM\Z/ # removal from guild
  1089. self.guild_reset
  1090. return true
  1091. when /\AGLE\t(.+)/ # new guild leader
  1092. @guildleader = $1
  1093. return true
  1094. when /\APMA\t(.+)/ # retrieved PMs
  1095. # evaluate received data
  1096. data = eval("[#{$1}]")
  1097. # get PM data
  1098. pms = self.decode_pm_data(data)
  1099. # display each PM
  1100. pms.each {|pm| self.add_info(pm)}
  1101. return true
  1102. when /\APMO\t(.+)\t(.+)\t(.+)/ # opened PM
  1103. sender, time, message = $1, $2, $3
  1104. # get time
  1105. time = time.split(',')
  1106. time = Time.mktime(time[0], time[1], time[2], time[3], time[4], time[5])
  1107. time += Time.now.utc_offset
  1108. # create display string
  1109. string = RMXOS::Data::PMText.sub('SENDER') {sender}
  1110. string.sub!('TIME') {time.strftime('%Y-%m-%d %H:%M:%S')}
  1111. string.sub!('MESSAGE') {message}
  1112. # display PM
  1113. self.add_chat(string)
  1114. return true
  1115. end
  1116. return false
  1117. end
  1118. #--------------------------------------------------------------------------
  1119. # Checks connection and account related messages.
  1120. # message - the received message
  1121. # Returns: True or false whether to stop checking this message.
  1122. #--------------------------------------------------------------------------
  1123. def check_connection(message)
  1124. case message
  1125. when /\AUID\t(.+)\t(.+)\t(.+)\t(.+)/ # user data
  1126. @user_id = $1.to_i
  1127. @username = $2
  1128. @usergroup = $3.to_i
  1129. @buddies = eval("[#{$4}]").compact.sort
  1130. return true
  1131. when /\AGIN\t(.+)\t(.+)\t(.+)/ # guild info
  1132. @guildname = $1
  1133. @guildleader = $2
  1134. @guildmembers = eval("[#{$3}]").compact.sort
  1135. return true
  1136. when /\ACON\t(.+)\t(.+)\t(.+)/ # received connection message
  1137. # pass message to game about connection try
  1138. case $1.to_i
  1139. when RMXOS::Result::SUCCESS then @messages.push(RMXOS::CONNECTION_SUCCESS)
  1140. when RMXOS::Result::DENIED then @messages.push(RMXOS::CONNECTION_DENIED)
  1141. when RMXOS::Result::SERVER_VERSION_MISMATCH then @messages.push(RMXOS::CONNECTION_CLIENT_VERSION)
  1142. when RMXOS::Result::GAME_VERSION_MISMATCH then @messages.push(RMXOS::CONNECTION_GAME_VERSION)
  1143. end
  1144. # server version
  1145. @version = $2.to_f
  1146. # game version
  1147. @game_version = $3.to_f
  1148. return true
  1149. when /\ALIN\t(.+)/ # login result
  1150. # pass message to game about login try
  1151. case $1.to_i
  1152. when RMXOS::Result::SUCCESS then @messages.push(RMXOS::LOGIN_SUCCESS)
  1153. when RMXOS::Result::DENIED then @messages.push(RMXOS::LOGIN_BANNED)
  1154. when RMXOS::Result::PLAYER_NOT_EXIST then @messages.push(RMXOS::LOGIN_NOUSER)
  1155. when RMXOS::Result::PASSWORD_INCORRECT then @messages.push(RMXOS::LOGIN_NOPASS)
  1156. end
  1157. return true
  1158. when /\AREG\t(.+)/ # register result
  1159. # pass message to game about register try
  1160. case $1.to_i
  1161. when RMXOS::Result::SUCCESS then @messages.push(RMXOS::REGISTER_SUCCESS)
  1162. when RMXOS::Result::DENIED then @messages.push(RMXOS::REGISTER_BANNED)
  1163. when RMXOS::Result::ACCOUNT_ALREADY_EXIST then @messages.push(RMXOS::REGISTER_EXIST)
  1164. end
  1165. return true
  1166. when /\AKCK\Z/ # kicked
  1167. # disconnect
  1168. $network.force_disconnect
  1169. # show message
  1170. p RMXOS::Data::Kicked
  1171. # return to server selection
  1172. SceneManager.goto Scene_Servers
  1173. return true
  1174. end
  1175. return false
  1176. end
  1177. #--------------------------------------------------------------------------
  1178. # Checks messages related to loading of game data.
  1179. # message - the received message
  1180. # Returns: True or false whether to stop checking this message.
  1181. #--------------------------------------------------------------------------
  1182. def check_loading(message)
  1183. case message
  1184. when /\ALOA\t(.+)\t(.+)/ # game data message
  1185. # create data string entry
  1186. @load_data[$1] = $2
  1187. @load_sizes.push(@load_data.size)
  1188. @messages.push(RMXOS::LOADING_UPDATE)
  1189. return true
  1190. when /\ALOS\t(.+)/ # game data size
  1191. @load_size = $1.to_i
  1192. @load_sizes.push(0)
  1193. @messages.push(RMXOS::LOADING_UPDATE)
  1194. return true
  1195. when /\ALEN\Z/ # loading end
  1196. @load_sizes.push(@load_data.size)
  1197. self.load_game
  1198. # broadcasts server entry of new player
  1199. self.enter_server
  1200. # remove loading data
  1201. @load_data = {}
  1202. @messages.push(RMXOS::LOADING_END)
  1203. return true
  1204. end
  1205. return false
  1206. end
  1207. #--------------------------------------------------------------------------
  1208. # Adds a chat message to the queue to be drawn.
  1209. # data - raw data received from the server
  1210. # Returns: Array of PM data strings.
  1211. #--------------------------------------------------------------------------
  1212. def decode_pm_data(data)
  1213. # evaluate received data
  1214. pms = []
  1215. (0...(data.size / 8)).each {|i|
  1216. # split PM data
  1217. pm = data[i * 8, 8]
  1218. # get data fragments
  1219. message_id = pm.shift
  1220. sender = pm.shift
  1221. # get time
  1222. time = Time.mktime(pm[0], pm[1], pm[2], pm[3], pm[4], pm[5])
  1223. time += Time.now.utc_offset
  1224. # create display string
  1225. string = RMXOS::Data::PMInfo.sub('NUMBER') {message_id.to_s}
  1226. string.sub!('SENDER') {sender}
  1227. string.sub!('TIME') {time.strftime('%Y-%m-%d %H:%M:%S')}
  1228. # add string to final result
  1229. pms.push(string)}
  1230. return pms
  1231. end
  1232. #--------------------------------------------------------------------------
  1233. # Adds an error message to the queue to be drawn.
  1234. # message - the message to add
  1235. #--------------------------------------------------------------------------
  1236. def add_error(message)
  1237. self.add_message(nil, message, RMXOS::Data::ColorError)
  1238. end
  1239. #--------------------------------------------------------------------------
  1240. # Adds an info message to the queue to be drawn.
  1241. # message - the message to add
  1242. #--------------------------------------------------------------------------
  1243. def add_info(message)
  1244. self.add_message(0, message, RMXOS::Data::ColorInfo)
  1245. end
  1246. #--------------------------------------------------------------------------
  1247. # Adds an explicit chat message to the queue to be drawn.
  1248. # message - the message to add
  1249. #--------------------------------------------------------------------------
  1250. def add_chat(message)
  1251. self.add_message(nil, message, RMXOS::Data::ColorNormal)
  1252. end
  1253. #--------------------------------------------------------------------------
  1254. # Adds a chat message to the queue to be drawn.
  1255. # user_id - user ID of the sender
  1256. # message - the message to add
  1257. # color - message color
  1258. # action - action message flag
  1259. #--------------------------------------------------------------------------
  1260. def add_message(id, message, color, action = false)
  1261. # create a bitmap
  1262. bitmap = Bitmap.new(1, 1)
  1263. bitmap.font.size = RMXOS::Data::ChatFontHeight
  1264. # if not generic chat message
  1265. if id != nil
  1266. # if sent by a player
  1267. if id > 0
  1268. # message from this player
  1269. if @user_id == id
  1270. player = $game_player
  1271. username = @username
  1272. # message from other player
  1273. elsif @players.has_key?(id)
  1274. player = @players[id]
  1275. username = player.username
  1276. else
  1277. player = nil
  1278. username = nil
  1279. end
  1280. # if really sent by a player
  1281. if player != nil
  1282. # if chat bubbles active
  1283. if RMXOS::Options::CHAT_BUBBLES
  1284. # slice the text for chat bubbles
  1285. slices = bitmap.slice_text(action ? '* ' + message : message,
  1286. RMXOS::Data::ChatBubbleMaxWidth)
  1287. # add messages for bubble chat
  1288. player.add_chat_messages(slices, color)
  1289. end
  1290. # add username to message
  1291. if action
  1292. message = "* #{username} #{message}"
  1293. else
  1294. message = "#{username}: #{message}"
  1295. end
  1296. end
  1297. end
  1298. end
  1299. # slice the text if necessary
  1300. slices = bitmap.slice_text(message, RMXOS::Options::CHATBOX_WIDTH - 40)
  1301. bitmap.dispose
  1302. # add each text slice to chat display
  1303. slices.each {|slice| $game_temp.chat_messages.push(
  1304. RMXOS::ChatMessage.new(slice, color))
  1305. }
  1306. # if exceeding log size
  1307. if $game_temp.chat_messages.size > RMXOS::Data::ChatLineEntries
  1308. # remove a few messages from before
  1309. i = $game_temp.chat_messages.size
  1310. lines = RMXOS::Data::ChatLineEntries
  1311. $game_temp.chat_messages = $game_temp.chat_messages[i - lines, lines]
  1312. end
  1313. # chat box needs refreshing
  1314. $game_temp.chat_refresh = 0 if !$game_temp.chat_refresh
  1315. $game_temp.chat_refresh += slices.size
  1316. end
  1317. #--------------------------------------------------------------------------
  1318. # Requests a valid game connection from the server.
  1319. #--------------------------------------------------------------------------
  1320. def request_connection
  1321. self.send('CON', RMXOS::VERSION, RMXOS::Options::GAME_VERSION)
  1322. end
  1323. #--------------------------------------------------------------------------
  1324. # Requests a login. The server responds with whether the login has
  1325. # succeeded or failed.
  1326. # username - username of the player
  1327. # password - password of the player
  1328. #--------------------------------------------------------------------------
  1329. def try_login(username, password)
  1330. self.send('LIN', username, encrypt_password(password))
  1331. end
  1332. #--------------------------------------------------------------------------
  1333. # Requests the registering of an acocunt. The server responds with whether
  1334. # the login has succeeded or failed.
  1335. # username - username of the player
  1336. # password - password of the player
  1337. #--------------------------------------------------------------------------
  1338. def try_register(username, password)
  1339. self.send('REG', username, encrypt_password(password))
  1340. end
  1341. #--------------------------------------------------------------------------
  1342. # Broadcasts leaving of a map.
  1343. #--------------------------------------------------------------------------
  1344. def leave_map
  1345. self.send('MEX')
  1346. end
  1347. #--------------------------------------------------------------------------
  1348. # Broadcasts entering of a new map.
  1349. #--------------------------------------------------------------------------
  1350. def enter_map
  1351. self.send('MEN', $game_map.map_id)
  1352. self.ping_server
  1353. end
  1354. #--------------------------------------------------------------------------
  1355. # Broadcasts entering of the server.
  1356. #--------------------------------------------------------------------------
  1357. def enter_server
  1358. self.send('ENT')
  1359. end
  1360. #--------------------------------------------------------------------------
  1361. # Waits for server to send all map data.
  1362. # Note: Do not call directly. This must go after an enter_map call.
  1363. #--------------------------------------------------------------------------
  1364. def wait_for_map_data
  1365. # set waiting flag
  1366. $game_temp.entering_map = true
  1367. # wait for server to reply
  1368. while $game_temp.entering_map
  1369. $network.update_server_ping
  1370. $network.listen
  1371. Graphics.update
  1372. end
  1373. end
  1374. #--------------------------------------------------------------------------
  1375. # Updates server ping timeout.
  1376. #--------------------------------------------------------------------------
  1377. def update_server_ping
  1378. @ping_timeout -= 1
  1379. self.ping_server if @ping_timeout <= 0
  1380. end
  1381. #--------------------------------------------------------------------------
  1382. # Pings the server (keep-alive).
  1383. #--------------------------------------------------------------------------
  1384. def ping_server
  1385. self.send('PNG')
  1386. @ping_timeout = RMXOS::Options::PING_TIMEOUT * 40
  1387. end
  1388. #--------------------------------------------------------------------------
  1389. # Sends a chatbox message.
  1390. # message - the message to be sent
  1391. # color - the message color
  1392. # prefix - message code with additional data
  1393. #--------------------------------------------------------------------------
  1394. def send_chat_message(message, color, prefix)
  1395. color = sprintf('%02X%02X%02X', color.red.to_i, color.green.to_i, color.blue.to_i)
  1396. self.send(prefix, color, @user_id, message)
  1397. end
  1398. #--------------------------------------------------------------------------
  1399. # Sends player exchange variables to the server.
  1400. # variables - player exchange variables
  1401. #--------------------------------------------------------------------------
  1402. def send_exchange_variables(variables = nil)
  1403. variables = $game_player.get_exchange_variables if variables == nil
  1404. self.send('MEV', variables.inspect)
  1405. end
  1406. #--------------------------------------------------------------------------
  1407. # Encrypts the password into an unsigned 32-bit hash value as string.
  1408. # password - original password
  1409. # Returns: Unsigned 32-bit hash of the given password as string.
  1410. #--------------------------------------------------------------------------
  1411. def encrypt_password(password)
  1412. # encrypting password
  1413. encrypted = password.crypt(RMXOS::Options::ENCRYPTION_SALT)
  1414. # removing first two characters which actually are the salt for safety
  1415. return encrypted[2, encrypted.size - 2]
  1416. end
  1417. #--------------------------------------------------------------------------
  1418. # Sends a trade confirmation message.
  1419. #--------------------------------------------------------------------------
  1420. def trade_confirm
  1421. self.send('TCO', $game_temp.trade_id)
  1422. end
  1423. #--------------------------------------------------------------------------
  1424. # Sends a message to abort the trade.
  1425. #--------------------------------------------------------------------------
  1426. def trade_abort
  1427. self.send('TCA', $game_temp.trade_id)
  1428. end
  1429. #--------------------------------------------------------------------------
  1430. # Sends a message with trade item data.
  1431. #--------------------------------------------------------------------------
  1432. def trade_send_items(items)
  1433. items = items.clone
  1434. items.keys.each {|key| items.delete(key) if items[key] == 0}
  1435. data = items.inspect.gsub(' '){''}.gsub('{'){''}.gsub('}'){''}.gsub('='){''}
  1436. self.send('TRI', $game_temp.trade_id, data)
  1437. end
  1438. #--------------------------------------------------------------------------
  1439. # Sends a trade cancelation message.
  1440. #--------------------------------------------------------------------------
  1441. def trade_cancel
  1442. self.send('TRC', $game_temp.trade_id)
  1443. end
  1444. #--------------------------------------------------------------------------
  1445. # Sends a trade cancel confirmation message.
  1446. #--------------------------------------------------------------------------
  1447. def trade_confirm_cancel
  1448. self.send('TCC', $game_temp.trade_id)
  1449. end
  1450. #--------------------------------------------------------------------------
  1451. # Sends a trade execution message.
  1452. #--------------------------------------------------------------------------
  1453. def trade_execute
  1454. self.send('TRX', $game_temp.trade_id)
  1455. end
  1456. #--------------------------------------------------------------------------
  1457. # Checks actions that require not to be in a guild.
  1458. # Returns: Whether the action can be executed or not.
  1459. #--------------------------------------------------------------------------
  1460. def check_no_guild_action
  1461. # if in a guild
  1462. if self.in_guild?
  1463. # show error message
  1464. self.add_error(RMXOS::Data::GuildAlready)
  1465. return false
  1466. end
  1467. return true
  1468. end
  1469. #--------------------------------------------------------------------------
  1470. # Checks actions that require to be in a guild.
  1471. # Returns: Whether the action can be executed or not.
  1472. #--------------------------------------------------------------------------
  1473. def check_guild_action
  1474. # if not in a guild
  1475. if !self.in_guild?
  1476. # show error message
  1477. self.add_error(RMXOS::Data::GuildNone)
  1478. return false
  1479. end
  1480. return true
  1481. end
  1482. #--------------------------------------------------------------------------
  1483. # Checks actions that require to be the guild leader.
  1484. # Returns: Whether the action can be executed or not.
  1485. #--------------------------------------------------------------------------
  1486. def check_guildleader_action
  1487. # if not guild leader
  1488. if !self.guildleader?
  1489. # show error message
  1490. self.add_error(RMXOS::Data::GuildNotLeader)
  1491. return false
  1492. end
  1493. return true
  1494. end
  1495. #--------------------------------------------------------------------------
  1496. # Checks a chat message for chat commands.
  1497. # message - the message to be checked
  1498. # Returns: Whether this message is a command or not.
  1499. #--------------------------------------------------------------------------
  1500. def check_chat_commands(message)
  1501. if !RMXOS.chat_command_disabled?(message) &&
  1502. RMXOS.chat_command_permission?(message, @usergroup)
  1503. return true if check_admin_commands(message)
  1504. return true if check_mod_commands(message)
  1505. return true if check_normal_commands(message)
  1506. return true if check_buddy_commands(message)
  1507. return true if check_pm_commands(message)
  1508. return true if check_guild_commands(message)
  1509. end
  1510. return true if check_command_error(message)
  1511. return false
  1512. end
  1513. #--------------------------------------------------------------------------
  1514. # Checks a chat message for admin commands.
  1515. # message - the message to be checked
  1516. # Returns: Whether this message is a command or not.
  1517. #--------------------------------------------------------------------------
  1518. def check_admin_commands(message)
  1519. case message
  1520. when /\A\/admin (\S+)\Z/ # giving secondary admin permission group
  1521. command_usergroup_change($1, RMXOS::GROUP_2NDADMIN)
  1522. return true
  1523. when /\A\/kickall\Z/ # kicking all players
  1524. command_kickall
  1525. return true
  1526. when /\A\/mod (\S+)\Z/ # giving mod permission group
  1527. command_usergroup_change($1, RMXOS::GROUP_MOD)
  1528. return true
  1529. when /\A\/revoke (\S+)\Z/ # revoking of all permission groups
  1530. command_usergroup_change($1, RMXOS::GROUP_PLAYER)
  1531. return true
  1532. when /\A\/pass (\S+) (\S+)\Z/ # forced user password change
  1533. command_forced_password_change($1, $2, 'APA')
  1534. return true
  1535. when /\A\/gpass (\S+) (\S+)\Z/ # forced guild password change
  1536. command_forced_password_change($1, $2, 'AGP')
  1537. return true
  1538. when /\A\/eval (\S{1}.*)/ # script evaluation on own machine
  1539. command_eval_script($1)
  1540. return true
  1541. when /\A\/geval (\S{1}.*)/ # script evaluation on every connected client
  1542. command_eval_script($1, true)
  1543. return true
  1544. when /\A\/seval (\S{1}.*)/ # script evaluation on server
  1545. command_server_script($1)
  1546. return true
  1547. when /\A\/sql (\S{1}.*)/ # SQL script evaluation on server
  1548. command_sql_script($1)
  1549. return true
  1550. end
  1551. return false
  1552. end
  1553. #--------------------------------------------------------------------------
  1554. # Checks a chat message for mod commands.
  1555. # message - the message to be checked
  1556. # Returns: Whether this message is a command or not.
  1557. #--------------------------------------------------------------------------
  1558. def check_mod_commands(message)
  1559. case message
  1560. when /\A\/kick (\S+)\Z/ # kick player
  1561. command_kick_player($1)
  1562. return true
  1563. when /\A\/ban (\S+)\Z/ # ban player
  1564. command_ban_player($1)
  1565. return true
  1566. when /\A\/unban (\S+)\Z/ # unban player
  1567. command_unban_player($1)
  1568. return true
  1569. when /\A\/global (\S{1}.*)/ # global message
  1570. command_global_chat($1)
  1571. return true
  1572. end
  1573. return false
  1574. end
  1575. #--------------------------------------------------------------------------
  1576. # Checks a chat message for normal commands.
  1577. # message - the message to be checked
  1578. # Returns: Whether this message is a command or not.
  1579. #--------------------------------------------------------------------------
  1580. def check_normal_commands(message)
  1581. case message
  1582. when /\A\/w (\S+) (\S{1}.*)/ # whisper chat
  1583. command_whisper_chat($2, $1)
  1584. return true
  1585. when /\A\/wr (\S{1}.*)/ # whisper chat
  1586. command_whisper_chat($1)
  1587. return true
  1588. when /\A\/me (\S{1}.*)/ # action chat
  1589. command_action_chat($1)
  1590. return true
  1591. when /\A\/trade (\S{1}.*)/ # trade request
  1592. command_trade_request($1)
  1593. return true
  1594. when /\A\/newpass (\S+) (\S+)\Z/ # password change
  1595. command_password_change($1, $2)
  1596. return true
  1597. when /\A\/y (\S+)\Z/ # answer YES to an action request
  1598. command_yes($1)
  1599. return true
  1600. when /\A\/n (\S+)\Z/ # answer NO to an action request
  1601. command_no($1)
  1602. return true
  1603. when /\A\/cancel (\S+)\Z/ # cancel action request
  1604. command_cancel($1)
  1605. return true
  1606. when /\A\/req\Z/ # display all action requests
  1607. command_req
  1608. return true
  1609. when /\A\/cmd\Z/, /\A\/help(\s*)\Z/ # listing of all commands
  1610. command_show_commands
  1611. return true
  1612. when /\A\/help (\S+)/ # display help for a command
  1613. command_help($1)
  1614. return true
  1615. end
  1616. return false
  1617. end
  1618. #--------------------------------------------------------------------------
  1619. # Checks a chat message for buddy list commands.
  1620. # message - the message to be checked
  1621. # Returns: Whether this message is a command or not.
  1622. #--------------------------------------------------------------------------
  1623. def check_buddy_commands(message)
  1624. case message
  1625. when /\A\/badd (\S+)\Z/ # adding a player to the buddy list
  1626. command_buddy_add($1)
  1627. return true
  1628. when /\A\/bremove (\S+)\Z/ # removing a player from the buddy list
  1629. command_buddy_remove($1)
  1630. return true
  1631. when /\A\/bshow\Z/ # displays the buddy list
  1632. command_buddy_show
  1633. return true
  1634. end
  1635. return false
  1636. end
  1637. #--------------------------------------------------------------------------
  1638. # Checks a chat message for normal commands.
  1639. # message - the message to be checked
  1640. # Returns: Whether this message is a command or not.
  1641. #--------------------------------------------------------------------------
  1642. def check_pm_commands(message)
  1643. case message
  1644. when /\A\/pmsend (\S+) (\S{1}.*)/ # sending a PM to a buddy
  1645. command_pm_send($1, $2)
  1646. return true
  1647. when /\A\/pmunread\Z/ # getting unread PMs
  1648. command_pm_get_unread
  1649. return true
  1650. when /\A\/pmall\Z/ # getting all PMs
  1651. command_pm_get_all
  1652. return true
  1653. when /\A\/pmopen (\d+)\Z/ # opening a PM
  1654. command_pm_open($1.to_i)
  1655. return true
  1656. when /\A\/pmdelete (\d+)\Z/ # deleting a PM
  1657. command_pm_delete($1.to_i)
  1658. return true
  1659. when /\A\/pmdelall\Z/ # deleting all PMs
  1660. command_pm_delete_all
  1661. return true
  1662. when /\A\/pmstatus\Z/ # inbox status
  1663. command_pm_status
  1664. return true
  1665. end
  1666. return false
  1667. end
  1668. #--------------------------------------------------------------------------
  1669. # Checks a chat message for normal commands.
  1670. # message - the message to be checked
  1671. # Returns: Whether this message is a command or not.
  1672. #--------------------------------------------------------------------------
  1673. def check_guild_commands(message)
  1674. case message
  1675. when /\A\/gcreate (\S+) (\S+)\Z/ # creating a guild
  1676. command_guild_create($1, $2)
  1677. return true
  1678. when /\A\/gnewpass (\S+) (\S+)\Z/ # changing the guild password
  1679. command_password_change($1, $2, 'GPS') if self.check_guildleader_action
  1680. return true
  1681. when /\A\/gdisband (\S+)\Z/ # disbanding the guild
  1682. command_guild_disband($1)
  1683. return true
  1684. when /\A\/gtransfer (\S+) (\S+)\Z/ # transferring leadership of guild
  1685. command_guild_transfer($1, $2)
  1686. return true
  1687. when /\A\/ginvite (\S+)\Z/ # inviting a player into the guild
  1688. command_guild_invite($1)
  1689. return true
  1690. when /\A\/gremove (\S+) (\S+)\Z/ # removing a player from the guild
  1691. command_guild_remove($1, $2)
  1692. return true
  1693. when /\A\/gleave (\S+)\Z/ # leaving the guild
  1694. command_guild_leave($1)
  1695. return true
  1696. when /\A\/gmsg (\S{1}.*)/ # message to all online guild members
  1697. command_guild_chat($1)
  1698. return true
  1699. when /\A\/ginfo\Z/ # guild information
  1700. command_guild_info
  1701. return true
  1702. end
  1703. return false
  1704. end
  1705. #--------------------------------------------------------------------------
  1706. # Checks a chat message for errorous commands.
  1707. # message - the message to be checked
  1708. # Returns: Whether this message is an invalid command or not.
  1709. #--------------------------------------------------------------------------
  1710. def check_command_error(message)
  1711. # if command usage
  1712. if message =~ /\A\/(\S+)/
  1713. used_command = $1
  1714. # get all commands
  1715. commands = RMXOS::Documentation.get_command_list
  1716. # get commands with no permission
  1717. other_commands = RMXOS::Documentation::DESCRIPTIONS.keys - commands
  1718. # check proper command syntax for available commands
  1719. commands.each {|command|
  1720. # command used wrongly
  1721. if message =~ /\A\/#{command}/
  1722. self.add_error(RMXOS::Error.get_command_error(command))
  1723. return true
  1724. end
  1725. }
  1726. # check for all commands without permission
  1727. other_commands.each {|command|
  1728. # no permission to use command
  1729. if message =~ /\A\/#{command}/
  1730. self.add_error(RMXOS::Error.get_permission_command_error(command))
  1731. return true
  1732. end
  1733. }
  1734. # command simply doesn't exist
  1735. self.add_error(RMXOS::Error.get_no_command_error(used_command))
  1736. return true
  1737. end
  1738. return false
  1739. end
  1740. #--------------------------------------------------------------------------
  1741. # Executes chat command for usergroup change.
  1742. # username - username of the player
  1743. # group - new usergroup
  1744. #--------------------------------------------------------------------------
  1745. def command_usergroup_change(username, group)
  1746. self.send('GRC', username, group)
  1747. end
  1748. #--------------------------------------------------------------------------
  1749. # Executes chat command for kicking all players.
  1750. #--------------------------------------------------------------------------
  1751. def command_kickall
  1752. self.send('AKA')
  1753. end
  1754. #--------------------------------------------------------------------------
  1755. # Executes chat command for forced password change.
  1756. # entity - name of the entity (player or guild)
  1757. # password - new password
  1758. # prefix - message prefix code
  1759. #--------------------------------------------------------------------------
  1760. def command_forced_password_change(entity, password, prefix)
  1761. self.send(prefix, entity, encrypt_password(password))
  1762. end
  1763. #--------------------------------------------------------------------------
  1764. # Executes chat command for executing a script.
  1765. # script - string containing Ruby script code
  1766. # global - execution on all connected clients.
  1767. #--------------------------------------------------------------------------
  1768. def command_eval_script(script, global = false)
  1769. begin
  1770. eval(script)
  1771. self.send('AEV', script) if global
  1772. rescue SyntaxError
  1773. self.add_error("#{RMXOS::Error::InvalidSyntax} #{script}")
  1774. rescue
  1775. self.add_error("#{$!.message} #{script}")
  1776. end
  1777. end
  1778. #--------------------------------------------------------------------------
  1779. # Executes chat command for executing a Ruby script on the server.
  1780. # script - string containing Ruby script code
  1781. #--------------------------------------------------------------------------
  1782. def command_server_script(script)
  1783. self.send('ASE', script)
  1784. end
  1785. #--------------------------------------------------------------------------
  1786. # Executes chat command for executing an SQL script on the server.
  1787. # script - string containing SQL script code
  1788. #--------------------------------------------------------------------------
  1789. def command_sql_script(script)
  1790. self.send('ASQ', script)
  1791. end
  1792. #--------------------------------------------------------------------------
  1793. # Executes chat command for kicking a player.
  1794. # username - username of the player
  1795. #--------------------------------------------------------------------------
  1796. def command_kick_player(username)
  1797. self.send('MKI', username)
  1798. end
  1799. #--------------------------------------------------------------------------
  1800. # Executes chat command for banning a player.
  1801. # username - username of the player
  1802. #--------------------------------------------------------------------------
  1803. def command_ban_player(username)
  1804. self.send('MBA', username)
  1805. end
  1806. #--------------------------------------------------------------------------
  1807. # Executes chat command for unbanning a player.
  1808. # username - username of the player
  1809. #--------------------------------------------------------------------------
  1810. def command_unban_player(username)
  1811. self.send('MUB', username)
  1812. end
  1813. #--------------------------------------------------------------------------
  1814. # Executes chat command for a normal chat message.
  1815. # message - the message to be sent
  1816. #--------------------------------------------------------------------------
  1817. def command_chat(message)
  1818. self.send_chat_message(message, RMXOS::Data::ColorNormal, 'CHT')
  1819. end
  1820. #--------------------------------------------------------------------------
  1821. # Executes chat command for a global chat message.
  1822. # message - the message to be sent
  1823. #--------------------------------------------------------------------------
  1824. def command_global_chat(message)
  1825. self.send_chat_message(message, RMXOS::Data::ColorGlobal, 'MGM')
  1826. end
  1827. #--------------------------------------------------------------------------
  1828. # Executes chat command for a whisper chat message.
  1829. # username - the target player for the message
  1830. # message - the message to be sent
  1831. #--------------------------------------------------------------------------
  1832. def command_whisper_chat(message, username = nil)
  1833. @last_whisper_name = username if username != nil
  1834. if @last_whisper_name != ''
  1835. self.send_chat_message(message, RMXOS::Data::ColorWhisper,
  1836. RMXOS.make_message('WCH', @last_whisper_name))
  1837. else
  1838. self.add_error(RMXOS::Data::WhisperNoLastName)
  1839. end
  1840. end
  1841. #--------------------------------------------------------------------------
  1842. # Executes chat command for a action chat message.
  1843. # message - the message to be sent
  1844. #--------------------------------------------------------------------------
  1845. def command_action_chat(message)
  1846. self.send_chat_message(message, RMXOS::Data::ColorAction, 'CHA')
  1847. end
  1848. #--------------------------------------------------------------------------
  1849. # Executes chat command for a guild chat message.
  1850. # message - the message to be sent
  1851. #--------------------------------------------------------------------------
  1852. def command_guild_chat(message)
  1853. if self.check_guild_action
  1854. self.send_chat_message(message, RMXOS::Data::ColorGuild, 'GME')
  1855. end
  1856. end
  1857. #--------------------------------------------------------------------------
  1858. # Executes chat command for trade request.
  1859. # username - the target player for the trade request
  1860. #--------------------------------------------------------------------------
  1861. def command_trade_request(username)
  1862. # if self
  1863. if @username == username
  1864. # show error message
  1865. self.add_error(RMXOS::Data::TradeSelfError)
  1866. else
  1867. # send request
  1868. self.send('TRQ', username)
  1869. end
  1870. end
  1871. #--------------------------------------------------------------------------
  1872. # Executes chat command for password change.
  1873. # old - old password
  1874. # new - new password
  1875. # prefix - message prefix code
  1876. #--------------------------------------------------------------------------
  1877. def command_password_change(old, new, prefix = 'NPS')
  1878. self.send(prefix, encrypt_password(old), encrypt_password(new))
  1879. end
  1880. #--------------------------------------------------------------------------
  1881. # Executes chat command for answering YES to an action request.
  1882. # request_id - the ID of the action request
  1883. #--------------------------------------------------------------------------
  1884. def command_yes(request_id)
  1885. self.send('YES', request_id)
  1886. end
  1887. #--------------------------------------------------------------------------
  1888. # Executes chat command for answering NO to an action request.
  1889. # request_id - the ID of the action request
  1890. #--------------------------------------------------------------------------
  1891. def command_no(request_id)
  1892. self.send('NOO', request_id)
  1893. end
  1894. #--------------------------------------------------------------------------
  1895. # Executes chat command for canceling an action request.
  1896. # request_id - the ID of the action request
  1897. #--------------------------------------------------------------------------
  1898. def command_cancel(request_id)
  1899. self.send('CAN', request_id)
  1900. end
  1901. #--------------------------------------------------------------------------
  1902. # Executes chat command for displaying all currently active action
  1903. # requests.
  1904. #--------------------------------------------------------------------------
  1905. def command_req
  1906. self.send('REQ')
  1907. end
  1908. #--------------------------------------------------------------------------
  1909. # Executes chat command for displaying all available commands.
  1910. #--------------------------------------------------------------------------
  1911. def command_show_commands
  1912. text = RMXOS::Data::HelpText + ' ' + RMXOS::Data::AvailableCommands
  1913. self.add_info(text + ' ' + RMXOS::Documentation.get_command_list.join(', '))
  1914. end
  1915. #--------------------------------------------------------------------------
  1916. # Executes chat command for displaying help text for a command.
  1917. # command - the command to be displayed
  1918. #--------------------------------------------------------------------------
  1919. def command_help(command)
  1920. self.add_info(RMXOS::Documentation.get_command_help(command))
  1921. end
  1922. #--------------------------------------------------------------------------
  1923. # Executes chat command for adding a player to the buddy list.
  1924. # username - username of the player
  1925. #--------------------------------------------------------------------------
  1926. def command_buddy_add(username)
  1927. # if already a buddy
  1928. if @buddies.include?(username)
  1929. # show error message
  1930. self.add_error(RMXOS::Data::BuddyAlreadyInList)
  1931. # if self
  1932. elsif @username == username
  1933. # show error message
  1934. self.add_error(RMXOS::Data::BuddySelfError)
  1935. else
  1936. # send request
  1937. self.send('BAD', username)
  1938. end
  1939. end
  1940. #--------------------------------------------------------------------------
  1941. # Executes chat command for removing a player from the buddy list.
  1942. # username - username of the player
  1943. #--------------------------------------------------------------------------
  1944. def command_buddy_remove(username)
  1945. # if not a buddy
  1946. if !@buddies.include?(username)
  1947. # show error message
  1948. self.add_error(RMXOS::Data::BuddyNotInList)
  1949. else
  1950. # send request
  1951. self.send('BRE', username)
  1952. end
  1953. end
  1954. #--------------------------------------------------------------------------
  1955. # Executes chat command for displaying the buddy list.
  1956. #--------------------------------------------------------------------------
  1957. def command_buddy_show
  1958. # show buddy list
  1959. if @buddies.size > 0
  1960. # add '(ON)' to buddies that are online right now
  1961. buddies = @buddies.map {|username|
  1962. if @players.any? {|key, value| value.username == username}
  1963. username += RMXOS::Data::OnlineTag
  1964. else
  1965. username = username
  1966. end
  1967. }
  1968. # create final display text
  1969. text = RMXOS::Data::BuddyList.sub('BUDDIES') {buddies.join(', ')}
  1970. else
  1971. # create display text, no buddies
  1972. text = RMXOS::Data::BuddyList.sub('BUDDIES') {'none'}
  1973. end
  1974. self.add_info(text)
  1975. end
  1976. #--------------------------------------------------------------------------
  1977. # Executes chat command for sending a PM.
  1978. # username - username of the player
  1979. # message - the message to be sent
  1980. #--------------------------------------------------------------------------
  1981. def command_pm_send(username, message)
  1982. # if not a buddy
  1983. if !@buddies.include?(username)
  1984. # show error message
  1985. self.add_error(RMXOS::Data::BuddyNotInList)
  1986. else
  1987. chars = message.scan(/./m)
  1988. # if PM is too long
  1989. if chars.size > RMXOS::Options::PM_MAX_LENGTH
  1990. # show error message
  1991. count = chars.size - RMXOS::Options::PM_MAX_LENGTH
  1992. error = RMXOS::Data::PMTooLong.sub('COUNT') {count}
  1993. self.add_error(error)
  1994. else
  1995. # send message
  1996. self.send('PMM', username, message)
  1997. end
  1998. end
  1999. end
  2000. #--------------------------------------------------------------------------
  2001. # Executes chat command for getting unread PMs.
  2002. #--------------------------------------------------------------------------
  2003. def command_pm_get_unread
  2004. self.send('PMU')
  2005. end
  2006. #--------------------------------------------------------------------------
  2007. # Executes chat command for getting all PMs.
  2008. #--------------------------------------------------------------------------
  2009. def command_pm_get_all
  2010. self.send('PMA')
  2011. end
  2012. #--------------------------------------------------------------------------
  2013. # Executes chat command for opening a PM.
  2014. # pm_id - ID of the PM
  2015. #--------------------------------------------------------------------------
  2016. def command_pm_open(pm_id)
  2017. self.send('PMO', pm_id)
  2018. end
  2019. #--------------------------------------------------------------------------
  2020. # Executes chat command for deleting a PM.
  2021. # pm_id - ID of the PM
  2022. #--------------------------------------------------------------------------
  2023. def command_pm_delete(pm_id)
  2024. self.send('PMD', pm_id)
  2025. end
  2026. #--------------------------------------------------------------------------
  2027. # Executes chat command for deleting all PMs.
  2028. #--------------------------------------------------------------------------
  2029. def command_pm_delete_all
  2030. self.send('PMC')
  2031. end
  2032. #--------------------------------------------------------------------------
  2033. # Executes chat command for getting the inbox status.
  2034. #--------------------------------------------------------------------------
  2035. def command_pm_status
  2036. self.send('PMS')
  2037. end
  2038. #--------------------------------------------------------------------------
  2039. # Executes chat command for creating a new guild.
  2040. # guildname - name of the new guild
  2041. # password - password of the new guild
  2042. #--------------------------------------------------------------------------
  2043. def command_guild_create(guildname, password)
  2044. # if allowed to execute action
  2045. if self.check_no_guild_action
  2046. # if guildname is reserved
  2047. if RMXOS.reserved_guildname?(guildname)
  2048. # show error message
  2049. self.add_error(RMXOS::Data::GuildReserved)
  2050. # if guildname is too long
  2051. elsif guildname.scan(/./m).size > RMXOS::Options::GUILDNAME_MAX_LENGTH
  2052. # show error message
  2053. self.add_error(RMXOS::Data::GuildTooLong)
  2054. else
  2055. # register the guild
  2056. self.send('GCR', guildname, encrypt_password(password))
  2057. end
  2058. end
  2059. end
  2060. #--------------------------------------------------------------------------
  2061. # Executes chat command for disbanding the guild.
  2062. # password - password of the guild
  2063. #--------------------------------------------------------------------------
  2064. def command_guild_disband(password)
  2065. # if allowed to execute action
  2066. if self.check_guildleader_action
  2067. # send password
  2068. self.send('GDI', encrypt_password(password))
  2069. end
  2070. end
  2071. #--------------------------------------------------------------------------
  2072. # Executes chat command for transferring guild leadership.
  2073. # username - username of the new guild leader
  2074. # password - password of the guild
  2075. #--------------------------------------------------------------------------
  2076. def command_guild_transfer(username, password)
  2077. # if allowed to execute action
  2078. if self.check_guildleader_action
  2079. # if username is self
  2080. if @username == username
  2081. # show error message
  2082. self.add_error(RMXOS::Data::GuildAlreadyLeader)
  2083. # if player is not a member of the guild
  2084. elsif !@guildmembers.include?(username)
  2085. # show error message
  2086. self.add_error(RMXOS::Data::GuildNotMember)
  2087. else
  2088. # send username and password
  2089. self.send('GTR', username, encrypt_password(password))
  2090. end
  2091. end
  2092. end
  2093. #--------------------------------------------------------------------------
  2094. # Executes chat command for inviting a new member into the guild.
  2095. # username - username of the new guild member
  2096. #--------------------------------------------------------------------------
  2097. def command_guild_invite(username)
  2098. # if allowed to execute action
  2099. if self.check_guildleader_action
  2100. # if already in the guild
  2101. if @guildmembers.include?(username)
  2102. # show error message
  2103. self.add_error(RMXOS::Data::GuildAlreadyMember)
  2104. else
  2105. # send invitation
  2106. self.send('GIN', username)
  2107. end
  2108. end
  2109. end
  2110. #--------------------------------------------------------------------------
  2111. # Executes chat command for removing a member from the guild.
  2112. # username - username of the guild member to be removed
  2113. # password - password of the guild
  2114. #--------------------------------------------------------------------------
  2115. def command_guild_remove(username, password)
  2116. # if allowed to execute action
  2117. if self.check_guildleader_action
  2118. # if already in the guild
  2119. if !@guildmembers.include?(username)
  2120. # show error message
  2121. self.add_error(RMXOS::Data::GuildAlreadyMember)
  2122. else
  2123. # send username and password
  2124. self.send('GRE', username, encrypt_password(password))
  2125. end
  2126. end
  2127. end
  2128. #--------------------------------------------------------------------------
  2129. # Executes chat command for leaving the guild.
  2130. # password - password of the player
  2131. #--------------------------------------------------------------------------
  2132. def command_guild_leave(password)
  2133. # if allowed to execute action
  2134. if self.guildleader?
  2135. # show error message
  2136. self.add_error(RMXOS::Data::GuildCannotLeave)
  2137. # if allowed to execute action
  2138. elsif self.check_guild_action
  2139. # send new password
  2140. self.send('GLE', encrypt_password(password))
  2141. end
  2142. end
  2143. #--------------------------------------------------------------------------
  2144. # Executes chat command for displaying guild information.
  2145. #--------------------------------------------------------------------------
  2146. def command_guild_info
  2147. # if allowed to execute action
  2148. if self.check_guild_action
  2149. # show guild info
  2150. text = RMXOS::Data::GuildInfo.sub('GUILD') {@guildname}
  2151. text = text.sub('LEADER') {@guildleader}
  2152. if @guildmembers.size > 1
  2153. # add '(ON)' to buddies that are online right now
  2154. members = (@guildmembers - [@guildleader]).map {|username|
  2155. if @players.any? {|key, value| value.username == username}
  2156. username += RMXOS::Data::OnlineTag
  2157. else
  2158. username = username
  2159. end
  2160. }
  2161. text = text.sub('MEMBERS') {members.join(', ')}
  2162. else
  2163. text = text.sub('MEMBERS') {'none'}
  2164. end
  2165. self.add_info(text)
  2166. end
  2167. end
  2168. #--------------------------------------------------------------------------
  2169. # Sends a load request server.
  2170. #--------------------------------------------------------------------------
  2171. def send_load_request
  2172. self.send('LRQ')
  2173. end
  2174. #--------------------------------------------------------------------------
  2175. # Sends save data to the server.
  2176. #--------------------------------------------------------------------------
  2177. def send_save_data
  2178. # marshal data
  2179. data = Marshal.dump(self.get_save_containers)
  2180. # create a hex stream
  2181. stream = data.unpack('H*').join('')
  2182. # send it to the server
  2183. self.send(RMXOS.make_message('SAV', 'no-legacy', stream))
  2184. end
  2185. #--------------------------------------------------------------------------
  2186. # Sends save data to the server.
  2187. #--------------------------------------------------------------------------
  2188. def send_save_data_legacy
  2189. serializations = []
  2190. # for each save container
  2191. self.get_save_containers.each {|container|
  2192. # if the container's class is on this saving list
  2193. if RMXOS::Options::SAVE_DATA[container.class] != nil
  2194. # recursively get save serializations
  2195. serializations += container.rmxos_serialize_legacy
  2196. end
  2197. }
  2198. # find all literals
  2199. literals = RMXOS::Options::SAVE_DATA.keys.find_all {|key|
  2200. !key.is_a?(Class)
  2201. }
  2202. # create serializations for literal saving data
  2203. literals.each {|key|
  2204. serializations.push(RMXOS.make_message('SAV', key, eval(key)))
  2205. }
  2206. # send all save serializations
  2207. serializations.each {|query| self.send(query)}
  2208. end
  2209. #--------------------------------------------------------------------------
  2210. # Saves the game. Only data from selected classes will be saved.
  2211. # classes - an array of classes which should be saved.
  2212. #--------------------------------------------------------------------------
  2213. def save
  2214. # abort if not logged in or not data exists (to prevent corruption)
  2215. return if @user_id <= 0 || !@game_loaded
  2216. # clear leftover data
  2217. self.send('SCL')
  2218. # send save data to server
  2219. if !RMXOS::Options::LEGACY_SAVE_METHOD
  2220. send_save_data
  2221. else
  2222. send_save_data_legacy
  2223. end
  2224. # send save end message to begin saving process
  2225. self.send('SEN')
  2226. # double autosave timer
  2227. @autosave_time *= 2
  2228. end
  2229. #--------------------------------------------------------------------------
  2230. # Gets the actual game data that can be saved.
  2231. # Returns: An array of all instances that can be saved.
  2232. #--------------------------------------------------------------------------
  2233. def get_save_containers
  2234. containers = []
  2235. RMXOS::Options::SAVE_CONTAINERS.each {|str| containers.push(eval(str))}
  2236. return containers
  2237. end
  2238. #--------------------------------------------------------------------------
  2239. # Loads the game from the data received from the server.
  2240. #--------------------------------------------------------------------------
  2241. def load_game_data
  2242. return if @load_data.size == 0
  2243. # get data
  2244. hex = @load_data['no-legacy']
  2245. # first reconstruct the original stream from the hex values
  2246. stream = hex.scan(/../).map {|h| ("0x" + h).hex.chr}.join('')
  2247. # unmarshal data
  2248. loaded = Marshal.load(stream)
  2249. # load data
  2250. RMXOS::Options::SAVE_CONTAINERS.each {|str|
  2251. break if loaded.size == 0
  2252. eval("#{str} = loaded.shift")
  2253. }
  2254. end
  2255. #--------------------------------------------------------------------------
  2256. # Loads the game from the data received from the server.
  2257. #--------------------------------------------------------------------------
  2258. def load_game_data_legacy
  2259. containers = self.get_save_containers
  2260. # get all loading data entries sorted ascending by string length
  2261. keys = @load_data.keys.sort {|a, b| a.size - b.size}
  2262. # filter out only high level entries
  2263. keys = keys.find_all {|key| key.split('/').size == 1}
  2264. # for each high level save data entry
  2265. keys.each {|name|
  2266. # evaluate the entry
  2267. data = eval(name)
  2268. # if entry is a class
  2269. if data.is_a?(Class)
  2270. # for each save container
  2271. containers.each {|container|
  2272. # if container class matches save data class
  2273. if container.class == data
  2274. # load this container's data with the entry's name
  2275. container.rmxos_deserialize_legacy(name)
  2276. break
  2277. end
  2278. }
  2279. else
  2280. # set the literal
  2281. eval("#{name} = #{data.inspect}")
  2282. end
  2283. }
  2284. end
  2285. #--------------------------------------------------------------------------
  2286. # Loads the game from the data received from the server.
  2287. #--------------------------------------------------------------------------
  2288. def load_game
  2289. # load received data
  2290. if !RMXOS::Options::LEGACY_SAVE_METHOD
  2291. load_game_data
  2292. else
  2293. load_game_data_legacy
  2294. end
  2295. end
  2296.  
  2297. end
  2298.  
  2299. end
  2300.  
  2301. #==============================================================================
  2302. # module PointerDerefence
  2303. #------------------------------------------------------------------------------
  2304. # Provides memory copying.
  2305. #==============================================================================
  2306.  
  2307. module PointerDerefence
  2308.  
  2309. #----------------------------------------------------------------------------
  2310. # Copies data from a pointer.
  2311. # length - number of bytes
  2312. # Returns: The copied data.
  2313. #----------------------------------------------------------------------------
  2314. def ref(length)
  2315. buffer = "\0" * length
  2316. Win32API.new('kernel32', 'RtlMoveMemory', 'ppl', '').call(buffer, self, length)
  2317. return buffer
  2318. end
  2319.  
  2320. end
  2321.  
  2322. class Numeric; include PointerDerefence; end;
  2323. class String; include PointerDerefence; end;
  2324.  
  2325. #==============================================================================
  2326. # module Winsock
  2327. #------------------------------------------------------------------------------
  2328. # Serves as wrapper for the used Win32API Socket functions.
  2329. #==============================================================================
  2330.  
  2331. module Winsock
  2332.  
  2333. DLL = 'ws2_32'
  2334.  
  2335. Win32API_bind = Win32API.new(DLL, 'bind', 'ppl', 'l')
  2336. Win32API_closesocket = Win32API.new(DLL, 'closesocket', 'p', 'l')
  2337. Win32API_setsockopt = Win32API.new(DLL, 'setsockopt', 'pllpl', 'l')
  2338. Win32API_connect = Win32API.new(DLL, 'connect', 'ppl', 'l')
  2339. Win32API_gethostbyname = Win32API.new(DLL, 'gethostbyname', 'p', 'l')
  2340. Win32API_recv = Win32API.new(DLL, 'recv', 'ppll', 'l')
  2341. Win32API_select = Win32API.new(DLL, 'select', 'lpppp', 'l')
  2342. Win32API_send = Win32API.new(DLL, 'send', 'ppll', 'l')
  2343. Win32API_socket = Win32API.new(DLL, 'socket', 'lll', 'l')
  2344. Win32API_WSAGetLastError = Win32API.new(DLL, 'WSAGetLastError', '', 'l')
  2345.  
  2346. def self.bind(*args); Win32API_bind.call(*args); end;
  2347. def self.closesocket(*args); Win32API_closesocket.call(*args); end;
  2348. def self.setsockopt(*args); Win32API_setsockopt.call(*args); end;
  2349. def self.connect(*args); Win32API_connect.call(*args); end;
  2350. def self.gethostbyname(*args); Win32API_gethostbyname.call(*args); end;
  2351. def self.recv(*args); Win32API_recv.call(*args); end;
  2352. def self.select(*args); Win32API_select.call(*args); end;
  2353. def self.send(*args); Win32API_send.call(*args); end;
  2354. def self.socket(*args); Win32API_socket.call(*args); end;
  2355. def self.WSAGetLastError(*args); Win32API_WSAGetLastError.call(*args); end;
  2356.  
  2357. end
  2358.  
  2359. #==============================================================================
  2360. # Socket
  2361. #------------------------------------------------------------------------------
  2362. # Creates and manages sockets.
  2363. #==============================================================================
  2364.  
  2365. class Socket
  2366.  
  2367. AF_INET = 2
  2368. SOCK_STREAM = 1
  2369. SOCK_DGRAM = 2
  2370. IPPROTO_TCP = 6
  2371. IPPROTO_UDP = 17
  2372.  
  2373. # set all accessible variables
  2374. attr_reader :host
  2375. attr_reader :port
  2376.  
  2377. #----------------------------------------------------------------------------
  2378. # Returns information about the given hostname.
  2379. #----------------------------------------------------------------------------
  2380. def self.gethostbyname(name)
  2381. data = Winsock.gethostbyname(name)
  2382. raise SocketError::ENOASSOCHOST if data == 0
  2383. host = data.ref(16).unpack('LLssL')
  2384. name = host[0].ref(256).unpack("c*").pack("c*").split("\0")[0]
  2385. address_type = host[2]
  2386. address_list = host[4].ref(4).unpack('L')[0].ref(4).unpack("c*").pack("c*")
  2387. return [name, [], address_type, address_list]
  2388. end
  2389. #----------------------------------------------------------------------------
  2390. # Creates an INET-sockaddr struct.
  2391. #----------------------------------------------------------------------------
  2392. def self.sockaddr_in(host, port)
  2393. begin
  2394. [AF_INET, port].pack('sn') + gethostbyname(host)[3] + [].pack('x8')
  2395. rescue
  2396. end
  2397. end
  2398. #----------------------------------------------------------------------------
  2399. # Creates a new socket and connects it to the given host and port.
  2400. #----------------------------------------------------------------------------
  2401. def self.open(*args)
  2402. socket = new(*args)
  2403. if block_given?
  2404. begin
  2405. yield socket
  2406. ensure
  2407. socket.close
  2408. end
  2409. end
  2410. return nil
  2411. end
  2412. #----------------------------------------------------------------------------
  2413. # Creates a new socket.
  2414. #----------------------------------------------------------------------------
  2415. def initialize(domain, type, protocol)
  2416. @descriptor = Winsock.socket(domain, type, protocol)
  2417. SocketError.check if @descriptor == -1
  2418. return @descriptor
  2419. end
  2420. #----------------------------------------------------------------------------
  2421. # Binds a socket to the given sockaddr.
  2422. #----------------------------------------------------------------------------
  2423. def bind(sockaddr)
  2424. result = Winsock.bind(@descriptor, sockaddr, sockaddr.size)
  2425. SocketError.check if result == -1
  2426. return result
  2427. end
  2428. #----------------------------------------------------------------------------
  2429. # Closes a socket.
  2430. #----------------------------------------------------------------------------
  2431. def close
  2432. result = Winsock.closesocket(@descriptor)
  2433. SocketError.check if result == -1
  2434. return result
  2435. end
  2436. #----------------------------------------------------------------------------
  2437. # Connects a socket to the given sockaddr.
  2438. #----------------------------------------------------------------------------
  2439. def connect(host, port)
  2440. @host, @port = host, port
  2441. sockaddr = Socket.sockaddr_in(@host, @port)
  2442. result = Winsock.connect(@descriptor, sockaddr, sockaddr.size)
  2443. SocketError.check if result == -1
  2444. return result
  2445. end
  2446. #----------------------------------------------------------------------------
  2447. # Checks waiting data's status.
  2448. #----------------------------------------------------------------------------
  2449. def select(timeout)
  2450. result = Winsock.select(1, [1, @descriptor].pack('ll'), 0, 0, [timeout, timeout * 1000000].pack('ll'))
  2451. SocketError.check if result == -1
  2452. return result
  2453. end
  2454. #----------------------------------------------------------------------------
  2455. # Checks if data is waiting.
  2456. #----------------------------------------------------------------------------
  2457. def ready?
  2458. return (self.select(0) != 0)
  2459. end
  2460. #----------------------------------------------------------------------------
  2461. # Returns recieved data.
  2462. #----------------------------------------------------------------------------
  2463. def recv(length, flags = 0)
  2464. buffer = "\0" * length
  2465. result = Winsock.recv(@descriptor, buffer, length, flags)
  2466. SocketError.check if result == -1
  2467. return '' if result == 0
  2468. return buffer[0, result].unpack("c*").pack("c*") # gets rid of a bunch of \0
  2469. end
  2470. #----------------------------------------------------------------------------
  2471. # Sends data to a host.
  2472. #----------------------------------------------------------------------------
  2473. def send(data, flags = 0)
  2474. result = Winsock.send(@descriptor, data, data.size, flags)
  2475. SocketError.check if result == -1
  2476. return result
  2477. end
  2478.  
  2479. end
  2480.  
  2481. #==============================================================================
  2482. # TCPSocket
  2483. #------------------------------------------------------------------------------
  2484. # Represents a TCP Socket Connection.
  2485. #==============================================================================
  2486.  
  2487. class TCPSocket < Socket
  2488.  
  2489. #----------------------------------------------------------------------------
  2490. # Initialization.
  2491. # host - IP or URL of the hots
  2492. # port - port number
  2493. #----------------------------------------------------------------------------
  2494. def initialize(host = nil, port = nil)
  2495. super(AF_INET, SOCK_STREAM, IPPROTO_TCP)
  2496. self.connect(host, port) if host != nil && port != nil
  2497. end
  2498.  
  2499. end
  2500.  
  2501. #==============================================================================
  2502. # SocketError
  2503. #------------------------------------------------------------------------------
  2504. # Default exception class for sockets.
  2505. #==============================================================================
  2506.  
  2507. class SocketError < StandardError
  2508.  
  2509. ENOASSOCHOST = 'getaddrinfo: no address associated with hostname.'
  2510.  
  2511. def self.check
  2512. errno = Winsock.WSAGetLastError
  2513. raise Errno.const_get(Errno.constants.detect {|c|
  2514. Errno.const_get(c).new.errno == errno}
  2515. )
  2516. end
  2517.  
  2518. end
  2519.  
  2520. class Hangup < Exception
  2521. end
  2522.  
  2523. #==============================================================================
  2524. # Object
  2525. #------------------------------------------------------------------------------
  2526. # Enhanced with methods for self-encoding of contained data and methods for
  2527. # decoding of saved game data that was received from the server.
  2528. #==============================================================================
  2529.  
  2530. class Object
  2531.  
  2532. #----------------------------------------------------------------------------
  2533. # Checks whether this object is actually a literal. (Literals are here
  2534. # defined as strings, numbers, ranges, true, false and nil.)
  2535. # Returns: True or false.
  2536. #----------------------------------------------------------------------------
  2537. def literal?
  2538. return (self.is_a?(String) || self.is_a?(Numeric) || self.is_a?(Range) ||
  2539. self.is_a?(TrueClass) || self.is_a?(FalseClass) || self.is_a?(NilClass))
  2540. end
  2541. #----------------------------------------------------------------------------
  2542. # Serializes the object and all contained objects for the RMX-OS SQL
  2543. # database.
  2544. # prefix - semantical prefix for the serializations
  2545. # Returns: Array of serialization strings.
  2546. #----------------------------------------------------------------------------
  2547. def rmxos_serialize_legacy(prefix = nil)
  2548. # add prefix extension if this isn't a top level class
  2549. (prefix == nil ? prefix = "SAV\t" : prefix += '/')
  2550. # add class name
  2551. prefix += self.class.name
  2552. # prepare result and data arrays
  2553. serializations, data = [], []
  2554. # for each variable that this class should save
  2555. RMXOS::Options::SAVE_DATA[self.class].each {|variable|
  2556. # get value of variable
  2557. value = self.instance_variable_get(variable)
  2558. # if value is of a class that should be saved as well
  2559. if RMXOS::Options::SAVE_DATA[value.class] != nil ||
  2560. value.is_a?(Array) || value.is_a?(Hash)
  2561. # get serializations from this value with this class as prefix
  2562. serializations += value.rmxos_serialize_legacy("#{prefix}/#{variable}")
  2563. data.push(value.class)
  2564. # if value is literal
  2565. elsif value.literal?
  2566. data.push(value)
  2567. else
  2568. # can't save this value
  2569. raise RMXOS::Error.get_save_error(value)
  2570. end
  2571. }
  2572. # if there is any data
  2573. if data.size > 0
  2574. # inspect and compress
  2575. data = data.inspect.gsub(', ') {','}
  2576. # add data array query
  2577. serializations.unshift("#{prefix}\t#{data}")
  2578. end
  2579. return serializations
  2580. end
  2581. #----------------------------------------------------------------------------
  2582. # Serializes array and hashes for the RMX-OS SQL database.
  2583. # prefix - semantical prefix for the serializations
  2584. # indices - array of indices (array) or keys (hash)
  2585. # all_literals - whether all elements are literals or not
  2586. # Returns: Array serialization strings.
  2587. #----------------------------------------------------------------------------
  2588. def rmxos_serialize_legacy_collection(prefix, indices, all_literals)
  2589. # prepare result
  2590. serializations = []
  2591. # if all array elements are literals
  2592. if all_literals
  2593. # get as string
  2594. data = self.inspect
  2595. else
  2596. # create new instance of this class
  2597. data = self.class.new
  2598. # for each index in enumerable
  2599. indices.each {|i|
  2600. # if element is literal
  2601. if self[i].literal?
  2602. # add it to the result
  2603. data[i] = self[i]
  2604. # if element is of a class that should be saved as well
  2605. elsif RMXOS::Options::SAVE_DATA[self[i].class] != nil ||
  2606. self[i].is_a?(Array) || self[i].is_a?(Hash)
  2607. # get serializations from this element with this class as prefix
  2608. serializations += self[i].rmxos_serialize_legacy("#{prefix}[#{i.inspect}]")
  2609. # add elements's class to data array
  2610. data[i] = self[i].class
  2611. else
  2612. # can't save this value
  2613. raise RMXOS::Error.get_save_error(self[i])
  2614. end
  2615. }
  2616. # inspect and compress
  2617. data = data.inspect
  2618. end
  2619. # add a little bit of compression :)
  2620. data.gsub!(', ') {','}
  2621. # add data array query
  2622. serializations.push("#{prefix}\t#{data}")
  2623. return serializations
  2624. end
  2625. #----------------------------------------------------------------------------
  2626. # Deserializes data retrieved from the server into this object.
  2627. # name - the key for the hash data retrieved from the server
  2628. #----------------------------------------------------------------------------
  2629. def rmxos_deserialize_legacy(name)
  2630. # evaluate the data for this class which turns into an array
  2631. data = eval($network.load_data[name])
  2632. # iterate through all indices of variables that are to be saved
  2633. RMXOS::Options::SAVE_DATA[self.class].each_index {|i|
  2634. # get variable name
  2635. variable = RMXOS::Options::SAVE_DATA[self.class][i]
  2636. # if this variable's loaded value is a class
  2637. if data[i].is_a?(Class)
  2638. # access key for loaded data
  2639. key = "#{name}/#{variable}"
  2640. # if it's an array
  2641. if data[i] == Array
  2642. # evaluate and get the loaded array
  2643. data[i] = eval($network.load_data[key])
  2644. # load all classes contained in this array
  2645. rmxos_deserialize_legacy_collection(name, variable, data[i],
  2646. (0...data[i].size).to_a)
  2647. elsif data[i] == Hash
  2648. # evaluate and get the loaded hash
  2649. data[i] = eval($network.load_data[key])
  2650. # load all classes contained in this hash
  2651. rmxos_deserialize_legacy_collection(name, variable, data[i], data[i].keys)
  2652. else
  2653. # load this class
  2654. data[i] = rmxos_deserialize_legacy_object(key, data[i])
  2655. end
  2656. end
  2657. # set the variable to this value
  2658. self.instance_variable_set(variable, data[i])
  2659. }
  2660. end
  2661. #----------------------------------------------------------------------------
  2662. # Deserializes data retrieved from an array or a hash.
  2663. # name - the key for the hash data retrieved from the server
  2664. # variable - name of the variable containing the array
  2665. # data - actual array or hash
  2666. # indices - array of indices (array) or keys (hash)
  2667. #----------------------------------------------------------------------------
  2668. def rmxos_deserialize_legacy_collection(name, variable, data, indices)
  2669. # iterate through all indices
  2670. indices.each {|i|
  2671. # if data is a class
  2672. if data[i].is_a?(Class)
  2673. # access key for loaded data
  2674. key = "#{name}/#{variable}[#{i.inspect}]"
  2675. # if it's an array
  2676. if data[i] == Array
  2677. # evaluate and get the loaded array
  2678. data[i] = eval($network.load_data[key])
  2679. # load all classes contained in this array
  2680. rmxos_deserialize_legacy_collection(name, "#{variable}[#{i.inspect}]",
  2681. data[i], (0...data[i].size).to_a)
  2682. elsif data[i] == Hash
  2683. # evaluate and get the loaded hash
  2684. data[i] = eval($network.load_data[key])
  2685. # load all classes contained in this hash
  2686. rmxos_deserialize_legacy_collection(name, "#{variable}[#{i.inspect}]",
  2687. data[i], data[i].keys)
  2688. else
  2689. # load this class
  2690. data[i] = rmxos_deserialize_legacy_object(key, data[i])
  2691. end
  2692. end
  2693. }
  2694. end
  2695. #----------------------------------------------------------------------------
  2696. # Deserializes data retrieved from the server into this object.
  2697. # prefix - semantical prefix for loaded data access
  2698. # classe - class that needs to be instantiated
  2699. # Returns: New instance of a class after loading.
  2700. #----------------------------------------------------------------------------
  2701. def rmxos_deserialize_legacy_object(prefix, classe)
  2702. # if classe requires additional creation arguments
  2703. if RMXOS::Options::CREATION_DATA.has_key?(classe)
  2704. # get the arguments
  2705. args = RMXOS::Options::CREATION_DATA[classe]
  2706. # create an instance with those arguments
  2707. new = eval("#{classe.name}.new(#{args})")
  2708. else
  2709. # simply instantiate the class
  2710. new = classe.new
  2711. end
  2712. # load data for this class
  2713. new.rmxos_deserialize_legacy("#{prefix}/#{classe.name}")
  2714. return new
  2715. end
  2716.  
  2717. end
  2718.  
  2719. #==============================================================================
  2720. # Array
  2721. #------------------------------------------------------------------------------
  2722. # Arrays need to be encoded and decoded differently than other obejcts.
  2723. #==============================================================================
  2724.  
  2725. class Array
  2726.  
  2727. #----------------------------------------------------------------------------
  2728. # Serializes the object and all contained objects for the RMX-OS SQL
  2729. # database.
  2730. # prefix - semantical prefix for the serializations
  2731. # Returns: Array of serialization strings.
  2732. #----------------------------------------------------------------------------
  2733. def rmxos_serialize_legacy(prefix)
  2734. # all indices
  2735. indices = (0...self.size).to_a
  2736. # are all elements literals
  2737. all_literals = !self.any? {|val| !val.literal?}
  2738. # return serializations from this array
  2739. return self.rmxos_serialize_legacy_collection(prefix, indices, all_literals)
  2740. end
  2741.  
  2742. end
  2743.  
  2744. #==============================================================================
  2745. # Hash
  2746. #------------------------------------------------------------------------------
  2747. # Hashes need to be encoded and decoded differently than other obejcts.
  2748. #==============================================================================
  2749.  
  2750. class Hash
  2751.  
  2752. #----------------------------------------------------------------------------
  2753. # Serializes the object and all contained objects for the RMX-OS SQL
  2754. # database.
  2755. # prefix - semantical prefix for the serializations
  2756. # Returns: Array of serialization strings.
  2757. #----------------------------------------------------------------------------
  2758. def rmxos_serialize_legacy(prefix)
  2759. # all keys
  2760. indices = self.keys
  2761. # are all elements literals
  2762. all_literals = !self.any? {|key, val| !val.literal?}
  2763. # return serializations from this hash
  2764. return self.rmxos_serialize_legacy_collection(prefix, indices, all_literals)
  2765. end
  2766.  
  2767. end
  2768.  
  2769. #==============================================================================
  2770. # Bitmap
  2771. #------------------------------------------------------------------------------
  2772. # Extended with text handling methods.
  2773. #==============================================================================
  2774.  
  2775. class Bitmap
  2776.  
  2777. #----------------------------------------------------------------------------
  2778. # Uses an aliased version of draw_text to draw outlined text.
  2779. # x2 - x-coordinate
  2780. # y2 - y-coordinate
  2781. # w2 - width
  2782. # h2 - height
  2783. # text2 - text
  2784. # a2 - align
  2785. #----------------------------------------------------------------------------
  2786. # if method not aliased already
  2787. if $tons_version == nil || $tons_version < 1.6
  2788. # alias original method
  2789. alias draw_text_shaded_later draw_text
  2790. end
  2791. def draw_text_full(x2, y2, w2 = 0, h2 = 0, text2 = '', a2 = 0)
  2792. # if x2 is a rectangle
  2793. if x2.is_a?(Rect)
  2794. # set temporary variables
  2795. x, y, w, h, text, a = x2.x, x2.y, x2.width, x2.height, y2, w2
  2796. else
  2797. # set temporary variables
  2798. x, y, w, h, text, a = x2, y2, w2, h2, text2, a2
  2799. end
  2800. # save old font color
  2801. save_color = self.font.color.clone
  2802. # set new font color (black)
  2803. self.font.color = Color.new(0, 0, 0)
  2804. # draw text with offsets in all directions
  2805. [x - 1, x + 1].each {|xx|
  2806. [y - 1, y + 1].each {|yy|
  2807. draw_text_shaded_later(xx, yy, w, h, text, a)
  2808. }
  2809. }
  2810. # restore original color
  2811. self.font.color = save_color
  2812. # drw text at normal postion
  2813. draw_text_shaded_later(x, y, w, h, text, a)
  2814. end
  2815. #----------------------------------------------------------------------------
  2816. # Slices text to fit a specific width.
  2817. # text - text to slice
  2818. # width - max width of the text
  2819. # Returns: Array of text slices
  2820. #----------------------------------------------------------------------------
  2821. def slice_text(text, width)
  2822. # split string by words
  2823. words = text.split(' ')
  2824. # only one word, no need to split
  2825. return words if words.size == 1
  2826. # initialize
  2827. result, current_text = [], words.shift
  2828. # check each word
  2829. words.each_index {|i|
  2830. # if too long
  2831. if self.text_size("#{current_text} #{words[i]}").width > width
  2832. # save the text from before
  2833. result.push(current_text)
  2834. # next word
  2835. current_text = words[i]
  2836. else
  2837. # add to text from before
  2838. current_text = "#{current_text} #{words[i]}"
  2839. end
  2840. # add last word
  2841. result.push(current_text) if i >= words.size - 1
  2842. }
  2843. return result
  2844. end
  2845.  
  2846. end
  2847.  
  2848. #==============================================================================
  2849. # Game_Temp
  2850. #==============================================================================
  2851.  
  2852. class Game_Temp
  2853.  
  2854. # setting all accessible variables
  2855. attr_accessor :chat_calling
  2856. attr_accessor :chat_visible
  2857. attr_accessor :chat_active
  2858. attr_accessor :chat_messages
  2859. attr_accessor :chat_logs
  2860. attr_accessor :chat_refresh
  2861. attr_accessor :chat_sprites
  2862. attr_accessor :name_sprites
  2863. attr_accessor :entering_map
  2864. attr_accessor :trade_active
  2865. attr_accessor :trade_host
  2866. attr_accessor :trade_id
  2867. attr_accessor :trade_items
  2868. attr_accessor :trade_abort
  2869. attr_accessor :trade_confirmed
  2870. attr_accessor :trade_canceled
  2871. attr_accessor :trade_cancel_confirmed
  2872. attr_accessor :trade_finalized
  2873. #----------------------------------------------------------------------------
  2874. # Altered to instantiate new variables.
  2875. #----------------------------------------------------------------------------
  2876. alias initialize_rmxos_later initialize
  2877. def initialize
  2878. initialize_rmxos_later
  2879. @chat_calling = false
  2880. @chat_visible = true
  2881. @chat_active = false
  2882. @chat_messages = []
  2883. @chat_logs = []
  2884. @chat_refresh = false
  2885. @chat_sprites = true
  2886. @name_sprites = true
  2887. @entering_map = false
  2888. self.trade_reset
  2889. end
  2890. #----------------------------------------------------------------------------
  2891. # Resets all variables for trading.
  2892. #----------------------------------------------------------------------------
  2893. def trade_reset
  2894. @trade_active = false
  2895. @trade_host = false
  2896. @trade_id = -1
  2897. @trade_items = {}
  2898. @trade_abort = false
  2899. @trade_confirmed = false
  2900. @trade_canceled = false
  2901. @trade_cancel_confirmed = false
  2902. @trade_finalized = nil
  2903. end
  2904.  
  2905. end
  2906.  
  2907. #==============================================================================
  2908. # Game_Character
  2909. #==============================================================================
  2910.  
  2911. class Game_Map
  2912.  
  2913. #----------------------------------------------------------------------------
  2914. # Altered for map change execution.
  2915. #----------------------------------------------------------------------------
  2916. alias update_rmxos_later update
  2917. def update(main = false)
  2918. update_rmxos_later(main)
  2919. if $game_temp.entering_map
  2920. # remove all current players from this map
  2921. $network.clear_map_players
  2922. $network.send_exchange_variables
  2923. # enter new map
  2924. $network.enter_map
  2925. $network.wait_for_map_data
  2926. end
  2927. end
  2928.  
  2929. end
  2930.  
  2931. #==============================================================================
  2932. # Game_Character
  2933. #==============================================================================
  2934.  
  2935. class Game_Character
  2936.  
  2937. # setting all accessible variables
  2938. attr_reader :anime_count
  2939. attr_reader :chat_messages
  2940. #----------------------------------------------------------------------------
  2941. # Altered to updates chat message bubbles.
  2942. #----------------------------------------------------------------------------
  2943. alias update_rmxos_later update
  2944. def update
  2945. update_rmxos_later
  2946. update_chat_messages
  2947. update_exchange_variables
  2948. end
  2949. #----------------------------------------------------------------------------
  2950. # Updates all chat message bubbles and removes the one that have expired.
  2951. #----------------------------------------------------------------------------
  2952. def update_chat_messages
  2953. @chat_messages = [] if @chat_messages == nil
  2954. @chat_messages.clone.each {|chat_message|
  2955. if chat_message.expired?
  2956. @chat_messages.delete(chat_message)
  2957. else
  2958. chat_message.time -= 1
  2959. end
  2960. }
  2961. end
  2962. #----------------------------------------------------------------------------
  2963. # Adds chat messages to bubble chat display queue.
  2964. # messages - array of messages
  2965. # color - text display color
  2966. #----------------------------------------------------------------------------
  2967. def add_chat_messages(messages, color)
  2968. @chat_messages = [] if @chat_messages == nil
  2969. messages.each {|text|
  2970. @chat_messages.push(RMXOS::ChatBubbleMessage.new(text, color))
  2971. }
  2972. while @chat_messages.size > RMXOS::Data::ChatBubbleEntries
  2973. @chat_messages.shift
  2974. end
  2975. end
  2976. #----------------------------------------------------------------------------
  2977. # Gets the used exchange variable names.
  2978. # Returns: Array with variable names.
  2979. #----------------------------------------------------------------------------
  2980. def get_exchange_variable_names
  2981. return []
  2982. end
  2983. #----------------------------------------------------------------------------
  2984. # Stores exchange variables.
  2985. # variables - the exchange variables
  2986. #----------------------------------------------------------------------------
  2987. def store_exchange_variables(variables)
  2988. # update the exchange variable records
  2989. @exchange_variables = {} if @exchange_variables == nil
  2990. variables.each_key {|key| @exchange_variables[key] = variables[key]}
  2991. end
  2992. #----------------------------------------------------------------------------
  2993. # Sends a hash of exchange variables to the server.
  2994. # variables - the exchange variables the will be sent
  2995. # Returns: The variables that were actually sent.
  2996. #----------------------------------------------------------------------------
  2997. def send_exchange_variables(variables = nil)
  2998. return (variables != nil ? variables : self.get_exchange_variables)
  2999. end
  3000. #----------------------------------------------------------------------------
  3001. # Gets a hash with the current values of the exchange variables.
  3002. # names - names of the exchange variables
  3003. # Returns: Hash with values of variables.
  3004. #----------------------------------------------------------------------------
  3005. def get_exchange_variables(names = nil)
  3006. # get all exchange variables if none were specified
  3007. names = get_exchange_variable_names if names == nil
  3008. variables = {}
  3009. # for each exchange variable name
  3010. names.each {|name|
  3011. keys = name.split('|')
  3012. current = self
  3013. # recursively get the value
  3014. while keys.size > 0 && current != nil
  3015. current = current.instance_variable_get(keys.shift)
  3016. end
  3017. variables[name] = current if keys.size == 0
  3018. }
  3019. return variables
  3020. end
  3021. #----------------------------------------------------------------------------
  3022. # Gets a hash with exchange variable values that have changed.
  3023. # Returns: Hash with changed variables.
  3024. #----------------------------------------------------------------------------
  3025. def get_exchange_variables_changes
  3026. @exchange_variables = {} if @exchange_variables == nil
  3027. # get all variables
  3028. variables = self.get_exchange_variables
  3029. changed = {}
  3030. # find new keys
  3031. new_keys = variables.keys - @exchange_variables.keys
  3032. # new variables need to be updated
  3033. new_keys.each {|key| changed[key] = variables[key]}
  3034. # get changed variables
  3035. (@exchange_variables.keys - new_keys).each {|key|
  3036. if @exchange_variables[key] != variables[key]
  3037. changed[key] = variables[key]
  3038. end
  3039. }
  3040. return changed
  3041. end
  3042. #----------------------------------------------------------------------------
  3043. # Updates exchange variable values and sends them to server if necessary.
  3044. #----------------------------------------------------------------------------
  3045. def update_exchange_variables
  3046. end
  3047. #----------------------------------------------------------------------------
  3048. # Evaluates player exchange variables received from the server.
  3049. # variables - hash of exchange_variables
  3050. #----------------------------------------------------------------------------
  3051. def evaluate(variables)
  3052. # for each variable
  3053. variables.each_key {|key|
  3054. current = self
  3055. keys = key.split('|')
  3056. name = keys.pop
  3057. # recursively get object
  3058. while keys.size > 0 && current != nil
  3059. current = current.instance_variable_get(keys.shift)
  3060. end
  3061. # set variable
  3062. current.instance_variable_set(name, variables[key]) if current != nil
  3063. }
  3064. end
  3065.  
  3066. end
  3067.  
  3068. #==============================================================================
  3069. # Game_Player
  3070. #==============================================================================
  3071.  
  3072. class Game_Player
  3073.  
  3074. # setting all accessible variables
  3075. attr_reader :move_speed
  3076. #----------------------------------------------------------------------------
  3077. # Altered to send player coordinates to the server when there is a change
  3078. # in positioning or other related attributes.
  3079. #----------------------------------------------------------------------------
  3080. alias update_network_later update
  3081. def update
  3082. # no freezing condition
  3083. if !$game_temp.chat_active
  3084. # call original method
  3085. update_network_later
  3086. else
  3087. super
  3088. end
  3089. end
  3090. #----------------------------------------------------------------------------
  3091. # Gets the used exchange variable names.
  3092. # Returns: Array with variable names.
  3093. #----------------------------------------------------------------------------
  3094. def get_exchange_variable_names
  3095. return RMXOS::Options::EXCHANGE_VARIABLES.clone
  3096. end
  3097. #----------------------------------------------------------------------------
  3098. # Updates exchange variable values and sends them to server if necessary.
  3099. #----------------------------------------------------------------------------
  3100. def update_exchange_variables
  3101. changed = self.get_exchange_variables_changes
  3102. if changed.size > 0
  3103. self.send_exchange_variables(changed)
  3104. self.store_exchange_variables(changed)
  3105. end
  3106. end
  3107. #----------------------------------------------------------------------------
  3108. # Sends a hash of exchange variables to the server.
  3109. # variables - the exchange variables the will be sent
  3110. # Returns: The variables that were actually sent.
  3111. #----------------------------------------------------------------------------
  3112. def send_exchange_variables(variables = nil)
  3113. variables = super(variables)
  3114. # send variables over network
  3115. $network.send_exchange_variables(variables)
  3116. return variables
  3117. end
  3118.  
  3119. end
  3120.  
  3121. #==============================================================================
  3122. # Sprite_Character
  3123. #==============================================================================
  3124.  
  3125. class Sprite_Character
  3126.  
  3127. #--------------------------------------------------------------------------
  3128. # Altered to update the name sprite as well.
  3129. #--------------------------------------------------------------------------
  3130. alias update_rmxos_later update
  3131. def update
  3132. # call original method
  3133. update_rmxos_later
  3134. # if name sprites are on
  3135. if $game_temp.name_sprites
  3136. # update name sprites
  3137. update_name_sprite
  3138. # if name sprite exists
  3139. elsif @name_sprite != nil
  3140. # delete it
  3141. @name_sprite.dispose
  3142. @name_sprite = nil
  3143. end
  3144. # if chat sprites are on
  3145. if $game_temp.chat_sprites
  3146. # update chat sprites if chat bubbles are active
  3147. update_chat_sprite if RMXOS::Options::CHAT_BUBBLES
  3148. # if chat sprite exists
  3149. elsif @chat_sprite != nil
  3150. # delete it
  3151. @chat_sprite.dispose
  3152. @chat_sprite = nil
  3153. end
  3154. end
  3155. #--------------------------------------------------------------------------
  3156. # Updates the name sprite.
  3157. #--------------------------------------------------------------------------
  3158. def update_name_sprite
  3159. username = nil
  3160. usergroup = nil
  3161. guildname = nil
  3162. # if player
  3163. if @character == $game_player
  3164. # get name
  3165. username = $network.username
  3166. guildname = $network.guildname
  3167. # if any other player
  3168. elsif @character.is_a?(Game_OnlineCharacter)
  3169. # get name and group
  3170. username = @character.username
  3171. usergroup = @character.usergroup
  3172. guildname = @character.guildname
  3173. end
  3174. # if name exists and either sprite doesn't exist or name wasn't set yet
  3175. if username != nil && (@name_sprite == nil || @username != username ||
  3176. @usergroup != usergroup || @guildname != guildname)
  3177. # set username
  3178. @username = username
  3179. # set usergroup
  3180. @usergroup = usergroup
  3181. # set guildname
  3182. @guildname = guildname
  3183. # remove old sprite if one exists
  3184. @name_sprite.dispose if @name_sprite != nil
  3185. # create new sprite
  3186. @name_sprite = Sprite.new
  3187. @name_sprite.bitmap = Bitmap.new(1, 1)
  3188. @name_sprite.bitmap.font.size = 21
  3189. # calculate width of name
  3190. has_guild = (RMXOS::Options::GUILD_NAME_SPRITES && guildname != '')
  3191. text = username
  3192. w = @name_sprite.bitmap.text_size(text).width + 2
  3193. # coordinates offsets
  3194. y = 0
  3195. h = 24
  3196. guild_text = "[#{guildname}]"
  3197. # if has guild text
  3198. if has_guild
  3199. # modify coordinates
  3200. y += 22
  3201. h += 22
  3202. guild_w = @name_sprite.bitmap.text_size(guild_text).width + 2
  3203. w = guild_w if w < guild_w
  3204. end
  3205. # create bitmap
  3206. @name_sprite.bitmap = Bitmap.new(w, h)
  3207. @name_sprite.bitmap.font.size = 21
  3208. # set coordinates
  3209. @name_sprite.ox = w / 2
  3210. @name_sprite.oy = self.bitmap.height / 4 + h
  3211. # draw guild text
  3212. if has_guild
  3213. @name_sprite.bitmap.font.color = RMXOS::Data::COLORS['guild']
  3214. @name_sprite.bitmap.draw_text_full(1, 1, w, 24, guild_text, 1)
  3215. end
  3216. # if this player
  3217. if usergroup == nil
  3218. # self color
  3219. @name_sprite.bitmap.font.color = RMXOS::Data::COLORS['self']
  3220. # if group color exists
  3221. elsif RMXOS::Data::COLORS.has_key?(usergroup)
  3222. # get group color
  3223. @name_sprite.bitmap.font.color = RMXOS::Data::COLORS[usergroup]
  3224. else
  3225. # white
  3226. @name_sprite.bitmap.font.color = RMXOS::Data::COLORS[GROUP_PLAYER]
  3227. end
  3228. # draw name
  3229. @name_sprite.bitmap.draw_text_full(1, y + 1, w, 24, username, 1)
  3230. end
  3231. # if sprite exists
  3232. if @name_sprite != nil
  3233. # make sure name sprite is at the proper position
  3234. @name_sprite.x, @name_sprite.y, @name_sprite.z = self.x, self.y, self.z
  3235. end
  3236. end
  3237. #--------------------------------------------------------------------------
  3238. # Updates the chat sprite.
  3239. #--------------------------------------------------------------------------
  3240. def update_chat_sprite
  3241. # if this player or any other player
  3242. if @character == $game_player || @character.is_a?(Game_OnlineCharacter)
  3243. # get messages
  3244. chat_messages = @character.chat_messages
  3245. else
  3246. chat_messages = nil
  3247. end
  3248. # if chat messages have changed
  3249. if chat_messages != nil && @chat_messages != chat_messages
  3250. @chat_messages = chat_messages.clone
  3251. # if sprite exists
  3252. if @chat_sprite != nil
  3253. # remove old bitmap and sprite
  3254. @chat_sprite.bitmap.dispose
  3255. @chat_sprite.dispose
  3256. end
  3257. # if there are no chat messages
  3258. if @chat_messages.size == 0
  3259. @chat_sprite = nil
  3260. else
  3261. # create new sprite
  3262. @chat_sprite = Sprite.new
  3263. @chat_sprite.bitmap = Bitmap.new(1, 1)
  3264. @chat_sprite.bitmap.font.size = RMXOS::Data::ChatFontHeight
  3265. # calculate width of maximum message
  3266. w = 0
  3267. @chat_messages.each {|message|
  3268. width = @chat_sprite.bitmap.text_size(message.text).width + 4
  3269. w = width if width > w
  3270. }
  3271. h = 24
  3272. h += 24 if (RMXOS::Options::GUILD_NAME_SPRITES && @guildname != '')
  3273. # set offsets
  3274. @chat_sprite.ox = w / 2
  3275. @chat_sprite.oy = self.bitmap.height / 4 + h + @chat_messages.size *
  3276. RMXOS::Data::ChatFontHeight
  3277. @chat_sprite.bitmap.dispose
  3278. @chat_sprite.bitmap = Bitmap.new(w, @chat_messages.size *
  3279. RMXOS::Data::ChatFontHeight)
  3280. @chat_sprite.bitmap.font.size = RMXOS::Data::ChatFontHeight
  3281. @chat_sprite.bitmap.fill_rect(0, 0, w, @chat_sprite.bitmap.height,
  3282. Frame::BACK_COLOR)
  3283. # font height
  3284. h = RMXOS::Data::ChatFontHeight
  3285. # if using Tons of Add-ons that has Simple Shaded Text
  3286. if $tons_version != nil && $tons_version >= 1.6
  3287. # skip shadow drawing
  3288. @chat_messages.each_index {|i|
  3289. # draw message
  3290. @chat_sprite.bitmap.font.color = @chat_messages[i].color
  3291. @chat_sprite.bitmap.draw_text_shaded_later(2, i * h - 1, w, h,
  3292. @chat_messages[i].text)
  3293. }
  3294. else
  3295. # draw normally
  3296. @chat_messages.each_index {|i|
  3297. # draw message
  3298. @chat_sprite.bitmap.font.color = @chat_messages[i].color
  3299. @chat_sprite.bitmap.draw_text(2, i * h - 1, w, h,
  3300. @chat_messages[i].text)
  3301. }
  3302. end
  3303. end
  3304. end
  3305. # if sprite exists
  3306. if @chat_sprite != nil
  3307. # make sure name sprite is at the proper position
  3308. @chat_sprite.x, @chat_sprite.y, @chat_sprite.z = self.x, self.y, self.z
  3309. end
  3310. end
  3311. #--------------------------------------------------------------------------
  3312. # Altered to dispose the additional name sprite.
  3313. #--------------------------------------------------------------------------
  3314. alias dispose_rmxos_later dispose
  3315. def dispose
  3316. @name_sprite.dispose if @name_sprite != nil
  3317. @chat_sprite.dispose if @chat_sprite != nil
  3318. dispose_rmxos_later
  3319. end
  3320.  
  3321. end
  3322.  
  3323. #==============================================================================
  3324. # Spriteset_Map
  3325. #==============================================================================
  3326.  
  3327. class Spriteset_Map
  3328.  
  3329. #----------------------------------------------------------------------------
  3330. # Altered to include a hash of other's player characters so they can be
  3331. # checked for changes in the actual hash for players in Network.
  3332. #----------------------------------------------------------------------------
  3333. alias initialize_rmxos_later initialize
  3334. def initialize
  3335. @players = {}
  3336. # call original method
  3337. initialize_rmxos_later
  3338. update
  3339. end
  3340. #----------------------------------------------------------------------------
  3341. # Altered to include the creation and disposal of characters that enter/leave
  3342. # the map or connect/disconnect.
  3343. #----------------------------------------------------------------------------
  3344. alias update_rmxos_later update
  3345. def update
  3346. # call original method
  3347. update_rmxos_later
  3348. # for each removed player
  3349. (@players.keys - $network.map_players.keys).each {|id|
  3350. # dispose sprite
  3351. dispose_character_sprite(@players[id])
  3352. # remove nil values from sprites
  3353. @character_sprites.compact!
  3354. }
  3355. # for each new player
  3356. ($network.map_players.keys - @players.keys).each {|id|
  3357. # create a sprite
  3358. create_character_sprite($network.map_players[id])
  3359. }
  3360. # store current players on the map
  3361. @players = $network.map_players.clone
  3362. end
  3363. #----------------------------------------------------------------------------
  3364. # Creates a sprite for the given character.
  3365. # character - character that needs a sprite
  3366. #----------------------------------------------------------------------------
  3367. def create_character_sprite(character)
  3368. @character_sprites.push(Sprite_Character.new(@viewport1, character))
  3369. end
  3370. #----------------------------------------------------------------------------
  3371. # Disposes the sprite of a character.
  3372. # character - character that is being removed
  3373. #----------------------------------------------------------------------------
  3374. def dispose_character_sprite(character)
  3375. # iterate through all character sprites
  3376. @character_sprites.each_index {|i|
  3377. # if sprite's character matches
  3378. if @character_sprites[i].character == character
  3379. # dispose the sprite
  3380. @character_sprites[i].dispose
  3381. # remove the disposed sprite
  3382. @character_sprites[i] = nil
  3383. break
  3384. end
  3385. }
  3386. end
  3387.  
  3388. end
  3389.  
  3390. #==============================================================================
  3391. # Window_Command
  3392. #==============================================================================
  3393.  
  3394. class Window_Command
  3395.  
  3396. # setting all accessible variables
  3397. attr_reader :commands
  3398. #----------------------------------------------------------------------------
  3399. # Changes commands used in a window rather than instantiating a new window.
  3400. # commands - new array of commands
  3401. #----------------------------------------------------------------------------
  3402. def set_commands(commands)
  3403. # store new commands
  3404. @commands = commands
  3405. @item_max = @commands.size
  3406. # delete old bitmap
  3407. self.contents.dispose if self.contents != nil
  3408. # if there are any commands
  3409. if @item_max > 0
  3410. # create a new display
  3411. self.contents = Bitmap.new(width - 32, @item_max * 32)
  3412. refresh
  3413. else
  3414. # remove the disposed bitmap
  3415. self.contents = nil
  3416. end
  3417. end
  3418.  
  3419. end
  3420.  
  3421. #==============================================================================
  3422. # Scene_Title
  3423. #------------------------------------------------------------------------------
  3424. # Altered to switch to RMX-OS Server selection scene instead.
  3425. #==============================================================================
  3426.  
  3427. class Scene_Title
  3428.  
  3429. #----------------------------------------------------------------------------
  3430. # Overriden to disconnect and change the scene immediately.
  3431. #----------------------------------------------------------------------------
  3432. def main
  3433. $network.disconnect
  3434. SceneManager.goto Scene_Servers
  3435. end
  3436.  
  3437. end
  3438.  
  3439. #==============================================================================
  3440. # Scene_Map
  3441. #==============================================================================
  3442.  
  3443. class Scene_Map
  3444.  
  3445. #----------------------------------------------------------------------------
  3446. # Altered to create a chat window.
  3447. #----------------------------------------------------------------------------
  3448. alias main_rmxos_later main
  3449. def main
  3450. create_chat_window if $game_temp.chat_visible
  3451. $game_temp.chat_active = false
  3452. # call original method
  3453. main_rmxos_later
  3454. dispose_chat_window
  3455. dispose_trade_windows if @trade_command_window != nil
  3456. end
  3457. #----------------------------------------------------------------------------
  3458. # Altered to accept server messages and update all player characters on the
  3459. # map.
  3460. #----------------------------------------------------------------------------
  3461. alias update_rmxos_later update
  3462. def update
  3463. $network.update_server_ping
  3464. $network.update_autosave if !$game_temp.trade_active
  3465. $network.listen
  3466. $network.update_map_players
  3467. # update chat
  3468. update_chat
  3469. # update trade or call original method
  3470. $game_temp.trade_active ? update_trade : update_rmxos_later
  3471. end
  3472. #----------------------------------------------------------------------------
  3473. # Altered to update player data on the server when changing maps.
  3474. #----------------------------------------------------------------------------
  3475. alias transfer_player_rmxos_later perform_transfer
  3476. def perform_transfer
  3477. # if map has changed
  3478. if $game_temp.player_new_map_id != $game_map.map_id
  3479. # make clear that player is changing the map
  3480. $network.leave_map
  3481. # setup flag for map entering
  3482. $game_temp.entering_map = true
  3483. end
  3484. # call original method
  3485. transfer_player_rmxos_later
  3486. # save game after map change
  3487. $network.save
  3488. end
  3489. #----------------------------------------------------------------------------
  3490. # Creates the chat windows.
  3491. #----------------------------------------------------------------------------
  3492. def create_chat_window
  3493. @chatinput_window = Frame_ChatInput.new
  3494. @chat_window = Frame_Chat.new
  3495. end
  3496. #----------------------------------------------------------------------------
  3497. # Disposes the chat windows.
  3498. #----------------------------------------------------------------------------
  3499. def dispose_chat_window
  3500. if @chatinput_window != nil
  3501. @chatinput_window.dispose
  3502. @chatinput_window = nil
  3503. @chat_window.dispose
  3504. @chat_window = nil
  3505. end
  3506. end
  3507. #----------------------------------------------------------------------------
  3508. # Updates everything related to chat.
  3509. #----------------------------------------------------------------------------
  3510. def update_chat
  3511. if self.special_update?
  3512. # Ff triggers the chat window
  3513. if Input.trigger?(Input::Key['F5'])
  3514. $game_temp.chat_visible = !$game_temp.chat_visible
  3515. $game_temp.chat_active = false if !$game_temp.chat_visible
  3516. # F6 shows the chat window as well if it's not visible
  3517. elsif Input.trigger?(Input::Key['F6'])
  3518. $game_temp.chat_visible = true
  3519. if $game_temp.chat_active
  3520. $game_temp.chat_active = false
  3521. else
  3522. # prepare calling chat
  3523. $game_temp.chat_calling = true
  3524. end
  3525. end
  3526. end
  3527. # if chat window doesn't exist yet
  3528. if @chatinput_window == nil
  3529. # create if display is active
  3530. create_chat_window if $game_temp.chat_visible
  3531. # if display not active
  3532. elsif !$game_temp.chat_visible
  3533. dispose_chat_window
  3534. else
  3535. # apply chat active mode if the mode has changed
  3536. if @chatinput_window.active != $game_temp.chat_active
  3537. @chatinput_window.active = $game_temp.chat_active
  3538. @chat_window.active = @chatinput_window.active
  3539. end
  3540. # update chat windows
  3541. @chatinput_window.update
  3542. @chat_window.update
  3543. end
  3544. # if not moving and calling chat mode
  3545. if !$game_player.moving? && $game_temp.chat_calling
  3546. # activate chat mode
  3547. $game_temp.chat_calling = false
  3548. $game_temp.chat_active = true
  3549. end
  3550. end
  3551. #----------------------------------------------------------------------------
  3552. # Checks if specific code fragments should be updated.
  3553. # Returns: Whether to execute special updates or not.
  3554. #----------------------------------------------------------------------------
  3555. def special_update?
  3556. return !($game_player.moving? || $game_map.interpreter.running? ||
  3557. $game_player.move_route_forcing || $game_message.visible)
  3558. end
  3559. #----------------------------------------------------------------------------
  3560. # Updates trade execution.
  3561. #----------------------------------------------------------------------------
  3562. def update_trade
  3563. # create all windows if there are none yet
  3564. create_trade_windows if @trade_command_window == nil
  3565. # part of normal map update
  3566. $game_map.update
  3567. $game_map.interpreter.update
  3568. $game_system.update
  3569. $game_screen.update
  3570. @spriteset.update
  3571. @message_window.update
  3572. $game_player.update_chat_messages
  3573. # trade abortion
  3574. if $game_temp.trade_abort
  3575. dispose_trade_windows
  3576. return
  3577. end
  3578. # abort if chat is active
  3579. return if $game_temp.chat_active
  3580. # if cancel attempt from a non-host
  3581. if $game_temp.trade_host && $game_temp.trade_canceled
  3582. $network.trade_confirm_cancel
  3583. $game_temp.trade_confirmed = false
  3584. $game_temp.trade_canceled = false
  3585. end
  3586. @trade_partner_window.update
  3587. # update proper submenu
  3588. if @trade_command_window.active
  3589. update_trade_command
  3590. elsif @trade_player_window.active
  3591. update_trade_player
  3592. elsif @trade_partner_window.active
  3593. update_trade_partner
  3594. else
  3595. update_trade_wait
  3596. end
  3597. # cancel confirmation needs to be cleared
  3598. $game_temp.trade_cancel_confirmed = false
  3599. end
  3600. #----------------------------------------------------------------------------
  3601. # Creates all windows needed for trade.
  3602. #----------------------------------------------------------------------------
  3603. def create_trade_windows
  3604. # trade command window
  3605. @trade_command_window = Window_CommandHorizontal.new(152,
  3606. RMXOS::Data::TradeCommands)
  3607. @trade_command_window.active = true
  3608. @trade_command_window.opacity = 160
  3609. @trade_command_window.z = 10000
  3610. # own item selection
  3611. @trade_player_window = Window_TradePlayer.new
  3612. @trade_player_window.z = 10000
  3613. @trade_player_window.opacity = 160
  3614. # other's item selection
  3615. @trade_partner_window = Window_TradePartner.new
  3616. @trade_partner_window.z = 10000
  3617. @trade_partner_window.opacity = 160
  3618. # wait message
  3619. @trade_wait_window = Window_Button.new(0, 256, 640, RMXOS::Data::TradeWait)
  3620. @trade_wait_window.z = 10000
  3621. @trade_wait_window.opacity = 160
  3622. @trade_wait_window.visible = false
  3623. end
  3624. #----------------------------------------------------------------------------
  3625. # Dispose all trade windows.
  3626. #----------------------------------------------------------------------------
  3627. def dispose_trade_windows
  3628. @trade_command_window.dispose
  3629. @trade_command_window = nil
  3630. @trade_partner_window.dispose
  3631. @trade_partner_window = nil
  3632. @trade_player_window.dispose
  3633. @trade_player_window = nil
  3634. @trade_wait_window.dispose
  3635. @trade_wait_window = nil
  3636. $game_temp.trade_reset
  3637. end
  3638. #----------------------------------------------------------------------------
  3639. # Updates trade command window execution.
  3640. #----------------------------------------------------------------------------
  3641. def update_trade_command
  3642. @trade_command_window.update
  3643. # if pressed cancel
  3644. if Input.trigger?(Input::B)
  3645. Sound.play_cancel
  3646. # abort trade
  3647. $network.trade_abort
  3648. dispose_trade_windows
  3649. # if pressed confirm
  3650. elsif Input.trigger?(Input::C)
  3651. Sound.play_ok
  3652. case @trade_command_window.index
  3653. when 0
  3654. # activate your window
  3655. @trade_command_window.active = false
  3656. @trade_player_window.active = true
  3657. @trade_player_window.index = 0
  3658. when 1
  3659. # activate other window
  3660. @trade_command_window.active = false
  3661. @trade_partner_window.active = true
  3662. @trade_partner_window.index = 0
  3663. when 2
  3664. # confirm
  3665. @trade_command_window.active = false
  3666. # if player exists
  3667. if $network.players[$game_temp.trade_id] != nil
  3668. # get wait text
  3669. text = RMXOS::Data::TradeWait.gsub('PLAYER') {
  3670. $network.players[$game_temp.trade_id].username
  3671. }
  3672. # show it
  3673. @trade_wait_window.set_command(text)
  3674. else
  3675. # other player is gone
  3676. @trade_wait_window.set_command(RMXOS::Data::TradeNoPlayer)
  3677. end
  3678. @trade_wait_window.visible = true
  3679. # if host
  3680. if $game_temp.trade_host
  3681. # if already confirmed by other
  3682. if $game_temp.trade_confirmed
  3683. # execute the trade
  3684. $network.trade_confirm
  3685. execute_trade
  3686. end
  3687. else
  3688. # wait for other
  3689. $network.trade_confirm
  3690. end
  3691. when 3
  3692. # abort completely
  3693. $network.trade_abort
  3694. dispose_trade_windows
  3695. end
  3696. end
  3697. end
  3698. #----------------------------------------------------------------------------
  3699. # Updates execution of trade window with own items.
  3700. #----------------------------------------------------------------------------
  3701. def update_trade_player
  3702. @trade_player_window.update
  3703. value = 1
  3704. value *= 10 if Input.press?(Input::X)
  3705. value *= 100 if Input.press?(Input::Y)
  3706. value *= 1000 if Input.press?(Input::Z)
  3707. # if pressed cancel
  3708. if Input.trigger?(Input::B)
  3709. Sound.play_cancel
  3710. @trade_player_window.active = false
  3711. @trade_player_window.index = -1
  3712. @trade_command_window.active = true
  3713. # if pressed confirm
  3714. elsif Input.trigger?(Input::C)
  3715. Sound.play_ok
  3716. @trade_player_window.active = false
  3717. @trade_player_window.index = -1
  3718. @trade_command_window.active = true
  3719. # if pressed left
  3720. elsif Input.repeat?(Input::LEFT)
  3721. # if quantity has changed
  3722. if @trade_player_window.decrease_quantity(value)
  3723. Sound.play_cursor
  3724. # send new data to other
  3725. $network.trade_send_items(@trade_player_window.items)
  3726. # cancel other's trade confirmation
  3727. $network.trade_confirm_cancel
  3728. else
  3729. Sound.play_buzzer
  3730. end
  3731. # if pressed right
  3732. elsif Input.repeat?(Input::RIGHT)
  3733. # if quantity has changed
  3734. if @trade_player_window.increase_quantity(value)
  3735. Sound.play_cursor
  3736. # send new data to other
  3737. $network.trade_send_items(@trade_player_window.items)
  3738. # cancel other's trade confirmation
  3739. $network.trade_confirm_cancel
  3740. else
  3741. Sound.play_buzzer
  3742. end
  3743. end
  3744. end
  3745. #----------------------------------------------------------------------------
  3746. # Updates execution of trade window with other's items.
  3747. #----------------------------------------------------------------------------
  3748. def update_trade_partner
  3749. # if pressed cancel
  3750. if Input.trigger?(Input::B)
  3751. Sound.play_cancel
  3752. # deactivate other window
  3753. @trade_partner_window.active = false
  3754. @trade_partner_window.index = -1
  3755. @trade_command_window.active = true
  3756. # if pressed confirm
  3757. elsif Input.trigger?(Input::C)
  3758. Sound.play_ok
  3759. # deactivate other window
  3760. @trade_partner_window.active = false
  3761. @trade_partner_window.index = -1
  3762. @trade_command_window.active = true
  3763. end
  3764. end
  3765. #----------------------------------------------------------------------------
  3766. # Updates execution of waiting for trade confirmation.
  3767. #----------------------------------------------------------------------------
  3768. def update_trade_wait
  3769. # if trade is in finalizing stage
  3770. if $game_temp.trade_finalized != nil
  3771. # finish if finalization is done
  3772. dispose_trade_windows if $game_temp.trade_finalized
  3773. # if trade cancel confirmed
  3774. elsif $game_temp.trade_cancel_confirmed
  3775. Sound.play_cancel
  3776. # cancel confirmed trade
  3777. @trade_command_window.active = true
  3778. @trade_wait_window.visible = false
  3779. $game_temp.trade_canceled = false
  3780. $game_temp.trade_cancel_confirmed = false
  3781. # if not host and trade canceled
  3782. elsif !$game_temp.trade_host && $game_temp.trade_canceled
  3783. # if pressed cancel during cancelation process
  3784. if Input.trigger?(Input::B)
  3785. Sound.play_cancel
  3786. # other player might got stuck, abort trade completely
  3787. $network.trade_abort
  3788. dispose_trade_windows
  3789. end
  3790. # if confirmed trade
  3791. elsif $game_temp.trade_confirmed
  3792. Sound.play_ok
  3793. # execute trade
  3794. execute_trade
  3795. # send confirmation if host
  3796. $network.trade_confirm if $game_temp.trade_host
  3797. # if pressed cancel
  3798. elsif Input.trigger?(Input::B)
  3799. # if host
  3800. if $game_temp.trade_host
  3801. # cancel trade
  3802. Sound.play_cancel
  3803. @trade_command_window.active = true
  3804. @trade_wait_window.visible = false
  3805. else
  3806. # request cancel trade
  3807. $network.trade_cancel
  3808. # waiting for host to confirm the cancelation
  3809. @trade_wait_window.set_command(RMXOS::Data::CancelingTradeAbort)
  3810. $game_temp.trade_canceled = true
  3811. end
  3812. end
  3813. end
  3814. #----------------------------------------------------------------------------
  3815. # Updates execution of waiting for trade confirmation.
  3816. #----------------------------------------------------------------------------
  3817. def execute_trade
  3818. # execute item/gold exchange
  3819. @trade_player_window.items.each {|id, value|
  3820. if id != 0
  3821. $game_party.lose_item(id, value)
  3822. else
  3823. $game_party.lose_gold(value)
  3824. end
  3825. }
  3826. @trade_partner_window.items.each {|id, value|
  3827. if id != 0
  3828. $game_party.gain_item(id, value)
  3829. else
  3830. $game_party.gain_gold(value)
  3831. end
  3832. }
  3833. # send data for saving the game
  3834. if !RMXOS::Options::LEGACY_SAVE_METHOD
  3835. $network.send_save_data
  3836. else
  3837. $network.send_save_data_legacy
  3838. end
  3839. # request server to execute the final trade confirmation
  3840. $network.trade_execute
  3841. # waiting for server to finalize the trade
  3842. $game_temp.trade_finalized = false
  3843. # waiting for server to execute trade message
  3844. @trade_wait_window.set_command(RMXOS::Data::ExecutingTrade)
  3845. end
  3846.  
  3847. end
  3848.  
  3849. #==============================================================================
  3850. # Game_OnlineCharacter
  3851. #------------------------------------------------------------------------------
  3852. # Represents other players on the map.
  3853. #==============================================================================
  3854.  
  3855. class Game_OnlineCharacter < Game_Character
  3856.  
  3857. # setting all accessible variables
  3858. attr_reader :user_id
  3859. attr_reader :username
  3860. attr_reader :usergroup
  3861. attr_reader :guildname
  3862. attr_accessor :map_id
  3863. #----------------------------------------------------------------------------
  3864. # Sets player data.
  3865. # user_id - user ID
  3866. # username - username
  3867. # usergroup - usergroup
  3868. # guildname - guildname
  3869. #----------------------------------------------------------------------------
  3870. def set_user_data(user_id, username, usergroup, guildname)
  3871. @user_id = user_id
  3872. @username = username
  3873. @usergroup = usergroup
  3874. @guildname = guildname
  3875. end
  3876.  
  3877. end
  3878.  
  3879. #==============================================================================
  3880. # Frame
  3881. #------------------------------------------------------------------------------
  3882. # Represents an advanced sprite class. It is lighter than a window and avoids
  3883. # usage of window specific additions that cannot be turned off. This class is
  3884. # abstract and should not be instantiated as such.
  3885. #==============================================================================
  3886.  
  3887. class Frame < Sprite
  3888.  
  3889. # constants
  3890. BORDER_COLOR = Color.new(255, 255, 255, 160)
  3891. BACK_COLOR = Color.new(0, 0, 0, 160)
  3892. # setting all accessible variables
  3893. attr_accessor :active
  3894. attr_reader :width
  3895. attr_reader :height
  3896. #----------------------------------------------------------------------------
  3897. # Initialization.
  3898. # x - x coordinate
  3899. # y - y coordinate
  3900. # width - width of the sprite
  3901. # height - height of the sprite
  3902. #----------------------------------------------------------------------------
  3903. def initialize(x, y, width, height)
  3904. # create the actual sprite
  3905. super()
  3906. # set dimensions
  3907. @width = width
  3908. @height = height
  3909. # create background sprite
  3910. create_background_sprite
  3911. # set position
  3912. self.x, self.y, self.z = x, y, 1000
  3913. # store variables
  3914. @active = true
  3915. end
  3916. #----------------------------------------------------------------------------
  3917. # Creates a background sprite.
  3918. #----------------------------------------------------------------------------
  3919. def create_background_sprite
  3920. # create background sprite
  3921. @background = Sprite.new
  3922. create_background_bitmap
  3923. end
  3924. #----------------------------------------------------------------------------
  3925. # Creates the background bitmap.
  3926. #----------------------------------------------------------------------------
  3927. def create_background_bitmap
  3928. @background.bitmap = Bitmap.new(@width, @height)
  3929. @background.bitmap.fill_rect(0, 0, @width, @height, BORDER_COLOR)
  3930. @background.bitmap.fill_rect(1, 1, @width - 2, @height - 2, BACK_COLOR)
  3931. end
  3932. #----------------------------------------------------------------------------
  3933. # Updates the background sprite.
  3934. #----------------------------------------------------------------------------
  3935. def update_background
  3936. @background.x, @background.y, @background.z = self.x, self.y, self.z - 1
  3937. end
  3938. #----------------------------------------------------------------------------
  3939. # Changes the sprite width.
  3940. # value - new width
  3941. #----------------------------------------------------------------------------
  3942. def width=(value)
  3943. # if width had changed
  3944. if @width != value
  3945. # delete old bitmap
  3946. @background.bitmap.dispose if @background.bitmap != nil
  3947. @width = value
  3948. # create new background bitmap
  3949. create_background_bitmap
  3950. end
  3951. end
  3952. #----------------------------------------------------------------------------
  3953. # Changes the sprite height.
  3954. # value - new height
  3955. #----------------------------------------------------------------------------
  3956. def height=(value)
  3957. # if width had changed
  3958. if @height != value
  3959. # delete old bitmap
  3960. @background.bitmap.dispose if @background.bitmap != nil
  3961. @height = value
  3962. # create new background bitmap
  3963. create_background_bitmap
  3964. end
  3965. end
  3966. #----------------------------------------------------------------------------
  3967. # Changes sprite x.
  3968. # value - new x coordinate
  3969. #----------------------------------------------------------------------------
  3970. def x=(value)
  3971. super
  3972. update_background
  3973. end
  3974. #----------------------------------------------------------------------------
  3975. # Changes sprite y.
  3976. # value - new y coordinate
  3977. #----------------------------------------------------------------------------
  3978. def y=(value)
  3979. super
  3980. update_background
  3981. end
  3982. #----------------------------------------------------------------------------
  3983. # Changes sprite z.
  3984. # value - new z coordinate
  3985. #----------------------------------------------------------------------------
  3986. def z=(value)
  3987. super
  3988. update_background
  3989. end
  3990. #----------------------------------------------------------------------------
  3991. # Refreshes the display. Abstract method.
  3992. #----------------------------------------------------------------------------
  3993. def refresh
  3994. end
  3995. #----------------------------------------------------------------------------
  3996. # Disposes the additional background sprite.
  3997. #----------------------------------------------------------------------------
  3998. def dispose
  3999. if @background.bitmap != nil
  4000. @background.bitmap.dispose
  4001. @background.bitmap = nil
  4002. end
  4003. @background.dispose
  4004. super
  4005. end
  4006.  
  4007. end
  4008.  
  4009. #==============================================================================
  4010. # Frame_Text
  4011. #------------------------------------------------------------------------------
  4012. # Handles basic user input from the keyboard for text related entries. This
  4013. # class is abstract and should not be instantiated as such.
  4014. #==============================================================================
  4015.  
  4016. class Frame_Text < Frame
  4017.  
  4018. # constants
  4019. CURSOR_COLOR = Color.new(255, 255, 255)
  4020. # setting all accessible variables
  4021. attr_reader :text
  4022. attr_reader :password_char
  4023. #----------------------------------------------------------------------------
  4024. # Initialization.
  4025. # x - x coordinate
  4026. # y - y coordinate
  4027. # width - width of the sprite
  4028. # height - height of the sprite
  4029. # caption - title text displayed
  4030. # text - default text entered
  4031. # password_char - password character used to hide text (no hiding if empty)
  4032. #----------------------------------------------------------------------------
  4033. def initialize(x, y, width, height, text = '', password_char = '')
  4034. # store variables
  4035. @frame = 0
  4036. @text = text
  4037. @password_char = password_char
  4038. # set cursor position at the end
  4039. @cursor_position = text.scan(/./m).size
  4040. # maximum text length
  4041. self.max_length = RMXOS::Options::CHATINPUT_MAX_LENGTH
  4042. # create the actual sprite
  4043. super(x, y, width, height)
  4044. # filter for input, allows all printable characters
  4045. @input_filter = //
  4046. end
  4047. #----------------------------------------------------------------------------
  4048. # Changes sprite x.
  4049. # value - new x coordinate
  4050. #----------------------------------------------------------------------------
  4051. def x=(value)
  4052. super
  4053. update_cursor
  4054. end
  4055. #----------------------------------------------------------------------------
  4056. # Changes sprite y.
  4057. # value - new y coordinate
  4058. #----------------------------------------------------------------------------
  4059. def y=(value)
  4060. super
  4061. update_cursor
  4062. end
  4063. #----------------------------------------------------------------------------
  4064. # Changes sprite z.
  4065. # value - new z coordinate
  4066. #----------------------------------------------------------------------------
  4067. def z=(value)
  4068. super
  4069. update_cursor
  4070. end
  4071. #----------------------------------------------------------------------------
  4072. # Sets displayed text. Refreshes the display immediately.
  4073. # new_text - new text to be displayed
  4074. #----------------------------------------------------------------------------
  4075. def text=(new_text)
  4076. @text = new_text
  4077. refresh
  4078. update_cursor
  4079. end
  4080. #----------------------------------------------------------------------------
  4081. # Sets password character. Refreshes the display immediately.
  4082. # new_password_char - new password character to be used
  4083. #----------------------------------------------------------------------------
  4084. def password_char=(new_password_char)
  4085. @password_char = new_password_char
  4086. refresh
  4087. update_cursor
  4088. end
  4089. #----------------------------------------------------------------------------
  4090. # Changes maximum length of allowed text and truncates text if too long.
  4091. # new_max_length - new_max_length
  4092. #----------------------------------------------------------------------------
  4093. def max_length=(new_max_length)
  4094. @max_length = new_max_length
  4095. chars = @text.scan(/./m)
  4096. @text = chars[0, @max_length].join if chars.size > @max_length
  4097. self.cursor_move_to_end if @cursor_position > chars.size
  4098. end
  4099. #----------------------------------------------------------------------------
  4100. # Gets the text that should be displayed. This method is needed so when using
  4101. # a password character the original text can stay unchanged while it's
  4102. # actually being displayed in password characters.
  4103. # Returns: The text that should be displayed.
  4104. #----------------------------------------------------------------------------
  4105. def get_display_text
  4106. return (@password_char == '' ? @text : @text.gsub(/./m) {@password_char})
  4107. end
  4108. #----------------------------------------------------------------------------
  4109. # Moves the cursor to the left if possible.
  4110. #----------------------------------------------------------------------------
  4111. def cursor_move_left
  4112. @cursor_position -= 1 if self.cursor_can_move_left?
  4113. self.reset_cursor_blinking
  4114. end
  4115. #----------------------------------------------------------------------------
  4116. # Moves the cursor to the right if possible.
  4117. #----------------------------------------------------------------------------
  4118. def cursor_move_right
  4119. @cursor_position += 1 if self.cursor_can_move_right?
  4120. self.reset_cursor_blinking
  4121. end
  4122. #----------------------------------------------------------------------------
  4123. # Moves the cursor to the left end of a word.
  4124. #----------------------------------------------------------------------------
  4125. def cursor_move_left_word
  4126. chars = @text.scan(/./m)
  4127. # skip all whitespaces first
  4128. while @cursor_position > 0 && chars[@cursor_position - 1] == ' '
  4129. @cursor_position -= 1
  4130. end
  4131. # skip all non-whitespaces
  4132. while @cursor_position > 0 && chars[@cursor_position - 1] != ' '
  4133. @cursor_position -= 1
  4134. end
  4135. self.reset_cursor_blinking
  4136. end
  4137. #----------------------------------------------------------------------------
  4138. # Moves the cursor to the right end of a word.
  4139. #----------------------------------------------------------------------------
  4140. def cursor_move_right_word
  4141. chars = @text.scan(/./m)
  4142. # skip all non-whitespaces first
  4143. while @cursor_position < chars.size && chars[@cursor_position] != ' '
  4144. @cursor_position += 1
  4145. end
  4146. # skip all whitespaces
  4147. while @cursor_position < chars.size && chars[@cursor_position] == ' '
  4148. @cursor_position += 1
  4149. end
  4150. self.reset_cursor_blinking
  4151. end
  4152. #----------------------------------------------------------------------------
  4153. # Moves the cursor to the beginning.
  4154. #----------------------------------------------------------------------------
  4155. def cursor_move_to_beginning
  4156. @cursor_position = 0
  4157. self.reset_cursor_blinking
  4158. end
  4159. #----------------------------------------------------------------------------
  4160. # Moves the cursor to the end.
  4161. #----------------------------------------------------------------------------
  4162. def cursor_move_to_end
  4163. @cursor_position = @text.scan(/./m).size
  4164. self.reset_cursor_blinking
  4165. end
  4166. #----------------------------------------------------------------------------
  4167. # Checks if the cursor can move further left.
  4168. # Returns: True of false.
  4169. #----------------------------------------------------------------------------
  4170. def cursor_can_move_left?
  4171. return (@cursor_position > 0)
  4172. end
  4173. #----------------------------------------------------------------------------
  4174. # Checks if the cursor can move further right.
  4175. # Returns: True of false.
  4176. #----------------------------------------------------------------------------
  4177. def cursor_can_move_right?
  4178. return (@cursor_position < @text.scan(/./m).size)
  4179. end
  4180. #----------------------------------------------------------------------------
  4181. # Deletes the character left of the cursor if there is one.
  4182. # count - how many characters should be deleted
  4183. #----------------------------------------------------------------------------
  4184. def delete_left(count = 1)
  4185. if self.cursor_can_move_left?
  4186. # limiting character count
  4187. count = @cursor_position if count > @cursor_position
  4188. # split text at cursor with one character removed left from the cursor
  4189. chars = @text.scan(/./m)
  4190. left = (@cursor_position > count ? chars[0, @cursor_position - count] : [])
  4191. if @cursor_position < chars.size
  4192. right = chars[@cursor_position, chars.size - @cursor_position]
  4193. else
  4194. right = []
  4195. end
  4196. # set cursor at right position
  4197. @cursor_position -= count
  4198. # put together the split halves
  4199. self.text = (left + right).join
  4200. self.reset_cursor_blinking
  4201. end
  4202. end
  4203. #----------------------------------------------------------------------------
  4204. # Deletes the character right of the cursor if there is one.
  4205. # count - how many characters should be deleted
  4206. #----------------------------------------------------------------------------
  4207. def delete_right(count = 1)
  4208. if self.cursor_can_move_right?
  4209. # limiting character count
  4210. chars = @text.scan(/./m)
  4211. if count > chars.size - @cursor_position
  4212. count = chars.size - @cursor_position
  4213. end
  4214. # moving cursor to the right
  4215. @cursor_position += count
  4216. # deleting everything left from cursor
  4217. self.delete_left(count)
  4218. self.reset_cursor_blinking
  4219. end
  4220. end
  4221. #----------------------------------------------------------------------------
  4222. # Deletes the word left of the cursor.
  4223. #----------------------------------------------------------------------------
  4224. def delete_left_word
  4225. chars = @text.scan(/./m)
  4226. position = @cursor_position
  4227. # skip all whitespaces first
  4228. while position > 0 && chars[position - 1] == ' '
  4229. position -= 1
  4230. end
  4231. # skip all non-whitespaces
  4232. while position > 0 && chars[position - 1] != ' '
  4233. position -= 1
  4234. end
  4235. delete_left(@cursor_position - position) if @cursor_position > position
  4236. self.reset_cursor_blinking
  4237. end
  4238. #----------------------------------------------------------------------------
  4239. # Deletes the word right of the cursor.
  4240. #----------------------------------------------------------------------------
  4241. def delete_right_word
  4242. chars = @text.scan(/./m)
  4243. position = @cursor_position
  4244. # skip all non-whitespaces first
  4245. while position < chars.size && chars[position] != ' '
  4246. position += 1
  4247. end
  4248. # skip all whitespaces
  4249. while position < chars.size && chars[position] == ' '
  4250. position += 1
  4251. end
  4252. delete_right(position - @cursor_position) if position > @cursor_position
  4253. self.reset_cursor_blinking
  4254. end
  4255. #----------------------------------------------------------------------------
  4256. # Inserts a character into the text right from the current cursor position
  4257. # and moves the cursor positions.
  4258. # text - text that will be inserted into the current text
  4259. #----------------------------------------------------------------------------
  4260. def insert(text)
  4261. chars = @text.scan(/./m)
  4262. return if chars.size >= @max_length
  4263. # limiting characters
  4264. new_chars = text.scan(/./m)
  4265. if chars.size + new_chars.size > @max_length
  4266. new_chars = new_chars[0, @max_length - chars.size]
  4267. end
  4268. # it's possible that text contains tab characters which are forbidden
  4269. while new_chars.include?("\t")
  4270. new_chars.delete("\t")
  4271. end
  4272. return if new_chars.size == 0
  4273. # split text at cursor position
  4274. left = (@cursor_position > 0 ? chars[0, @cursor_position] : [])
  4275. if @cursor_position < chars.size
  4276. right = chars[@cursor_position, chars.size - @cursor_position]
  4277. else
  4278. right = []
  4279. end
  4280. # move cursor
  4281. @cursor_position += new_chars.size
  4282. # put together the split halves with the new text inbetween
  4283. self.text = (left + new_chars + right).join
  4284. self.reset_cursor_blinking
  4285. end
  4286. #----------------------------------------------------------------------------
  4287. # Resets cursor blinking.
  4288. #----------------------------------------------------------------------------
  4289. def reset_cursor_blinking
  4290. @frame = 0
  4291. end
  4292. #----------------------------------------------------------------------------
  4293. # Shows/hides the cursor when activating/deactivating the window.
  4294. # value - true or false
  4295. #----------------------------------------------------------------------------
  4296. def active=(value)
  4297. super
  4298. self.reset_cursor_blinking
  4299. update_cursor
  4300. end
  4301. #----------------------------------------------------------------------------
  4302. # Updates the window behavior.
  4303. #----------------------------------------------------------------------------
  4304. def update
  4305. super
  4306. # blinking period of 1 second
  4307. @frame = (@frame + 1) % RMXOS::Data::CursorBlinkPeriod
  4308. update_input
  4309. update_cursor
  4310. end
  4311. #----------------------------------------------------------------------------
  4312. # Updates user input (moving cursor, deleting characters).
  4313. # Returns: Whether to stop updating or not.
  4314. #----------------------------------------------------------------------------
  4315. def update_input
  4316. # left key moves the cursor to the left
  4317. if Input.repeat?(Input::LEFT)
  4318. if Input.press?(Input::CTRL)
  4319. self.cursor_move_left_word
  4320. else
  4321. self.cursor_move_left
  4322. end
  4323. return true
  4324. end
  4325. # right key moves the cursor to the left
  4326. if Input.repeat?(Input::RIGHT)
  4327. if Input.press?(Input::CTRL)
  4328. self.cursor_move_right_word
  4329. else
  4330. self.cursor_move_right
  4331. end
  4332. return true
  4333. end
  4334. # home moves to the beginning
  4335. if Input.trigger?(Input::Key['Home'])
  4336. self.cursor_move_to_beginning
  4337. return true
  4338. end
  4339. # end moves to the end
  4340. if Input.trigger?(Input::Key['End'])
  4341. self.cursor_move_to_end
  4342. return true
  4343. end
  4344. # backspace deletes to the left
  4345. if Input.repeat?(Input::Key['Backspace'])
  4346. if Input.press?(Input::CTRL)
  4347. self.delete_left_word
  4348. else
  4349. self.delete_left
  4350. end
  4351. return true
  4352. end
  4353. # backspace deletes to the right
  4354. if Input.repeat?(Input::Key['Delete'])
  4355. if Input.press?(Input::CTRL)
  4356. self.delete_right_word
  4357. else
  4358. self.delete_right
  4359. end
  4360. return true
  4361. end
  4362. # get text
  4363. text = Input.get_input_string
  4364. # put text through input filter
  4365. text.gsub!(@input_filter) {''}
  4366. # if text is not empty
  4367. if text != ''
  4368. # insert it in the text
  4369. self.insert(text)
  4370. return true
  4371. end
  4372. return false
  4373. end
  4374. #----------------------------------------------------------------------------
  4375. # Gets the x offset of the cursor.
  4376. # Returns: X offset for the cursor.
  4377. #----------------------------------------------------------------------------
  4378. def cursor_x
  4379. # x is "0" if cursor position at 0
  4380. return -self.src_rect.x if !self.cursor_can_move_left?
  4381. # find cursor position from text left from it
  4382. display_text = get_display_text.scan(/./m)[0, @cursor_position].join
  4383. return self.bitmap.text_size(display_text).width - self.src_rect.x
  4384. end
  4385. #----------------------------------------------------------------------------
  4386. # Gets the y offset of the cursor.
  4387. # Returns: Y offset for the cursor.
  4388. #----------------------------------------------------------------------------
  4389. def cursor_y
  4390. return 2
  4391. end
  4392. #----------------------------------------------------------------------------
  4393. # Gets the height of the cursor.
  4394. # Returns: Height for the cursor.
  4395. #----------------------------------------------------------------------------
  4396. def cursor_height
  4397. return 28
  4398. end
  4399. #----------------------------------------------------------------------------
  4400. # Updates the cursor display.
  4401. #----------------------------------------------------------------------------
  4402. def update_cursor
  4403. # if not active or blinking timer has exceeded value
  4404. if !self.active || @frame >= RMXOS::Data::CursorBlinkPeriod / 2
  4405. # if cursor exists
  4406. if @cursor != nil
  4407. # delete cursor
  4408. @cursor.dispose
  4409. @cursor = nil
  4410. end
  4411. else
  4412. # if cursor does not exist
  4413. @cursor = Sprite.new if @cursor == nil
  4414. if @cursor.bitmap != nil && @cursor.bitmap.height != cursor_height
  4415. @cursor.bitmap.dispose
  4416. @cursor.bitmap = nil
  4417. end
  4418. if @cursor.bitmap == nil
  4419. # create bitmap
  4420. @cursor.bitmap = Bitmap.new(1, cursor_height)
  4421. @cursor.bitmap.fill_rect(0, 0, 1, cursor_height, CURSOR_COLOR)
  4422. end
  4423. # position the cursor
  4424. @cursor.x, @cursor.y = self.x + cursor_x, self.y + cursor_y
  4425. @cursor.z = self.z + 1
  4426. end
  4427. end
  4428. #----------------------------------------------------------------------------
  4429. # Disposes the additional cursor sprite.
  4430. #----------------------------------------------------------------------------
  4431. def dispose
  4432. if @cursor != nil
  4433. @cursor.bitmap.dispose if @cursor.bitmap != nil
  4434. @cursor.dispose
  4435. @cursor = nil
  4436. end
  4437. super
  4438. end
  4439.  
  4440. end
  4441.  
  4442. #==============================================================================
  4443. # Frame_Caption
  4444. #------------------------------------------------------------------------------
  4445. # Displays a text entry window with a caption. It allows the entry of usernames
  4446. # and passwords with a limited characterset of alphanumeric characters
  4447. # inluding "-" (minus) and "_" (underscore).
  4448. #==============================================================================
  4449.  
  4450. class Frame_Caption < Frame_Text
  4451.  
  4452. #----------------------------------------------------------------------------
  4453. # Initialization.
  4454. # x - x coordinate
  4455. # y - y coordinate
  4456. # width - width of the window
  4457. # caption - title text displayed
  4458. # text - default text entered
  4459. # password_char - password character used to hide text (no hiding if empty)
  4460. #----------------------------------------------------------------------------
  4461. def initialize(x, y, width, caption, text = '', password_char = '')
  4462. # create the actual window
  4463. super(x, y, width, 32, text, password_char)
  4464. # store variables
  4465. @caption = caption
  4466. # change max length
  4467. self.max_length = RMXOS::Options::USERPASS_MAX_LENGTH
  4468. # create display
  4469. self.bitmap = Bitmap.new(@width, @height)
  4470. # filter for input, allows all characters except white-space and apostrophe
  4471. @input_filter = /([^\S])/
  4472. refresh
  4473. end
  4474. #----------------------------------------------------------------------------
  4475. # Refreshes the display.
  4476. #----------------------------------------------------------------------------
  4477. def refresh
  4478. self.bitmap.clear
  4479. # draw caption
  4480. self.bitmap.draw_text(4, 0, 160, 32, @caption, 2)
  4481. # draw text
  4482. self.bitmap.draw_text(172, 0, @width - 8 - 168, 32, get_display_text)
  4483. end
  4484. #----------------------------------------------------------------------------
  4485. # Gets the x offset of the cursor.
  4486. # Returns: X offset for the cursor.
  4487. #----------------------------------------------------------------------------
  4488. def cursor_x
  4489. return (super + 172)
  4490. end
  4491.  
  4492. end
  4493.  
  4494. #==============================================================================
  4495. # Frame_ChatInput
  4496. #------------------------------------------------------------------------------
  4497. # Allows the entry of text for chatting and includes sending history.
  4498. #==============================================================================
  4499.  
  4500. class Frame_ChatInput < Frame_Text
  4501.  
  4502. #----------------------------------------------------------------------------
  4503. # Initialization.
  4504. #----------------------------------------------------------------------------
  4505. def initialize
  4506. # create the actual window
  4507. h = RMXOS::Data::ChatFontHeight
  4508. super(0, Graphics.height - h, RMXOS::Options::CHATINPUT_WIDTH, h)
  4509. self.z = 10000
  4510. @log_index = $game_temp.chat_logs.size
  4511. self.active = false
  4512. # create display
  4513. self.bitmap = Bitmap.new(1, 1)
  4514. refresh
  4515. end
  4516. #----------------------------------------------------------------------------
  4517. # Refreshes the display.
  4518. #----------------------------------------------------------------------------
  4519. def refresh
  4520. width = self.bitmap.text_size(@text).width + 8
  4521. self.bitmap.dispose
  4522. # create new bitmap
  4523. x = self.src_rect.x
  4524. self.bitmap = Bitmap.new(width + 4, @height)
  4525. self.bitmap.font.size = RMXOS::Data::ChatFontHeight
  4526. self.src_rect.x = x
  4527. self.src_rect.width = @width
  4528. # if using Tons of Add-ons that has Simple Shaded Text
  4529. if $tons_version != nil && $tons_version >= 1.6
  4530. # draw text
  4531. self.bitmap.draw_text_shaded_later(2, -1, width - 4,
  4532. RMXOS::Data::ChatFontHeight, @text)
  4533. else
  4534. # draw text
  4535. self.bitmap.draw_text(2, -1, width - 4,
  4536. RMXOS::Data::ChatFontHeight, @text)
  4537. end
  4538. end
  4539. #----------------------------------------------------------------------------
  4540. # Gets the x offset of the cursor.
  4541. # Returns: X offset for the cursor.
  4542. #----------------------------------------------------------------------------
  4543. def cursor_x
  4544. return (super + 2)
  4545. end
  4546. #----------------------------------------------------------------------------
  4547. # Gets the height of the cursor.
  4548. # Returns: Height for the cursor.
  4549. #----------------------------------------------------------------------------
  4550. def cursor_height
  4551. return (RMXOS::Data::ChatFontHeight - 4)
  4552. end
  4553. #----------------------------------------------------------------------------
  4554. # Updates user input (moving cursor, deleting characters).
  4555. # Returns: Whether to stop updating or not.
  4556. #----------------------------------------------------------------------------
  4557. def update_input
  4558. # abort if not active
  4559. return false if !self.active
  4560. # if holding CTRL
  4561. if Input.press?(Input::CTRL)
  4562. # if pressed UP
  4563. if Input.repeat?(Input::UP)
  4564. # if not at beginning of history
  4565. if @log_index > 0
  4566. @log_index -= 1
  4567. # get current entry
  4568. self.text = $game_temp.chat_logs[@log_index].clone
  4569. self.cursor_move_to_end
  4570. end
  4571. return true
  4572. # if pressed DOWN
  4573. elsif Input.repeat?(Input::DOWN)
  4574. # if there are still logs in the history
  4575. if @log_index < $game_temp.chat_logs.size
  4576. @log_index += 1
  4577. # get current entry
  4578. if @log_index < $game_temp.chat_logs.size
  4579. self.text = $game_temp.chat_logs[@log_index].clone
  4580. else
  4581. self.text = ''
  4582. end
  4583. self.cursor_move_to_end
  4584. end
  4585. return true
  4586. end
  4587. end
  4588. # if pressed enter
  4589. if Input.repeat?(Input::Key['Enter'])
  4590. # if any text entered
  4591. if @text.size > 0
  4592. Sound.play_ok
  4593. # if not a special command
  4594. if !$network.check_chat_commands(@text)
  4595. # send this text per chat
  4596. $network.command_chat(@text)
  4597. end
  4598. # save this message in chat log
  4599. $game_temp.chat_logs.push(@text)
  4600. if $game_temp.chat_logs.size > RMXOS::Data::ChatLogSize
  4601. $game_temp.chat_logs.shift
  4602. end
  4603. # reset
  4604. @log_index = $game_temp.chat_logs.size
  4605. self.text = ''
  4606. self.cursor_move_to_beginning
  4607. end
  4608. return true
  4609. end
  4610. # call superclass method
  4611. return super
  4612. end
  4613. #----------------------------------------------------------------------------
  4614. # Updates the cursor display.
  4615. #----------------------------------------------------------------------------
  4616. def update_cursor
  4617. x = cursor_x
  4618. if x < 2
  4619. self.src_rect.x += x - 2
  4620. elsif x >= @width - 2
  4621. self.src_rect.x += x - (@width - 2) + 1
  4622. end
  4623. super
  4624. end
  4625.  
  4626. end
  4627.  
  4628. #==============================================================================
  4629. # Frame_Chat
  4630. #------------------------------------------------------------------------------
  4631. # Displays a chat log.
  4632. #==============================================================================
  4633.  
  4634. class Frame_Chat < Frame
  4635.  
  4636. #----------------------------------------------------------------------------
  4637. # Initialization.
  4638. #----------------------------------------------------------------------------
  4639. def initialize
  4640. # create the actual window
  4641. height = RMXOS::Options::CHATBOX_LINES * RMXOS::Data::ChatFontHeight
  4642. super(0, Graphics.height - height - RMXOS::Data::ChatFontHeight,
  4643. RMXOS::Options::CHATBOX_WIDTH, height)
  4644. self.z = 10000
  4645. self.active = false
  4646. # create display
  4647. refresh
  4648. if self.bitmap != nil && self.bitmap.height > @height
  4649. self.src_rect.y = self.bitmap.height - @height
  4650. end
  4651. end
  4652. #----------------------------------------------------------------------------
  4653. # Refreshes the display.
  4654. #----------------------------------------------------------------------------
  4655. def refresh
  4656. if self.bitmap != nil
  4657. # remove old bitmap
  4658. self.bitmap.dispose
  4659. self.bitmap = nil
  4660. end
  4661. # abort if no messages
  4662. return if $game_temp.chat_messages.size == 0
  4663. # create new bitmap
  4664. h = $game_temp.chat_messages.size * RMXOS::Data::ChatFontHeight
  4665. self.bitmap = Bitmap.new(@width, h)
  4666. self.bitmap.font.size = RMXOS::Data::ChatFontHeight
  4667. self.src_rect.height = @height
  4668. self.draw_messages
  4669. end
  4670. #----------------------------------------------------------------------------
  4671. # Refreshes part of the display.
  4672. #----------------------------------------------------------------------------
  4673. def refresh_chat
  4674. new_lines = $game_temp.chat_refresh
  4675. $game_temp.chat_refresh = false
  4676. # abort if no messages
  4677. return if $game_temp.chat_messages.size == 0
  4678. # if no messages are being displayed yet
  4679. if self.bitmap == nil
  4680. # just draw them all
  4681. refresh
  4682. return
  4683. end
  4684. # store current display
  4685. bitmap = self.bitmap
  4686. h = $game_temp.chat_messages.size * RMXOS::Data::ChatFontHeight
  4687. # scrolling down if at bottom
  4688. if self.src_rect.y >= bitmap.height - @height && h > @height
  4689. src_y = h - @height
  4690. else
  4691. src_y = self.src_rect.y
  4692. end
  4693. # creating a new bitmap
  4694. self.bitmap = Bitmap.new(@width, h)
  4695. self.bitmap.font.size = RMXOS::Data::ChatFontHeight
  4696. self.src_rect.y = src_y
  4697. self.src_rect.height = @height
  4698. # y offset for drawing
  4699. if bitmap.height == h
  4700. y = new_lines * RMXOS::Data::ChatFontHeight
  4701. else
  4702. y = 0
  4703. end
  4704. self.bitmap.blt(0, 0, bitmap, Rect.new(0, y, @width, bitmap.height - y))
  4705. # delete old bitmap
  4706. bitmap.dispose
  4707. # draw new messages
  4708. self.draw_messages($game_temp.chat_messages.size - new_lines)
  4709. end
  4710. #----------------------------------------------------------------------------
  4711. # Draws specific messages onto the display.
  4712. # start - starting message index
  4713. #----------------------------------------------------------------------------
  4714. def draw_messages(start = 0)
  4715. h = RMXOS::Data::ChatFontHeight
  4716. # if using Tons of Add-ons that has Simple Shaded Text
  4717. if $tons_version != nil && $tons_version >= 1.6
  4718. # skip shadow drawing
  4719. (start...$game_temp.chat_messages.size).each {|i|
  4720. # draw message
  4721. self.bitmap.font.color = $game_temp.chat_messages[i].color
  4722. self.bitmap.draw_text_shaded_later(2, i * h - 1, @width - 4, h,
  4723. $game_temp.chat_messages[i].text)
  4724. }
  4725. else
  4726. # draw normally
  4727. (start...$game_temp.chat_messages.size).each {|i|
  4728. # draw message
  4729. self.bitmap.font.color = $game_temp.chat_messages[i].color
  4730. self.bitmap.draw_text(2, i * h - 1, @width - 4, h,
  4731. $game_temp.chat_messages[i].text)
  4732. }
  4733. end
  4734. end
  4735. #----------------------------------------------------------------------------
  4736. # Updates the window.
  4737. #----------------------------------------------------------------------------
  4738. def update
  4739. super
  4740. refresh_chat if $game_temp.chat_refresh
  4741. # if active and not holding CTRL
  4742. if self.active && !Input.press?(Input::CTRL)
  4743. # if pressed UP
  4744. if Input.repeat?(Input::UP)
  4745. # scroll up if possible
  4746. self.src_rect.y -= RMXOS::Data::ChatFontHeight if self.src_rect.y > 0
  4747. return true
  4748. # if pressed DOWN
  4749. elsif Input.repeat?(Input::DOWN)
  4750. if self.bitmap != nil && self.src_rect.y < self.bitmap.height - @height
  4751. self.src_rect.y += RMXOS::Data::ChatFontHeight
  4752. end
  4753. # scroll down if possible
  4754. return true
  4755. end
  4756. end
  4757. end
  4758.  
  4759. end
  4760.  
  4761. #==============================================================================
  4762. # Window_Button
  4763. #------------------------------------------------------------------------------
  4764. # Wraps the command window into a button-like appearance.
  4765. #==============================================================================
  4766.  
  4767. class Window_Button < Window_Selectable
  4768.  
  4769. #----------------------------------------------------------------------------
  4770. # Initialization.
  4771. # x - x coordinate
  4772. # y - y coordinate
  4773. # width - window width
  4774. # command - command to be displayed
  4775. #----------------------------------------------------------------------------
  4776. def initialize(x, y, width, command)
  4777. super(x, y, width, 64)
  4778. self.x, self.y = x, y
  4779. self.index = -1
  4780. @command = command
  4781. self.contents = Bitmap.new(width - 32, 32)
  4782. refresh
  4783. end
  4784. #----------------------------------------------------------------------------
  4785. # Refreshes the display.
  4786. #----------------------------------------------------------------------------
  4787. def refresh
  4788. self.contents.clear
  4789. self.contents.font.color = normal_color
  4790. self.contents.draw_text(0, 0, width - 32, 32, @command, 1)
  4791. end
  4792. #----------------------------------------------------------------------------
  4793. # Changes the command that is displayed.
  4794. #----------------------------------------------------------------------------
  4795. def set_command(command)
  4796. @command = command
  4797. refresh
  4798. end
  4799.  
  4800. end
  4801.  
  4802. class Window_RMXOSCommand < Window_Command
  4803.  
  4804. def initialize(width, commands)
  4805. # Compute window height from command quantity
  4806. @rmxos_width = width
  4807. @commands = commands
  4808. super(0, 0)
  4809. end
  4810.  
  4811. def make_command_list
  4812. @commands.each do |cmd|
  4813. add_command(cmd, cmd)
  4814. end
  4815. end
  4816.  
  4817. def window_width
  4818. return @rmxos_width
  4819. end
  4820.  
  4821. end
  4822.  
  4823. #==============================================================================
  4824. # Window_ServerCommand
  4825. #------------------------------------------------------------------------------
  4826. # Allows quick change of displayed commands.
  4827. #==============================================================================
  4828.  
  4829. class Window_ServerCommand < Window_RMXOSCommand
  4830.  
  4831. #----------------------------------------------------------------------------
  4832. # Overrides the drawing of a command once.
  4833. # i - item index
  4834. # command - command to draw
  4835. # color - text color
  4836. #----------------------------------------------------------------------------
  4837. def draw_command(i, command, color = normal_color)
  4838. commands = @commands.clone
  4839. @commands[i] = command
  4840. self.draw_item(i)
  4841. @commands = commands
  4842. end
  4843.  
  4844. #----------------------------------------------------------------------------
  4845. # Overrides the drawing of a command to use specific colors for certain
  4846. # words.
  4847. # i - item index
  4848. #----------------------------------------------------------------------------
  4849. def draw_item(index)
  4850. if @commands[index] == RMXOS::Data::ServerOnline
  4851. color = RMXOS::Data::ColorServerOnline
  4852. elsif @commands[index] == RMXOS::Data::ServerOffline
  4853. color = RMXOS::Data::ColorServerOffline
  4854. else
  4855. color = normal_color
  4856. end
  4857. change_color(color, command_enabled?(index))
  4858. draw_text(item_rect_for_text(index), command_name(index), alignment)
  4859. end
  4860.  
  4861. #----------------------------------------------------------------------------
  4862. # Updats cursor rectangle.
  4863. #----------------------------------------------------------------------------
  4864. def page_row_max
  4865. result = super
  4866. result += 1 if self.active && self.index >= 0 && self.index < @commands.length - 1
  4867. return result
  4868. end
  4869.  
  4870. end
  4871.  
  4872. #==============================================================================
  4873. # Window_CommandHorizontal
  4874. #------------------------------------------------------------------------------
  4875. # This window deals with general command choices, but the display is
  4876. # horizontal.
  4877. #==============================================================================
  4878.  
  4879. class Window_CommandHorizontal < Window_RMXOSCommand
  4880.  
  4881. #----------------------------------------------------------------------------
  4882. # Initialization.
  4883. #----------------------------------------------------------------------------
  4884. def initialize(width, commands)
  4885. super
  4886. self.width, self.height = commands.size * width + 32, 64
  4887. @column_max = commands.size
  4888. self.contents.dispose
  4889. self.contents = Bitmap.new(self.width - 32, self.height - 32)
  4890. refresh
  4891. update_cursor_rect
  4892. end
  4893. #----------------------------------------------------------------------------
  4894. # Draws one item.
  4895. # i - item index
  4896. # color - text color
  4897. #----------------------------------------------------------------------------
  4898. def draw_item(i, color)
  4899. self.contents.font.color = color
  4900. w = (self.width - 32) / @column_max
  4901. x = i % @column_max * w
  4902. rect = Rect.new(x, 0, self.contents.width / @column_max, 32)
  4903. self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
  4904. self.contents.draw_text(rect, @commands[i], 1)
  4905. end
  4906. #----------------------------------------------------------------------------
  4907. # Updates the cursor rectangle.
  4908. #----------------------------------------------------------------------------
  4909. def update_cursor_rect
  4910. # if no cursor position
  4911. if @index < 0
  4912. self.cursor_rect.empty
  4913. return
  4914. end
  4915. # match rows
  4916. row = @index / @column_max
  4917. self.top_row = row if row < self.top_row
  4918. if row > self.top_row + (self.page_row_max - 1)
  4919. self.top_row = row - (self.page_row_max - 1)
  4920. end
  4921. # set cursor position
  4922. cursor_width = (self.width - 32) / @column_max
  4923. x = @index % @column_max * cursor_width
  4924. self.cursor_rect.set(x, 0, cursor_width, 32)
  4925. end
  4926.  
  4927. end
  4928.  
  4929. #==============================================================================
  4930. # Window_TradeItem
  4931. #------------------------------------------------------------------------------
  4932. # Displays items for trading.
  4933. #==============================================================================
  4934.  
  4935. class Window_TradeItem < Window_ItemList
  4936.  
  4937. # setting all accessible variables
  4938. attr_reader :item_max
  4939. attr_reader :items
  4940. #----------------------------------------------------------------------------
  4941. # Initialization
  4942. #----------------------------------------------------------------------------
  4943. def initialize
  4944. super
  4945. # setup dimensions
  4946. self.y, self.z = 64, 11000
  4947. self.width, self.height = 320, 192
  4948. # initialize
  4949. @column_max = 1
  4950. self.active = false
  4951. self.cursor_rect.empty
  4952. # refresh display
  4953. refresh
  4954. end
  4955. #----------------------------------------------------------------------------
  4956. # Draws the data on the window.
  4957. #----------------------------------------------------------------------------
  4958. def refresh
  4959. # if bitmap exists
  4960. if self.contents != nil
  4961. # delete bitmap
  4962. self.contents.dispose
  4963. self.contents = nil
  4964. end
  4965. # set up all items for display
  4966. setup_items
  4967. # if there are any items
  4968. if @item_max > 0
  4969. # create bitmap
  4970. self.contents = Bitmap.new(width - 32, @item_max * 32)
  4971. # if using Dyna Edition scripts
  4972. if $fontface != nil
  4973. # set font name and size
  4974. self.contents.font.name = $fontface
  4975. self.contents.font.size = $fontsize
  4976. # if using PK Edition 2
  4977. elsif $defaultfonttype != nil
  4978. # set font name and size
  4979. self.contents.font.name = $defaultfonttype
  4980. self.contents.font.size = $defaultfontsize
  4981. end
  4982. # draws all items
  4983. draw_items
  4984. end
  4985. end
  4986. #----------------------------------------------------------------------------
  4987. # Sets up all items displayed.
  4988. #----------------------------------------------------------------------------
  4989. def setup_items
  4990. # empty data
  4991. @data = [0] # this is gold!
  4992. @items = {}
  4993. # iterate through all items without the no-trade items
  4994. ((1...$data_items.size).to_a - RMXOS::Data::NoTradeItems).each {|i|
  4995. # add item
  4996. @data.push($data_items[i])
  4997. }
  4998. # set size
  4999. @item_max = @data.size
  5000. end
  5001. #----------------------------------------------------------------------------
  5002. # Draws all items.
  5003. #----------------------------------------------------------------------------
  5004. def draw_items
  5005. (0...@item_max).each {|i| draw_item(i)}
  5006. end
  5007. #----------------------------------------------------------------------------
  5008. # Draws one item completely.
  5009. # i - item index
  5010. #----------------------------------------------------------------------------
  5011. def draw_item(i)
  5012. y = i * 32
  5013. # clear the display for the item
  5014. self.contents.fill_rect(Rect.new(4, y, 288, 32), Color.new(0, 0, 0, 0))
  5015. # draw icon bitmap if not gold
  5016. if @data[i] != 0
  5017. bitmap = RPG::Cache.icon(@data[i].icon_name)
  5018. opacity = self.contents.font.color == normal_color ? 255 : 128
  5019. self.contents.blt(4, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
  5020. end
  5021. self.contents.font.color = normal_color
  5022. # draw item/gold name
  5023. name = (@data[i] != 0 ? @data[i].name : $data_system.words.gold)
  5024. self.contents.draw_text(32, y, 212, 32, name)
  5025. self.draw_item_remaining(i)
  5026. end
  5027. #----------------------------------------------------------------------------
  5028. # Draws the remaining number of an item.
  5029. # i - item index
  5030. #----------------------------------------------------------------------------
  5031. def draw_item_remaining(i)
  5032. y = i * 32
  5033. # if not gold
  5034. if @data[i] != 0
  5035. # draw number of items left
  5036. self.contents.draw_text(244, y, 16, 32, ':', 1)
  5037. number = $game_party.item_number(@data[i].id)
  5038. self.contents.draw_text(260, y, 24, 32, number.to_s, 2)
  5039. else
  5040. # draw gold left
  5041. self.contents.draw_text(188, y, 96, 96, $game_party.gold.to_s, 2)
  5042. end
  5043. end
  5044.  
  5045. end
  5046.  
  5047. #==============================================================================
  5048. # Window_TradePlayer
  5049. #------------------------------------------------------------------------------
  5050. # Displays items selected for trading.
  5051. #==============================================================================
  5052.  
  5053. class Window_TradePlayer < Window_TradeItem
  5054.  
  5055. #----------------------------------------------------------------------------
  5056. # Adds a selection counter for items.
  5057. #----------------------------------------------------------------------------
  5058. def setup_items
  5059. super
  5060. # for each item
  5061. @data.each_index {|i|
  5062. # if not gold
  5063. if @data[i] != 0
  5064. # set up values
  5065. id = @data[i].id
  5066. number = $game_party.item_number(@data[i].id)
  5067. else
  5068. # set up gold values
  5069. id = 0
  5070. number = $game_party.gold
  5071. end
  5072. # if in possession
  5073. if number > 0
  5074. # initialize number of that item
  5075. @items[id] = 0
  5076. else
  5077. # delete item
  5078. @data[i] = nil
  5079. end
  5080. }
  5081. # remove all nil values
  5082. @data.compact!
  5083. # set size and autocorrect index
  5084. @item_max = @data.size
  5085. @index = @item_max - 1 if @index >= @item_max
  5086. end
  5087. #----------------------------------------------------------------------------
  5088. # Increases the quantity of an item to trade.
  5089. # value - by how much
  5090. # Returns: Whether the quantity was changed or not.
  5091. #----------------------------------------------------------------------------
  5092. def increase_quantity(value)
  5093. # if not gold
  5094. if @data[@index] != 0
  5095. # set up values
  5096. id = @data[@index].id
  5097. number = $game_party.item_number(@data[@index].id)
  5098. else
  5099. # set up gold values
  5100. id = 0
  5101. number = $game_party.gold
  5102. end
  5103. value = number - @items[id] if value > number - @items[id]
  5104. # increase
  5105. if @items[id] < number
  5106. @items[id] += value
  5107. self.draw_item(@index)
  5108. return true
  5109. end
  5110. return false
  5111. end
  5112. #----------------------------------------------------------------------------
  5113. # Decreases the quantity of an item to trade.
  5114. # value - by how much
  5115. # Returns: Whether the quantity was changed or not.
  5116. #----------------------------------------------------------------------------
  5117. def decrease_quantity(value)
  5118. # if not gold
  5119. if @data[@index] != 0
  5120. # set up values
  5121. id = @data[@index].id
  5122. number = $game_party.item_number(@data[@index].id)
  5123. else
  5124. # set up gold values
  5125. id = 0
  5126. number = $game_party.gold
  5127. end
  5128. value = @items[id] if value > @items[id]
  5129. # decrease
  5130. if @items[id] > 0
  5131. @items[id] -= value
  5132. self.draw_item(@index)
  5133. return true
  5134. end
  5135. return false
  5136. end
  5137. #----------------------------------------------------------------------------
  5138. # Draws the remaining number of an item.
  5139. # i - item index
  5140. #----------------------------------------------------------------------------
  5141. def draw_item_remaining(i)
  5142. y = i * 32
  5143. # if not gold
  5144. if @data[i] != 0
  5145. # draw number of items left
  5146. self.contents.draw_text(220, y, 24, 32, @items[@data[i].id].to_s, 2)
  5147. self.contents.draw_text(244, y, 16, 32, '/', 1)
  5148. number = $game_party.item_number(@data[i].id)
  5149. self.contents.draw_text(260, y, 24, 32, number.to_s, 2)
  5150. else
  5151. # draw number of items left
  5152. self.contents.draw_text(100, y, 84, 32, @items[0].to_s, 2)
  5153. self.contents.draw_text(184, y, 16, 32, '/', 1)
  5154. self.contents.draw_text(200, y, 84, 32, $game_party.gold.to_s, 2)
  5155. end
  5156. end
  5157.  
  5158. end
  5159.  
  5160. #==============================================================================
  5161. # Window_TradePartner
  5162. #------------------------------------------------------------------------------
  5163. # Displays items from the other player selected for trading.
  5164. #==============================================================================
  5165.  
  5166. class Window_TradePartner < Window_TradeItem
  5167.  
  5168. #----------------------------------------------------------------------------
  5169. # Initialization
  5170. #----------------------------------------------------------------------------
  5171. def initialize
  5172. super
  5173. self.x = 320
  5174. end
  5175. #----------------------------------------------------------------------------
  5176. # Refreshes the display upon item change.
  5177. #----------------------------------------------------------------------------
  5178. def update
  5179. super if self.active
  5180. if @items != $game_temp.trade_items
  5181. # remove 0 count items
  5182. $game_temp.trade_items.keys.each {|i|
  5183. $game_temp.trade_items.delete(i) if $game_temp.trade_items[i] == 0
  5184. }
  5185. # refresh the display
  5186. setup_items
  5187. refresh
  5188. end
  5189. end
  5190. #----------------------------------------------------------------------------
  5191. # Adds a selection counter for items.
  5192. #----------------------------------------------------------------------------
  5193. def setup_items
  5194. super
  5195. # for each item
  5196. @data.each_index {|i|
  5197. # that is not in the list
  5198. id = (@data[i] != 0 ? @data[i].id : 0)
  5199. if $game_temp.trade_items[id] == nil
  5200. # delete it
  5201. @data[i] = nil
  5202. end
  5203. }
  5204. # remove all nil values
  5205. @data.compact!
  5206. # set number of that item
  5207. @items = $game_temp.trade_items
  5208. # set size and autocorrect index
  5209. @item_max = @data.size
  5210. @index = @item_max - 1 if @index >= @item_max
  5211. end
  5212. #----------------------------------------------------------------------------
  5213. # Draws the remaining number of an item.
  5214. # i - item index
  5215. #----------------------------------------------------------------------------
  5216. def draw_item_remaining(i)
  5217. y = i * 32
  5218. # if not gold
  5219. if @data[i] != 0
  5220. # draw number of items
  5221. self.contents.draw_text(244, y, 16, 32, ':', 1)
  5222. self.contents.draw_text(260, y, 24, 32, @items[@data[i].id].to_s, 2)
  5223. else
  5224. # draw number of gold
  5225. self.contents.draw_text(200, y, 84, 32, @items[0].to_s, 2)
  5226. end
  5227. end
  5228.  
  5229. end
  5230.  
  5231. #==============================================================================
  5232. # Scene_BaseRMXOS
  5233. #------------------------------------------------------------------------------
  5234. # Serves as superclass for special scenes used in RMX-OS. This class is used
  5235. # for consistency, a stable framework and reusability to minimize the amount
  5236. # of coding that needs to be done. It is an abstract class and should not be
  5237. # instantiated as such.
  5238. #==============================================================================
  5239.  
  5240. class Scene_BaseRMXOS
  5241.  
  5242. #----------------------------------------------------------------------------
  5243. # Main loop for RMX-OS scenes.
  5244. #----------------------------------------------------------------------------
  5245. def main
  5246. setup_scene
  5247. create_scene
  5248. start_scene
  5249. loop do
  5250. Graphics.update
  5251. Input.update
  5252. update
  5253. break if SceneManager.scene != self
  5254. end
  5255. finish_scene
  5256. finalize_scene
  5257. dispose_scene
  5258. end
  5259. #----------------------------------------------------------------------------
  5260. # Sets up different parameters used in the scene. Abstract method.
  5261. #----------------------------------------------------------------------------
  5262. def setup_scene
  5263. end
  5264. #----------------------------------------------------------------------------
  5265. # Sets up visual elements of a scene. Abstract method.
  5266. #----------------------------------------------------------------------------
  5267. def create_scene
  5268. end
  5269. #----------------------------------------------------------------------------
  5270. # Starts the scene.
  5271. #----------------------------------------------------------------------------
  5272. def start_scene
  5273. Graphics.transition(10)
  5274. end
  5275. #----------------------------------------------------------------------------
  5276. # Finishes the scene.
  5277. #----------------------------------------------------------------------------
  5278. def finish_scene
  5279. Graphics.freeze
  5280. end
  5281. #----------------------------------------------------------------------------
  5282. # Finalizes all non-visual data in the scene. Abstract method.
  5283. #----------------------------------------------------------------------------
  5284. def finalize_scene
  5285. end
  5286. #----------------------------------------------------------------------------
  5287. # Disposes all visual elements of the scene. Abstract method.
  5288. #----------------------------------------------------------------------------
  5289. def dispose_scene
  5290. end
  5291. #----------------------------------------------------------------------------
  5292. # Updates the scene's behavior.
  5293. #----------------------------------------------------------------------------
  5294. def update
  5295. SceneManager.exit if Input.trigger?(Input::B)
  5296. end
  5297.  
  5298. end
  5299.  
  5300. #==============================================================================
  5301. # Scene_Network
  5302. #------------------------------------------------------------------------------
  5303. # Serves as superclass for all network based scenes during the connection to
  5304. # the server.
  5305. #==============================================================================
  5306.  
  5307. class Scene_Network < Scene_BaseRMXOS
  5308.  
  5309. #----------------------------------------------------------------------------
  5310. # Initialization.
  5311. # helptext - the text displayed initially in the help window.
  5312. #----------------------------------------------------------------------------
  5313. def initialize(helptext)
  5314. @helptext = helptext
  5315. end
  5316. #----------------------------------------------------------------------------
  5317. # Adds a wait count.
  5318. #----------------------------------------------------------------------------
  5319. def setup_scene
  5320. super
  5321. @wait_count = 0
  5322. end
  5323.  
  5324. #--------------------------------------------------------------------------
  5325. # * Move Sprite to Screen Center
  5326. #--------------------------------------------------------------------------
  5327. def center_sprite(sprite)
  5328. sprite.ox = sprite.bitmap.width / 2
  5329. sprite.oy = sprite.bitmap.height / 2
  5330. sprite.x = Graphics.width / 2
  5331. sprite.y = Graphics.height / 2
  5332. end
  5333.  
  5334. #--------------------------------------------------------------------------
  5335. # * Create Background
  5336. #--------------------------------------------------------------------------
  5337. def create_background
  5338. @sprite1 = Sprite.new
  5339. @sprite1.bitmap = Cache.title1($data_system.title1_name)
  5340. @sprite2 = Sprite.new
  5341. @sprite2.bitmap = Cache.title2($data_system.title2_name)
  5342. center_sprite(@sprite1)
  5343. center_sprite(@sprite2)
  5344. end
  5345.  
  5346. #----------------------------------------------------------------------------
  5347. # Creates a title screen background, a version display and a help window.
  5348. #----------------------------------------------------------------------------
  5349. def create_scene
  5350. # play the title music
  5351. $data_system.title_bgm.play
  5352. # stop playing ME and BGS
  5353. Audio.me_stop
  5354. Audio.bgs_stop
  5355. # load the title screen
  5356. create_background
  5357. # create a sprite displaying the version of RMX-OS
  5358. @version = Sprite.new
  5359. @version.x, @version.y = 4, Graphics.height - 32
  5360. @version.bitmap = Bitmap.new(160, 32)
  5361. # if using Dyna Edition scripts
  5362. if $fontface != nil
  5363. # set font name and size
  5364. @version.bitmap.font.name = $fontface
  5365. # if using PK Edition 2
  5366. elsif $defaultfonttype != nil
  5367. # set font name and size
  5368. @version.bitmap.font.name = $defaultfonttype
  5369. end
  5370. @version.bitmap.font.name = 'Arial'
  5371. @version.bitmap.font.size = 24
  5372. @version.bitmap.draw_text(4, 0, 152, 32,
  5373. "#{RMXOS::Data::Version}: #{RMXOS::Options::GAME_VERSION}")
  5374. # create help window
  5375. @help_window = Window_Help.new
  5376. @help_window.set_text(@helptext)
  5377. end
  5378. #----------------------------------------------------------------------------
  5379. # Disposes title screen background and a version display.
  5380. #----------------------------------------------------------------------------
  5381. def dispose_scene
  5382. super
  5383. @sprite1.bitmap.dispose
  5384. @sprite2.bitmap.dispose
  5385. @sprite1.dispose
  5386. @sprite2.dispose
  5387. @version.dispose
  5388. @help_window.dispose
  5389. end
  5390. #----------------------------------------------------------------------------
  5391. # Wait for the server to respond to a request. Abstract method.
  5392. # Returns: True or false.
  5393. #----------------------------------------------------------------------------
  5394. def waiting_for_server
  5395. return false
  5396. end
  5397. #----------------------------------------------------------------------------
  5398. # Wait for the server to respond to a request. Abstract method.
  5399. # Returns: True or false.
  5400. #----------------------------------------------------------------------------
  5401. def waiting?
  5402. # if waiting timer active
  5403. if @wait_count > 0
  5404. @wait_count -= 1
  5405. # if timer expired
  5406. if @wait_count == 0
  5407. # server did not respond
  5408. p RMXOS::Data::NoResponse
  5409. return true
  5410. end
  5411. # skip update if waiting for server
  5412. return true if waiting_for_server
  5413. @wait_count = 0
  5414. end
  5415. return false
  5416. end
  5417.  
  5418. end
  5419.  
  5420. #==============================================================================
  5421. # Scene_Servers
  5422. #------------------------------------------------------------------------------
  5423. # Displays a connection dialog to connect to an existing server.
  5424. #==============================================================================
  5425.  
  5426. class Scene_Servers < Scene_Network
  5427.  
  5428. #----------------------------------------------------------------------------
  5429. # Initialization.
  5430. #----------------------------------------------------------------------------
  5431. def initialize
  5432. super(RMXOS::Data::SelectServer)
  5433. end
  5434. #----------------------------------------------------------------------------
  5435. # Adds several variables used in this scene.
  5436. #----------------------------------------------------------------------------
  5437. def setup_scene
  5438. super
  5439. @refresh_count = 1
  5440. @server_states = []
  5441. # for each server add a server state and test state text
  5442. RMXOS::Options::SERVERS.size.times {@server_states.push(false)}
  5443. # create game data
  5444. create_game_data
  5445. end
  5446. #----------------------------------------------------------------------------
  5447. # Creates initial instances of the game classes.
  5448. #----------------------------------------------------------------------------
  5449. def create_game_data
  5450. $game_temp = Game_Temp.new
  5451. $game_system = Game_System.new
  5452. $game_switches = Game_Switches.new
  5453. $game_variables = Game_Variables.new
  5454. $game_self_switches = Game_SelfSwitches.new
  5455. $game_screen = Game_Screen.new
  5456. $game_actors = Game_Actors.new
  5457. $game_party = Game_Party.new
  5458. $game_troop = Game_Troop.new
  5459. $game_map = Game_Map.new
  5460. $game_player = Game_Player.new
  5461. end
  5462.  
  5463. def exit_handler
  5464. Sound.play_ok
  5465. SceneManager.exit
  5466. end
  5467.  
  5468. def server_handler
  5469. # if selected server is tested to be online
  5470. if @server_states[@server_window.index]
  5471. Sound.play_ok
  5472. @online_window.draw_command(@server_window.index, RMXOS::Data::Connecting)
  5473. Graphics.update
  5474. # get data
  5475. server = RMXOS::Options::SERVERS[@server_window.index]
  5476. $network.start_connection(server.host, server.port)
  5477. $network.request_connection
  5478. # set waiting timer for server answer
  5479. @wait_count = RMXOS::Options::SERVER_TIMEOUT
  5480. @refresh_count = RMXOS::Options::SERVER_REFRESH
  5481. else
  5482. Sound.play_buzzer
  5483. end
  5484. end
  5485.  
  5486. #----------------------------------------------------------------------------
  5487. # Creates a display for available servers and whether they are online or not.
  5488. #----------------------------------------------------------------------------
  5489. def create_scene
  5490. super
  5491. # get all server names
  5492. server_names = []
  5493. RMXOS::Options::SERVERS.each {|server| server_names.push(server.name)}
  5494. server_names.push(RMXOS::Data::Exit)
  5495. # create server selection window
  5496. @server_window = Window_ServerCommand.new(224, server_names)
  5497. @server_window.x = 32
  5498. @server_window.y = (Graphics.height - @server_window.height) / 2
  5499. @server_window.y = 96 if @server_window.y < 96
  5500. if @server_window.height > Graphics.height - 128
  5501. @server_window.height = Graphics.height - 128
  5502. end
  5503. server_names.each do |name|
  5504. next if name == RMXOS::Data::Exit
  5505. @server_window.set_handler(name, method(:server_handler))
  5506. end
  5507. @server_window.set_handler(RMXOS::Data::Exit, method(:exit_handler))
  5508.  
  5509. @server_window.active = true
  5510. @server_window.index = 0
  5511. # create server states window
  5512. states = []
  5513. @server_states.size.times {states.push(RMXOS::Data::ServerOffline)}
  5514. @online_window = Window_ServerCommand.new(
  5515. Graphics.width - 320, states)
  5516. @online_window.x, @online_window.y = 288, @server_window.y
  5517. if @online_window.height > Graphics.height - 160
  5518. @online_window.height = Graphics.height - 160
  5519. end
  5520. @online_window.active = false
  5521. @online_window.index = -1
  5522. end
  5523. #----------------------------------------------------------------------------
  5524. # Refreshes the online status of the servers.
  5525. #----------------------------------------------------------------------------
  5526. def refresh_server_states
  5527. states = self.make_server_states
  5528. @online_window.set_commands(states)
  5529. Graphics.update
  5530. end
  5531. #----------------------------------------------------------------------------
  5532. # Refreshes the online status of the servers.
  5533. #----------------------------------------------------------------------------
  5534. def make_server_states
  5535. states = []
  5536. RMXOS::Options::SERVERS.each_index {|i|
  5537. # add online/offline text
  5538. states.push(@server_states[i] ? RMXOS::Data::ServerOnline :
  5539. RMXOS::Data::ServerOffline)
  5540. }
  5541. # for each server
  5542. RMXOS::Options::SERVERS.each_index {|i|
  5543. # this server is being tested now
  5544. states[i] = RMXOS::Data::ServerTesting
  5545. # refresh server display
  5546. @online_window.set_commands(states)
  5547. Graphics.update
  5548. # if server is actually available
  5549. if @server_states[i] != nil
  5550. # get connection data
  5551. server = RMXOS::Options::SERVERS[i]
  5552. # test connection to server and store the result
  5553. @server_states[i] = $network.test_connection(server.host, server.port, i)
  5554. # add online/offline text
  5555. if @server_states[i]
  5556. states[i] = RMXOS::Data::ServerOnline
  5557. else
  5558. states[i] = RMXOS::Data::ServerOffline
  5559. end
  5560. else
  5561. states[i] = RMXOS::Data::ServerOffline
  5562. end
  5563. }
  5564. return states
  5565. end
  5566. #----------------------------------------------------------------------------
  5567. # Disposes the windows.
  5568. #----------------------------------------------------------------------------
  5569. def dispose_scene
  5570. super
  5571. @server_window.dispose
  5572. @online_window.dispose
  5573. end
  5574. #----------------------------------------------------------------------------
  5575. # Updates the scene's behavior.
  5576. #----------------------------------------------------------------------------
  5577. def update
  5578. return if waiting?
  5579. # check for server connections
  5580. check_server_states
  5581. @server_window.update
  5582. @online_window.oy = @server_window.oy
  5583. # if pressed cancel
  5584. if Input.trigger?(Input::B)
  5585. # exit
  5586. Sound.play_cancel
  5587. SceneManager.exit
  5588. end
  5589. end
  5590. #----------------------------------------------------------------------------
  5591. # Checks for server connections when necessary.
  5592. #----------------------------------------------------------------------------
  5593. def check_server_states
  5594. # decrease timer
  5595. @refresh_count -= 1
  5596. # if timer expired
  5597. if @refresh_count <= 0 || Input.trigger?(Input::F5)
  5598. refresh_server_states
  5599. # renew timer
  5600. @refresh_count = RMXOS::Options::SERVER_REFRESH
  5601. end
  5602. end
  5603. #----------------------------------------------------------------------------
  5604. # Wait for server to answer to the requested data.
  5605. # Returns: Whether to skip the rest of the update or not.
  5606. #----------------------------------------------------------------------------
  5607. def waiting_for_server
  5608. $network.listen
  5609. # check each message
  5610. $network.messages.each {|message|
  5611. case message
  5612. when RMXOS::CONNECTION_SUCCESS # connection granted
  5613. # proceed to login
  5614. SceneManager.goto Scene_Login
  5615. return false
  5616. when RMXOS::CONNECTION_DENIED # server is full
  5617. # disconnect from server
  5618. $network.disconnect
  5619. # show error
  5620. @online_window.draw_command(@server_window.index,
  5621. RMXOS::Error::ServerFull, RMXOS::Data::ColorServerError)
  5622. return false
  5623. when RMXOS::CONNECTION_CLIENT_VERSION # client version does not match
  5624. # disconnect from server
  5625. $network.disconnect
  5626. # show error
  5627. @online_window.draw_command(@server_window.index,
  5628. RMXOS::Error.get_client_version_error, RMXOS::Data::ColorServerError)
  5629. return false
  5630. when RMXOS::CONNECTION_GAME_VERSION # game version does not match
  5631. # disconnect from server
  5632. $network.disconnect
  5633. # show error
  5634. @online_window.draw_command(@server_window.index,
  5635. RMXOS::Error.get_game_version_error, RMXOS::Data::ColorServerError)
  5636. return false
  5637. end
  5638. }
  5639. return true
  5640. end
  5641.  
  5642. end
  5643.  
  5644. #==============================================================================
  5645. # Scene_UserPass
  5646. #------------------------------------------------------------------------------
  5647. # Handles scenes where the player is prompted for a username and password.
  5648. # This class is abstract and should not be instantiated as such.
  5649. #==============================================================================
  5650.  
  5651. class Scene_UserPass < Scene_Network
  5652.  
  5653. #----------------------------------------------------------------------------
  5654. # Creates all necessary visuals.
  5655. #----------------------------------------------------------------------------
  5656. def create_scene
  5657. super
  5658. create_windows
  5659. create_buttons
  5660. end
  5661. #----------------------------------------------------------------------------
  5662. # Creates all windows.
  5663. #----------------------------------------------------------------------------
  5664. def create_windows
  5665. @input_frames = []
  5666. y, h1, h2 = self._get_window_ys
  5667. # create username and password windows
  5668. @username_window = Frame_Caption.new(32, y,
  5669. Graphics.width - 64, RMXOS::Data::Username)
  5670. @password_window = Frame_Caption.new(32, y + 32 + h1,
  5671. Graphics.width - 64, RMXOS::Data::Password)
  5672. @password_window.password_char = RMXOS::Data::PassChar
  5673. @password_window.active = false
  5674. @input_frames.push(@username_window)
  5675. @input_frames.push(@password_window)
  5676. end
  5677. #----------------------------------------------------------------------------
  5678. # Prepares button array.
  5679. #----------------------------------------------------------------------------
  5680. def create_buttons
  5681. @buttons = []
  5682. end
  5683. #----------------------------------------------------------------------------
  5684. # Removes all visuals.
  5685. #----------------------------------------------------------------------------
  5686. def dispose_scene
  5687. super
  5688. @input_frames.each {|window| window.dispose}
  5689. @buttons.each {|button| button.dispose}
  5690. end
  5691. #----------------------------------------------------------------------------
  5692. # Calculates the GUI element positions depending on screen height
  5693. # Returns: Y coordinate of first window, offset height between frames and
  5694. # additional offset height for buttons.
  5695. #----------------------------------------------------------------------------
  5696. def _get_window_ys
  5697. y, h1, h2 = 128, 32, 32
  5698. if Graphics.height < 480
  5699. y -= (480 - Graphics.height) / 2
  5700. y = 96 if y < 96
  5701. h2 = 0
  5702. if Graphics.height < 384
  5703. h1 = (Graphics.height - 288) / 3
  5704. end
  5705. end
  5706. return [y, h1, h2]
  5707. end
  5708. #----------------------------------------------------------------------------
  5709. # Updates the scene's behavior.
  5710. #----------------------------------------------------------------------------
  5711. def update
  5712. $network.listen
  5713. return if waiting?
  5714. # update username window and password window if they are active
  5715. @input_frames.each {|window| window.update if window.active}
  5716. @buttons.each {|button| button.update}
  5717. # if pressed cancel
  5718. if Input.trigger?(Input::B)
  5719. Sound.play_cancel
  5720. command_cancel
  5721. # if pressed confirm
  5722. elsif Input.trigger?(Input::C)
  5723. command_confirm
  5724. # if pressed down
  5725. elsif Input.repeat?(Input::DOWN)
  5726. command_down
  5727. # if pressed up
  5728. elsif Input.repeat?(Input::UP)
  5729. command_up
  5730. # if pressed left
  5731. elsif Input.repeat?(Input::LEFT)
  5732. command_left
  5733. # if pressed right
  5734. elsif Input.repeat?(Input::RIGHT)
  5735. command_right
  5736. end
  5737. end
  5738. #----------------------------------------------------------------------------
  5739. # Executed upon choosing the "cancel" choice. Abstract method.
  5740. #----------------------------------------------------------------------------
  5741. def command_cancel
  5742. end
  5743. #----------------------------------------------------------------------------
  5744. # Executed upon choosing the "confirm" choice.
  5745. #----------------------------------------------------------------------------
  5746. def command_confirm
  5747. # if confirm button active
  5748. if @buttons[0].index == 0
  5749. Sound.play_ok
  5750. submit_to_server
  5751. # if cancel button active
  5752. elsif @buttons[@buttons.size - 1].index == 0
  5753. Sound.play_ok
  5754. command_cancel
  5755. # if bottom input frame is active
  5756. elsif @input_frames[@input_frames.size - 1].active
  5757. Sound.play_ok
  5758. submit_to_server
  5759. # if username window active
  5760. else
  5761. # switch to next input frame if possible
  5762. window = @input_frames.find {|w| w.active}
  5763. if window != nil
  5764. Sound.play_ok
  5765. window.active = false
  5766. @input_frames[@input_frames.index(window) + 1].active = true
  5767. end
  5768. end
  5769. end
  5770. #----------------------------------------------------------------------------
  5771. # Submits data to the server.
  5772. #----------------------------------------------------------------------------
  5773. def submit_to_server
  5774. @wait_count = RMXOS::Options::SERVER_TIMEOUT
  5775. end
  5776. #----------------------------------------------------------------------------
  5777. # Saves current username and password.
  5778. #----------------------------------------------------------------------------
  5779. def save_user_pass
  5780. # if login remember option is on
  5781. if RMXOS::Options::REMEMBER_LOGIN
  5782. # create data stream
  5783. stream = "#{@username_window.text}\t#{@password_window.text}"
  5784. # zip stream
  5785. rawdata = Zlib::Deflate.deflate(stream, 9)
  5786. # save stream into file
  5787. file = File.open('account.dat', 'wb')
  5788. file.write(rawdata)
  5789. file.close
  5790. end
  5791. end
  5792. #----------------------------------------------------------------------------
  5793. # Executed upon pressing "down".
  5794. #----------------------------------------------------------------------------
  5795. def command_down
  5796. Sound.play_cursor
  5797. # if last frame active
  5798. if @input_frames[@input_frames.size - 1].active
  5799. @input_frames[@input_frames.size - 1].active = false
  5800. @buttons[0].index = 0
  5801. else
  5802. # switch to next input frame if possible
  5803. window = @input_frames.find {|w| w.active}
  5804. if window != nil
  5805. window.active = false
  5806. @input_frames[@input_frames.index(window) + 1].active = true
  5807. else
  5808. # switch to username window
  5809. @buttons.each {|button| button.index = -1}
  5810. @input_frames[0].active = true
  5811. end
  5812. end
  5813. end
  5814. #----------------------------------------------------------------------------
  5815. # Executed upon pressing "up".
  5816. #----------------------------------------------------------------------------
  5817. def command_up
  5818. Sound.play_cursor
  5819. # if last frame active
  5820. if @input_frames[0].active
  5821. @input_frames[0].active = false
  5822. @buttons[0].index = 0
  5823. else
  5824. # switch to next input frame if possible
  5825. window = @input_frames.find {|w| w.active}
  5826. if window != nil
  5827. window.active = false
  5828. @input_frames[@input_frames.index(window) - 1].active = true
  5829. else
  5830. # switch to username window
  5831. @buttons.each {|button| button.index = -1}
  5832. @input_frames[@input_frames.size - 1].active = true
  5833. end
  5834. end
  5835. end
  5836. #----------------------------------------------------------------------------
  5837. # Executed upon pressing "left".
  5838. #----------------------------------------------------------------------------
  5839. def command_left
  5840. # check each button
  5841. @buttons.each_index {|i|
  5842. # if active
  5843. if @buttons[i].index == 0
  5844. Sound.play_cursor
  5845. # circularry switch to the left button
  5846. @buttons[i].index = -1
  5847. @buttons[(i + @buttons.size - 1) % @buttons.size].index = 0
  5848. return
  5849. end
  5850. }
  5851. end
  5852. #----------------------------------------------------------------------------
  5853. # Executed upon pressing "right".
  5854. #----------------------------------------------------------------------------
  5855. def command_right
  5856. # check each button
  5857. @buttons.each_index {|i|
  5858. # if active
  5859. if @buttons[i].index == 0
  5860. Sound.play_cursor
  5861. # circularry switch to the right button
  5862. @buttons[i].index = -1
  5863. @buttons[(i + 1) % @buttons.size].index = 0
  5864. return
  5865. end
  5866. }
  5867. end
  5868.  
  5869. end
  5870.  
  5871. #==============================================================================
  5872. # Scene_Login
  5873. #------------------------------------------------------------------------------
  5874. # Handles logging in of a player.
  5875. #==============================================================================
  5876.  
  5877. class Scene_Login < Scene_UserPass
  5878.  
  5879. #----------------------------------------------------------------------------
  5880. # Initialization.
  5881. #----------------------------------------------------------------------------
  5882. def initialize
  5883. super(RMXOS::Data::EnterUserPass)
  5884. end
  5885. #----------------------------------------------------------------------------
  5886. # Makes the password characters disappear and loads account.dat.
  5887. #----------------------------------------------------------------------------
  5888. def create_windows
  5889. super
  5890. # stop if not active or file doesn't exist
  5891. return if !RMXOS::Options::REMEMBER_LOGIN || !FileTest.exist?('account.dat')
  5892. # read data from file
  5893. file = File.open('account.dat', 'rb')
  5894. rawdata = file.read
  5895. file.close
  5896. # stop if file was empty
  5897. return if rawdata.size == 0
  5898. begin
  5899. # unzip data from file
  5900. lines = Zlib::Inflate.inflate(rawdata).split("\t")
  5901. # if file data is valid
  5902. if lines.size == 2
  5903. # set read username and password
  5904. @username_window.text, @password_window.text = lines
  5905. @username_window.cursor_move_to_end
  5906. @username_window.update_cursor
  5907. @password_window.cursor_move_to_end
  5908. end
  5909. rescue
  5910. end
  5911. end
  5912. #----------------------------------------------------------------------------
  5913. # Creates all buttons.
  5914. #----------------------------------------------------------------------------
  5915. def create_buttons
  5916. super
  5917. y, h1, h2 = self._get_window_ys
  5918. y += 96 + h1 * 3 + h2
  5919. w = (Graphics.width - 64) / 3
  5920. # create Login button
  5921. @buttons.push(Window_Button.new(32, y, w, RMXOS::Data::Login))
  5922. # create Register button
  5923. @buttons.push(Window_Button.new(32 + w, y, w, RMXOS::Data::Register))
  5924. # create Cancel button
  5925. @buttons.push(Window_Button.new(32 + w * 2, y, w, RMXOS::Data::Cancel))
  5926. end
  5927. #----------------------------------------------------------------------------
  5928. # Executed upon choosing the "cancel" choice.
  5929. #----------------------------------------------------------------------------
  5930. def command_cancel
  5931. # disconnect
  5932. $network.disconnect
  5933. # return to server selection
  5934. SceneManager.goto Scene_Servers
  5935. end
  5936. #----------------------------------------------------------------------------
  5937. # Executed upon choosing the "confirm" choice.
  5938. #----------------------------------------------------------------------------
  5939. def command_confirm
  5940. # if register button is active
  5941. if @buttons[1].index == 0
  5942. # proceed to registering
  5943. Sound.play_ok
  5944. SceneManager.goto Scene_Register
  5945. else
  5946. super
  5947. end
  5948. end
  5949. #----------------------------------------------------------------------------
  5950. # Submits the player login request to the server.
  5951. #----------------------------------------------------------------------------
  5952. def submit_to_server
  5953. # try to login
  5954. $network.try_login(@username_window.text, @password_window.text)
  5955. # show waiting message
  5956. @help_window.set_text(RMXOS::Data::LoggingIn)
  5957. super
  5958. end
  5959. #----------------------------------------------------------------------------
  5960. # Wait for server to answer to the requested data.
  5961. # Returns: Whether to skip the rest of the update or not.
  5962. #----------------------------------------------------------------------------
  5963. def waiting_for_server
  5964. # check each message
  5965. $network.messages.each {|message|
  5966. case message
  5967. when RMXOS::LOGIN_SUCCESS # login was a success
  5968. # display messsage
  5969. @help_window.set_text(RMXOS::Data::LoggedIn)
  5970. # save username and password
  5971. save_user_pass
  5972. # proceed to game
  5973. SceneManager.goto Scene_Loading
  5974. return false
  5975. when RMXOS::LOGIN_NOUSER # username does not exist
  5976. # display messsage
  5977. @help_window.set_text(RMXOS::Data::NoUsername)
  5978. return false
  5979. when RMXOS::LOGIN_NOPASS # wrong password
  5980. # display messsage
  5981. @help_window.set_text(RMXOS::Data::WrongPassword)
  5982. return false
  5983. when RMXOS::LOGIN_BANNED # banned
  5984. # display messsage
  5985. @help_window.set_text(RMXOS::Data::Banned)
  5986. return false
  5987. end
  5988. }
  5989. return true
  5990. end
  5991.  
  5992. end
  5993.  
  5994. #==============================================================================
  5995. # Scene_Register
  5996. #------------------------------------------------------------------------------
  5997. # Handles registering of a player.
  5998. #==============================================================================
  5999.  
  6000. class Scene_Register < Scene_UserPass
  6001.  
  6002. #----------------------------------------------------------------------------
  6003. # Initialization.
  6004. #----------------------------------------------------------------------------
  6005. def initialize
  6006. super(RMXOS::Data::RegisterUserPass)
  6007. end
  6008. #----------------------------------------------------------------------------
  6009. # Creates all windows.
  6010. #----------------------------------------------------------------------------
  6011. def create_windows
  6012. super
  6013. @confirm_window = Frame_Caption.new(
  6014. @password_window.x, @password_window.y * 2 - @username_window.y,
  6015. @password_window.width, RMXOS::Data::Repeat)
  6016. @confirm_window.password_char = RMXOS::Data::PassChar
  6017. @confirm_window.active = false
  6018. @input_frames.push(@confirm_window)
  6019. end
  6020. #----------------------------------------------------------------------------
  6021. # Creates all buttons.
  6022. #----------------------------------------------------------------------------
  6023. def create_buttons
  6024. super
  6025. y, h1, h2 = self._get_window_ys
  6026. y += 96 + h1 * 3 + h2
  6027. w = (Graphics.width - 64) / 2
  6028. # create Submit button
  6029. @buttons.push(Window_Button.new(32, y, w, RMXOS::Data::Submit))
  6030. # create Cancel button
  6031. @buttons.push(Window_Button.new(32 + w, y, w, RMXOS::Data::Cancel))
  6032. end
  6033. #----------------------------------------------------------------------------
  6034. # Executed upon choosing the "cancel" choice.
  6035. #----------------------------------------------------------------------------
  6036. def command_cancel
  6037. SceneManager.goto Scene_Login
  6038. end
  6039. #----------------------------------------------------------------------------
  6040. # Submits the player register request to the server.
  6041. #----------------------------------------------------------------------------
  6042. def submit_to_server
  6043. # if username too short
  6044. if @username_window.text.size < RMXOS::Options::USERPASS_MIN_LENGTH
  6045. @help_window.set_text(RMXOS::Data::UserTooShort)
  6046. # if username is reserved
  6047. elsif RMXOS.reserved_username?(@username_window.text)
  6048. @help_window.set_text(RMXOS::Data::UserReserved)
  6049. # if password too short
  6050. elsif @password_window.text.size < RMXOS::Options::USERPASS_MIN_LENGTH
  6051. @help_window.set_text(RMXOS::Data::PassTooShort)
  6052. # if password not repeated properly
  6053. elsif @password_window.text != @confirm_window.text
  6054. @help_window.set_text(RMXOS::Data::PassNotRepeated)
  6055. else
  6056. # try to register
  6057. $network.try_register(@username_window.text, @password_window.text)
  6058. # show waiting message
  6059. @help_window.set_text(RMXOS::Data::Registering)
  6060. super
  6061. end
  6062. end
  6063. #----------------------------------------------------------------------------
  6064. # Wait for server to answer to the requested data.
  6065. # Returns: Whether to skip the rest of the update or not.
  6066. #----------------------------------------------------------------------------
  6067. def waiting_for_server
  6068. # check each message
  6069. $network.messages.each {|message|
  6070. case message
  6071. when RMXOS::REGISTER_SUCCESS # register was a success
  6072. # display messsage
  6073. @help_window.set_text(RMXOS::Data::UserRegistered)
  6074. # save username and password
  6075. save_user_pass
  6076. # proceed to game
  6077. SceneManager.goto Scene_Loading
  6078. return false
  6079. when RMXOS::REGISTER_BANNED # banned
  6080. # display messsage
  6081. @help_window.set_text(RMXOS::Data::Banned)
  6082. return false
  6083. when RMXOS::REGISTER_EXIST # username already exists
  6084. # display messsage
  6085. @help_window.set_text(RMXOS::Data::UserRegisteredAlready)
  6086. return false
  6087. end
  6088. }
  6089. return true
  6090. end
  6091.  
  6092. end
  6093.  
  6094. #==============================================================================
  6095. # Scene_Loading
  6096. #------------------------------------------------------------------------------
  6097. # Waits for the server to send all saved game data.
  6098. #==============================================================================
  6099.  
  6100. class Scene_Loading < Scene_Network
  6101.  
  6102. #----------------------------------------------------------------------------
  6103. # Initialization.
  6104. #----------------------------------------------------------------------------
  6105. def initialize
  6106. # send a loading request to the server pre-emptively
  6107. $network.send_load_request
  6108. if RMXOS::Options::LEGACY_SAVE_METHOD
  6109. super(RMXOS::Data::ReceivingMessageLegacy.sub('NOW', '0').sub('MAX', '???'))
  6110. else
  6111. super(RMXOS::Data::ReceivingMessage)
  6112. end
  6113. end
  6114. #----------------------------------------------------------------------------
  6115. # Waits for server to send all loading data to be able to load the game.
  6116. #----------------------------------------------------------------------------
  6117. def update
  6118. $network.listen
  6119. loading_end = false
  6120. # check each message
  6121. $network.messages.each {|message|
  6122. case message
  6123. when RMXOS::LOADING_UPDATE
  6124. size = $network.load_sizes.shift
  6125. if RMXOS::Options::LEGACY_SAVE_METHOD
  6126. text = RMXOS::Data::ReceivingMessageLegacy.sub(
  6127. 'NOW', size.to_s).sub('MAX', $network.load_size.to_s)
  6128. @help_window.set_text(text)
  6129. 5.times {Graphics.update} if size == $network.load_size
  6130. end
  6131. when RMXOS::LOADING_END # game has been loaded
  6132. @help_window.set_text(RMXOS::Data::LoadingMessage)
  6133. 5.times {Graphics.update}
  6134. loading_end = true
  6135. end
  6136. }
  6137. if loading_end
  6138. # load game and proceed to map
  6139. self.load_game
  6140. SceneManager.goto Scene_Map
  6141. end
  6142. end
  6143. #----------------------------------------------------------------------------
  6144. # Sets up the map data for a loaded game. In case the game of a newly
  6145. # registered user, a new game will be started.
  6146. #----------------------------------------------------------------------------
  6147. def load_game
  6148. # if game was loaded
  6149. if $game_map.map_id != 0
  6150. # setup map and player
  6151. $game_map.setup($game_map.map_id)
  6152. $game_player.center($game_player.x, $game_player.y)
  6153. else
  6154. # start a new game
  6155. $game_party.setup_starting_members
  6156. $game_map.setup($data_system.start_map_id)
  6157. $game_player.moveto($data_system.start_x, $data_system.start_y)
  6158. end
  6159. # prepare everything for starting the game
  6160. $game_player.refresh
  6161. $game_map.autoplay
  6162. $game_temp.entering_map = true
  6163. $game_map.update
  6164. $network.game_loaded = true
  6165. end
  6166.  
  6167. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement