Holy87

Modulo di supporto v8

Sep 28th, 2020 (edited)
92
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. =begin
  2.  ==============================================================================
  3.   ■ Utility universali di Holy87
  4.       versione 1.8.0
  5.       Difficoltà utente: ★★★★★
  6.       Licenza: CC-BY. Chiunque può scaricare, modificare, distribuire e utilizzare
  7.       lo script nei propri progetti, sia amatoriali che commerciali. Vietata
  8.       l'attribuzione impropria.
  9.  
  10.   ■ Questo modulo serve a espandere a nuovi livelli i vostri script e permetter-
  11.     vi di creare feature nel vostro gioco prima impensabili, nel modo più
  12.     semplice e immediato possibile. Cosa è possibile fare?
  13.     ● Salvare delle variabili indipendenti dal salvataggio
  14.     ● Ottenere informazioni dal sistema, quali la risoluzione dello schermo,
  15.       la lingua del sistema, la versione di Windows, il nome utente, il
  16.       percorso della cartella documenti ecc...
  17.     ● Scaricare un file e/o inviare una richiesta ed ottenere risposta da un web
  18.       server, anche in modo asincrono e nel modo più facile possibile
  19.     ● Ottenere informazioni sulla versione del gioco o impostarla
  20.     ● Codificare/decodificare una stringa in rot13 o Base64
  21.     ● Altro ancora!
  22.  ==============================================================================
  23.   ■ Changelog
  24.     ● V 1.8.0
  25.       - Ottiene informazioni sul mouse (posizione, click, visibilità...)
  26.       - Supporto HTTPS per richieste web POST
  27.       - HTTP.send_post_request DEPRECATO
  28.       - await_response_async DEPRECATO
  29.       - Nuovo sistema per gestire le richieste dal web! (vedi doc.)
  30.       - Nuovi metodi per richieste web:
  31.         HTTP.get, HTTP.post, HTTP.put, HTTP.delete
  32.         Queste restituiranno un oggetto Response (vedi documentazione sotto)
  33.       - Metodo per donwload dei file migliorato
  34.       - Cache.web_picture per caricare una picture direttamente da internet
  35.       - Aggiunta dei metodi minutes, hours e days negli integer (vedi esempi)
  36.       - La versione del gioco può essere inserita nel file Game.ini
  37.         invece che nel file dedicato Version.ini
  38.       - Nuovo metodo per ottenere la lingua del sistema: Win.locale_name al posto
  39.         di Win.language. A differenza di quest'ultimo, ora è possibile ottenere
  40.         direttamente la descrizione della lingua corrente (es. en-US, it-IT ecc...)
  41.       - Win.language DEPRECATO
  42.       - Win.temp_flush DEPRECATO
  43.       - Sistemazione e rifinitura del codice
  44.       - Aggiunti i metodi on_vx_ace? e on_vx? che determinano su che versione
  45.         di RPG Maker sta girando lo script.
  46.       - Molti miglioramenti e correzioni.
  47.     ● V 1.7.1
  48.       - Bugfix
  49.       - Win.get_folderPath deprecato. Al suo posto utilizzare il nuovo metodo
  50.         Win.get_folder_path
  51.       - Miglioramenti generali nel codice
  52.     ● V 1.7.0
  53.       - Possibilità di inviare richieste POST ad un servizio Web
  54.       - Possibilità di leggere un testo copiato negli appunti
  55.       - Possibilità di ottenere la bitmap dell'immagine del giorno di Bing
  56.       - Aggiunta di correzioni e robustezza
  57.     ● V 1.6.3
  58.       - Bugfix e correzioni generali
  59.     ● V 1.6.2
  60.       - Aggiunti metodi di download asincroni anche in Game_Interpreter per
  61.         avvio download da call script
  62.     ● V 1.6.1
  63.       - Bugfix che poteva mandare in crash il gioco se non si era connessi ad
  64.         internet
  65.     ● V 1.6.0
  66.       - aggiunti metodi al kernel base64_encode e base64_decode
  67.       - bugfix
  68.     ● V 1.5.0
  69.       - Puoi ottenere la lingua del sistema con Win.language
  70.       - Aggiunta possibilità di codificare o decodificare una stringa in Base64
  71.       - Puoi aggiungere in Game.ini la versione del gioco e richiamarla in
  72.       - $game_system.game_version
  73.       - aggiunti metodi asincroni per il download nelle finestre
  74.     ● V 1.4.0
  75.       - Possibilità di ottenere risposte da un sito web tramite GET
  76.       - metodi asincroni per gestire i download (vedere la documentazione)
  77.       - funzione per generare stringhe random di lunghezza arbitraria
  78.       - funzione per codificare una stringa in ROT13
  79.       - get_folderPath per ottenere i percorsi delle cartelle del PC
  80.       - fix problemi di download su VX Ace
  81.  
  82.  ==============================================================================
  83.   ■ Compatibilità
  84.     DataManager -> alias load_normal_database, load_battle_test_database
  85.     Scene_Base  -> alias update
  86.     Window_Base -> alias update
  87.  ==============================================================================
  88.   ■ Installazione
  89.     Installare questo script sotto Materials e prima del Main. Metterlo sopra a
  90.     tutti gli altri script che fanno uso di questo modulo.
  91.  ==============================================================================
  92.   ■ Istruzioni
  93.     Usare da script o da chiama evento le seguenti chiamate: quando vedi delle
  94.     parentesi quadre [] a dei valori significa che è facoltativo.
  95.  
  96.   ▼ Valori universali di gioco
  97.     L'oggetto $game_settings è una classe universale che salva e conserva un
  98.     valore indipendentemente dal salvataggio. Può essere usato per memorizzare
  99.     impostazioni nella schermata del titolo, sbloccare gli extra o gestire gli
  100.     obiettivi, o qualsiasi cosa ti venga in mente.
  101.  
  102.     ● $game_settings[quellochevuoi] = ilvalorechevuoi
  103.       memorizza il valore che vuoi, e viene automaticamente salvato nel file
  104.       game_settings.rvdata, che si trova nella cartella del gioco. Il valore
  105.       viene salvato anche se la partita non è stata salvata.
  106.  
  107.     ● $game_settings[quellochevuoi]
  108.       restituisce il valore di quellochevuoi.
  109.  
  110.     ● Puoi impostare la versione del gioco creando un file nel progetto con il
  111.       nome "version.ini", e all'interno scriverci la versione come 1.0.2.5
  112.       Puoi richiamare la versione dal gioco da $game_system.game_version
  113.       Es. versione = $game_system.game_version
  114.       print versione.major => 1
  115.       print versione.minor => 0
  116.       print versione.build => 2
  117.       print versione.revision => 5
  118.       print versione => 1.0.2.5
  119.       print versione > "1.0.1.7" => false
  120.  
  121.   ▼ Chiamate di sistema
  122.  
  123.     ● Win.version:
  124.       restituisce un decimale con il numero di versione di Windows in uso.
  125.         5.0 -> Windows 2000
  126.         5.1 -> Windows Xp
  127.         5.2 -> Windows Xp (64 bit)
  128.         6.0 -> Windows Vista
  129.         6.1 -> Windows 7
  130.         6.2 -> Windows 8
  131.         6.3 -> Windows 8.1
  132.         10.0-> Windows 10
  133.  
  134.     ● Win.username
  135.       Restituisce una stringa con nome utente di Windows attualmente in uso
  136.  
  137.     ● Win.homepath
  138.       Restituisce il percorso utente del computer. Esempio:
  139.       C:/Users/nomeutente/                      in Windows Vista e succ.
  140.       C:/Documents and Settings/nomeutente      in Windows 2000 e Xp
  141.  
  142.     ● Win.get_folder_path([simbolo])
  143.       Restituisce il percorso di una cartella definita dal simbolo:
  144.         :docs -> cartella documenti dell'utente
  145.         :imgs -> cartella immagini dell'utente
  146.         :dskt -> destkop dell'utente
  147.         :musc -> cartella musica dell'utente
  148.         :vdeo -> cartella video dell'utente
  149.         :prog -> cartella dei programmi installati (C:\Programmi (x86))
  150.         * se non è definito un simbolo, viene preso :docs
  151.  
  152.     ● Win.shutdown[(mode)]
  153.       Spegne il computer, a seconda di mode (se si omette è 0):
  154.         0: spegnimento normale
  155.         1: riavvio
  156.         2: ibernazione
  157.  
  158.     ● Win.open(filepath)
  159.       Apre una cartella o un file sul PC. Specificare il percorso in filepath
  160.       Esempi:
  161.         Win.open(C:/Windows/system32/calc.exe) avvierà la calcolatrice
  162.         Win.open(Win.homepath+"/Desktop") aprirà la cartella del desktop
  163.  
  164.     ● Win.temp_flush(nomefile) - DEPRECATO
  165.       elimina il file dai file temporanei di internet. Utilizzarlo prima di un
  166.       download di un file che viene aggiornato molto spesso.
  167.  
  168.     ● Win.datenow[(partition)]
  169.       Restituisce la data attuale in stringa in formato "gg/mm/aaaa". Se
  170.       viene inserito partition come valore:
  171.       0: restituisce il numero del giorno in intero
  172.       1: restituisce il numero del mese attuale in intero
  173.       2: restituisce il numero dell'anno attuale in intero
  174.  
  175.     ● Win.timenow[(partition)]
  176.       Restituisce l'ora attuale in formato "hh:mm" (h 0~24)
  177.       partition: 0 -> restituisce le ore in intero
  178.       partition: 1 -> restituisce il minuto attuale 0~59
  179.       partition: 2 -> restituisce i secondi 0~59
  180.  
  181.     ● Win.locale_name
  182.       Restituisce la localizzazione corrente del sistema. Ad es.
  183.       Win.locale_name -> 'it-IT'
  184.  
  185.     ● Win.screen_resolution
  186.       restituisce un array di due interi contenenti la risoluzione in lunghezza
  187.       e altezza dello schermo (es. [1024,730]). Ricordati che non restituisce
  188.       la risoluzione completa, ma solo la parte di schermo utilizzabile (cioè
  189.       quella non nascosta dalla barra delle applicazioni)
  190.  
  191.     ● Screen.resize(lunghezza, larghezza)
  192.       ridimensiona la finestra di gioco. Ricordati che questa funzione non
  193.       aumenta la risoluzione del gioco, ma stretcha l'immagine.
  194.  
  195.   ▼ Appunti
  196.     ● Clipboard.read_text
  197.       Restituisce una stringa di testo copiato dagli appunti (ad esempio,
  198.       quando si fa copia da un testo selezionato)
  199.  
  200.   ▼ Funzioni per le stringhe
  201.  
  202.     ● String.random([n_caratteri])
  203.       Restituisce una stringa casuale di n_caratteri. Se n_caratteri non è
  204.       definito, la stringa sarà di 4.
  205.       Esempi:
  206.       print String.random     #=> ajpf
  207.       print String.random(7)  #=> opetnpg
  208.  
  209.     ● crypt_rot13
  210.       Cripta una stringa in rot13 in modo da essere illeggibile (sposta ogni
  211.       carattere di 13 posti nell'alfabeto). Richiamare il metodo alla stringa
  212.       crittografata per farla tornare normale. Esempi:
  213.       print "Casa".crypt_rot13    #=> "Pnfn"
  214.       print "Pnfn".crypt_rot13    #=> "Casa"
  215.  
  216.     ● Base64.encode(stringa) e Base64.decode(stringa)
  217.       Restituisce una stringa in Base64 per l'interscambio di dati web
  218.       Per ulteriori informazioni: http://it.wikipedia.org/wiki/Base64
  219.  
  220.     ● Integer #minutes, #hours, #days
  221.       restituiscono minuti, giorni ed ore come numero di secondi. Esempio:
  222.       5.minutes => 300 (300 secondi costituiscono 5 minuti)
  223.       10.hours => 36000
  224.       può essere comodo per calcolare il tempo di gioco da Graphics.frame_count.
  225.  
  226.   ▼ Internet e HTTP
  227.  
  228.     ● HTTP.domain
  229.       Restituisce il dominio principale del tuo gioco (configurabile in basso)
  230.       Questa opzione è molto utile quando devi trasferire il sito su un altro
  231.       dominio e non devi cambiare tutte le stringhe di gioco.
  232.  
  233.     GET, POST, PUT, DELETE
  234.     In genere questi sono i metodi HTTP che vengono utilizzati per le richieste
  235.     web (ce ne sono altri, ma per semplificare ho limitato questi 4)
  236.     GET serve per ottenere le informazioni
  237.     POST serve per inviare delle informazioni (per la modifica, ad esempio)
  238.     PUT serve per creare qualcosa di nuovo
  239.     DELETE serve per cancellare
  240.  
  241.     Questi metodi sono solo delle convenzioni, nulla ti vieta di usare GET
  242.     ovunque tu voglia (a patto di rispettare i requisiti del server che chiami)
  243.  
  244.     ● HTTP.get(url[, parametri])
  245.       Invia una richiesta GET ad un server remoto tramite url e la restituisce
  246.       in un oggetto HTTP::Response (vedi in basso)
  247.       I parametri sono opzionali e consistono in un hash di valori. Esempio:
  248.       url = HTTP.domain + 'get_status.php'
  249.       params = {user_name: 'Pippo Baudo', password: '12345'}
  250.       response = HTTP.get(url, params)
  251.  
  252.       La chiamata verrà converita in http://www.miosito.com/get_status.php?user_name=Pippo+Baudo&passord=12345
  253.       L'oggetto Response conterrà il risultato della richiesta.
  254.  
  255.     ● HTTP.post, HTTP.put, HTTP.delete
  256.       Si usano allo stesso modo della get, con la differenza che i parametri
  257.       non vengono aggiunti all'URL ma nell'header della richiesta HTTP in modo da
  258.       non avere limiti di spazio e non rendere visibili le informazioni dall'url.
  259.  
  260.     ● Come gestire le risposte
  261.       Come detto in precedenza, le chiamate HTTP restituiscono un oggetto Response.
  262.       response = response = HTTP.get(url, params)
  263.       - response.ok?: ti dice se la richiesta è andata a buon fine ed hai ottenuto
  264.         i dati della risposta (praticamente se il codice è 200)
  265.       - response.code: restituisce il codice della risposta (ad es., 200 se tutto
  266.         OK, 404 se non trovato ecc...)
  267.       - response.body: restituisce il contenuto della risposta (il messaggio)
  268.       - response.json?: ti dice se hai ricevuto un JSON come risposta
  269.       - response.description: ti stampa il codice e la sua spiegazione (es. 200 OK, 404 NOT FOUND...)
  270.  
  271.     ● HTTP.download(url[, save_path, filename, secure])
  272.       - Scarica un file in modo asincrono (cioè che il gioco non attende che si scarica)
  273.         url: url del file da scaricare
  274.       - save_path: opzionale, indica la cartella dove scaricare il file (se non metti nulla,
  275.         è la cartella root del progetto)
  276.       - filename: opzionale, il nome del file scaricato. Se non inserito, lo script proverà
  277.         a ricavarlo dall'URL.
  278.       Il download restituirà un oggetto di tipo HTTP::Request.
  279.       Questo oggetto contiene la tracciabilità del download (stato di completamento, thread,
  280.       risposta ecc...)
  281.       request = HTTP.download('http://www.miosito.com/gallery/pippo.jpg', 'Pippo.jpg')
  282.       request.terminated indica se il download è terminato (true) oppure no (false)
  283.       request.size ti dirà (in Byte) quanto pesa il download.
  284.       request.download_rate ti indicherà la percentuale di completamento (da 0.0 a 1.0)
  285.       request.abort annullerà il download
  286.       request.response restituirà la risposta.
  287.  
  288.     ● Browser.open(url)
  289.       apre il browser ad un sito scelto. Ricordati che se l'url è troppo grande,
  290.       potrebbe non avviare il sito. In questo caso ti consiglio di usare tinyurl
  291.       o goo.gl per rimpicciolire il link.
  292.  
  293.     Questi sono metodi semplificati all'interno delle Scene_MenuBase, in quanto
  294.     non dovrai occuparti di gestire il download in modo complicato.
  295.  
  296.     ● download_async(url, metodo[, cartella])
  297.       scarica dall'url. Quando il download termina, viene chiamato
  298.       il metodo definito da metodo. Se il metodo in questione accetta
  299.       un parametro, gli verrà passato l'url del file. Se ne accetta due,
  300.       gli verrà passato anche l'oggetto della risposta.
  301.       Ricordati che il riferimento al metodo viene dato con method(:nome_metodo).
  302.  
  303.     ● abort_download(nomefile)
  304.       Annulla il download di nomefile.
  305.  
  306.     ● download_status(filename)
  307.       Restituisce un numero intero da 0 a 100 rappresentante lo stato di download.
  308.  
  309.     ● download_completed?(filename)
  310.       Determina se il download del file è stato completato.
  311.  
  312.     ----------------------------------------------------------------------------
  313.     * Ottenere immagini dal web
  314.     ----------------------------------------------------------------------------
  315.       Hai presente quando, chiamando Cache.picture(nomefile) ottieni la bitmap
  316.       del file? Ecco, ora puoi fare lo stesso, ma invece di caricarla dal progetto,
  317.       la scarica direttamente da internet!
  318.  
  319.     ● Cache.web_picture(url[, nomefile])
  320.       Scarica, mette in cache e restituisce l'immagine dal web come bitmap.
  321.       Se il nomefile non è specificato, verrà assegnato automaticamente.
  322.       Le immagini vengono salvate nella cartella Graphics/Cache.
  323.       Esempio
  324.       sprite = Sprite.new
  325.       sprite.bitmap = Cache.web_picture('www.miosito.com/foto_marmotta.jpg')
  326.       Ecco fatto! Semplice, no?
  327.  
  328.       Puoi far cancellare la cache con Cache.clear_cache_folder.
  329.  
  330.     ----------------------------------------------------------------------------
  331.     * Immagine del giorno di Bing
  332.     ----------------------------------------------------------------------------
  333.       Bing propone ogni giorno una nuova foto dal mondo. Puoi ottenere quest'im-
  334.       magine dal modulo Cache:
  335.  
  336.     ● Cache.bing_daily
  337.       ti restituirà una Bitmap pronta per l'utilizzo (restituisce nil se ci sono
  338.       problemi di connessione)
  339.       La risoluzione predefinita è 640x480, ma puoi ottenerne altre impostando
  340.       la risoluzione nel secondo parametro:
  341.       Cache.bing_daily('1920x1080')
  342.       Non tutti i formati sono disponibili. Alcune delle risoluzioni sono:
  343.         QVGA (320x240, 4:3)
  344.         VGA (640x480, 4:3)
  345.         SVGA (800x600, 4:3)
  346.         XGA (1024x768, 4:3)
  347.         WXGA (1280x720 o 1280x800, 16:9)
  348.         HD768 (1366x768, 16:9)
  349.         FULLHD (1920x1080,16:9)
  350.         WUXGA (1920x1200, 16:10)
  351.       Puoi anche selezionare la risoluzione da Resolution. esempio:
  352.         Cache.bing_daily(Resolution::SVGA)
  353.         Cache.bing_daily(Resolution::WXGA)
  354.  
  355.     ● Cache.bing_daily_copyright
  356.       Puoi ottenere l'origine dell'immagine (soggetto, autore e copyright)
  357.       Attenzione: da usare dopo aver preso l'immagine!
  358. =end
  359.  
  360. #==============================================================================
  361. module H87_ModConfig
  362.   HTTPDOMAIN = 'http://miosito.com/' #dominio principale
  363.   SETTINGNAME = 'game_settings.rvdata2' #file impostazioni universali
  364.   VERSIONFILE = 'version.ini' #file versione di gioco
  365.   PROCESSNAME = 'RGSS Player' #nome del processo
  366.   RMUSERAGENT = 'RMVXA' #nome user agent per richieste POST
  367. end
  368.  
  369. $imported = {} if $imported == nil
  370. $imported['H87_UniversalModule'] = 1.8
  371.  
  372. #==============================================================================
  373. # ** Win
  374. #------------------------------------------------------------------------------
  375. #  Questo modulo gestisce le chiamate di sistema e recupera informazioni sul
  376. #  computer
  377. #==============================================================================
  378. module Win
  379.   # HOW TO HANDLE WINDOWS DATA TYPES:
  380.   # https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types
  381.   # | Type Name        | Data Type                      | pack-unpack character |
  382.   # | BOOL             | 32-bit signed integer (0/1)    | l                     |
  383.   # | BOOLEAN          | same as BYTE                   | C
  384.   # | BYTE             | 8-bit unsigned char            | C                     |
  385.   # | SHORT            | 16-bit integer                 | s                     |
  386.   # | LONG             | 32-bit signed integer          | l                     |
  387.   # | WORD             | 16-bit unsigned integer        | S                     |
  388.   # | DWORD            | 32-bit unsigned integer        | L                     |
  389.   # | UINT             | 32-bit unsigned integer        | L                     |
  390.   # | WPARAM/UINT_PTR  | 32/64-bit unsigned int         | I_                    |
  391.   # | LPARAM/LONG_PTR  | 32/64-bit signed Long          | l_                    |
  392.   # | LPTSTR           | null-terminated string pointer | A*                    |
  393.   # * note: Game.exe is 32-bit program, WPARAM and LPARAM are always 32-bit.
  394.  
  395.  
  396.   # Win32APIs
  397.   # noinspection RubyConstantNamingConvention
  398.   GetUserName = Win32API.new('advapi32', 'GetUserName', 'PP', 'I')
  399.   # noinspection RubyConstantNamingConvention
  400.   GetEnvironmentVariable = Win32API.new('kernel32', 'GetEnvironmentVariable', 'PPL', 'L')
  401.   # noinspection RubyConstantNamingConvention
  402.   SHGetFolderPath = Win32API.new('shell32', 'SHGetFolderPath', 'LLLLP', 'L')
  403.   # noinspection RubyConstantNamingConvention
  404.   GetSystemMetrics = Win32API.new('user32', 'GetSystemMetrics', 'I', 'I')
  405.   # noinspection RubyConstantNamingConvention
  406.   GetVersionEx = Win32API.new('kernel32', 'GetVersionEx', 'P', 'I')
  407.   # noinspection RubyConstantNamingConvention - deprecato
  408.   GetUserDefaultLCID = Win32API.new('kernel32', 'GetUserDefaultLCID', [], 'I')
  409.   # https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getsystemdefaultlocalename
  410.   GetSystemDefaultLocaleName = Win32API.new('kernel32', 'GetSystemDefaultLocaleName', 'PI', 'I')
  411.   # noinspection RubyConstantNamingConvention
  412.   GetWindowRect = Win32API.new('user32', 'GetWindowRect', 'PP', 'I')
  413.   # https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror
  414.   GetLastError = Win32API.new('kernel32', 'GetLastError', '', 'I')
  415.  
  416.   # useful error codes
  417.   ERROR_SUCCESS = 0
  418.   ERROR_INVALID_FUNCTION = 1
  419.   ERROR_FILE_NOT_FOUND = 2
  420.   ERROR_PATH_NOT_FOUND = 3
  421.   ERROR_TOO_MANY_OPEN_FILES = 4
  422.   ERROR_ACCESS_DENIED = 5
  423.   ERROR_INVALID_HANDLE = 6
  424.   ERROR_NOT_ENOUGH_MEMORY = 8
  425.   ERROR_OUTOFMEMORY = 14
  426.  
  427.   # max length of filename
  428.   MAX_PATH = 255
  429.  
  430.   # Constants
  431.   SM_CYFULLSCREEN = 17 # The height of the client area for a full-screen window
  432.   #                      on the primary display monitor, in pixels
  433.   SM_CXFULLSCREEN = 16 # The width of the client area for a full-screenwindow
  434.   #                      on the primary display monitor, in pixels
  435.   SM_CXHTHUMB = 10 # The width of the thumb box in a horizontal scroll bar
  436.   SM_CYCAPTION = 4 # The height of a caption area, in pixels.
  437.   SM_CXFIXEDFRAME = 7 # The thickness of the frame around the perimeter of a
  438.   #                      window that has a caption but is not sizable
  439.   SM_CYFIXEDFRAME = 8 # The width of the vertical border the perimeter of a
  440.   #                      window that has a caption but is not sizable
  441.   SM_CXSCREEN = 0 # The width of the screen of the primary display monitor
  442.  
  443.   # Default locale name length
  444.   LOCALE_NAME_MAX_LENGTH = 85
  445.  
  446.   # Restituisce il nome utente di Windows
  447.   # @return [String]
  448.   def self.username
  449.     name = ' ' * 128
  450.     size = '128'
  451.     GetUserName.call(name, size)
  452.     username = name.unpack('A*')
  453.     return username[0]
  454.   end
  455.  
  456.   # Restituisce la cartella utente di Windows
  457.   # @return [String]
  458.   def self.homepath
  459.     username = ' ' * 256 #userprofile
  460.     GetEnvironmentVariable.call('userprofile', username, 256)
  461.     username.unpack('A*')[0].gsub('\\', '/')
  462.   end
  463.  
  464.   # Restituisce il percorso di una cartella del computer
  465.   # @param [Symbol] symbol
  466.   # @return [String]
  467.   def self.get_folder_path(symbol = :docs)
  468.     case symbol
  469.     when :user
  470.       index = 40
  471.     when :docs, :documents
  472.       index = 5
  473.     when :imgs, :images, :pictures
  474.       index = 39
  475.     when :musc, :music
  476.       index = 13
  477.     when :vdeo, :video
  478.       index = 14
  479.     when :strp, :start_menu
  480.       index = 2
  481.     when :prog, :program_files
  482.       index = 38
  483.     when :appd, :app_data
  484.       index = 28
  485.     when :desktop
  486.       index = 0
  487.     when :favs, :favorites
  488.       index = 6
  489.     when :roaming
  490.       index = 26
  491.     else
  492.       index = 0
  493.     end
  494.     path = "\0" * 128
  495.     SHGetFolderPath.call(0, index, 0, 2, path)
  496.     path.unpack('A*')[0].gsub('\\', '/')
  497.   end
  498.  
  499.   # Returns the Vista+ saved games folder
  500.   # @return [String]
  501.   def self.saved_games_folder
  502.     get_folder_path(:user) + '/Saved Games'
  503.   end
  504.  
  505.   # Deprecated, left for compatibility
  506.   # @param [Symbol] symbol
  507.   # @return [String]
  508.   # @deprecated
  509.   def self.getFolderPath(symbol = :docs)
  510.     get_folder_path(symbol)
  511.   end
  512.  
  513.   # Restituisce la larghezza della cornice della finestra
  514.   # @return [String]
  515.   def self.window_frame_width
  516.     GetSystemMetrics.call(SM_CXFIXEDFRAME)
  517.   end
  518.  
  519.   # Restituisce l'altezza della barra del titolo
  520.   # @return [String]
  521.   def self.window_title_height
  522.     GetSystemMetrics.call(SM_CYCAPTION)
  523.   end
  524.  
  525.   # Elimina il file temporaneo per aggiornarlo prima di un download.
  526.   #   inserire il nome del file.
  527.   # @param [String] filename
  528.   # @deprecated non viene più utilizzato
  529.   def self.temp_flush(filename)
  530.     if version < 6
  531.       path = homepath + "/Impostazioni locali/Temporary Internet Files"
  532.       unless File.directory?(path)
  533.         path = homepath + "/Local Settings/Temporary Internet Files"
  534.         return unless File.directory?(path)
  535.       end
  536.       #noinspection Rails3Deprecated
  537.       fetch_folder_for_delete(path, filename)
  538.     else
  539.       path = homepath + '/AppData/Local/Microsoft/Windows/Temporary Internet Files/Content.IE5'
  540.       unless File.directory?(path)
  541.         path = homepath + '/AppData/Local/Microsoft/Windows/INetCache/IE'
  542.       end
  543.       return unless File.directory?(path)
  544.       Dir.foreach(path) { |x| #per ogni file nel percorso
  545.       next if x == "." or x == '..' #passa al prossimo se è ind.
  546.       if File.directory?(path + "/" + x) #se il file è una cartella
  547.         folder = path + "/" + x #entra nella cartella
  548.         #noinspection Rails3Deprecated
  549.         fetch_folder_for_delete(folder, filename)
  550.       end
  551.       }
  552.     end
  553.   end
  554.  
  555.   # Cerca nella cartella il file da cancellare
  556.   #   path: directory
  557.   #   nomefile: file da cancellare
  558.   # @deprecated
  559.   def self.fetch_folder_for_delete(path, nomefile)
  560.     Dir.foreach(path) { |y| #per ogni file nella cartella
  561.     next if File.directory?(path + '/' + y) #passa al prossimo se è una c.
  562.                             #noinspection Rails3Deprecated
  563.     if no_ext(nomefile) == y[0..no_ext(nomefile).size - 1] #se l'inizio del nome corrisp.
  564.       begin
  565.         File.delete(path + '/' + y) #eliminalo
  566.       rescue
  567.         next
  568.       end
  569.     end
  570.     }
  571.   end
  572.  
  573.   # Restituisce la versione di Windows in uso
  574.   # @return [String]
  575.   def self.version
  576.     s = [20 + 128, 0, 0, 0, 0, ''].pack('LLLLLa128')
  577.     GetVersionEx.call(s)
  578.     a = s.unpack('LLLLLa128')
  579.     indice = a[1].to_f
  580.     dec = a[2].to_f / 10
  581.     return indice + dec
  582.   end
  583.  
  584.   # Restituisce il nome del file senza estensione.
  585.   # @return [String]
  586.   # @deprecated
  587.   def self.no_ext(nomefile)
  588.     nome = nomefile.split(".")
  589.     return nome[0..nome.size - 2]
  590.   end
  591.  
  592.   # Returns a rect containing the screen
  593.   # @return [Rect]
  594.   def self.screen
  595.     width = GetSystemMetrics.call(SM_CXFULLSCREEN)
  596.     height = GetSystemMetrics.call(SM_CYFULLSCREEN)
  597.     Rect.new(0, 0, width, height)
  598.   end
  599.  
  600.   # Restituisce un array di larghezza e altezza della parte utilizzabile dello
  601.   #   schermo: non conta lo spazio della barra delle applicazioni.
  602.   # @deprecated use Win::screen instead
  603.   def self.screen_resolution
  604.     x = GetSystemMetrics.call(SM_CXFULLSCREEN)
  605.     y = GetSystemMetrics.call(SM_CYFULLSCREEN)
  606.     return [x, y]
  607.   end
  608.  
  609.   # returns the system locale name (ex. it-IT, en-US, ...)
  610.   # @return [String]
  611.   def self.locale_name
  612.     buff = " " * LOCALE_NAME_MAX_LENGTH
  613.     GetSystemDefaultLocaleName.call(buff, LOCALE_NAME_MAX_LENGTH)
  614.     buff.unpack('A' * LOCALE_NAME_MAX_LENGTH).delete_if { |x| x == "" } * ''
  615.   end
  616.  
  617.   # Restituisce un intero come codice della lingua del sistema
  618.   # @deprecated use locale_name
  619.   def self.language
  620.     GetUserDefaultLCID.call
  621.   end
  622.  
  623.   # Restituisce la data attuale
  624.   def self.datenow(partition = -1)
  625.     date = Time.now
  626.     case partition
  627.     when -1
  628.       return sprintf('%d/%d/%d', date.day, date.month, date.year)
  629.     when 0
  630.       return date.day
  631.     when 1
  632.       return date.month
  633.     when 2
  634.       return date.year
  635.     else
  636.       return -1
  637.     end
  638.   end
  639.  
  640.   # Restituisce l'ora attuale
  641.   def self.timenow(partition = -1)
  642.     date = Time.now
  643.     case partition
  644.     when -1
  645.       return sprintf('%d:%d', date.hour, date.min)
  646.     when 0
  647.       return date.hour
  648.     when 1
  649.       return date.min
  650.     when 2
  651.       return date.sec
  652.     else
  653.       return -1
  654.     end
  655.   end
  656.  
  657.   # arresta il computer in modalità diverse.
  658.   def self.shutdown(mode = 0)
  659.     string = 'system '
  660.     case mode
  661.     when 0
  662.       string += '-s'
  663.     when 1
  664.       string += '-r'
  665.     when 2
  666.       string += '-h'
  667.     else
  668.       return -1
  669.     end
  670.     system(string)
  671.   end
  672.  
  673.   # this method should be used within Win32 API functions that need HWND
  674.   # parameters
  675.   # @return [Integer]
  676.   def self.current_window
  677.     Screen::FindWindowEx.call(0, 0, H87_ModConfig::PROCESSNAME, nil)
  678.   end
  679.  
  680.   # gets the system window rect.
  681.   # @return [Rect]
  682.   def self.get_window_rect
  683.     w_rect = [0, 0, 0, 0].pack('l_l_l_l_')
  684.     this_window = current_window
  685.     GetWindowRect.call(this_window, w_rect)
  686.     rect = w_rect.unpack('l_l_l_l_')
  687.     Rect.new(rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1])
  688.   end
  689. end #win
  690.  
  691. #==============================================================================
  692. # ** Clipboard
  693. #------------------------------------------------------------------------------
  694. #  This module handles the Windows clibpoard.
  695. #==============================================================================
  696. # noinspection ALL
  697. module Clipboard
  698.   # Clipboard types
  699.   CF_TEXT = 1 #plain text
  700.   CF_BITMAP = 2 #bitmap
  701.   CF_METAFILEPICT = 3 #metafile
  702.   CF_SYLK = 4 #symbolic link
  703.   CF_DIF = 5 #data interchange format
  704.   CF_TIFF = 6 #tiff text format
  705.   CF_OEMTEXT = 7 #OEM text format. Not sure it's useful
  706.   CF_DIB = 8 #Device Independent Bitmap Format
  707.  
  708.   # Windows APIs
  709.   OpenClipboard = Win32API.new('user32', 'OpenClipboard', 'L', 'I')
  710.   GetClipboardData = Win32API.new('user32', 'GetClipboardData', 'I', 'I')
  711.   SetClipboardData = Win32API.new('user32', 'SetClipboardData', 'IP', 'p')
  712.   CloseClipboard = Win32API.new('user32', 'CloseClipboard', 'V', 'I')
  713.   GlobalLock = Win32API.new('kernel32', 'GlobalLock', 'L', 'L')
  714.   GlobalUnlock = Win32API.new('kernel32', 'GlobalUnlock', 'L', '')
  715.   GlobalSize = Win32API.new('kernel32', 'GlobalSize', 'L', 'L')
  716.   MemCpy = Win32API.new('ntdll', 'memcpy', 'PPL', 'L')
  717.   IsClipboardFormatAvailable = Win32API.new('user32', 'IsClipboardFormatAvailable', 'I', 'I')
  718.   # Returns a copied text from Windows clipboard. Can raise an error.
  719.   # @return [String]
  720.   # @raise [ClipboardDataAccessException]
  721.   def self.read_text
  722.     return '' unless open
  723.     begin
  724.       if format_avaiable?(CF_TEXT)
  725.         handle = get_clipboard_data(CF_TEXT)
  726.         buff_size = data_size(handle)
  727.         buffer = ' ' * (buff_size - 1)
  728.         copy_memory(buffer, handle, buff_size)
  729.         data = buffer.gsub('\0', '')
  730.       else
  731.         puts 'No text avaiable in clipboard'
  732.         data = ''
  733.       end
  734.     rescue
  735.       Logger.warning 'Read clipboard error!'
  736.       data = ''
  737.     ensure
  738.       CloseClipboard.call
  739.     end
  740.     data
  741.   end
  742.  
  743.   # Returns a copied text from Windows clipboard without exceptions.
  744.   # @return [String]
  745.   def self.read_text_safe
  746.     read_text rescue ''
  747.   end
  748.  
  749.   # Opens the clipboard
  750.   # @return [Integer]
  751.   def self.open
  752.     OpenClipboard.call(0)
  753.   end
  754.  
  755.   # Closes the clipboard
  756.   def self.close
  757.     CloseClipboard.call
  758.   end
  759.  
  760.   # @param [Integer] format
  761.   # @return [Integer]
  762.   def self.format_avaiable?(type)
  763.     IsClipboardFormatAvailable.call(type)
  764.   end
  765.  
  766.   # @param [Object] handle
  767.   # @return [Integer]
  768.   def self.data_size(handle)
  769.     GlobalSize.call(handle)
  770.   end
  771.  
  772.   # @param [Integer] type
  773.   # @return [Object]
  774.   def self.get_clipboard_data(type)
  775.     GetClipboardData.call(type)
  776.   end
  777.  
  778.   # @param [String] data
  779.   # @param [Object] handle
  780.   # @param [Integer] size
  781.   # @return [String]
  782.   def self.copy_memory(data, handle, size)
  783.     MemCpy.call(data, handle, size)
  784.   end
  785. end #clipboard
  786.  
  787. #==============================================================================
  788. # ** Screen
  789. #------------------------------------------------------------------------------
  790. #  Questo modulo gestisce il ridimensionamento della finestra di gioco
  791. #==============================================================================
  792. module Screen
  793.   MoveWindow = Win32API.new("user32", "MoveWindow", 'LIIIIL', 'L')
  794.   FindWindowEx = Win32API.new("user32", "FindWindowEx", 'LLPP', 'I')
  795.  
  796.   # ridimensiona la finestra e la centra
  797.   # @param[Integer] width nuova larghezza
  798.   # @param[Integer] height nuova altezza
  799.   def self.resize(width, height)
  800.     this_window = FindWindowEx.call(0, 0, H87_ModConfig::PROCESSNAME, nil)
  801.     res_x = Win.screen_resolution[0] #risoluzione x
  802.     res_y = Win.screen_resolution[1] #risoluzione y
  803.     width += Win.window_frame_width * 2
  804.     height += Win.window_frame_width * 2 + Win.window_title_height
  805.     new_x = [(res_x - width) / 2, 0].max #ottiene la nuova coordinata, ma non
  806.     new_y = [(res_y - height) / 2, 0].max #fa passare oltre il bordo
  807.     MoveWindow.call(this_window, new_x, new_y, width, height, 1)
  808.   end
  809. end #screen
  810.  
  811. #==============================================================================
  812. # ** HTTP
  813. #------------------------------------------------------------------------------
  814. #  Questo modulo permette di interfacciarsi ad internet e gestire i download.
  815. #  Ringraziamenti: Berka (il codice è ispirato al suo)
  816. #==============================================================================
  817. module HTTP
  818.   # Connection types
  819.   INTERNET_OPEN_TYPE_PRECONFIG = 0
  820.   INTERNET_OPEN_TYPE_DIRECT = 1
  821.   INTERNET_OPEN_TYPE_PROXY = 3
  822.  
  823.  
  824.   # Internet service types
  825.   INTERNET_SERVICE_URL = 0
  826.   INTERNET_SERVICE_FTP = 1
  827.   INTERNET_SERVICE_GOPHER = 2
  828.   INTERNET_SERVICE_HTTP = 3
  829.  
  830.   # Internet ports
  831.   INTERNET_INVALID_PORT_NUMBER = 0
  832.   INTERNET_DEFAULT_FTP_PORT = 21
  833.   INTERNET_DEFAULT_GOPHER_PORT = 70
  834.   INTERNET_DEFAULT_HTTP_PORT = 80
  835.   INTERNET_DEFAULT_HTTPS_PORT = 443
  836.   INTERNET_DEFAULT_SOCKS_PORT = 1080
  837.  
  838.   # Internet flags
  839.  
  840.   # Makes only asynchronous requests on handles descended from the
  841.   # handle returned from this function
  842.   INTERNET_FLAG_ASYNC = 0
  843.  
  844.   # Forces a download of the requested file, object, or directory listing
  845.   # from the origin server, not from the cache. The FtpFindFirstFile,
  846.   # FtpGetFile, FtpOpenFile, FtpPutFile, HttpOpenRequest, and InternetOpenUrl
  847.   # functions use this flag.
  848.   INTERNET_FLAG_RELOAD = 0x80000000
  849.   INTERNET_FLAG_NO_CACHE_WRITE = 0x04000000
  850.  
  851.   # Returns the data as a WIN32_FIND_DATA structure when retrieving
  852.   # FTP directory information. If this flag is not specified or if the call is made
  853.   # through a CERN proxy, InternetOpenUrl returns the HTML version of the directory.
  854.   # Only the InternetOpenUrl function uses this flag.
  855.   INTERNET_FLAG_RAW_DATA = 1073741824
  856.  
  857.   # Uses secure transaction semantics.
  858.   # This translates to using Secure Sockets Layer/Private Communications Technology
  859.   # (SSL/PCT) and is only meaningful in HTTP requests.
  860.   # This flag is used by HttpOpenRequest and InternetOpenUrl, but this is redundant
  861.   # if https:// appears in the URL.The InternetConnect function uses this flag for
  862.   # HTTP connections; all the request handles created under this connection will
  863.   # inherit this flag.
  864.   INTERNET_FLAG_SECURE = 0x00800000
  865.  
  866.   # Transfers file as ASCII (FTP only).
  867.   # This flag can be used by FtpOpenFile, FtpGetFile, and FtpPutFile.
  868.   INTERNET_FLAG_TRANSFER_ASCII = 0x00000001
  869.  
  870.   # Transfers file as binary (FTP only).
  871.   # This flag can be used by FtpOpenFile, FtpGetFile, and FtpPutFile.
  872.   INTERNET_FLAG_TRANSFER_BINARY = 0x00000002
  873.  
  874.   # Indicates that no callbacks should be made for that API.
  875.   # This is used for the dxContext parameter of the functions that allow asynchronous operations.
  876.   INTERNET_NO_CALLBACK = 0x00000000
  877.  
  878.   # Attempts to use an existing InternetConnect object if one exists with the same attributes
  879.   # required to make the request. This is useful only with FTP operations, since FTP is the
  880.   # only protocol that typically performs multiple operations during the same session. WinINet
  881.   # caches a single connection handle for each HINTERNET handle generated by InternetOpen.
  882.   # The InternetOpenUrl and InternetConnect functions use this flag for Http and Ftp connections.
  883.   INTERNET_FLAG_EXISTING_CONNECT = 0x20000000
  884.  
  885.   # Does not add the returned entity to the cache.
  886.   # This is identical to the preferred value, INTERNET_FLAG_NO_CACHE_WRITE.
  887.   INTERNET_FLAG_DONT_CACHE = 0x04000000
  888.  
  889.   # Indicates that this is a Forms submission.
  890.   INTERNET_FLAG_FORMS_SUBMIT = 0x00000040
  891.  
  892.   # Does not make network requests. All entities are returned from the cache.
  893.   # If the requested item is not in the cache, a suitable error, such as
  894.   # ERROR_FILE_NOT_FOUND, is returned. Only the InternetOpen function uses this flag.
  895.   INTERNET_FLAG_FROM_CACHE = 0x01000000
  896.  
  897.   # Disables detection of this special type of redirect. When this flag is used,
  898.   # WinINet transparently allows redirects from HTTPS to HTTP URLs.
  899.   # This flag can be used by HttpOpenRequest and InternetOpenUrl (for HTTP requests).
  900.   INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP = 0x00008000
  901.  
  902.   # Disables detection of this special type of redirect. When this flag is used,
  903.   # WinINet transparently allow redirects from HTTP to HTTPS URLs.
  904.   # This flag can be used by HttpOpenRequest and InternetOpenUrl (for HTTP requests).
  905.   INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS = 0x00004000
  906.  
  907.   # Uses keep-alive semantics, if available, for the connection.
  908.   # This flag is used by HttpOpenRequest and InternetOpenUrl (for HTTP requests).
  909.   # This flag is required for Microsoft Network (MSN), NTLM, and other types of
  910.   # authentication.
  911.   INTERNET_FLAG_KEEP_CONNECTION = 0x00400000
  912.  
  913.   # QUERY INFO FLAGS
  914.  
  915.   # Retrieves the acceptable media types for the response.
  916.   HTTP_QUERY_ACCEPT = 24
  917.  
  918.   # Retrieves the acceptable character sets for the response.
  919.   HTTP_QUERY_ACCEPT_CHARSET = 25
  920.  
  921.   # Retrieves the acceptable content-coding values for the response.
  922.   HTTP_QUERY_ACCEPT_ENCODING = 26
  923.  
  924.   # Retrieves the cache control directives.
  925.   HTTP_QUERY_CACHE_CONTROL = 49
  926.  
  927.   # Retrieves the size of the resource, in bytes.
  928.   HTTP_QUERY_CONTENT_LENGTH = 5
  929.  
  930.   # Retrieves an MD5 digest of the entity-body for the purpose of providing
  931.   # an end-to-end message integrity check (MIC) for the entity-body.
  932.   # For more information, see RFC1864, The Content-MD5 Header Field,
  933.   # at https://ftp.isi.edu/in-notes/rfc1864.txt.
  934.   HTTP_QUERY_CONTENT_MD5 = 52
  935.  
  936.   # Receives the content type of the resource (such as text/html).
  937.   HTTP_QUERY_CONTENT_TYPE = 1
  938.  
  939.   # Retrieves any cookies associated with the request.
  940.   HTTP_QUERY_COOKIE = 44
  941.  
  942.   # Receives the status code returned by the server.
  943.   # For more information and a list of possible values, see HTTP Status Codes.
  944.   HTTP_QUERY_STATUS_CODE = 19
  945.  
  946.  
  947.   # HTTP Status Codes
  948.  
  949.   # The request can be continued.
  950.   HTTP_STATUS_CONTINUE = 100
  951.  
  952.   # The request completed successfully.
  953.   HTTP_STATUS_OK = 200
  954.  
  955.   # The request has been fulfilled and resulted in the creation of a new resource.
  956.   HTTP_STATUS_CREATED = 201
  957.  
  958.   # The request has been accepted for processing,
  959.   # but the processing has not been completed
  960.   HTTP_STATUS_ACCEPTED = 202
  961.  
  962.   # The requested resource has been assigned to a new permanent URI
  963.   # (Uniform Resource Identifier), and any future references to this resource
  964.   # should be done using one of the returned URIs.
  965.   HTTP_STATUS_MOVED = 301
  966.  
  967.   # The requested resource resides temporarily under a different URI
  968.   # (Uniform Resource Identifier).
  969.   HTTP_STATUS_REDIRECT = 302
  970.  
  971.   # The request could not be processed by the server due to invalid syntax.
  972.   HTTP_STATUS_BAD_REQUEST = 400
  973.  
  974.   # The requested resource requires user authentication.
  975.   HTTP_STATUS_DENIED = 401
  976.  
  977.   # The server understood the request, but is refusing to fulfill it.
  978.   HTTP_STATUS_FORBIDDEN = 403
  979.  
  980.   # The server has not found anything matching the requested
  981.   # URI (Uniform Resource Identifier).
  982.   HTTP_STATUS_NOT_FOUND = 404
  983.  
  984.   # The HTTP verb used is not allowed.
  985.   HTTP_STATUS_BAD_METHOD = 405
  986.  
  987.   # The server timed out waiting for the request.
  988.   HTTP_STATUS_REQUEST_TIMEOUT = 408
  989.  
  990.   # The server encountered an unexpected condition that prevented it from fulfilling the request.
  991.   HTTP_STATUS_SERVER_ERROR = 500
  992.  
  993.   # The server does not support the functionality required to fulfill the request.
  994.   HTTP_STATUS_NOT_SUPPORTED = 501
  995.  
  996.   # The server, while acting as a gateway or proxy, received an invalid response
  997.   # from the upstream server it accessed in attempting to fulfill the request.
  998.   HTTP_STATUS_BAD_GATEWAY = 502
  999.  
  1000.   # The service is temporarily overloaded.
  1001.   HTTP_STATUS_SERVICE_UNAVAIL = 503
  1002.  
  1003.   RESPONSE_CODE_DESCRIPTIONS = {
  1004.       0 => 'HOST UNREACHABLE',
  1005.       HTTP_STATUS_OK => 'OK',
  1006.       HTTP_STATUS_BAD_REQUEST => 'BAD REQUEST',
  1007.       HTTP_STATUS_BAD_GATEWAY => 'BAD GATEWAY',
  1008.       HTTP_STATUS_MOVED => 'MOVED',
  1009.       HTTP_STATUS_REDIRECT => 'REDIRECTED',
  1010.       HTTP_STATUS_FORBIDDEN => 'FORBIDDEN',
  1011.       HTTP_STATUS_BAD_METHOD => 'BAD METHOD',
  1012.       HTTP_STATUS_NOT_FOUND => 'NOT FOUND',
  1013.       HTTP_STATUS_SERVER_ERROR => 'INTERNAL SERVER ERROR',
  1014.       HTTP_STATUS_SERVICE_UNAVAIL => 'SERVICE UNAVAILABLE',
  1015.       HTTP_STATUS_REQUEST_TIMEOUT => 'REQUEST TIMEOUT',
  1016.       HTTP_STATUS_BAD_GATEWAY => 'BAD GATEWAY'
  1017.   }
  1018.  
  1019.  
  1020.   #API Calls
  1021.   #SetPrClass = Win32API.new('kernel32','SetPriorityClass','pi','i').call(-1,128)
  1022.   InternetOpenA = Win32API.new("wininet", 'InternetOpenA', 'plppl', 'l').call(
  1023.       H87_ModConfig::RMUSERAGENT, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, INTERNET_FLAG_ASYNC)
  1024.   InternetConnectA = Win32API.new("wininet", 'InternetConnectA', 'lplpplll', 'l')
  1025.   InternetOpenUrl = Win32API.new("wininet", 'InternetOpenUrl', 'lppllp', 'l')
  1026.   InternetReadFile = Win32API.new("wininet", 'InternetReadFile', 'lpip', 'l')
  1027.   InternetCloseHandle = Win32API.new('wininet', 'InternetCloseHandle', 'l', 'l')
  1028.   HttpQueryInfo = Win32API.new('wininet', 'HttpQueryInfo', 'LLPPP', 'I')
  1029.   HttpOpenRequest = Win32API.new('wininet', 'HttpOpenRequestA', 'pppppplp', 'l')
  1030.   HttpSendRequest = Win32API.new('wininet', 'HttpSendRequestA', 'PPLPL', 'L')
  1031.  
  1032.   # launches an HTTP GET request
  1033.   # @param [String] url
  1034.   # @param [Hash] params
  1035.   # @return [Response]
  1036.   def self.get(url, params = {}, secure = false)
  1037.     url += '?' + prepare_request(params) if params.size > 0
  1038.     send_request Request.new(url), :get, {}, secure
  1039.   end
  1040.  
  1041.   # launches an HTTP POST request
  1042.   # @param [String] url
  1043.   # @param [Hash] params
  1044.   # @return [Response]
  1045.   def self.post(url, params, secure = false)
  1046.     send_request Request.new(url), :post, params, secure
  1047.   end
  1048.  
  1049.   # launches an HTTP PUT request
  1050.   # @param [String] url
  1051.   # @param [Hash] params
  1052.   # @return [Response]
  1053.   def self.put(url, params, secure = false)
  1054.     send_request Request.new(url), :put, params, secure
  1055.   end
  1056.  
  1057.   # launch an HTTP DELETE request
  1058.   # @param [String] url
  1059.   # @param [Hash] params
  1060.   # @return [Response]
  1061.   def self.delete(url, params, secure = false)
  1062.     send_request Request.new(url), :delete, params, secure
  1063.   end
  1064.  
  1065.   # saves a file async and returns the data request.
  1066.   # Use
  1067.   # @return [HTTP::Request]
  1068.   # @param [String] url
  1069.   # @param [String] save_path
  1070.   # @param [String] filename
  1071.   def self.download(url, save_path = './', filename = nil, secure = false)
  1072.     request = Request.new(url, filename)
  1073.     filename = url_info(url)[:filename] if filename.nil?
  1074.     request.uri = url
  1075.     request.thread = Thread.start(request, save_path, filename, secure) do |request, save_path, filename, secure|
  1076.       begin
  1077.         send_request(request, :get, {}, secure)
  1078.         if request.response.ok?
  1079.           save_file(save_path, filename, request.response.body)
  1080.           request.terminated = true
  1081.         end
  1082.       rescue
  1083.         Logger.error($!)
  1084.         request.terminated = true
  1085.       end
  1086.     end
  1087.     request
  1088.   end
  1089.  
  1090.  
  1091.   # @return [HTTP::Request]
  1092.   # @param [String] url
  1093.   # @param [Boolean] secure
  1094.   def self.read_async(url, secure = false)
  1095.     request = Request.new(url)
  1096.     request.thread = Thread.start(request, secure) do |request, secure|
  1097.       begin
  1098.         send_request(request, :get, {}, secure)
  1099.       rescue => error
  1100.         Logger.error(error.class, error.message)
  1101.       ensure
  1102.         request.terminated = true
  1103.       end
  1104.     end
  1105.     request
  1106.   end
  1107.  
  1108.   # launches a request with more options
  1109.   # @param [HTTP::Request] request
  1110.   # @param [Symbol, String] method
  1111.   # @param [Hash] params
  1112.   # @param [Array<Integer>] flags
  1113.   # @return [Response]
  1114.   def self.send_request(request, method = :get, params = {}, force_https = false, flags = [INTERNET_FLAG_RELOAD])
  1115.     url = request.uri
  1116.     Logger.info sprintf('%s -> %s', method.to_s.upcase, url)
  1117.     force_https = true if url =~ /^https:\/\//
  1118.     info = url_info(url)
  1119.     server = info[:server]
  1120.     root = info[:root]
  1121.     accept = '*/*'
  1122.     headers = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'
  1123.     port = force_https ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT
  1124.     service = INTERNET_SERVICE_HTTP
  1125.     request_params = prepare_request(params)
  1126.     flags.push(INTERNET_FLAG_SECURE) if force_https
  1127.     opts = flags.uniq.inject(0) { |o, flag| o | flag }
  1128.     response = Response.new
  1129.     request.response = response
  1130.  
  1131.     session = InternetConnectA.call(InternetOpenA, server, port, nil, nil, service, 0, 1)
  1132.  
  1133.     if session.nil?
  1134.       response.code = Win::GetLastError.call
  1135.       response.body = "Error while connecting to the server (code: #{response.code})"
  1136.       Logger.info response.description
  1137.       return response
  1138.     end
  1139.  
  1140.     h_file = HttpOpenRequest.call(session, method.to_s.upcase, root, nil, nil, accept, opts, 0)
  1141.  
  1142.     if HttpSendRequest.call(h_file, headers, headers.size, request_params, request_params.size)
  1143.       response.code = status_code h_file
  1144.       response.size = content_size h_file
  1145.       internet_read_file h_file, response.body
  1146.     else
  1147.       response.code = Win::GetLastError.call
  1148.       response.body = "Error while sending request (code: #{response.code})."
  1149.     end
  1150.     InternetCloseHandle.call(h_file)
  1151.     Logger.info response.description
  1152.     response
  1153.   end
  1154.  
  1155.   # reads a resource from the web using HTTP protocol
  1156.   # @return [HTTP::Response]
  1157.   # @param [HTTP::Request] ref
  1158.   # @param [String] url
  1159.   # @param [Array<Integer>] flags
  1160.   def self.open_resource(ref, url, flags = [], force_https = false)
  1161.     force_https = true if url =~ /^https:\/\//
  1162.     info = url_info(url)
  1163.     server = info[:server]
  1164.     headers = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'
  1165.     url += '?' + prepare_request(params)
  1166.     port = force_https ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT
  1167.     service = INTERNET_SERVICE_HTTP
  1168.     flags.push(INTERNET_FLAG_SECURE) if force_https
  1169.     opts = flags.uniq.inject(0) { |o, flag| o | flag }
  1170.     response = ref.response
  1171.  
  1172.     connection = InternetConnectA.call(InternetOpenA, server, port, '', '', service,
  1173.                                        INTERNET_FLAG_TRANSFER_ASCII, 0)
  1174.  
  1175.     if connection.nil?
  1176.       Logger.error 'Error while connecting to the server.'
  1177.       raise InternetConnectionException.new 'Error while connecting to the server.'
  1178.     end
  1179.  
  1180.     file = InternetOpenUrl.call(InternetOpenA, url, headers, headers.size, opts, nil)
  1181.     response.code = status_code file
  1182.     response.size = content_size file
  1183.     response.body = internet_read_file file, ref
  1184.     InternetCloseHandle.call(file)
  1185.     response
  1186.   end
  1187.  
  1188.   # Sends a post-type request.
  1189.   # @param [String] url
  1190.   # @param [Hash] params
  1191.   # @param [Integer] method
  1192.   # @return [String]
  1193.   # @deprecated use HTTP::post instead
  1194.   def self.send_post_request(url, params = {}, force_https = false)
  1195.     post(url, params, force_https).body
  1196.   end
  1197.  
  1198.   # Gets the url info
  1199.   # @param [String] uri
  1200.   # @return [Hash]
  1201.   def self.url_info(uri)
  1202.     address = uri.gsub(/^http[s]?:\/\//i, '').split('/')
  1203.     {
  1204.         :server => address[0],
  1205.         :root => address.size > 1 ? address[1..address.size].join('/') : address[0],
  1206.         :filename => address[-1],
  1207.  
  1208.     }
  1209.   end
  1210.  
  1211.   # Gets the request string
  1212.   # @param [Hash] request_array
  1213.   # @return [String]
  1214.   def self.prepare_request(request_array)
  1215.     array = []
  1216.     request_array.each_pair { |key, value|
  1217.       array.push(sprintf('%s=%s', key.to_s, value.to_s.gsub(' ', '+')))
  1218.     }
  1219.     array * '&'
  1220.   end
  1221.  
  1222.   def self.save_file(folder, filename, data)
  1223.     if File.directory?(folder)
  1224.       obj = File.open(folder + filename, 'wb') << data
  1225.       obj.close #chiusura del file
  1226.       Logger.info("File saved: #{folder + filename}")
  1227.     else
  1228.       string = '%s is not a valid folder, so %s will not be saved.'
  1229.       Logger.warning sprintf(string, folder, filename)
  1230.     end
  1231.   end
  1232.  
  1233.  
  1234.   # @param [Object] h_file
  1235.   # @param [String] read buffer
  1236.   # @param [Integer] buffer_size
  1237.   # @return [String]
  1238.   def self.internet_read_file(h_file, response = '', buffer_size = 1024)
  1239.     loop do
  1240.       lp_buffer = ' ' * buffer_size
  1241.       bytes_read = [0].pack('i!')
  1242.       read_ok = InternetReadFile.call(h_file, lp_buffer, buffer_size, bytes_read)
  1243.       read_size = bytes_read.unpack('i!')[0]
  1244.       response << lp_buffer[0, read_size]
  1245.       break if read_ok and read_size == 0 or read_size == "NaN"
  1246.     end
  1247.     response
  1248.   end
  1249.  
  1250.   # gets some (int) info from web resource
  1251.   # @param [Object] file the header file
  1252.   # @param [Integer] info_code the info code (see query constants)
  1253.   # @return [Integer]
  1254.   def self.http_query_info(file, info_code)
  1255.     buffer = "\0" * 128
  1256.     buffer_length = [buffer.size - 1].pack('l')
  1257.     status = HttpQueryInfo.call(file, info_code, buffer, buffer_length, nil)
  1258.     raise InternetConnectionException.new('Failed to receive the data') unless status
  1259.     buffer.delete!("\0").to_i
  1260.   end
  1261.  
  1262.   # gets the status code (200 OK, 500 Server error, 404...)
  1263.   # @return [Integer]
  1264.   def self.status_code(file)
  1265.     http_query_info file, HTTP_QUERY_STATUS_CODE
  1266.   end
  1267.  
  1268.   # gets the resource download size
  1269.   # @return [Integer]
  1270.   def self.content_size(file)
  1271.     http_query_info file, HTTP_QUERY_CONTENT_LENGTH
  1272.   end
  1273.  
  1274.   # Ottiene la dimensione di un file remoto
  1275.   def self.get_file_size(url)
  1276.     file = InternetOpenUrl.call(InternetOpenA, url, nil, 0, 0, 0)
  1277.     size = content_size file
  1278.     InternetCloseHandle.call(file)
  1279.     size
  1280.   end
  1281.  
  1282.   # Ottiene la risposta del server e la piazza nell'array delle rispose
  1283.   #   url: indirizzo della richiesta
  1284.   #   response_name: nome della risposta (per poterla leggere)
  1285.   #   low_priority: priorità (false se normale, true se bassa)
  1286.   # @deprecated utilizza HTTP::read_async
  1287.   #noinspection RubyUnusedLocalVariable
  1288.   def self.get_server_response(url, _response_name, _low_priority = false)
  1289.     get(url)
  1290.   end
  1291.  
  1292.   # Restituisce direttamente il testo di risposta dal server, interrompendo
  1293.   #   l'esecuzione del gioco fino a quando non arriva la risposta.
  1294.   #   url: indirizzo della richiesta
  1295.   # @deprecated utilizza HTTP.get
  1296.   def self.await_get_server_response(url)
  1297.     get(url).body
  1298.   end
  1299.  
  1300.   class << self
  1301.     alias await_response await_get_server_response
  1302.   end
  1303.  
  1304.   # Restituisce il dominio principale
  1305.   def self.domain
  1306.     H87_ModConfig::HTTPDOMAIN
  1307.   end
  1308.  
  1309.   class Response
  1310.     attr_accessor :code
  1311.     attr_accessor :head
  1312.     # @return [String]
  1313.     attr_accessor :body
  1314.     attr_accessor :size
  1315.  
  1316.     def initialize
  1317.       @code = 0
  1318.       @head = ''
  1319.       @body = ''
  1320.       @size = 0
  1321.     end
  1322.  
  1323.     def ok?
  1324.       @code | HTTP_STATUS_OK == @code
  1325.     end
  1326.  
  1327.     def progress
  1328.       @body.size.to_f / @size.to_f
  1329.     end
  1330.  
  1331.     # the response code
  1332.     # @return [Integer]
  1333.     def code
  1334.       @code.to_i
  1335.     end
  1336.  
  1337.     def json?
  1338.       return false if @body.nil?
  1339.       return false if @body.empty?
  1340.       #noinspection RegExpRedundantEscape
  1341.       @body =~ /^(\{.+\}|\[.*\])$/smi
  1342.     end
  1343.  
  1344.     # @return [String]
  1345.     def description
  1346.       description = RESPONSE_CODE_DESCRIPTIONS[@code] || ''
  1347.       sprintf('%d %s', @code, description)
  1348.     end
  1349.  
  1350.     def to_s
  1351.       @body
  1352.     end
  1353.   end
  1354.  
  1355.  
  1356.   class Request
  1357.     attr_accessor :terminated
  1358.     # @return [String]
  1359.     attr_accessor :uri
  1360.     # @return [Thread]
  1361.     attr_accessor :thread
  1362.     # @return [HTTP::Response]
  1363.     attr_accessor :response
  1364.     # @return [Method] the callback method when the resource is ready
  1365.     attr_accessor :callback_method
  1366.     # @return [String] the filename
  1367.     attr_accessor :filename
  1368.  
  1369.  
  1370.     def initialize(uri, filename = nil)
  1371.       @uri = uri
  1372.       @thread = nil
  1373.       @terminated = false
  1374.       @filename = filename || HTTP.url_info(uri)[:filename]
  1375.     end
  1376.  
  1377.     def byte_downloaded
  1378.       return 0 if response.nil?
  1379.       response.body.size
  1380.     end
  1381.  
  1382.     def size
  1383.       return 0 if response.nil?
  1384.       response.size
  1385.     end
  1386.  
  1387.     def download_rate
  1388.       return 0 if size == 0
  1389.       [byte_downloaded.to_f / size, 1.0].min
  1390.     end
  1391.  
  1392.     def abort
  1393.       return if @terminated
  1394.       return if self.thread.nil?
  1395.       self.thread.kill
  1396.     end
  1397.   end
  1398. end
  1399.  
  1400. #==============================================================================
  1401. # ** Async_Downloads
  1402. #------------------------------------------------------------------------------
  1403. #  Dev'essere incluso nelle classi che fanno uso dei metodi download_async.
  1404. #==============================================================================
  1405. module Async_Downloads
  1406.   # Scarica un file in modo asincrono lanciando automaticamente il metodo.
  1407.   #   url:          indirizzo del file
  1408.   #   method_name:  nome del metodo, in simbolo (ad es. :apri)
  1409.   #   low:          true se è a bassa incidenza, false altrimenti
  1410.   #   folder:       percorso del file di salvataggio
  1411.   # @param [String] url
  1412.   # @param [] method
  1413.   # @param [String] folder
  1414.   # @param [TrueClass] https
  1415.   # @return [HTTP::Request]
  1416.   def download_async(url, method, folder = "./", https = true)
  1417.     filename = url.split('/')[-1]
  1418.     if filename.downcase.include? ".php"
  1419.       Logger.warning 'This download is a call to a PHP File and should not be saved'
  1420.       return
  1421.     end
  1422.     @async_downloads = {} if @async_downloads.nil?
  1423.     @async_downloads[filename] = HTTP.download(url, folder, nil, https)
  1424.     @async_downloads[filename].callback_method = method
  1425.     @async_downloads[filename]
  1426.   end
  1427.  
  1428.   # @return [Hash{Symbol->HTTP::Request}]
  1429.   def async_downloads
  1430.     @async_downloads = {}
  1431.   end
  1432.  
  1433.   # Restituisce direttamente la stringa di risposta dal server
  1434.   #   url: indirizzo della richiesta
  1435.   # @param [String] url
  1436.   # @return [String]
  1437.   # @raise [InternetConnectionException]
  1438.   # @deprecated use HTTP.get
  1439.   def await_response(url)
  1440.     HTTP.get(url).body
  1441.   end
  1442.  
  1443.   # Controlla i download e lancia il metodo associato se completato.
  1444.   def check_async_downloads
  1445.     async_downloads.each_pair do |key, request|
  1446.       next unless request.terminated
  1447.       @async_downloads.delete(key)
  1448.       case request.callback_method.arity
  1449.       when 1
  1450.         request.callback_method.call(key)
  1451.       when 2
  1452.         request.callback_method.call(key, request.response)
  1453.       else
  1454.         request.callback_method.call
  1455.       end
  1456.     end
  1457.   end
  1458.  
  1459.   # Cancella un download o l'attesa di una risposta
  1460.   #   filename: nome del file o id della risposta
  1461.   def abort_download(filename)
  1462.     return if async_downloads[filename].nil?
  1463.     async_downloads[filename].abort
  1464.   end
  1465.  
  1466.   # Restituisce la percentuale di download da 0 a 100
  1467.   #   filename: nome del file
  1468.   # @param [String] filename
  1469.   # @return [Integer]
  1470.   def download_status(filename)
  1471.     return 1 if async_downloads[filename].nil?
  1472.     status = async_downloads[filename].download_rate * 100
  1473.     [[0, status].max, 100].min.to_i
  1474.   end
  1475.  
  1476.   # @param [String] filename
  1477.   def download_completed?(filename)
  1478.     return true if async_downloads[filename].nil?
  1479.     async_downloads[filename].terminated
  1480.   end
  1481.  
  1482.   # @param [String] url
  1483.   # @param [Object] method
  1484.   # @param [FalseClass] _priority
  1485.   # @deprecated use HTTP.get instead
  1486.   def get_response_async(url, method, _priority = false)
  1487.     method.call(HTTP.get(url).body)
  1488.   end
  1489. end
  1490.  
  1491. #==============================================================================
  1492. # ** Modulo Browser per aprire il browser predefinito del PC
  1493. #==============================================================================
  1494. module Browser
  1495.   # apre il browser
  1496.   #   url: url impostato
  1497.   # @param [String] url
  1498.   def self.open(url, avoid_protocol = false)
  1499.     #controlla che ci siano prefissi
  1500.     if url[0..6] != 'http://' and url[0..7] != 'https://' and !avoid_protocol
  1501.       open_url = 'http://' + url
  1502.     else
  1503.       open_url = url
  1504.     end
  1505.     shell = Win32API.new('Shell32', 'ShellExecute', %w(L P P P P L), 'L')
  1506.     Thread.new { shell.call(0, 'open', open_url, 0, 0, 1) }
  1507.     sleep(0.01)
  1508.     SceneManager.exit
  1509.   end
  1510. end #browser
  1511.  
  1512. #==============================================================================
  1513. # ** Mouse
  1514. #==============================================================================
  1515. module Mouse
  1516.   CURRPOS = Win32API.new('User32', 'GetCursorPos', 'P', 'I')
  1517.   # gets the current cursor position
  1518.   # @return [MousePoint]
  1519.   def self.cursor_position
  1520.     lpoint = [0, 0].pack('l_l_')
  1521.     result = CURRPOS.call(lpoint)
  1522.     if result > 0
  1523.       ary = lpoint.unpack('l_l_')
  1524.       MousePoint.new(ary[0], ary[1])
  1525.     else
  1526.       raise GetMousePosException.new('Error occurred when obtaining cursor position')
  1527.     end
  1528.   end
  1529. end
  1530.  
  1531. #==============================================================================
  1532. # ** MousePoint
  1533. # noinspection RubyInstanceVariableNamingConvention
  1534. #==============================================================================
  1535. class MousePoint
  1536.   # @attr[Fixnum] x
  1537.   # @attr[Fixnum] y
  1538.   attr_accessor :x
  1539.   attr_accessor :y
  1540.   # object initialization
  1541.   # @param [Fixnum] x
  1542.   # @param [Fixnum] y
  1543.   def initialize(x, y)
  1544.     @x = x
  1545.     @y = y
  1546.   end
  1547. end
  1548.  
  1549. #==============================================================================
  1550. # ** Modulo Browser per la codifica/decodifica di stringhe in Base64
  1551. #==============================================================================
  1552. module Base64
  1553.   # Restituisce una stringa decodificata da Base64
  1554.   #     string: stringa da decodificare
  1555.   # @param [String] string
  1556.   # @return [String]
  1557.   def self.decode(string)
  1558.     string.gsub(/\s+/, '').unpack('m')[0]
  1559.   end
  1560.  
  1561.   # Restituisce una stringa codificata in Base64
  1562.   #     string: stringa da codificare
  1563.   # @param [String] string
  1564.   # @return [String]
  1565.   def self.encode(string)
  1566.     [string].pack("m")
  1567.   end
  1568. end #base64
  1569.  
  1570. #==============================================================================
  1571. # ** Classe Settings (per le impostazioni comuni ai salvataggi)
  1572. #==============================================================================
  1573. class H87_Settings
  1574.   # @return [Hash]
  1575.   attr_accessor :settings
  1576.  
  1577.   # restituisce l'elemento corrispondente al parametro
  1578.   # @param [Object] param
  1579.   # @return [Object]
  1580.   def [](param)
  1581.     @settings ||= {}
  1582.     @settings[param]
  1583.   end
  1584.  
  1585.   # inizializzazione
  1586.   def initialize
  1587.     @settings = {}
  1588.   end
  1589.  
  1590.   # cambia o aggiunge un elemento dell'hash
  1591.   def []=(param_name, value)
  1592.     @settings[param_name] = value
  1593.     save
  1594.   end
  1595.  
  1596.   # Registra i dati salvati
  1597.   def save
  1598.     save_data($game_settings, DataManager.settings_path)
  1599.   end
  1600. end
  1601.  
  1602. #settings
  1603.  
  1604. #==============================================================================
  1605. # ** Game_Version
  1606. #------------------------------------------------------------------------------
  1607. # Questa classe è d'appoggio per gestire la versione del gioco.
  1608. #==============================================================================
  1609. class Game_Version
  1610.   include Comparable #per la verifica delle versioni se maggiore o minore
  1611.   attr_accessor :major #numero di major release
  1612.   attr_accessor :minor #numero di minor release
  1613.   attr_accessor :build #numero di versione build
  1614.   attr_accessor :revision #numero di revisione
  1615.   # Inizializzazione
  1616.   #     version_string: versione in stringa (ad es. 1.5.3.1)
  1617.   # @param [String] version_string
  1618.   # @param [Integer] starting_major
  1619.   def initialize(version_string, starting_major = 1)
  1620.     @major = starting_major
  1621.     @minor = 0
  1622.     @build = 0
  1623.     @revision = 0
  1624.     version_string.gsub!(/\s\n\r/, '')
  1625.     return unless version_string =~ /[\d]+([.\d]*)/
  1626.     version_string = version_string.split('.')
  1627.     @major = version_string[0].to_i
  1628.     return if version_string[1].nil?
  1629.     @minor = version_string[1].to_i
  1630.     return if version_string[2].nil?
  1631.     @build = version_string[2].to_i
  1632.     return if version_string[3].nil?
  1633.     @revision = version_string[3].to_i
  1634.   end
  1635.  
  1636.   # Restituisce la versione attuale del gioco
  1637.   # @return [Game_Version]
  1638.   def self.now
  1639.     if File.exist?(H87_ModConfig::VERSIONFILE)
  1640.       file = File.open(H87_ModConfig::VERSIONFILE, 'r')
  1641.       str = file.read
  1642.       file.close
  1643.       Game_Version.new(str)
  1644.     elsif get_version_from_game_ini != nil
  1645.       get_version_from_game_ini
  1646.     else
  1647.       Game_Version.new('1.0.0.0')
  1648.     end
  1649.   end
  1650.  
  1651.   # Ottiene la versione del gioco da Game.ini
  1652.   # @return [Game_Version]
  1653.   def self.get_version_from_game_ini
  1654.     return nil unless File.exist?('Game.ini')
  1655.     version = nil
  1656.     file = File.open('Game.ini', 'r')
  1657.     File.readlines.each { |line|
  1658.       if line =~ /version[ ]*=[ ]*([.\d]+)/i
  1659.         version = Game_Version.new($1)
  1660.       end
  1661.     }
  1662.     file.close
  1663.     version
  1664.   end
  1665.  
  1666.   # Compara una versione o una stringa con se stessa
  1667.   def <=>(other)
  1668.     return self <=> Game_Version.new(other) if other.is_a?(String)
  1669.     return self.major <=> other.major if self.major != other.major
  1670.     return self.minor <=> other.minor if self.minor != other.minor
  1671.     return self.build <=> other.build if self.build != other.build
  1672.     self.revision <=> other.revision
  1673.   end
  1674.  
  1675.   # restituisce la versione in stringa
  1676.   def to_s
  1677.     sprintf('%d.%d.%d.%d', @major, @minor, @build, @revision)
  1678.   end
  1679. end
  1680.  
  1681. #game_version
  1682.  
  1683. #==============================================================================
  1684. # ** RPG::System -> aggiunta del metodo per la versione del gioco
  1685. #==============================================================================
  1686. class Game_System
  1687.   # Restituisce la versione del gioco attuale
  1688.   def game_version
  1689.     Game_Version.now
  1690.   end
  1691. end
  1692.  
  1693. #rpg_system
  1694.  
  1695. #==============================================================================
  1696. # ** DataManager -> aggiunta dei metodi per caricare i settaggi
  1697. #==============================================================================
  1698. module DataManager
  1699.   # alias
  1700.   # noinspection RubyResolve
  1701.   class << self
  1702.     alias h87set_load_n_db load_normal_database
  1703.     alias h87set_load_b_db load_battle_test_database
  1704.   end
  1705.  
  1706.   # caricamento nd
  1707.   def self.load_normal_database
  1708.     load_h87settings
  1709.     h87set_load_n_db
  1710.   end
  1711.  
  1712.   # caricamento btd
  1713.   def self.load_battle_test_database
  1714.     load_h87settings
  1715.     h87set_load_b_db
  1716.   end
  1717.  
  1718.   # restituisce il percorso delle impostazioni
  1719.   def self.settings_path
  1720.     H87_ModConfig::SETTINGNAME
  1721.   end
  1722.  
  1723.   # carica le impostazioni universali
  1724.   def self.load_h87settings
  1725.     return if $game_settings
  1726.     if File.exist?(settings_path)
  1727.       $game_settings = load_data(settings_path)
  1728.     else
  1729.       $game_settings = H87_Settings.new
  1730.       save_data($game_settings, settings_path)
  1731.     end
  1732.   end
  1733. end #datamanager
  1734.  
  1735. #==============================================================================
  1736. # ** Resolution
  1737. #------------------------------------------------------------------------------
  1738. # Un contenitore di risoluzioni
  1739. #==============================================================================
  1740. module Resolution
  1741.   QVGA = '320x240' # 4:3
  1742.   VGA = '640x480' # 4:3
  1743.   WSVGA = '1024x600' # 16:9
  1744.   SVGA = '800x600' # 4:3
  1745.   XGA = '1024x768' # 4:3
  1746.   SXGA = '1280x1024' # 4:3
  1747.   WXGA = '1280x720' # 16:9
  1748.   HD768 = '1366x768' # 16:9
  1749.   FULLHD = '1920x1080' # 16:9
  1750.   WUXGA = '1920x1200' # 16:10
  1751. end
  1752.  
  1753. #==============================================================================
  1754. # ** Cache
  1755. #------------------------------------------------------------------------------
  1756. # Aggiunta della possibilità di scaricare l'immagine del giorno.
  1757. #==============================================================================
  1758. module Cache
  1759.   # downloads an image from the web.
  1760.   # @param [String] url
  1761.   # @param [String] filename
  1762.   # @return [Bitmap]
  1763.   def self.web_picture(url, filename = nil)
  1764.     filename = name_from_url(url) if filename.nil?
  1765.     @web_cache ||= {}
  1766.     @web_cache[filename] = web_bitmap(url, filename) unless in_download_cache?(filename)
  1767.     @web_cache[filename]
  1768.   end
  1769.  
  1770.   def self.in_download_cache?(key)
  1771.     @web_cache[key] != nil and !@web_cache[key].disposed?
  1772.   end
  1773.  
  1774.   # Restituisce l'immagine del giorno di Bing come bitmap.
  1775.   #   È possibile specificare una risoluzione. Risoluzioni supportate:
  1776.   #   QVGA, VGA, SVGA, XGA, WXGA, HD768, FULLHD, WUXGA
  1777.   # @param [String] resolution
  1778.   # @return [Bitmap]
  1779.   def self.bing_daily(resolution = Resolution::VGA)
  1780.     return empty_bitmap if bing_daily_metadata[:url_base].empty?
  1781.     url = "https://www.bing.com#{bing_daily_metadata[:url_base]}_#{resolution}.jpg"
  1782.     web_picture(url)
  1783.   end
  1784.  
  1785.   # @return [String]
  1786.   def self.cache_folder
  1787.     './Graphics/Cache/'
  1788.   end
  1789.  
  1790.   # delete ALL files in the Cache folder
  1791.   def self.clear_cache_folder
  1792.     Dir.foreach(cache_folder) do |file|
  1793.       next if file == '.'
  1794.       next if file == '..'
  1795.       next if File.directory?(cache_folder + '/' + file)
  1796.       File.delete(cache_folder + '/' + file)
  1797.     end
  1798.   end
  1799.  
  1800.   # Restituisce il copyright dell'immagine del giorno. usare solo se già
  1801.   #   scaricata l'immagine!
  1802.   # @return [String]
  1803.   def self.bing_daily_copyright
  1804.     @bing_metadata[:copyright]
  1805.   end
  1806.  
  1807.   # Ottiene il feed xml dell'immagine di Bing e ne restituisce un hash con
  1808.   #   informazioni, oppure nil se la connessione non è riuscita
  1809.   # @return [Hash]
  1810.   def self.bing_daily_metadata
  1811.     @bing_metadata ||= download_bing_daily_metadata
  1812.   end
  1813.  
  1814.   private
  1815.  
  1816.   # @param [String] url
  1817.   # @param [String] filename
  1818.   # @return [Bitmap]
  1819.   def self.web_bitmap(url, filename)
  1820.     Dir.mkdir(cache_folder) unless File.directory?(cache_folder)
  1821.     return load_bitmap(cache_folder, filename) if File.exist?(cache_folder + filename)
  1822.     request = HTTP.download(url, cache_folder, filename)
  1823.     loop { break if request.terminated }
  1824.     response = request.response
  1825.     if response.ok?
  1826.       bitmap = Bitmap.new(cache_folder + filename)
  1827.     else
  1828.       Logger.error 'Error downloading from ' + url
  1829.       bitmap = empty_bitmap
  1830.     end
  1831.     bitmap
  1832.   end
  1833.  
  1834.   def self.download_bing_daily_metadata
  1835.     lang = Win.locale_name
  1836.     url = "http://www.bing.com/HPImageArchive.aspx?format=xml&idx=0&n=1&mkt=#{lang}"
  1837.     response = HTTP.get(url, {}, true)
  1838.     if response.ok?
  1839.       info = {}
  1840.       info[:url_base] = read_xml(response.body, 'urlBase')
  1841.       info[:copyright] = read_xml(response.body, 'copyright')
  1842.       info[:headline] = read_xml(response.body, 'headline')
  1843.       info[:start_date] = read_xml(response.body, 'startdate')
  1844.       info
  1845.     else
  1846.       {}
  1847.     end
  1848.   end
  1849.  
  1850.   # reads a node value from xml text
  1851.   # @param [String] xml_str
  1852.   # @param [Object] node
  1853.   def self.read_xml(xml_str, node)
  1854.     xml_str =~ /<#{node}>(.+)<\/#{node}>/i ? $1 : ''
  1855.   end
  1856.  
  1857.   # @param [String] url
  1858.   # @return [String]
  1859.   def self.name_from_url(url)
  1860.     if url =~ /([A-Za--ÖØ-öø-ÿ0-9]+).(png|jpg|jpeg|bmp)($|\?|&)/
  1861.       $1 + '.' + $2
  1862.     else
  1863.       # fallback method
  1864.       base64_encode(url) + '.jpg'
  1865.     end
  1866.   end
  1867. end
  1868.  
  1869. #==============================================================================
  1870. # ** Aggiunta di alcuni metodi utili per le stringhe
  1871. #==============================================================================
  1872. class String
  1873.   # Metodo Random: restituisce una stringa a caso
  1874.   #   size: numero di caratteri della stringa
  1875.   # @param [Integer] size
  1876.   # @return [String]
  1877.   def self.random(size = 4)
  1878.     rand(36 ** size).to_s(36)
  1879.   end
  1880.  
  1881.   # Restituisce la stessa stringa ma crittografata in ROT13
  1882.   #   http://it.wikipedia.org/wiki/ROT13
  1883.   # @return [String]
  1884.   def crypt_rot13
  1885.     self.tr('A-Za-z', 'N-ZA-Mn-za-m')
  1886.   end
  1887. end
  1888.  
  1889. #fine della stringa
  1890.  
  1891. #==============================================================================
  1892. # ** Inclusione dei metodi asincroni in Scene_Base
  1893. #==============================================================================
  1894. class Scene_Base
  1895.   include Async_Downloads # inclusione del modulo
  1896.   # Alias del metodo d'aggiornamento
  1897.   alias h87_module_update update unless $@
  1898.  
  1899.   def update
  1900.     h87_module_update
  1901.     check_async_downloads #controlla i download
  1902.   end
  1903. end
  1904.  
  1905. #==============================================================================
  1906. # ** Integer
  1907. #==============================================================================
  1908. class Integer
  1909.   # returns minutes in seconds
  1910.   # @return [Integer]
  1911.   def minutes
  1912.     self * 60
  1913.   end
  1914.  
  1915.   # returns hours in seconds
  1916.   # @return [Integer]
  1917.   def hours
  1918.     self * 3600
  1919.   end
  1920.  
  1921.   def seconds
  1922.     self
  1923.   end
  1924.  
  1925.   # returns days in seconds
  1926.   # @return [Integer]
  1927.   def days
  1928.     hours * 24
  1929.   end
  1930. end
  1931.  
  1932. #==============================================================================
  1933. # ** Object
  1934. #------------------------------------------------------------------------------
  1935. # Metodi universali di gioco
  1936. #==============================================================================
  1937. class Object
  1938.   # Metodo di stampa riga
  1939.   # @deprecated not used anymore. Please use puts instead
  1940.   def println(*args)
  1941.     puts *args
  1942.   end
  1943.  
  1944.   # Metodi di conversione Base64
  1945.   # @param [String] string
  1946.   # @return [String]
  1947.   def base64_encode(string)
  1948.     Base64.encode(string)
  1949.   end
  1950.  
  1951.   # @param [String] string
  1952.   # @return [String]
  1953.   def base64_decode(string)
  1954.     Base64.decode(string)
  1955.   end
  1956.  
  1957.   # Restituisce direttamente la stringa di risposta dal server
  1958.   #   url: indirizzo della richiesta
  1959.   # @param [String] url
  1960.   # @return [String]
  1961.   def await_response(url)
  1962.     HTTP.get(url).body
  1963.   end
  1964.  
  1965.   # Restituisce direttamente la stringa di risposta dal server
  1966.   #   url: indirizzo della richiesta
  1967.   # @param [String] url
  1968.   # @param [Hash] params
  1969.   # @return [String]
  1970.   # @raise [InternetConnectionException]
  1971.   def submit_post_request(url, params = {}, https = false)
  1972.     HTTP.post(url, params, https).body
  1973.   end
  1974.  
  1975.   # Determina se il gioco è VX Ace
  1976.   def on_vx_ace?
  1977.     RUBY_VERSION == '1.9.2'
  1978.   end
  1979.  
  1980.   # Determina se il gioco è VX
  1981.   def on_vx?
  1982.     RUBY_VERSION == '1.8.1'
  1983.   end
  1984. end
  1985.  
  1986. #==============================================================================
  1987. # ** Time
  1988. #==============================================================================
  1989. class Time
  1990.   # @param [Date] date_str
  1991.   def self.from_string(date_str)
  1992.     if date_str =~ /(\d{4})-(\d{2})-(\d{2})/
  1993.       Time.new($1.to_i, $2.to_i, $3.to_i)
  1994.     else
  1995.       raise WrongDateFormatError('You must use format YYYY-MM-DD')
  1996.     end
  1997.   end
  1998. end
  1999.  
  2000. if on_vx?
  2001.   #==============================================================================
  2002.   # ** Hash
  2003.   #------------------------------------------------------------------------------
  2004.   # changed to_s method to better print
  2005.   #==============================================================================
  2006.   class Hash
  2007.     # hsh.to_s     -> string
  2008.     # hsh.inspect  -> string
  2009.     #
  2010.     # Return the contents of this hash as a string.
  2011.     #
  2012.     #     h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300  }
  2013.     #     h.to_s   #=> "{\"c\"=>300, \"a\"=>100, \"d\"=>400}"
  2014.     def to_s
  2015.       '{' + (self.inject([]) do |a, (key, value)|
  2016.         a.push(sprintf('%s=>%s', key, value))
  2017.       end * ',') + '}'
  2018.     end
  2019.   end
  2020. end
  2021.  
  2022.  
  2023. # launched when can't connect with the server
  2024. class InternetConnectionException < StandardError
  2025.   attr_accessor :code
  2026.  
  2027.   # @param [String] message
  2028.   # @param [Fixnum] code
  2029.   def initialize(message, code = nil)
  2030.     super(message)
  2031.     @code = code
  2032.   end
  2033.  
  2034.   # determines if the connection is not available
  2035.   def server_unreachable?
  2036.     @code == 0
  2037.   end
  2038. end
  2039.  
  2040. # launched when can't read from the clipboard
  2041. class ClipboardDataAccessException < Exception; end
  2042.  
  2043. # launched when fails to obtaining the mouse position
  2044. class GetMousePosException < Exception; end
  2045.  
  2046. class WrongDateFormatError < StandardError
  2047.  
  2048. end
  2049.  
  2050. unless $imported['H87-ConsoleLogger']
  2051.   module Logger
  2052.     def self.info(*args)
  2053.       args[0] = '[INFO] ' + args[0].to_s
  2054.       puts args
  2055.     end
  2056.  
  2057.     def self.error(*args)
  2058.       args[0] = '[ERROR] ' + args[0].to_s
  2059.       puts args
  2060.     end
  2061.  
  2062.     def self.warning(*args)
  2063.       args[0] = '[WARNING] ' + args[0].to_s
  2064.       puts args
  2065.     end
  2066.   end
  2067. end
RAW Paste Data