mirror of
https://github.com/bakustarver/rpgmakermlinux-cicpoffs.git
synced 2025-03-28 14:56:21 +01:00
Add files via upload
This commit is contained in:
parent
c0883b78b8
commit
07dd85c6fa
24 changed files with 11333 additions and 0 deletions
129
mkxp-z/Kawariki-patches/README.md
Normal file
129
mkxp-z/Kawariki-patches/README.md
Normal file
|
@ -0,0 +1,129 @@
|
|||
Kawariki MKXP runtime
|
||||
=====================
|
||||
|
||||
The MKXP runtime handles games based on the `Ruby Game Scripting System`, RGSS.
|
||||
|
||||
The RPG Maker editions based on RGSS are:
|
||||
- RPGMaker XP (RGSS1)
|
||||
- RPGMaker VX (RGSS2)
|
||||
- RPGMaker VX Ace (RGSS3)
|
||||
|
||||
[Official RPGMaker Website][rpgmakerweb]
|
||||
|
||||
MKXP-Z
|
||||
------
|
||||
|
||||
The specific implementation used in Kawariki is [mkxp-z][mkxp-z] by Roza/Struma,
|
||||
itself based on the original [mkxp][mkxp-github] by Ancurio.
|
||||
|
||||
Currently, a [repackaged distribution][mkxp-z-repack] of the [official releases][mkxp-z-releases] are used.
|
||||
This is required mostly for ease of automatic downloading in Kawariki.
|
||||
|
||||
Links: [mkxp-z GitHub][mkxp-z-github]
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
### mkxp.json
|
||||
|
||||
The mkxp-z configuration is merged from a number of files in order:
|
||||
- `<kawariki>/mkxp/mkxp.json`: Global mkxp config
|
||||
- `<game>/kawariki-mkxp.json`: Overrides specific for this game
|
||||
|
||||
See the [default included with mkxp-z for reference][mkxp-z-config]
|
||||
Note that the runtime doesn't understand JSON comments for now,
|
||||
unlike mkxp-z itself.
|
||||
|
||||
#### RTPs
|
||||
The situation with RTPs is not optimal at the moment, but they
|
||||
can be specified globally in `<kawariki>/mkxp/mkxp.json`:
|
||||
```json
|
||||
{
|
||||
"RTP": ["/path/to/rtp"]
|
||||
}
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
- `KAWARIKI_MKXP_DUMP_SCRIPTS=<dirname>`: Dump scripts to <dirname> before applying patches
|
||||
- `KAWARIKI_MKXP_DUMP_PATCHED_SCRIPTS=<dirname>`: Dump scripts to <dirname> after applying patches
|
||||
- `KAWARIKI_MKXP_FILTER_SCRIPTS=<name>[,...]`: Blacklist scripts/plugins by name
|
||||
- `KAWARIKI_MKXP_DRY_RUN=1`: Exit after patching scripts, don't run game
|
||||
- `KAWARIKI_MKXP_NO_FONT_EFFECTS=1`: Disable all font effects. See relevant patch in `pathces.rb`
|
||||
- `KAWARIKI_NO_OVERLAYNS=1` Disallow usage of overlayns-static
|
||||
|
||||
### versions.json
|
||||
This file specifies the mkxp-z versions known to the runtime:
|
||||
- `variant` *required string* Must be `"mkxp-z"` for now
|
||||
- `version` *required array-of-numbers* The version of this distribution (e.g. `[2,3,0]`)
|
||||
- `dist` *required string* The name of the directory the distribution is stored in.
|
||||
- `dist_url` *optional string* An URL to download the distribution from if not already available. It must point to a gzip/bzip2/xz compressed tar-archive.
|
||||
- `name` *optional string* An optional name given to the distribution. Defaults to the value of `dist`.
|
||||
|
||||
RGSS Plugins
|
||||
------------
|
||||
|
||||
All functionality in RGSS-based games is derived from the core scripts
|
||||
of it's respective RPGMaker edition and extended by usually rather large
|
||||
numbers of third-party engine plugins.
|
||||
|
||||
Unfortunately, as a consequence of RGSS being a rather simplistic engine
|
||||
and also being Windows-only, a lot of these plugins rely on assumptions
|
||||
that don't hold true on Linux (though MKXP already implements case-insensitive
|
||||
path lookups) or depend on the Win32 API or other (possibly custom) native
|
||||
Windows libraries by way of a FFI (`Win32API` in RGSS).
|
||||
As such, the runtime must apply a considerable amount of patches to a game
|
||||
to allow it to run on Linux/MXKP-Z.
|
||||
|
||||
### Ports
|
||||
|
||||
Ports are modifications or re-implementations of third-party plugins to make
|
||||
them work on Linux/MKXP-Z. They are contained in the `ports/` directory.
|
||||
|
||||
All ports retain their original license terms. If you are the original author
|
||||
of one of the included scripts and want it removed, please open an issue on GitHub.
|
||||
|
||||
### Patches
|
||||
|
||||
A patch tries to identify a third-party plugin and then either modify it's code
|
||||
or outright replace the plugin with a port from `ports/`. Patches are defined
|
||||
in [`patches.rb`](patches.rb)
|
||||
|
||||
### Win32API Stubs
|
||||
Win32API stubs are implemented in [`libs/Win32API.rb`](libs/Win32API.rb).
|
||||
They are automatically loaded if any reference to Win32API is found in plugin
|
||||
code after all patches are applied.
|
||||
|
||||
It is usually easier to port a heavily Win32API-dependent plugin instead of
|
||||
trying to re-implement the relevant Win32 APIs.
|
||||
|
||||
Currently, implementations are included for these common APIs:
|
||||
- kernel32/GetPrivateProfileString
|
||||
- kernel32/GetPrivateProfileInt
|
||||
- kernel32/WritePrivateProfileString
|
||||
|
||||
### Preload
|
||||
|
||||
The preload script `preload.rb` is registered with MKXP-Z and is responsible for
|
||||
applying the patches defined in `patches.rb`.
|
||||
|
||||
Some methods are provided for use in ports/patches:
|
||||
- `Preload::require()`: Require a library from the `libs/` directory (see below)
|
||||
- `Preload::print()`: Print to stderr. Note that Kernel.print may open a message box depending on RGSS version
|
||||
|
||||
### Libraries
|
||||
The `libs/` directory contains a few libraries to support porting plugins.
|
||||
- `ruby18.rb`: Some low-hanging compatibility modifications for RGSS1, which used Ruby 1.8
|
||||
- `Win32API.rb`: Wrapper around Win32API to intercept imports with included ruby implementations
|
||||
- `PreloadIni.rb`: Simple INI parser/generator for implementing {Get,Write}PrivateProfileString
|
||||
- `XP_TileMapOverrideLib.rb`: Workaround for a MKXP-Z issue related to GL texture sizes
|
||||
|
||||
|
||||
<!-- References -->
|
||||
[mkxp-z]: https://roza-gb.gitbook.io/mkxp-z
|
||||
[mkxp-z-config]: https://github.com/mkxp-z/mkxp-z/blob/release/mkxp.json
|
||||
[mkxp-z-github]: https://github.com/mkxp-z/mkxp-z
|
||||
[mkxp-z-releases]: https://github.com/mkxp-z/mkxp-z/releases
|
||||
[mkxp-z-repack]: https://github.com/Orochimarufan/Kawariki/releases/tag/mkxp-2.3.0-kk
|
||||
|
||||
[mkxp-github]: https://github.com/Ancurio/mkxp
|
||||
[rpgmakerweb]: https://www.rpgmakerweb.com/
|
439
mkxp-z/Kawariki-patches/libs/PreloadIni.rb
Normal file
439
mkxp-z/Kawariki-patches/libs/PreloadIni.rb
Normal file
|
@ -0,0 +1,439 @@
|
|||
# INI file tools for replacing Win32API usage
|
||||
# Key and Section names are case-preserving
|
||||
# Authors: Taeyeon Mori
|
||||
|
||||
module Preload
|
||||
module Ini
|
||||
# ********** Machinery **********
|
||||
class DummyReadFile
|
||||
def each_line(&p)
|
||||
end
|
||||
end
|
||||
|
||||
class IniBase
|
||||
def initialize(file)
|
||||
@file = file
|
||||
@section = ""
|
||||
@section_lc = ""
|
||||
end
|
||||
|
||||
attr_reader :section, :section_lc
|
||||
|
||||
def self.open(filename)
|
||||
if block_given? then
|
||||
File.open(filename, self::FileMode) do |file|
|
||||
yield self.new file
|
||||
end
|
||||
else
|
||||
return self.new File.new(filename, self::FileMode)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class IniWriter < IniBase
|
||||
FileMode = "wt"
|
||||
|
||||
def initialize(file)
|
||||
super file
|
||||
@newline = 1
|
||||
end
|
||||
|
||||
def writeLine(line=nil)
|
||||
if line.nil? || line.empty? then
|
||||
@file.write "\r\n"
|
||||
@newline += 1
|
||||
else
|
||||
@file.write "#{line}\r\n"
|
||||
@newline = 0
|
||||
end
|
||||
end
|
||||
|
||||
def writeComment(text)
|
||||
writeLine "; #{text}"
|
||||
end
|
||||
|
||||
def writeSection(name)
|
||||
lc = name.downcase
|
||||
return if lc == @section_lc
|
||||
writeLine if @newline < 1
|
||||
writeLine "[#{name}]"
|
||||
@section = name
|
||||
@section_lc = lc
|
||||
end
|
||||
|
||||
def writeKey(key, value)
|
||||
value = value.to_s
|
||||
value = "\"#{value}\"" if value.strip != value
|
||||
writeLine "#{key}=#{value}"
|
||||
end
|
||||
|
||||
def writeEntry(section, key, value)
|
||||
writeSection section
|
||||
writeKey key, value
|
||||
end
|
||||
|
||||
def forward(token, *args)
|
||||
# Can receive tokens from IniReader directly
|
||||
case token
|
||||
when :comment
|
||||
writeComment *args
|
||||
when :section
|
||||
writeSection *args
|
||||
when :key
|
||||
writeKey *args
|
||||
when :line
|
||||
writeLine *args
|
||||
when :empty
|
||||
writeLine
|
||||
when :eof
|
||||
else
|
||||
raise "Unknown token: #{token}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class IniReader < IniBase
|
||||
FileMode = "rt"
|
||||
|
||||
def self.open(filename)
|
||||
# Pretend file is empty if it doesn't exist
|
||||
if !File.exist? filename then
|
||||
if block_given? then
|
||||
yield self.new DummyReadFile.new
|
||||
else
|
||||
return self.new DummyReadFile.new
|
||||
end
|
||||
else
|
||||
return super
|
||||
end
|
||||
end
|
||||
|
||||
def readComment(line)
|
||||
line.slice!(0, line[1] == " " ? 2 : 1)
|
||||
[line]
|
||||
end
|
||||
|
||||
def readSection(line)
|
||||
raise "Malformed section header: '#{line}'" if line[0] != '[' || line[-1] != ']'
|
||||
@section = line[1...-1]
|
||||
@section_lc = @section.downcase
|
||||
return [@section]
|
||||
end
|
||||
|
||||
def readKey(line)
|
||||
key, value = line.split('=', 2)
|
||||
value.strip!
|
||||
# Allow quoting to keep surrounding whitespace
|
||||
value = value[1...-1] if value.size > 1 && "'\"".include?(value[0]) && value[0] == value[-1]
|
||||
[key.strip, value]
|
||||
rescue ArgumentError => e
|
||||
puts "Error processing line: #{line.inspect} - #{e.message}"
|
||||
nil
|
||||
end
|
||||
|
||||
def readLine(line)
|
||||
if line.valid_encoding?
|
||||
line.strip!
|
||||
else
|
||||
# Optionally, handle the invalid encoding here:
|
||||
# You can choose to skip the line, replace invalid characters, or log it.
|
||||
line = line.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '?')
|
||||
end
|
||||
return [:empty] if line.empty?
|
||||
return :comment, *readComment(line) if line[0] == ';'
|
||||
return :section, *readSection(line) if line[0] == '['
|
||||
return :key, *readKey(line) if line.include? '='
|
||||
# Just pass it through as last resort
|
||||
return :line, line
|
||||
end
|
||||
|
||||
def read
|
||||
raise "Must be called with block" unless block_given?
|
||||
last = nil
|
||||
@file.each_line do |line|
|
||||
tok = readLine line
|
||||
# Collapse empty lines
|
||||
next if tok[0] == :empty && last == :empty
|
||||
last = tok[0]
|
||||
yield tok
|
||||
end
|
||||
yield :eof
|
||||
end
|
||||
end
|
||||
|
||||
# ********** Simple API **********
|
||||
# Read
|
||||
def self.readIniString(filename, section, key)
|
||||
# Intended to be compatible with ReadPrivateProfileString
|
||||
section_lc = section.downcase
|
||||
key_lc = key.downcase
|
||||
found_section = section.empty?
|
||||
IniReader.open filename do |ir|
|
||||
ir.read do |type, *args|
|
||||
case type
|
||||
when :section
|
||||
found_section = ir.section_lc == section_lc
|
||||
when :key
|
||||
fkey, fval = *args
|
||||
return fval if found_section && fkey.downcase == key_lc
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.readIniStrings(filename, section, keys=nil)
|
||||
result = {}
|
||||
section_lc = section.downcase
|
||||
keys_lc = {}
|
||||
keys.each {|key| keys_lc[key.downcase] = key} unless keys.nil?
|
||||
found_section = section.empty?
|
||||
IniReader.open filename do |ir|
|
||||
ir.read do |type, *args|
|
||||
case type
|
||||
when :section
|
||||
found_section = ir.section_lc == section_lc
|
||||
when :key
|
||||
if found_section then
|
||||
fkey, fval = *args
|
||||
if keys.nil? then
|
||||
result[fkey] = fval
|
||||
else
|
||||
zkey = keys_lc[fkey.downcase]
|
||||
result[zkey] = fval unless zkey.nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
def self.readIniPaths(filename, paths=nil)
|
||||
result = {}
|
||||
paths_lc = {}
|
||||
paths.each {|path| lc = path.downcase; paths_lc[lc] = path unless paths_lc.include? lc} unless paths.nil?
|
||||
section_all = paths.nil? || paths.include?("/*")
|
||||
section_all_name = nil
|
||||
IniReader.open filename do |ir|
|
||||
ir.read do |type, *args|
|
||||
case type
|
||||
when :section
|
||||
unless paths.nil? then
|
||||
section_all_name = paths_lc["#{ir.section_lc}/*"]
|
||||
section_all = !section_all_name.nil?
|
||||
section_all_name.slice!(-2...) if section_all
|
||||
end
|
||||
when :key
|
||||
fkey, fval = *args
|
||||
if section_all then
|
||||
fpath = "#{section_all_name.nil? ? ir.section : section_all_name}/#{fkey}"
|
||||
result[fpath] = fval
|
||||
else
|
||||
fpath = "#{ir.section_lc}/#{fkey.downcase}"
|
||||
result[paths_lc[fpath]] = fval if paths_lc.key? fpath
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def self.readIniSections(filename)
|
||||
# Get a list of sections in the file
|
||||
# Note: may contain (possibly case-mismatched) duplicates.
|
||||
sections = []
|
||||
IniReader.open filename do |ir|
|
||||
ir.read do |type, *args|
|
||||
case type
|
||||
when :section
|
||||
sections.push args[0]
|
||||
end
|
||||
end
|
||||
end
|
||||
return sections
|
||||
end
|
||||
|
||||
def self.readIniKeys(filename, section)
|
||||
# Get a list of keys in a section
|
||||
# Note: may contain (possibly case-mismatched) duplicates.
|
||||
keys = []
|
||||
section_lc = section.downcase
|
||||
found_section = section.empty?
|
||||
IniReader.open filename do |ir|
|
||||
ir.read do |type, *args|
|
||||
case type
|
||||
when :section
|
||||
found_section = ir.section_lc == section_lc
|
||||
when :key
|
||||
keys.push args[0] if found_section
|
||||
end
|
||||
end
|
||||
end
|
||||
return keys
|
||||
end
|
||||
|
||||
# Write
|
||||
def self.writeIniString(filename, section, key, value)
|
||||
# Intended to be compatible with WritePrivateProfileString
|
||||
# Write to new file then rename over top.
|
||||
section_lc = section.downcase
|
||||
key_lc = key.downcase unless key.nil?
|
||||
found_section = section.empty?
|
||||
written = key.nil? || value.nil? # Delete instead if nil
|
||||
temp_name = "#{filename}.tmp"
|
||||
IniWriter.open temp_name do |iw|
|
||||
IniReader.open filename do |ir|
|
||||
ir.read do |type, *args|
|
||||
case type
|
||||
when :section
|
||||
# Insert new key before leaving section
|
||||
if found_section && !written then
|
||||
iw.writeKey key, value
|
||||
written = true
|
||||
end
|
||||
# Start new section or omit whole section if key == nil
|
||||
found_section = ir.section_lc == section_lc
|
||||
iw.writeSection ir.section unless found_section && key.nil?
|
||||
when :key
|
||||
fkey, fval = *args
|
||||
if found_section then
|
||||
if fkey.downcase == key_lc then
|
||||
# Replace matching key
|
||||
iw.writeKey key, value unless written
|
||||
written = true
|
||||
elsif !key.nil? then
|
||||
# Copy other keys
|
||||
iw.writeKey fkey, fval
|
||||
end
|
||||
else
|
||||
iw.writeKey fkey, fval
|
||||
end
|
||||
when :eof
|
||||
# Add to end of file if not found earlier
|
||||
iw.writeEntry section, key, value unless written
|
||||
else
|
||||
iw.forward type, *args
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
File.rename(temp_name, filename)
|
||||
end
|
||||
|
||||
def self.writeIniStrings(filename, section, hash)
|
||||
# Write to new file then rename over top.
|
||||
section_lc = section.downcase
|
||||
hash_lc = {}
|
||||
written = []
|
||||
hash.each_pair do |key, value|
|
||||
key_lc = key.downcase
|
||||
hash_lc[key_lc] = [key, value] unless value.nil?
|
||||
written.push key_lc if value.nil?
|
||||
end
|
||||
found_section = section.empty?
|
||||
temp_name = "#{filename}.tmp"
|
||||
IniWriter.open temp_name do |iw|
|
||||
IniReader.open filename do |ir|
|
||||
ir.read do |type, *args|
|
||||
case type
|
||||
when :section
|
||||
# Insert new keys before leaving section
|
||||
if found_section && !hash_lc.empty? then
|
||||
hash_lc.each_pair {|key_lc, kv| iw.writeKey *kv}
|
||||
written.push *hash_lc.keys
|
||||
hash_lc.clear
|
||||
end
|
||||
# Start new section or omit whole section if key == nil
|
||||
found_section = ir.section_lc == section_lc
|
||||
iw.writeSection ir.section
|
||||
when :key
|
||||
fkey, fval = *args
|
||||
if found_section then
|
||||
fkey_lc = fkey.downcase
|
||||
entry = hash_lc.delete fkey_lc
|
||||
if !entry.nil? then
|
||||
# Replace matching key
|
||||
iw.writeKey *entry
|
||||
written.push fkey_lc
|
||||
next
|
||||
elsif written.include? fkey_lc then
|
||||
next
|
||||
end
|
||||
end
|
||||
iw.writeKey fkey, fval
|
||||
when :eof
|
||||
# Add to end of file if not found earlier
|
||||
if !hash_lc.empty? then
|
||||
iw.writeSection section
|
||||
hash_lc.each_value {|key, value| iw.writeKey key, value}
|
||||
end
|
||||
else
|
||||
iw.forward type, *args
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
File.rename(temp_name, filename)
|
||||
end
|
||||
|
||||
def self.writeIniPaths(filename, hash)
|
||||
# Write to new file then rename over top.
|
||||
sections = {}
|
||||
hash.each_pair do |path, value|
|
||||
section, _, key = path.rpartition '/'
|
||||
section_lc = section.downcase
|
||||
sections[section_lc] = {name: section, written: [], keys: {}} unless sections.key? section_lc
|
||||
sections[section_lc][:keys][key.downcase] = [key, value]
|
||||
end
|
||||
current_section = sections[""]
|
||||
temp_name = "#{filename}.tmp"
|
||||
IniWriter.open temp_name do |iw|
|
||||
IniReader.open filename do |ir|
|
||||
ir.read do |type, *args|
|
||||
case type
|
||||
when :section
|
||||
# Write new keys before leaving section
|
||||
if !current_section.nil? then
|
||||
current_section[:keys].each_value {|key, value| iw.writeKey key, value}
|
||||
current_section[:written].push *current_section[:keys].keys
|
||||
current_section[:keys].clear
|
||||
end
|
||||
# new section
|
||||
iw.writeSection ir.section
|
||||
current_section = sections[ir.section_lc]
|
||||
when :key
|
||||
fkey, fval = *args
|
||||
fkey_lc = fkey.downcase
|
||||
# Replace matching key
|
||||
if !current_section.nil? then
|
||||
replacement = current_section[:keys].delete fkey_lc
|
||||
if !replacement.nil? then
|
||||
iw.writeKey *replacement unless replacement[1].nil?
|
||||
current_section[:written].push fkey_lc
|
||||
next
|
||||
elsif current_section[:written].include? fkey_lc then
|
||||
next
|
||||
end
|
||||
end
|
||||
# Copy other keys
|
||||
iw.writeKey fkey, fval
|
||||
when :eof
|
||||
# Add sections not previously seen
|
||||
sections.each_value do |sect|
|
||||
if !sect[:keys].empty? then
|
||||
iw.writeSection sect[:name]
|
||||
sect[:keys].each_value do |key, value|
|
||||
iw.writeKey key, value
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
iw.forward type, *args
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
File.rename(temp_name, filename)
|
||||
end
|
||||
end
|
||||
end
|
130
mkxp-z/Kawariki-patches/libs/Win32API.rb
Normal file
130
mkxp-z/Kawariki-patches/libs/Win32API.rb
Normal file
|
@ -0,0 +1,130 @@
|
|||
=begin
|
||||
Win32API emulation
|
||||
|
||||
MKXP-Z exposes an implementation of the Win32API module (called MiniFFI) by default.
|
||||
However, this alias is only actually useful on Windows. Therefore, we replace it
|
||||
with a pure-ruby version specifically implementing the most common imports.
|
||||
Real native libraries can still be accessed through MiniFII.new (e.g. in ports)
|
||||
|
||||
Lambdas are used for implementations as they replicate Win32API's #call interface.
|
||||
=end
|
||||
|
||||
# Don't expose MiniFFI as Win32API
|
||||
Object.remove_const :Win32API
|
||||
|
||||
module Win32API
|
||||
module Kernel32
|
||||
GetPrivateProfileInt = GetPrivateProfileIntA = ->(appname, keyname, default, filename) do
|
||||
Preload.require "PreloadIni.rb"
|
||||
s = Preload::Ini.readIniString filename, appname, keyname
|
||||
s.nil? ? default : s.to_i
|
||||
end
|
||||
GetPrivateProfileString = GetPrivateProfileStringA = ->(appname, keyname, default, ret, size, filename) do
|
||||
Preload.require "PreloadIni.rb"
|
||||
if appname.nil? then
|
||||
res = Preload::Ini.readIniSections(filename).join("\0") + "\0"
|
||||
elsif keyname.nil? then
|
||||
res = Preload::Ini.readIniKeys(filename, appname).join("\0") + "\0"
|
||||
else
|
||||
s = Preload::Ini.readIniString filename, appname, keyname
|
||||
res = s.nil? ? (default.nil? ? "" : default) : s
|
||||
end
|
||||
# C-String dance
|
||||
size -= 1
|
||||
if res.size > size then
|
||||
res.slice!(size...)
|
||||
res[size-1] = "\0" if appname.nil? or keyname.nil?
|
||||
end
|
||||
ret[...res.size] = res
|
||||
ret[res.size] = "\0"
|
||||
res.size
|
||||
end
|
||||
WritePrivateProfileString = WritePrivateProfileStringA = ->(appname, keyname, value, filename) do
|
||||
Preload.require "PreloadIni.rb"
|
||||
Preload::Ini.writeIniString filename, appname, keyname, value
|
||||
end
|
||||
end
|
||||
|
||||
module User32
|
||||
FindWindow = FindWindowA = ->(cls, wnd) do
|
||||
return 1
|
||||
end
|
||||
FindWindowEx = ->(parent, ca, cls, wnd) do
|
||||
return 1
|
||||
end
|
||||
GetAsyncKeyState = ->(key) do
|
||||
# Very naive
|
||||
return 128 if Input.pressex? key
|
||||
return 0
|
||||
end
|
||||
GetClientRect = ->(hWnd, out_rect) do
|
||||
return 0 unless hWnd == 1
|
||||
# out_rect.byteslice(0, 16, [0, 0, Graphics.width, Graphics.height].pack("llll"))
|
||||
out_rect[0, 16] = [0, 0, Graphics.width, Graphics.height].pack("llll")
|
||||
return 1
|
||||
end
|
||||
GetCursorPos = ->(out_point) do
|
||||
# Pack mouse coordinates into a binary string
|
||||
packed_coords = [Input.mouse_x, Input.mouse_y].pack("ll")
|
||||
|
||||
# Update the out_point string with the packed data (overwrite first 8 bytes)
|
||||
out_point[0, 8] = packed_coords
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
|
||||
GetKeyboardLayout = ->(thread) do
|
||||
return 0
|
||||
end
|
||||
GetSystemMetrics = ->(index) do
|
||||
return Graphics.width if index == 0 # SM_CXSCREEN - Primary screen width
|
||||
return Graphics.height if index == 1 # SM_CYSCREEN - Primary screen height
|
||||
return 0 if index == 4 # SM_CYCAPTION - Height of caption area (title bar?)
|
||||
return 0 if index == 5 # SM_CXBORDER - Width of window borders
|
||||
return 0 if index == 6 # SM_CYBORDER - Height of window borders
|
||||
return 0 if index == 23 # SM_SWAPBUTTON - Swap left/right mouse buttons
|
||||
return 0 if index == 45 # SM_CXEDGE - Width of 3D window borders
|
||||
Preload.print("Warning: user32#GetSystemMetrics index #{index} not implemented")
|
||||
return 0
|
||||
end
|
||||
GetWindowRect = ->(hWnd, out_rect) do
|
||||
return 0 unless hWnd == 1
|
||||
# out_rect.byteslice(0, 16, [0, 0, Graphics.width, Graphics.height].pack("llll"))
|
||||
out_rect[0, 16] = [0, 0, Graphics.width, Graphics.height].pack("llll")
|
||||
return 1
|
||||
end
|
||||
MapVirtualKeyEx = ->(code, map, layout) do
|
||||
return 0 unless layout == 0
|
||||
return code
|
||||
end
|
||||
ScreenToClient = ->(hWnd, point) do
|
||||
return 1 unless hWnd != 1
|
||||
return 0
|
||||
end
|
||||
ShowCursor = ->(show) do
|
||||
Graphics.show_cursor = show == 1
|
||||
return show
|
||||
end
|
||||
end
|
||||
|
||||
module SteamAPI
|
||||
# TODO: Forward to native steamapi?
|
||||
SteamAPI_Init = ->{1}
|
||||
SteamAPI_Shutdown = ->{}
|
||||
end
|
||||
|
||||
Libraries = {
|
||||
"kernel32" => Kernel32,
|
||||
"user32" => User32,
|
||||
"steam_api" => SteamAPI,
|
||||
}
|
||||
|
||||
def self.new(dllname, func, *rest)
|
||||
dllname = dllname[...-4] if dllname[...-4] == ".dll"
|
||||
lib = Libraries[dllname]
|
||||
return lib.const_get(func, false) if lib.const_defined?(func, false) unless lib.nil?
|
||||
Preload.print("Warning: Win32API not implemented: #{dllname}##{func}")
|
||||
return ->(*args){Preload.print "(STUB) #{dllname}##{func}: #{args}"}
|
||||
end
|
||||
end
|
346
mkxp-z/Kawariki-patches/libs/Win32APIl.rb
Normal file
346
mkxp-z/Kawariki-patches/libs/Win32APIl.rb
Normal file
|
@ -0,0 +1,346 @@
|
|||
=begin
|
||||
Win32API emulation
|
||||
|
||||
MKXP-Z exposes an implementation of the Win32API module (called MiniFFI) by default.
|
||||
However, this alias is only actually useful on Windows. Therefore, we replace it
|
||||
with a pure-ruby version specifically implementing the most common imports.
|
||||
Real native libraries can still be accessed through MiniFII.new (e.g. in ports)
|
||||
|
||||
Lambdas are used for implementations as they replicate Win32API's #call interface.
|
||||
=end
|
||||
|
||||
|
||||
module Scancodes
|
||||
SDL = { :UNKNOWN => 0x00,
|
||||
:A => 0x04, :B => 0x05, :C => 0x06, :D => 0x07,
|
||||
:E => 0x08, :F => 0x09, :G => 0x0A, :H => 0x0B,
|
||||
:I => 0x0C, :J => 0x0D, :K => 0x0E, :L => 0x0F,
|
||||
:M => 0x10, :N => 0x11, :O => 0x12, :P => 0x13,
|
||||
:Q => 0x14, :R => 0x15, :S => 0x16, :T => 0x17,
|
||||
:U => 0x18, :V => 0x19, :W => 0x1A, :X => 0x1B,
|
||||
:Y => 0x1C, :Z => 0x1D, :N1 => 0x1E, :N2 => 0x1F,
|
||||
:N3 => 0x20, :N4 => 0x21, :N5 => 0x22, :N6 => 0x23,
|
||||
:N7 => 0x24, :N8 => 0x25, :N9 => 0x26, :N0 => 0x27,
|
||||
:RETURN => 0x28, :ESCAPE => 0x29, :BACKSPACE => 0x2A, :TAB => 0x2B,
|
||||
:SPACE => 0x2C, :MINUS => 0x2D, :EQUALS => 0x2E, :LEFTBRACKET => 0x2F,
|
||||
:RIGHTBRACKET => 0x30, :BACKSLASH => 0x31, :NONUSHASH => 0x32, :SEMICOLON => 0x33,
|
||||
:APOSTROPHE => 0x34, :GRAVE => 0x35, :COMMA => 0x36, :PERIOD => 0x37,
|
||||
:SLASH => 0x38, :CAPSLOCK => 0x39, :F1 => 0x3A, :F2 => 0x3B,
|
||||
:F3 => 0x3C, :F4 => 0x3D, :F5 => 0x3E, :F6 => 0x3F,
|
||||
:F7 => 0x40, :F8 => 0x41, :F9 => 0x42, :F10 => 0x43,
|
||||
:F11 => 0x44, :F12 => 0x45, :PRINTSCREEN => 0x46, :SCROLLLOCK => 0x47,
|
||||
:PAUSE => 0x48, :INSERT => 0x49, :HOME => 0x4A, :PAGEUP => 0x4B,
|
||||
:DELETE => 0x4C, :END => 0x4D, :PAGEDOWN => 0x4E, :RIGHT => 0x4F,
|
||||
:LEFT => 0x50, :DOWN => 0x51, :UP => 0x52, :NUMLOCKCLEAR => 0x53,
|
||||
:KP_DIVIDE => 0x54, :KP_MULTIPLY => 0x55, :KP_MINUS => 0x56, :KP_PLUS => 0x57,
|
||||
:KP_ENTER => 0x58, :KP_1 => 0x59, :KP_2 => 0x5A, :KP_3 => 0x5B,
|
||||
:KP_4 => 0x5C, :KP_5 => 0x5D, :KP_6 => 0x5E, :KP_7 => 0x5F,
|
||||
:KP_8 => 0x60, :KP_9 => 0x61, :KP_0 => 0x62, :KP_PERIOD => 0x63,
|
||||
:NONUSBACKSLASH => 0x64, :APPLICATION => 0x65, :POWER => 0x66, :KP_EQUALS => 0x67,
|
||||
:F13 => 0x68, :F14 => 0x69, :F15 => 0x6A, :F16 => 0x6B,
|
||||
:F17 => 0x6C, :F18 => 0x6D, :F19 => 0x6E, :F20 => 0x6F,
|
||||
:F21 => 0x70, :F22 => 0x71, :F23 => 0x72, :F24 => 0x73,
|
||||
:EXECUTE => 0x74, :HELP => 0x75, :MENU => 0x76, :SELECT => 0x77,
|
||||
:STOP => 0x78, :AGAIN => 0x79, :UNDO => 0x7A, :CUT => 0x7B,
|
||||
:COPY => 0x7C, :PASTE => 0x7D, :FIND => 0x7E, :MUTE => 0x7F,
|
||||
:VOLUMEUP => 0x80, :VOLUMEDOWN => 0x81, :LOCKINGCAPSLOCK => 0x82, :LOCKINGNUMLOCK => 0x83,
|
||||
:LOCKINGSCROLLLOCK => 0x84, :KP_COMMA => 0x85, :KP_EQUALSAS400 => 0x86, :INTERNATIONAL1 => 0x87,
|
||||
:INTERNATIONAL2 => 0x88, :INTERNATIONAL3 => 0x89, :INTERNATIONAL4 => 0x8A, :INTERNATIONAL5 => 0x8B,
|
||||
:INTERNATIONAL6 => 0x8C, :INTERNATIONAL7 => 0x8D, :INTERNATIONAL8 => 0x8E, :INTERNATIONAL9 => 0x8F,
|
||||
:LANG1 => 0x90, :LANG2 => 0x91, :LANG3 => 0x92, :LANG4 => 0x93,
|
||||
:LANG5 => 0x94, :LANG6 => 0x95, :LANG7 => 0x96, :LANG8 => 0x97,
|
||||
:LANG9 => 0x98, :ALTERASE => 0x99, :SYSREQ => 0x9A, :CANCEL => 0x9B,
|
||||
:CLEAR => 0x9C, :PRIOR => 0x9D, :RETURN2 => 0x9E, :SEPARATOR => 0x9F,
|
||||
:OUT => 0xA0, :OPER => 0xA1, :CLEARAGAIN => 0xA2, :CRSEL => 0xA3,
|
||||
:EXSEL => 0xA4, :KP_00 => 0xB0, :KP_000 => 0xB1, :THOUSANDSSEPARATOR => 0xB2,
|
||||
:DECIMALSEPARATOR => 0xB3, :CURRENCYUNIT => 0xB4, :CURRENCYSUBUNIT => 0xB5, :KP_LEFTPAREN => 0xB6,
|
||||
:KP_RIGHTPAREN => 0xB7, :KP_LEFTBRACE => 0xB8, :KP_RIGHTBRACE => 0xB9, :KP_TAB => 0xBA,
|
||||
:KP_BACKSPACE => 0xBB, :KP_A => 0xBC, :KP_B => 0xBD, :KP_C => 0xBE,
|
||||
:KP_D => 0xBF, :KP_E => 0xC0, :KP_F => 0xC1, :KP_XOR => 0xC2,
|
||||
:KP_POWER => 0xC3, :KP_PERCENT => 0xC4, :KP_LESS => 0xC5, :KP_GREATER => 0xC6,
|
||||
:KP_AMPERSAND => 0xC7, :KP_DBLAMPERSAND => 0xC8, :KP_VERTICALBAR => 0xC9, :KP_DBLVERTICALBAR => 0xCA,
|
||||
:KP_COLON => 0xCB, :KP_HASH => 0xCC, :KP_SPACE => 0xCD, :KP_AT => 0xCE,
|
||||
:KP_EXCLAM => 0xCF, :KP_MEMSTORE => 0xD0, :KP_MEMRECALL => 0xD1, :KP_MEMCLEAR => 0xD2,
|
||||
:KP_MEMADD => 0xD3, :KP_MEMSUBTRACT => 0xD4, :KP_MEMMULTIPLY => 0xD5, :KP_MEMDIVIDE => 0xD6,
|
||||
:KP_PLUSMINUS => 0xD7, :KP_CLEAR => 0xD8, :KP_CLEARENTRY => 0xD9, :KP_BINARY => 0xDA,
|
||||
:KP_OCTAL => 0xDB, :KP_DECIMAL => 0xDC, :KP_HEXADECIMAL => 0xDD, :LCTRL => 0xE0,
|
||||
:LSHIFT => 0xE1, :LALT => 0xE2, :LGUI => 0xE3, :RCTRL => 0xE4,
|
||||
:RSHIFT => 0xE5, :RALT => 0xE6, :RGUI => 0xE7, :MODE => 0x101,
|
||||
:AUDIONEXT => 0x102, :AUDIOPREV => 0x103, :AUDIOSTOP => 0x104, :AUDIOPLAY => 0x105,
|
||||
:AUDIOMUTE => 0x106, :MEDIASELECT => 0x107, :WWW => 0x108, :MAIL => 0x109,
|
||||
:CALCULATOR => 0x10A, :COMPUTER => 0x10B, :AC_SEARCH => 0x10C, :AC_HOME => 0x10D,
|
||||
:AC_BACK => 0x10E, :AC_FORWARD => 0x10F, :AC_STOP => 0x110, :AC_REFRESH => 0x111,
|
||||
:AC_BOOKMARKS => 0x112, :BRIGHTNESSDOWN => 0x113, :BRIGHTNESSUP => 0x114, :DISPLAYSWITCH => 0x115,
|
||||
:KBDILLUMTOGGLE => 0x116, :KBDILLUMDOWN => 0x117, :KBDILLUMUP => 0x118, :EJECT => 0x119,
|
||||
:SLEEP => 0x11A, :APP1 => 0x11B, :APP2 => 0x11C
|
||||
}
|
||||
|
||||
SDL.default = SDL[:UNKNOWN]
|
||||
|
||||
WIN32 = {
|
||||
:LBUTTON => 0x01, :RBUTTON => 0x02, :MBUTTON => 0x04,
|
||||
|
||||
:BACK => 0x08, :TAB => 0x09, :RETURN => 0x0D, :SHIFT => 0x10,
|
||||
:CONTROL => 0x11, :MENU => 0x12, :PAUSE => 0x13, :CAPITAL => 0x14,
|
||||
:ESCAPE => 0x1B, :SPACE => 0x20, :PRIOR => 0x21, :NEXT => 0x22,
|
||||
:END => 0x23, :HOME => 0x24, :LEFT => 0x25, :UP => 0x26,
|
||||
:RIGHT => 0x27, :DOWN => 0x28, :PRINT => 0x2A, :INSERT => 0x2D,
|
||||
:DELETE => 0x2E,
|
||||
|
||||
:N0 => 0x30, :N1 => 0x31, :N2 => 0x32, :N3 => 0x33,
|
||||
:N4 => 0x34, :N5 => 0x35, :N6 => 0x36, :N7 => 0x37, :N8 => 0x38,
|
||||
:N9 => 0x39,
|
||||
|
||||
:A => 0x41, :B => 0x42, :C => 0x43, :D => 0x44, :E => 0x45, :F => 0x46,
|
||||
:G => 0x47, :H => 0x48, :I => 0x49, :J => 0x4A, :K => 0x4B, :L => 0x4C,
|
||||
:M => 0x4D, :N => 0x4E, :O => 0x4F, :P => 0x50, :Q => 0x51, :R => 0x52,
|
||||
:S => 0x53, :T => 0x54, :U => 0x55, :V => 0x56, :W => 0x57, :X => 0x58,
|
||||
:Y => 0x59, :Z => 0x5A,
|
||||
|
||||
:LWIN => 0x5B, :RWIN => 0x5C,
|
||||
|
||||
:NUMPAD0 => 0x60, :NUMPAD1 => 0x61, :NUMPAD2 => 0x62, :NUMPAD3 => 0x63,
|
||||
:NUMPAD4 => 0x64, :NUMPAD5 => 0x65, :NUMPAD6 => 0x66, :NUMPAD7 => 0x67,
|
||||
:NUMPAD8 => 0x68, :NUMPAD9 => 0x69,
|
||||
:MULTIPLY => 0x6A, :ADD => 0x6B, :SEPARATOR => 0x6C, :SUBSTRACT => 0x6D,
|
||||
:DECIMAL => 0x6E, :DIVIDE => 0x6F,
|
||||
|
||||
:F1 => 0x70, :F2 => 0x71, :F3 => 0x72, :F4 => 0x73,
|
||||
:F5 => 0x74, :F6 => 0x75, :F7 => 0x76, :F8 => 0x77,
|
||||
:F9 => 0x78, :F10 => 0x79, :F11 => 0x7A, :F12 => 0x7B,
|
||||
:F13 => 0x7C, :F14 => 0x7D, :F15 => 0x7E, :F16 => 0x7F,
|
||||
:F17 => 0x80, :F18 => 0x81, :F19 => 0x82, :F20 => 0x83,
|
||||
:F21 => 0x84, :F22 => 0x85, :F23 => 0x86, :F24 => 0x87,
|
||||
|
||||
:NUMLOCK => 0x90, :SCROLL => 0x91,
|
||||
:LSHIFT => 0xA0, :RSHIFT => 0xA1, :LCONTROL => 0xA2, :RCONTROL => 0xA3,
|
||||
:LMENU => 0xA4, :RMENU => 0xA5, :OEM_1 => 0xBA,
|
||||
:OEM_PLUS => 0xBB, :OEM_COMMA => 0xBC, :OEM_MINUS => 0xBD, :OEM_PERIOD => 0xBE,
|
||||
:OEM_2 => 0xBF, :OEM_3 => 0xC0, :OEM_4 => 0xDB, :OEM_5 => 0xDC,
|
||||
:OEM_6 => 0xDD, :OEM_7 => 0xDE
|
||||
}
|
||||
|
||||
WIN32INV = WIN32.invert
|
||||
|
||||
WIN2SDL = {
|
||||
:BACK => :BACKSPACE,
|
||||
:CAPITAL => :CAPSLOCK,
|
||||
:PRIOR => :PAGEUP, :NEXT => :PAGEDOWN,
|
||||
:PRINT => :PRINTSCREEN,
|
||||
|
||||
:LWIN => :LGUI, :RWIN => :RGUI,
|
||||
|
||||
:NUMPAD0 => :KP_0, :NUMPAD1 => :KP_1, :NUMPAD2 => :KP_2, :NUMPAD3 => :KP_3,
|
||||
:NUMPAD4 => :KP_4, :NUMPAD5 => :KP_5, :NUMPAD6 => :KP_6, :NUMPAD7 => :KP_7,
|
||||
:NUMPAD8 => :KP_8, :NUMPAD9 => :KP_9,
|
||||
:MULTIPLY => :KP_MULTIPLY, :ADD => :KP_PLUS, :SUBSTRACT => :KP_MINUS,
|
||||
:DECIMAL => :KP_DECIMAL, :DIVIDE => :KP_DIVIDE,
|
||||
|
||||
:NUMLOCK => :NUMLOCKCLEAR, :SCROLL => :SCROLLLOCK,
|
||||
:LCONTROL => :LCTRL, :RCONTROL => :RCTRL,
|
||||
# FIXME: Fill these out
|
||||
:LMENU => :LALT, :RMENU => :RALT, :OEM_1 => :SEMICOLON,
|
||||
:OEM_PLUS => :UNKNOWN, :OEM_COMMA => :UNKNOWN, :OEM_MINUS => :UNKNOWN, :OEM_PERIOD => :UNKNOWN,
|
||||
:OEM_2 => :UNKNOWN, :OEM_3 => :UNKNOWN, :OEM_4 => :UNKNOWN, :OEM_5 => :UNKNOWN,
|
||||
:OEM_6 => :UNKNOWN, :OEM_7 => :UNKNOWN
|
||||
}
|
||||
|
||||
WIN2SDL.default = :UNKNOWN
|
||||
end
|
||||
|
||||
$win32KeyStates = nil
|
||||
|
||||
module Graphics
|
||||
class << self
|
||||
alias_method(:win32wrap_update, :update)
|
||||
def update
|
||||
win32wrap_update
|
||||
$win32KeyStates = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_raw_keystates
|
||||
if $win32KeyStates == nil
|
||||
$win32KeyStates = Input.raw_key_states
|
||||
end
|
||||
|
||||
return $win32KeyStates
|
||||
end
|
||||
|
||||
def common_keystate(vkey)
|
||||
vkey_name = Scancodes::WIN32INV[vkey]
|
||||
|
||||
states = get_raw_keystates
|
||||
pressed = false
|
||||
|
||||
if vkey_name == :LBUTTON
|
||||
pressed = Input.press?(Input::MOUSELEFT)
|
||||
elsif vkey_name == :RBUTTON
|
||||
pressed = Input.press?(Input::MOUSERIGHT)
|
||||
elsif vkey_name == :MBUTTON
|
||||
pressed = Input.press?(Input::MOUSEMIDDLE)
|
||||
elsif vkey_name == :SHIFT
|
||||
pressed = double_state(states, :LSHIFT, :RSHIFT)
|
||||
elsif vkey_name == :MENU
|
||||
pressed = double_state(states, :LALT, :RALT)
|
||||
elsif vkey_name == :CONTROL
|
||||
pressed = double_state(states, :LCTRL, :RCTRL)
|
||||
else
|
||||
scan = nil
|
||||
if Scancodes::SDL.key?(vkey_name)
|
||||
scan = vkey_name
|
||||
else
|
||||
scan = Scancodes::WIN2SDL[vkey_name]
|
||||
end
|
||||
|
||||
pressed = state_pressed(states, scan)
|
||||
end
|
||||
|
||||
return pressed ? 1 : 0
|
||||
end
|
||||
|
||||
def memcpy_string(dst, src)
|
||||
i = 0
|
||||
src.each_byte do |b|
|
||||
dst.setbyte(i, b)
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
|
||||
def state_pressed(states, sdl_scan)
|
||||
return states[Scancodes::SDL[sdl_scan]]
|
||||
end
|
||||
|
||||
def double_state(states, left, right)
|
||||
return state_pressed(states, left) || state_pressed(states, right)
|
||||
end
|
||||
|
||||
# Don't expose MiniFFI as Win32API
|
||||
Object.remove_const :Win32API
|
||||
|
||||
module Win32API
|
||||
module Kernel32
|
||||
GetPrivateProfileInt = GetPrivateProfileIntA = ->(appname, keyname, default, filename) do
|
||||
Preload.require "PreloadIni.rb"
|
||||
s = Preload::Ini.readIniString filename, appname, keyname
|
||||
s.nil? ? default : s.to_i
|
||||
end
|
||||
GetPrivateProfileString = GetPrivateProfileStringA = ->(appname, keyname, default, ret, size, filename) do
|
||||
Preload.require "PreloadIni.rb"
|
||||
if appname.nil? then
|
||||
res = Preload::Ini.readIniSections(filename).join("\0") + "\0"
|
||||
elsif keyname.nil? then
|
||||
res = Preload::Ini.readIniKeys(filename, appname).join("\0") + "\0"
|
||||
else
|
||||
s = Preload::Ini.readIniString filename, appname, keyname
|
||||
res = s.nil? ? (default.nil? ? "" : default) : s
|
||||
end
|
||||
# C-String dance
|
||||
size -= 1
|
||||
if res.size > size then
|
||||
res.slice!(size...)
|
||||
res[size-1] = "\0" if appname.nil? or keyname.nil?
|
||||
end
|
||||
ret[...res.size] = res
|
||||
ret[res.size] = "\0"
|
||||
res.size
|
||||
end
|
||||
WritePrivateProfileString = WritePrivateProfileStringA = ->(appname, keyname, value, filename) do
|
||||
Preload.require "PreloadIni.rb"
|
||||
Preload::Ini.writeIniString filename, appname, keyname, value
|
||||
end
|
||||
MultiByteToWideChar = MultiByteToWideCharA = ->(codepage, flags, input_str, input_len, buffer, buffer_size) do
|
||||
puts codepage, flags, input_str, input_len, buffer, buffer_size
|
||||
|
||||
#Preload.require "PreloadIni.rb"
|
||||
#Preload::Ini.writeIniString filename, appname, keyname, value
|
||||
end
|
||||
end
|
||||
|
||||
module User32
|
||||
FindWindow = FindWindowA = ->(cls, wnd) do
|
||||
return 1
|
||||
end
|
||||
FindWindowEx = ->(parent, ca, cls, wnd) do
|
||||
return 1
|
||||
end
|
||||
GetAsyncKeyState = ->(key) do
|
||||
# Very naive
|
||||
return 128 if Input.pressex? key
|
||||
return 0
|
||||
end
|
||||
GetClientRect = ->(hWnd, out_rect) do
|
||||
return 0 unless hWnd == 1
|
||||
# out_rect.byteslice(0, 16, [0, 0, Graphics.width, Graphics.height].pack("llll"))
|
||||
out_rect[0, 16] = [0, 0, Graphics.width, Graphics.height].pack("llll")
|
||||
return 1
|
||||
end
|
||||
GetCursorPos = ->(out_point) do
|
||||
# Pack mouse coordinates into a binary string
|
||||
packed_coords = [Input.mouse_x, Input.mouse_y].pack("ll")
|
||||
|
||||
# Update the out_point string with the packed data (overwrite first 8 bytes)
|
||||
out_point[0, 8] = packed_coords
|
||||
|
||||
return 1
|
||||
end
|
||||
GetKeyState = ->(vkey) do
|
||||
puts 'bbb'
|
||||
return common_keystate(vkey[0])
|
||||
end
|
||||
|
||||
GetKeyboardLayout = ->(thread) do
|
||||
return 0
|
||||
end
|
||||
GetSystemMetrics = ->(index) do
|
||||
return Graphics.width if index == 0 # SM_CXSCREEN - Primary screen width
|
||||
return Graphics.height if index == 1 # SM_CYSCREEN - Primary screen height
|
||||
return 0 if index == 4 # SM_CYCAPTION - Height of caption area (title bar?)
|
||||
return 0 if index == 5 # SM_CXBORDER - Width of window borders
|
||||
return 0 if index == 6 # SM_CYBORDER - Height of window borders
|
||||
return 0 if index == 23 # SM_SWAPBUTTON - Swap left/right mouse buttons
|
||||
return 0 if index == 45 # SM_CXEDGE - Width of 3D window borders
|
||||
Preload.print("Warning: user32#GetSystemMetrics index #{index} not implemented")
|
||||
return 0
|
||||
end
|
||||
GetWindowRect = ->(hWnd, out_rect) do
|
||||
return 0 unless hWnd == 1
|
||||
# out_rect.byteslice(0, 16, [0, 0, Graphics.width, Graphics.height].pack("llll"))
|
||||
out_rect[0, 16] = [0, 0, Graphics.width, Graphics.height].pack("llll")
|
||||
return 1
|
||||
end
|
||||
MapVirtualKeyEx = ->(code, map, layout) do
|
||||
return 0 unless layout == 0
|
||||
return code
|
||||
end
|
||||
ScreenToClient = ->(hWnd, point) do
|
||||
return 1 unless hWnd != 1
|
||||
return 0
|
||||
end
|
||||
ShowCursor = ->(show) do
|
||||
Graphics.show_cursor = show == 1
|
||||
return show
|
||||
end
|
||||
end
|
||||
|
||||
module SteamAPI
|
||||
# TODO: Forward to native steamapi?
|
||||
SteamAPI_Init = ->{1}
|
||||
SteamAPI_Shutdown = ->{}
|
||||
end
|
||||
|
||||
Libraries = {
|
||||
"kernel32" => Kernel32,
|
||||
"user32" => User32,
|
||||
"steam_api" => SteamAPI,
|
||||
}
|
||||
|
||||
def self.new(dllname, func, *rest)
|
||||
dllname = dllname[...-4] if dllname[...-4] == ".dll"
|
||||
lib = Libraries[dllname]
|
||||
return lib.const_get(func, false) if lib.const_defined?(func, false) unless lib.nil?
|
||||
Preload.print("Warning: Win32API not implemented: #{dllname}##{func}")
|
||||
return ->(*args){Preload.print "(STUB) #{dllname}##{func}: #{args}"}
|
||||
end
|
||||
end
|
136
mkxp-z/Kawariki-patches/libs/XP_TilemapOverrideLib.rb
Normal file
136
mkxp-z/Kawariki-patches/libs/XP_TilemapOverrideLib.rb
Normal file
|
@ -0,0 +1,136 @@
|
|||
# ======================================================================
|
||||
# MKXP-Z Custom tilemap workaround tools
|
||||
#
|
||||
# Authors: Roza, Taeyeon Mori
|
||||
#
|
||||
# Contains library code only, must be added to custom
|
||||
# tilemap classes using a preload patch or similar.
|
||||
# ======================================================================
|
||||
# SUPER TILEMAP VERTICAL WRAPPER THING
|
||||
#
|
||||
# This is a little fix for Pokemon Essentials' custom tilemap code
|
||||
# that works around MKXP's GPU texture size limit that would normally
|
||||
# stop you from playing a lot of games.
|
||||
#
|
||||
# The concept is simple enough: If your tileset is too big, a new
|
||||
# bitmap will be constructed with all the excess pixels sent to the
|
||||
# image's right side. This basically means that you now have a limit
|
||||
# far higher than you should ever actually need.
|
||||
#
|
||||
# 1024 -> 4096
|
||||
# 2048 -> 16384 (enough to get the normal limit)
|
||||
# 4096 -> 65536 (enough to load pretty much any tileset)
|
||||
# 8192 -> 262144
|
||||
# 16384 -> 1048576 (what most people have at this point)
|
||||
#
|
||||
# Because of the extra math the game will have to do to find the right
|
||||
# pixels, this will probably cause a slight performance hit while on these
|
||||
# maps which would normally be megasurfaces.
|
||||
#
|
||||
# This script was written for games based on 17.1. This workaround is
|
||||
# already implemented in 19.
|
||||
#
|
||||
# ~Roza/Zoroark
|
||||
#=======================================================================
|
||||
|
||||
module TileWrap
|
||||
|
||||
MAX_TEX_SIZE = Bitmap.max_size
|
||||
TILESET_WIDTH = 0x100
|
||||
MAX_TEX_SIZE_BOOSTED = MAX_TEX_SIZE**2/TILESET_WIDTH
|
||||
|
||||
def self.clamp(val, min, max)
|
||||
val = max if val > max
|
||||
val = min if val < min
|
||||
return val
|
||||
end
|
||||
|
||||
def self.wrapTileset(originalbmp)
|
||||
width = originalbmp.width
|
||||
height = originalbmp.height
|
||||
if width == TILESET_WIDTH && originalbmp.mega?
|
||||
columns = (height / MAX_TEX_SIZE.to_f).ceil
|
||||
|
||||
if columns * TILESET_WIDTH > MAX_TEX_SIZE
|
||||
raise "Tilemap is too long!\n\nSIZE: #{originalbmp.height}px\nHARDWARE LIMIT: #{MAX_TEX_SIZE}px\nBOOSTED LIMIT: #{MAX_TEX_SIZE_BOOSTED}px"
|
||||
end
|
||||
bmp = Bitmap.new(TILESET_WIDTH*columns, MAX_TEX_SIZE)
|
||||
remainder = height % MAX_TEX_SIZE
|
||||
|
||||
columns.times{|col|
|
||||
srcrect = Rect.new(0, col * MAX_TEX_SIZE, width, (col + 1 == columns) ? remainder : MAX_TEX_SIZE)
|
||||
bmp.blt(col*TILESET_WIDTH, 0, originalbmp, srcrect)
|
||||
}
|
||||
return bmp
|
||||
end
|
||||
|
||||
return originalbmp
|
||||
end
|
||||
|
||||
def self.wrapRect(srcrect)
|
||||
column, y = srcrect.y.divmod MAX_TEX_SIZE
|
||||
raise "Rect split across column wrap!" if y + srcrect.height > MAX_TEX_SIZE
|
||||
return srcrect if column == 0
|
||||
Rect.new(column * MAX_TEX_SIZE + srcrect.x, y, srcrect.width, srcrect.height)
|
||||
end
|
||||
|
||||
def self.wrapRect!(rect)
|
||||
column, y = rect.y.divmod MAX_TEX_SIZE
|
||||
raise "Rect split across column wrap!" if y + rect.height > MAX_TEX_SIZE
|
||||
return if column == 0
|
||||
rect.x = column * MAX_TEX_SIZE + rect.x
|
||||
rect.y = y
|
||||
end
|
||||
|
||||
def self.blitWrappedPixels(destX, destY, dest, src, srcrect)
|
||||
if (srcrect.y + srcrect.width < MAX_TEX_SIZE)
|
||||
# Save the processing power
|
||||
return dest.blt(destX, destY, src, srcrect)
|
||||
end
|
||||
merge = (srcrect.y % MAX_TEX_SIZE) > ((srcrect.y + srcrect.height) % MAX_TEX_SIZE)
|
||||
|
||||
srcrect.x = clamp(srcrect.x, 0,TILESET_WIDTH)
|
||||
srcrect.width = clamp(srcrect.width, 0, TILESET_WIDTH - srcrect.x)
|
||||
col = (srcrect.y / MAX_TEX_SIZE.to_f).floor
|
||||
srcX = col * TILESET_WIDTH + srcrect.x
|
||||
srcY = srcrect.y % MAX_TEX_SIZE
|
||||
|
||||
if !merge
|
||||
dest.blt(destX, destY, src, Rect.new(srcX, srcY, srcrect.width, srcrect.height))
|
||||
else
|
||||
#FIXME won't work on heights longer than two columns, but nobody should need
|
||||
# more than 32k pixels high at once anyway
|
||||
side = {:a => MAX_TEX_SIZE - srcY, :b => srcrect.height - (MAX_TEX_SIZE - srcY)}
|
||||
dest.blt(destX, destY, src, Rect.new(srcX, srcY, srcrect.width, side[:a]))
|
||||
dest.blt(destX, destY + side[:a], src, Rect.new(srcX + TILESET_WIDTH, 0, srcrect.width, side[:b]))
|
||||
end
|
||||
end
|
||||
|
||||
# May be applied using Module#prepend
|
||||
# it's probably better to integrate custom tilemap code manually
|
||||
# XXX: is it OK to dispose of the original bitmaps?
|
||||
module TilemapPatch
|
||||
def tileset=(value)
|
||||
if value.mega?
|
||||
super TileWrap::wrapTileset value
|
||||
value.dispose
|
||||
else
|
||||
super value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module SpritePatch
|
||||
def bitmap=(bmp)
|
||||
if bmp.mega?
|
||||
super TileWrap.wrapTileset bmp
|
||||
bmp.dispose
|
||||
else
|
||||
super bmp
|
||||
end
|
||||
end
|
||||
def src_rect=(rect)
|
||||
super TileWrap.wrapRect rect
|
||||
end
|
||||
end
|
||||
end
|
71
mkxp-z/Kawariki-patches/libs/ruby18.rb
Normal file
71
mkxp-z/Kawariki-patches/libs/ruby18.rb
Normal file
|
@ -0,0 +1,71 @@
|
|||
# Ruby 1.8 compat
|
||||
module Ruby18
|
||||
module ObjectPatch
|
||||
# Object#type used to be an alias to Object#class
|
||||
def type
|
||||
self.class
|
||||
end
|
||||
end
|
||||
|
||||
class IncludeStringArray < Array
|
||||
def include?(thing)
|
||||
if thing.is_a?(String) then
|
||||
super(thing.to_sym)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module KernelPatch
|
||||
# Used to return a string array
|
||||
def methods(*)
|
||||
IncludeStringArray.new super
|
||||
end
|
||||
|
||||
def singleton_methods(*)
|
||||
IncludeStringArray.new super
|
||||
end
|
||||
end
|
||||
|
||||
module ModulePatch
|
||||
# Used to return string array.
|
||||
# Fix instance_methods.include? use-case by patching it to work with strings
|
||||
# The array will still be of symbols however
|
||||
def instance_methods(*)
|
||||
IncludeStringArray.new super
|
||||
end
|
||||
|
||||
def public_instance_methods(*)
|
||||
IncludeStringArray.new super
|
||||
end
|
||||
|
||||
def private_instance_methods(*)
|
||||
IncludeStringArray.new super
|
||||
end
|
||||
end
|
||||
|
||||
module ArrayPatch
|
||||
def nitems
|
||||
count {|i| !i.nil?}
|
||||
end
|
||||
|
||||
def choice
|
||||
sample
|
||||
end
|
||||
end
|
||||
|
||||
module HashPatch
|
||||
def index(value)
|
||||
key value
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Apply Patches
|
||||
Object.prepend ObjectPatch
|
||||
Module.prepend ModulePatch
|
||||
Kernel.prepend KernelPatch
|
||||
Array.prepend ArrayPatch
|
||||
Hash.prepend HashPatch
|
||||
end
|
182
mkxp-z/Kawariki-patches/patches.rb
Normal file
182
mkxp-z/Kawariki-patches/patches.rb
Normal file
|
@ -0,0 +1,182 @@
|
|||
# Kawariki MKXP patch/port collection
|
||||
# See preload.rb for Patch implementation
|
||||
|
||||
module Preload
|
||||
Patches = [
|
||||
# Ports
|
||||
Patch.new("Zeus Fullscreen: Use mkxp builtin fullscreen instead (Alt+Enter)")
|
||||
.imported?(:Zeus_Fullscreen)
|
||||
.replace!("Zeus_Fullscreen++.rb"),
|
||||
Patch.new("Zeus_Map_Effects fix")
|
||||
.imported?(:Zeus_Map_Effects)
|
||||
.sub!(":zoom_blur_length, :motion_blur_rate", ":zoom_blur_length, :motion_blur_rate\ndef update_animation_Integer(str,str2,str3,str4,str5,str6) @wave_amp = 0.0; end"),
|
||||
Patch.new("Zeus_Lights_Shadows fix")
|
||||
.imported?(:Zeus_Lights_Shadows)
|
||||
.sub!(/^RPG_VERSION =.*/, "RPG_VERSION ="+ ENV["vcode"])
|
||||
.sub!(" def update_animation_value", "def update_animation_Integer(str,str2,str3,str4,str5) @wave_amp = 0.0; end\ndef update_animation_value"),
|
||||
Patch.new("cyanic-SteamUserStatsLite fix")
|
||||
.include?('Win32API.new(self.steam_dll_name')
|
||||
# .remove!,
|
||||
.replace!("achievements.rb"),
|
||||
Patch.new("XIV's Simple Reputation System (SRS) for RGSS3 fix") #XIV's Simple Reputation System (SRS) for RGSS3 Romance Level Version: 1.1
|
||||
.include?("Simple Reputation System (SRS)")
|
||||
.sub!("$scene1 = Scene_Menu.new(0)", "$scene1 = Scene_Menu.new"),
|
||||
Patch.new("Nergal's Item Finding patch fix") #Nergal's Item Finding
|
||||
.include?("SEARCH_TYPES = [ ITEMS_TO_FIND_PERSON, ITEMS_TO_FIND_SCHOOL,")
|
||||
.include?("$scene1 = Scene_Menu.new(0)")
|
||||
.sub!("$scene1 = Scene_Menu.new(0)", "$scene1 = Scene_Menu.new"),
|
||||
Patch.new("Nergal's XP Gain") #Nergal's XP Gain
|
||||
.include?("CustomGab.display_message(stat + XpLevel::MAX_LVL_MESSAGE)")
|
||||
.include?("$scene4 = Scene_Menu.new(0)")
|
||||
.sub!("$scene4 = Scene_Menu.new(0)", "$scene4 = Scene_Menu.new"),
|
||||
Patch.new("WF-RGSS base patch") #【WF-RGSS】共通rev29 base
|
||||
.include?("'MultiByteToWideChar', %w(i l p i p i)")
|
||||
# .remove!,
|
||||
.replace!("testencode.rb"), #Window_Base
|
||||
Patch.new("window check content height fix (mgq paradox)")
|
||||
.if? {|script| script.name == "Window_Base"}
|
||||
# .replace!("basewt.rb"),
|
||||
.sub!("if contents_width > 0 && contents_height > 0", " if contents_height > 10000\nself.contents = Bitmap.new(1, 1)\nelsif contents_width > 0 && contents_height > 0"),
|
||||
Patch.new("temp bitmap load crash fix monster girl paradox disable preview") #ベース/Module
|
||||
#maybe the memory buffer is filled up too much??
|
||||
# .if? {|script| script.name == "Window_Base"}
|
||||
.include?('thumnail_file = "Save/Save#{Regexp.last_match(1)}.png"')
|
||||
.sub!("@thumbnails[Regexp.last_match(1).to_i - 1] = Bitmap.new(thumnail_file)", "@thumbnails[Regexp.last_match(1).to_i - 1] = @dummy_thumbnail #Bitmap.new(thumnail_file)"),
|
||||
# .replace!("savebitmanwin32api.rb"),
|
||||
Patch.new("WF-RGSS Exit-EX patch test") #▼ メイン【WF-RGSS】Exit-EX 終了処理
|
||||
.include?("Win32API.new('System/WFExit','hookExit','v','l')")
|
||||
# .remove!,
|
||||
.replace!("wxexittest.rb"),
|
||||
Patch.new("HimeWorks' Event Trigger Labels: Fix any_key_pressed? implementation")
|
||||
.imported?(:TH_EventTriggerLabels)
|
||||
.replace!("TH_EventTriggerLabels.rb"),
|
||||
Patch.new("HimeWorks' Simple Audio Encryption: Re-Implement with direct path detection")
|
||||
.imported?(:TH_SimpleAudioEncryption)
|
||||
.replace!("TH_SimpleAudioEncryption.rb"),
|
||||
Patch.new("MOG_Anti_Lag: Fix visible type error")
|
||||
.imported?(:mog_anti_lag)
|
||||
.sub!("self.visible = @character.can_update", "self.visible = !!@character.can_update"),
|
||||
Patch.new("KGC_BitmapExtension ? XP/VX ? error")
|
||||
.imported?(:BitmapExtension)
|
||||
# .sub!("class Win32API", "module Win32API"),
|
||||
.remove!,
|
||||
Patch.new("Galv's Event Pop-Ups: Fix bitmap constructor call")
|
||||
.imported?("Galv_Map_Popups")
|
||||
.match?(/\.font\.shadow\s*=\s*\d+/)
|
||||
.sub!(/\.font\.shadow\s*=\s*\d+/, ".font.shadow = true"),
|
||||
Patch.new("Basic Mouse Plugin test disable for now")
|
||||
.imported?(nil)
|
||||
.if? {|script| script.name == "BasicMouse"}
|
||||
.include?("include IBasicMouse")
|
||||
.sub!("def VZ; return @curr.lZ / 120; end", "def VZ; return 0 if @curr.nil? || @curr.lZ.nil?; return @curr.lZ / 120.0 end"),
|
||||
Patch.new("Screenshot plugin")
|
||||
.imported?(nil)
|
||||
.include?('SAVE_NAME = "ScreenShot/%Y%m%d%H%M%S.png"')
|
||||
# .sub!("def VZ; return @curr.lZ / 120; end", "def VZ; return 0 if @curr.nil? || @curr.lZ.nil?; return @curr.lZ / 120.0 end"),
|
||||
# .replace!("BasicMouse.rb"),
|
||||
.remove!,
|
||||
Patch.new("Super simple mouse script: Use mkxp mouse API")
|
||||
.imported?(nil)
|
||||
.include?("SUPER SIMPLE MOUSE SCRIPT")
|
||||
.replace!("Mouse.rb"),
|
||||
Patch.new("RMXP CustomResolution plugin")
|
||||
.imported?(nil)
|
||||
.include?("def snapshot(filename = 'Data/snap', quality = 0)")
|
||||
.replace!("XP_CustomResolution.rb"),
|
||||
Patch.new("Glitchfinder's Key Input: Shim with MKXP builtins")
|
||||
.imported?(nil)
|
||||
.include?("unless method_defined?(:keyinputmodule_input_update)")
|
||||
.replace!("Glitchfinder_Keyboard_Stub.rb"),
|
||||
Patch.new("Auto Font Install: Already included in MKXP")
|
||||
.imported?(nil)
|
||||
.include?("# ** Auto Font Install")
|
||||
.remove!,
|
||||
Patch.new("Extended Music Script: MKXP already supports .mod. other formats aren't available.")
|
||||
.imported?(nil)
|
||||
.include?("# Extended Music Script Version 3.5")
|
||||
.then!{|script|
|
||||
return if script.context.flag? :incompatible_bgm_checked
|
||||
unsupp = "wma,psf,minipsf,psf2,minipsf2,gsf,minigsf,usf,miniusf,hps,dsp,spc,gym,cym".split(",")
|
||||
# TODO: Find unsupported files in Audio/BGM. Then show msgbox if no converted versions available
|
||||
# Official MKXP-Z also doesn't support mp3
|
||||
script.context.mark :incompatible_bgm_checked
|
||||
}
|
||||
.remove!,
|
||||
Patch.new("CRDJ Input script: Use MKXP-Z input extensions")
|
||||
.imported?(nil)
|
||||
.include?("# A module that handles input data from a gamepad or keyboard.\r\n# Managed by symbols rather than button numbers in RGSS3.")
|
||||
.replace!("CRDJ_Input.rb"),
|
||||
# Specific Inline Patches
|
||||
Patch.new("Shokushu de sennou patch")
|
||||
.imported?(nil)
|
||||
.include?("alias _cao_log_terminate_message terminate_message")
|
||||
#.replace!("oldregex1.rb"),
|
||||
.sub!("@text.gsub!(/[", "#"),
|
||||
Patch.new("Try to fix superclass mismatches from MP Scene_Base")
|
||||
.imported?(nil)
|
||||
.include?("======\nMoonpearl's Scene_Base\n-----")
|
||||
.flag!(:redefinitions_overwrite_class),
|
||||
# Generic Inline Patches
|
||||
Patch.new("Disable all font effects")
|
||||
.flag?(:no_font_effects) # KAWARIKI_MKXP_NO_FONT_EFFECTS
|
||||
.match?(/(\.f|F)ont\.(default_)?(italic|outline|shadow|bold)/)
|
||||
# Font is a built-in API, so it's already available in preload
|
||||
.then!{Font.default_italic = Font.default_outline = Font.default_shadow = Font.default_bold = false}
|
||||
.sub!(/Font\.default_(italic|outline|shadow|bold)\s*=/, "Font.default_\\1 = false &&")
|
||||
.sub!(/\.font\.(italic|outline|shadow|bold)\s*\=/, ".font.\\1 = false &&"),
|
||||
Patch.new("Improve Ruby 1.8 Compatibility")
|
||||
.if?{|script| script.context[:rgss_version] < 3} # Never on VX Ace, which shipped 1.9
|
||||
.match?("self.type", /\Wtype\.to_s\W/, /\Winstance_methods\.include\?\(['"%]/)
|
||||
.then!{require "ruby18.rb"},
|
||||
Patch.new("Game_Player fix")
|
||||
.imported?(nil)
|
||||
.if? {|script| script.name == "Game_Player"}
|
||||
.if? {|script| script.source.include? "else return true"}
|
||||
.sub!("else return true", "true"),
|
||||
Patch.new("KGC Bitmap Extension fix")
|
||||
.imported?(nil)
|
||||
.if? {|script| script.source.include? "@@reel_stop = RPG::SE.new(CAO::PSLOT::SOUND_REEL_STOP"}
|
||||
.sub!("@@reel_stop =", "@reel_stop ="),
|
||||
Patch.new("Response improvement remove")
|
||||
.imported?(nil)
|
||||
.match?(/#.*_wdtk_resinp_update/)
|
||||
.remove!,
|
||||
Patch.new("Response improvement patch")
|
||||
.imported?(nil)
|
||||
# .if? {|script| script.name == "Response improvement script"}
|
||||
#.include?('@@press_count.each do')
|
||||
.if? {|script| script.source.include? "_wdtk_resinp_update" }
|
||||
.sub!('@@press_count', "@press_count")
|
||||
.sub!(/\b_wdtk_resinp_update\b(?!\s*update)/, "_wdtk_resinp_update;\n@press_count ||= {}"),
|
||||
# .sub!(/^(?!#.*)\b_wdtk_resinp_update\b(?!\s*update)/, "_wdtk_resinp_update;\n@press_count ||= {}"),
|
||||
# .sub!(/^(?!#.*)\b_wdtk_resinp_update\b(?!\s*update)/) { "_wdtk_resinp_update;\n@press_count ||= {}" },
|
||||
Patch.new("Item Script")
|
||||
.imported?(nil)
|
||||
# .if? {|script| script.name == "Response improvement script"}
|
||||
#.include?('@@press_count.each do')
|
||||
.include?("CATEGORIZE ITEM SCENE v1.0 ")
|
||||
# .if? {|script| script.source.include? "_wdtk_resinp_update"}
|
||||
.sub!("CATEGORY_IDENTIFIER.index(ITEM_DEFAULT_CATEGORY)", "CATEGORY_IDENTIFIER.keys.index(ITEM_DEFAULT_CATEGORY)")
|
||||
.sub!("CATEGORY_IDENTIFIER.index(:", "CATEGORY_IDENTIFIER.key(:"),
|
||||
Patch.new("Vitaminpl fix")
|
||||
.imported?(nil)
|
||||
.if? {|script| script.name == "Police"}
|
||||
.if? {|script| script.source.include? "Lucida Sans Unicode"}
|
||||
.if? {|script| script.source = "Font.default_size = 16"},
|
||||
Patch.new("Vitaminpl 2 fix")
|
||||
.imported?(nil)
|
||||
.include?("module Wora_NSS")
|
||||
.sub!("SCREENSHOT_IMAGE = true", "SCREENSHOT_IMAGE = false")
|
||||
.sub!("PREMADE_IMAGE = true", "PREMADE_IMAGE = false"),
|
||||
Patch.new("Dark Hero Party")
|
||||
.imported?(nil)
|
||||
.include?('text.push(self.to_s.scan(/#<(\S+):/)[0][0].to_s)')
|
||||
.remove!,
|
||||
Patch.new("Flirt quest")
|
||||
.imported?(nil)
|
||||
.include?('class Spriteset_BattleUnit')
|
||||
.include?('Spriteset_Kiseki')
|
||||
.sub!(/\bsuper\b(?!\s*\()/, 'super()'),
|
||||
|
||||
]
|
||||
end
|
158
mkxp-z/Kawariki-patches/ports/BasicMouse.rb
Normal file
158
mkxp-z/Kawariki-patches/ports/BasicMouse.rb
Normal file
|
@ -0,0 +1,158 @@
|
|||
module Input
|
||||
class BasicMouse
|
||||
include IBasicMouse
|
||||
|
||||
# コンストラクタ
|
||||
def initialize()
|
||||
# 関連付けられたウィンドウのハンドル
|
||||
@hWnd = 0
|
||||
|
||||
# 前回のマウスの状態
|
||||
@prev = nil
|
||||
|
||||
# 現在のマウスの状態
|
||||
@curr = nil
|
||||
|
||||
# ボタンの配列
|
||||
@buttons = Array.new(self.NumButtons()){ |i| i = ButtonInfo.new() }
|
||||
|
||||
# 何かボタンが押されているか
|
||||
@isPressedAnyButton = false
|
||||
|
||||
# ステータス情報文字列を更新すべきか
|
||||
@needToUpdate = true
|
||||
end
|
||||
|
||||
# 初期化処理
|
||||
def Initialize(hWnd)
|
||||
@hWnd = hWnd
|
||||
@curr = DIMOUSESTATE2.new(hWnd)
|
||||
end
|
||||
|
||||
# 更新処理
|
||||
def Update
|
||||
# マウスの更新処理
|
||||
@prev = @curr
|
||||
@curr.Update()
|
||||
|
||||
@isPressedAnyButton = false
|
||||
for i in 0..NumButtons() - 1
|
||||
@buttons[i].Update((@curr.rgbButtons[i] & 0x80) == 128 ? ButtonStatus::Pressed : ButtonStatus::Released)
|
||||
|
||||
if @buttons[i].Pressed()
|
||||
@isPressedAnyButton = true;
|
||||
end
|
||||
end
|
||||
|
||||
@needToUpdate = true
|
||||
end
|
||||
|
||||
# IBasicMouse::GetStatusString() オーバーライド
|
||||
def GetStatusString
|
||||
if @needToUpdate
|
||||
def Static
|
||||
leftButton = Keys::Key.new(0, "LeftButton", "左ボタン")
|
||||
rightButton = Keys::Key.new(1, "RightButton", "右ボタン")
|
||||
middleButton = Keys::Key.new(2, "MiddleButton", "中央ボタン")
|
||||
xButton1 = Keys::Key.new(3, "XButton1", "Xボタン1")
|
||||
xButton2 = Keys::Key.new(4, "XButton2", "Xボタン2")
|
||||
xButton3 = Keys::Key.new(5, "XButton3", "Xボタン3")
|
||||
xButton4 = Keys::Key.new(6, "XButton4", "Xボタン4")
|
||||
xButton5 = Keys::Key.new(7, "XButton5", "Xボタン5")
|
||||
@keyTable =
|
||||
[
|
||||
leftButton,
|
||||
rightButton,
|
||||
middleButton,
|
||||
xButton1,
|
||||
xButton2,
|
||||
xButton3,
|
||||
xButton4,
|
||||
xButton5
|
||||
]
|
||||
end
|
||||
self.Static()
|
||||
|
||||
puts sprintf("Position : (%5d,%5d)", self.X(), self.Y())
|
||||
puts sprintf("Velocity : (%5d,%5d,%5d)", self.VX(), self.VY(), self.VZ())
|
||||
puts "[ButtonName] [Pressed] [Released] [Repeated]"
|
||||
|
||||
for i in 0..(NumButtons() - 1)
|
||||
puts sprintf(
|
||||
"%-20s %4s%4s%6d %4s%4s %4s%6d",
|
||||
@keyTable[i].GetName(),
|
||||
@buttons[i].Pressed() ? "ON" : "OFF",
|
||||
@buttons[i].JustPressed() ? "ON" : "OFF",
|
||||
@buttons[i].GetContinuousCount(),
|
||||
@buttons[i].Released() ? "ON" : "OFF",
|
||||
@buttons[i].JustReleased() ? "ON" : "OFF",
|
||||
@buttons[i].Repeated() ? "ON" : "OFF",
|
||||
@buttons[i].GetRepeatCount()
|
||||
)
|
||||
end
|
||||
print("\n")
|
||||
end
|
||||
end
|
||||
|
||||
# マウスの最大ボタン数
|
||||
def NumButtons; return 8; end
|
||||
|
||||
# IBasicMouse::GetPosition() オーバーライド
|
||||
def GetPosition
|
||||
pos = System::Math::Vector2.Zero()
|
||||
pos.x = @curr.lX; pos.y = @curr.lY;
|
||||
return pos;
|
||||
end
|
||||
|
||||
# IBasicMouse::SetPosition() オーバーライド
|
||||
def SetPosition(x, y); Win32RGSS::Cursor::SetCursorPos(x, y); end
|
||||
|
||||
# IBasicMouse::GetVelocity() オーバーライド
|
||||
def GetVelocity
|
||||
pos = System::Math::Vector2.Zero()
|
||||
pos.x = @curr.lX; pos.y = @curr.lY;
|
||||
return pos
|
||||
end
|
||||
|
||||
# IBasicMouse::X() オーバーライド
|
||||
def X; return @curr.lX; end
|
||||
|
||||
# IBasicMouse::Y() オーバーライド
|
||||
def Y; return @curr.lY; end
|
||||
|
||||
# IBasicMouse::VX() オーバーライド
|
||||
def VX; return @curr.lX - @prev.lX; end
|
||||
|
||||
# IBasicMouse::VY() オーバーライド
|
||||
def VY; return @curr.lY - @prev.lY; end
|
||||
|
||||
# IBasicMouse::VZ() オーバーライド
|
||||
# def VZ; return @curr.lZ / 120; end
|
||||
def VZ
|
||||
# Check if @curr and @curr.lZ are valid (not nil)
|
||||
return 0 if @curr.nil? || @curr.lZ.nil?
|
||||
return @curr.lZ / 120.0 # Ensure division results in a float
|
||||
end
|
||||
|
||||
# IBasicMouse::LeftButton() オーバーライド
|
||||
def LeftButton; return @buttons[0]; end
|
||||
|
||||
# IBasicMouse::RightButton() オーバーライド
|
||||
def RightButton; return @buttons[1]; end
|
||||
|
||||
# IBasicMouse::MiddleButton() オーバーライド
|
||||
def MiddleButton; return @buttons[2]; end
|
||||
|
||||
# IBasicMouse::XButton1() オーバーライド
|
||||
def XButton1; return @buttons[3]; end
|
||||
|
||||
# IBasicMouse::XButton2() オーバーライド
|
||||
def XButton2; return @buttons[4]; end
|
||||
|
||||
# IBasicMouse::GetButtonState() オーバーライド
|
||||
def GetButtonState(index); return @buttons[index]; end
|
||||
|
||||
# 1つ以上のボタンが押し下げられている時にはtrueを返します。
|
||||
def IsPressedAnyButton; return @isPressedAnyButton; end
|
||||
end
|
||||
end
|
452
mkxp-z/Kawariki-patches/ports/CRDJ_Input.rb
Normal file
452
mkxp-z/Kawariki-patches/ports/CRDJ_Input.rb
Normal file
|
@ -0,0 +1,452 @@
|
|||
# CRDJ_Input.rb Kawariki MKXP-Z port
|
||||
# Date: 2023-06-01
|
||||
# TODO: - handle modified configuration
|
||||
# - Properly deal with the layout stuff?
|
||||
#==============================================================================
|
||||
# ** Input
|
||||
#-------------------------------------------------------------------------------
|
||||
# Created By Cidiomar R. Dias Junior
|
||||
# Originally posted at
|
||||
#
|
||||
# Terms of Use: Credit "Cidiomar R. Dias Junior"
|
||||
#
|
||||
# Maintained on Hime Works
|
||||
#-------------------------------------------------------------------------------
|
||||
# ** Description
|
||||
#
|
||||
# A module that handles input data from a gamepad or keyboard.
|
||||
# Managed by symbols rather than button numbers in RGSS3.
|
||||
#-------------------------------------------------------------------------------
|
||||
# ** Usage
|
||||
#
|
||||
# Scroll down to the configuration section. It is around line 185.
|
||||
# You can set up your key mappings there. Use the reference to get the names
|
||||
# of the keys.
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
module CRDJ_Input
|
||||
#--------------------------------------------------------------------------
|
||||
# * Keymap in symbols
|
||||
# To get a key from the keymap, you can use Input.key(sym) or Input:KEYMAP[sym]
|
||||
# Or if you want to use a symbol in a input function, just pass the symbol
|
||||
# as argument.
|
||||
#--------------------------------------------------------------------------
|
||||
KEYMAP = {
|
||||
LBUTTON: 0x01, RBUTTON: 0x02,
|
||||
CANCEL: 0x03, MBUTTON: 0x04,
|
||||
XBUTTON1: 0x05, XBUTTON2: 0x06,
|
||||
BACK: 0x08, TAB: 0x09,
|
||||
CLEAR: 0x0c, RETURN: 0x0d,
|
||||
SHIFT: 0x10, CONTROL: 0x11,
|
||||
MENU: 0x12, PAUSE: 0x13,
|
||||
CAPITAL: 0x14, KANA: 0x15,
|
||||
JUNJA: 0x17, FINAL: 0x18,
|
||||
HANJA: 0x19,
|
||||
ESCAPE: 0x1b, CONVERT: 0x1c,
|
||||
NONCONVERT: 0x1d, ACCEPT: 0x1e,
|
||||
MODECHANGE: 0x1f, SPACE: 0x20,
|
||||
PRIOR: 0x21, NEXT: 0x22,
|
||||
END: 0x23, HOME: 0x24,
|
||||
LEFT: 0x25, UP: 0x26,
|
||||
RIGHT: 0x27, DOWN: 0x28,
|
||||
SELECT: 0x29, PRINT: 0x2a,
|
||||
EXECUTE: 0x2b, SNAPSHOT: 0x2c,
|
||||
INSERT: 0x2d, DELETE: 0x2e,
|
||||
HELP: 0x2f, N0: 0x30,
|
||||
KEY_1: 0x31, KEY_2: 0x32,
|
||||
KEY_3: 0x33, KEY_4: 0x34,
|
||||
KEY_5: 0x35, KEY_6: 0x36,
|
||||
KEY_7: 0x37, KEY_8: 0x38,
|
||||
KEY_9: 0x39, colon: 0x3a,
|
||||
semicolon: 0x3b, less: 0x3c,
|
||||
equal: 0x3d, greater: 0x3e,
|
||||
question: 0x3f, at: 0x40,
|
||||
LETTER_A: 0x41, LETTER_B: 0x42,
|
||||
LETTER_C: 0x43, LETTER_D: 0x44,
|
||||
LETTER_E: 0x45, LETTER_F: 0x46,
|
||||
LETTER_G: 0x47, LETTER_H: 0x48,
|
||||
LETTER_I: 0x49, LETTER_J: 0x4a,
|
||||
LETTER_K: 0x4b, LETTER_L: 0x4c,
|
||||
LETTER_M: 0x4d, LETTER_N: 0x4e,
|
||||
LETTER_O: 0x4f, LETTER_P: 0x50,
|
||||
LETTER_Q: 0x51, LETTER_R: 0x52,
|
||||
LETTER_S: 0x53, LETTER_T: 0x54,
|
||||
LETTER_U: 0x55, LETTER_V: 0x56,
|
||||
LETTER_W: 0x57, LETTER_X: 0x58,
|
||||
LETTER_Y: 0x59, LETTER_Z: 0x5a,
|
||||
LWIN: 0x5b, RWIN: 0x5c,
|
||||
APPS: 0x5d, asciicircum: 0x5e,
|
||||
SLEEP: 0x5f, NUMPAD0: 0x60,
|
||||
NUMPAD1: 0x61, NUMPAD2: 0x62,
|
||||
NUMPAD3: 0x63, NUMPAD4: 0x64,
|
||||
NUMPAD5: 0x65, NUMPAD6: 0x66,
|
||||
NUMPAD7: 0x67, NUMPAD8: 0x68,
|
||||
NUMPAD9: 0x69, MULTIPLY: 0x6a,
|
||||
ADD: 0x6b, SEPARATOR: 0x6c,
|
||||
SUBTRACT: 0x6d, DECIMAL: 0x6e,
|
||||
DIVIDE: 0x6f, F1: 0x70,
|
||||
F2: 0x71, F3: 0x72,
|
||||
F4: 0x73, F5: 0x74,
|
||||
F6: 0x75, F7: 0x76,
|
||||
F8: 0x77, F9: 0x78,
|
||||
F10: 0x79, F11: 0x7a,
|
||||
F12: 0x7b, F13: 0x7c,
|
||||
F14: 0x7d, F15: 0x7e,
|
||||
F16: 0x7f, F17: 0x80,
|
||||
F18: 0x81, F19: 0x82,
|
||||
F20: 0x83, F21: 0x84,
|
||||
F22: 0x85, F23: 0x86,
|
||||
F24: 0x87, NUMLOCK: 0x90,
|
||||
SCROLL: 0x91, LSHIFT: 0xa0,
|
||||
RSHIFT: 0xa1, LCONTROL: 0xa2,
|
||||
RCONTROL: 0xa3, LMENU: 0xa4,
|
||||
RMENU: 0xa5, BROWSER_BACK: 0xa6,
|
||||
BROWSER_FORWARD: 0xa7, BROWSER_REFRESH: 0xa8,
|
||||
BROWSER_STOP: 0xa9, BROWSER_SEARCH: 0xaa,
|
||||
BROWSER_FAVORITES: 0xab, BROWSER_HOME: 0xac,
|
||||
VOLUME_MUTE: 0xad, VOLUME_DOWN: 0xae,
|
||||
VOLUME_UP: 0xaf, MEDIA_NEXT_TRACK: 0xb0,
|
||||
MEDIA_PREV_TRACK: 0xb1, MEDIA_STOP: 0xb2,
|
||||
MEDIA_PLAY_PAUSE: 0xb3, LAUNCH_MAIL: 0xb4,
|
||||
LAUNCH_MEDIA_SELECT: 0xb5, LAUNCH_APP1: 0xb6,
|
||||
LAUNCH_APP2: 0xb7, cedilla: 0xb8,
|
||||
onesuperior: 0xb9, masculine: 0xba,
|
||||
guillemotright: 0xbb, onequarter: 0xbc,
|
||||
onehalf: 0xbd, threequarters: 0xbe,
|
||||
questiondown: 0xbf, Agrave: 0xc0,
|
||||
Aacute: 0xc1, Acircumflex: 0xc2,
|
||||
Atilde: 0xc3, Adiaeresis: 0xc4,
|
||||
Aring: 0xc5, AE: 0xc6,
|
||||
Ccedilla: 0xc7, Egrave: 0xc8,
|
||||
Eacute: 0xc9, Ecircumflex: 0xca,
|
||||
Ediaeresis: 0xcb, Igrave: 0xcc,
|
||||
Iacute: 0xcd, Icircumflex: 0xce,
|
||||
Idiaeresis: 0xcf, ETH: 0xd0,
|
||||
Ntilde: 0xd1, Ograve: 0xd2,
|
||||
Oacute: 0xd3, Ocircumflex: 0xd4,
|
||||
Otilde: 0xd5, Odiaeresis: 0xd6,
|
||||
multiply: 0xd7, Oslash: 0xd8,
|
||||
Ugrave: 0xd9, Uacute: 0xda,
|
||||
Ucircumflex: 0xdb, Udiaeresis: 0xdc,
|
||||
Yacute: 0xdd, THORN: 0xde,
|
||||
ssharp: 0xdf, agrave: 0xe0,
|
||||
aacute: 0xe1, acircumflex: 0xe2,
|
||||
atilde: 0xe3, adiaeresis: 0xe4,
|
||||
PROCESSKEY: 0xe5, ae: 0xe6,
|
||||
PACKET: 0xe7, egrave: 0xe8,
|
||||
eacute: 0xe9, ecircumflex: 0xea,
|
||||
ediaeresis: 0xeb, igrave: 0xec,
|
||||
iacute: 0xed, icircumflex: 0xee,
|
||||
idiaeresis: 0xef, eth: 0xf0,
|
||||
ntilde: 0xf1, ograve: 0xf2,
|
||||
oacute: 0xf3, ocircumflex: 0xf4,
|
||||
otilde: 0xf5, ATTN: 0xf6,
|
||||
CRSEL: 0xf7, EXSEL: 0xf8,
|
||||
EREOF: 0xf9, PLAY: 0xfa,
|
||||
ZOOM: 0xfb, NONAME: 0xfc,
|
||||
PA1: 0xfd, thorn: 0xfe,
|
||||
ydiaeresis: 0xff
|
||||
}
|
||||
|
||||
KEYMAP[:WIN] = [KEYMAP[:LWIN], KEYMAP[:RWIN]]
|
||||
|
||||
#===============================================================================
|
||||
# Configuration
|
||||
#===============================================================================
|
||||
#--------------------------------------------------------------------------
|
||||
# * Default Keys, you can configure here instead of by pressing F1.
|
||||
#--------------------------------------------------------------------------
|
||||
UP = [KEYMAP[:UP]]
|
||||
DOWN = [KEYMAP[:DOWN]]
|
||||
LEFT = [KEYMAP[:LEFT]]
|
||||
RIGHT = [KEYMAP[:RIGHT]]
|
||||
A = [KEYMAP[:SHIFT]]
|
||||
B = [KEYMAP[:ESCAPE], KEYMAP[:LETTER_X]]
|
||||
C = [KEYMAP[:RETURN], KEYMAP[:LETTER_Z]]
|
||||
X = []
|
||||
Y = []
|
||||
Z = []
|
||||
L = [KEYMAP[:PRIOR]]
|
||||
R = [KEYMAP[:NEXT]]
|
||||
F5 = [KEYMAP[:F5]]
|
||||
F6 = [KEYMAP[:F6]]
|
||||
F7 = [KEYMAP[:F7]]
|
||||
F8 = [KEYMAP[:F8]]
|
||||
F9 = [KEYMAP[:F9]]
|
||||
SHIFT = [KEYMAP[:SHIFT]]
|
||||
CTRL = [KEYMAP[:CONTROL]]
|
||||
ALT = [KEYMAP[:MENU]]
|
||||
|
||||
#===============================================================================
|
||||
# Rest of script
|
||||
#===============================================================================
|
||||
#--------------------------------------------------------------------------
|
||||
# * Symbol version of default keys.
|
||||
#--------------------------------------------------------------------------
|
||||
SYM_KEYS = {
|
||||
:UP => UP,
|
||||
:LEFT => LEFT,
|
||||
:DOWN => DOWN,
|
||||
:RIGHT => RIGHT,
|
||||
:A => A,
|
||||
:B => B,
|
||||
:C => C,
|
||||
:X => X,
|
||||
:Y => Y,
|
||||
:Z => Z,
|
||||
:L => L,
|
||||
:R => R,
|
||||
:F5 => F5,
|
||||
:F6 => F6,
|
||||
:F7 => F7,
|
||||
:F8 => F8,
|
||||
:F9 => F9,
|
||||
:SHIFT => SHIFT,
|
||||
:CTRL => CTRL,
|
||||
:ALT => ALT
|
||||
}
|
||||
|
||||
# Letters that can have accent
|
||||
PssbLetters = "AEIOUCNYaeioucny"
|
||||
# Accents, in ASCII, configured at runtime to avoid encoding troubles
|
||||
Accents = [96.chr, 180.chr, 94.chr, 126.chr, 168.chr].join
|
||||
NonCompatChars = [180, 168]
|
||||
|
||||
module InputExtension
|
||||
#--------------------------------------------------------------------------
|
||||
# * Determines whether the button corresponding to the symbol sym is
|
||||
# currently being pressed.
|
||||
#
|
||||
# If the button is being pressed, returns TRUE. If not, returns FALSE.
|
||||
#
|
||||
# if Input.press?(:C)
|
||||
# do_something
|
||||
# end
|
||||
#--------------------------------------------------------------------------
|
||||
def press?(keys)
|
||||
if keys.is_a?(Numeric)
|
||||
k = keys.to_i
|
||||
return (self.pressex? k)
|
||||
elsif keys.is_a?(Array)
|
||||
return keys.any? {|key| self.pressex?(key) }
|
||||
elsif keys.is_a?(Symbol)
|
||||
if SYM_KEYS.key?(keys)
|
||||
return super(keys)
|
||||
return SYM_KEYS[keys].any? {|key| self.pressex?(key) }
|
||||
elsif KEYMAP.key?(keys)
|
||||
k = KEYMAP[keys]
|
||||
return self.pressex?(k)
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# * Determines whether the button corresponding to the symbol sym is
|
||||
# currently being pressed again.
|
||||
# "Pressed again" is seen as time having passed between the button being
|
||||
# not pressed and being pressed.
|
||||
#
|
||||
# If the button is being pressed, returns TRUE. If not, returns FALSE.
|
||||
#--------------------------------------------------------------------------
|
||||
def trigger?(keys)
|
||||
if keys.is_a?(Numeric)
|
||||
return Input.triggerex?(keys.to_i)
|
||||
elsif keys.is_a?(Array)
|
||||
return keys.any? {|key| self.triggerex?(key)}
|
||||
elsif keys.is_a?(Symbol)
|
||||
if SYM_KEYS.key?(keys)
|
||||
return super(keys)
|
||||
Preload.print "Trigger #{keys} #{SYM_KEYS[keys]} #{x}"
|
||||
return SYM_KEYS[keys].any? {|key| self.triggerex?(key)}
|
||||
elsif KEYMAP.key?(keys)
|
||||
return self.triggerex?(KEYMAP[keys])
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# * Determines whether the button corresponding to the symbol sym is
|
||||
# currently being pressed again.
|
||||
# Unlike trigger?, takes into account the repeated input of a button being
|
||||
# held down continuously.
|
||||
#
|
||||
# If the button is being pressed, returns TRUE. If not, returns FALSE.
|
||||
#--------------------------------------------------------------------------
|
||||
def repeat?(keys)
|
||||
if keys.is_a?(Numeric)
|
||||
key = keys.to_i
|
||||
return self.repeatex?(key)
|
||||
elsif keys.is_a?(Array)
|
||||
return keys.any? {|key| self.repeatex?(key)}
|
||||
elsif keys.is_a?(Symbol)
|
||||
if SYM_KEYS.key?(keys)
|
||||
return super(keys)
|
||||
return SYM_KEYS[keys].any? {|key| self.repeatex?(key)}
|
||||
elsif KEYMAP.key?(keys)
|
||||
return self.repeatex?(KEYMAP[keys])
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# * Determines whether the button corresponding to the symbol sym
|
||||
# was released.
|
||||
#
|
||||
# If the button was released, returns TRUE. If not, returns FALSE.
|
||||
#--------------------------------------------------------------------------
|
||||
def release?(keys)
|
||||
if keys.is_a?(Numeric)
|
||||
return self.releaseex? keys.to_i
|
||||
elsif keys.is_a?(Array)
|
||||
return keys.any? {|key| self.release?(key)}
|
||||
elsif keys.is_a?(Symbol)
|
||||
if SYM_KEYS.key?(keys)
|
||||
return super(keys)
|
||||
return SYM_KEYS[keys].any? {|key| self.releaseex?(key)}
|
||||
elsif KEYMAP.key?(keys)
|
||||
return self.releaseex?(KEYMAP[keys])
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# * Checks the status of the directional buttons, translates the data into
|
||||
# a specialized 4-direction input format, and returns the number pad
|
||||
# equivalent (2, 4, 6, 8).
|
||||
#
|
||||
# If no directional buttons are being pressed (or the equivalent), returns 0.
|
||||
#--------------------------------------------------------------------------
|
||||
# def dir4
|
||||
# return 2 if self.press?(DOWN)
|
||||
# return 4 if self.press?(LEFT)
|
||||
# return 6 if self.press?(RIGHT)
|
||||
# return 8 if self.press?(UP)
|
||||
# return 0
|
||||
# end
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# * Checks the status of the directional buttons, translates the data into
|
||||
# a specialized 8-direction input format, and returns the number pad
|
||||
# equivalent (1, 2, 3, 4, 6, 7, 8, 9).
|
||||
#
|
||||
#If no directional buttons are being pressed (or the equivalent), returns 0.
|
||||
#--------------------------------------------------------------------------
|
||||
# def dir8
|
||||
# down = self.press?(DOWN)
|
||||
# left = self.press?(LEFT)
|
||||
# return 1 if down and left
|
||||
# right = self.press?(RIGHT)
|
||||
# return 3 if down and right
|
||||
# up = self.press?(UP)
|
||||
# return 7 if up and left
|
||||
# return 9 if up and right
|
||||
# return 2 if down
|
||||
# return 4 if left
|
||||
# return 6 if right
|
||||
# return 8 if up
|
||||
# return 0
|
||||
# end
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# * Gets the character that correspond to vk using the keyboard layout
|
||||
#--------------------------------------------------------------------------
|
||||
def get_character(vk)
|
||||
# FIXME: do something smarter
|
||||
return vk
|
||||
end
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# * Accents Table, to bo used in conversion from ASCII to UTF8
|
||||
#--------------------------------------------------------------------------
|
||||
AccentsCharsConv = {
|
||||
"A" => ["A", "A", "A", "A", "A"],
|
||||
"E" => ["E", "E", "E", 0, "E"],
|
||||
"I" => ["I", "I", "I", 0, "I"],
|
||||
"O" => ["O", "O", "O", "O", "O"],
|
||||
"U" => ["U", "U", "U", 0, "U"],
|
||||
"C" => [ 0 , "C", 0 , 0, 0 ],
|
||||
"N" => [ 0 , 0, 0 , "N", 0 ],
|
||||
"Y" => [ 0 , "Y", 0 , 0, "?"],
|
||||
"a" => ["a", "a", "a", "a", "a"],
|
||||
"e" => ["e", "e", "e", 0 , "e"],
|
||||
"i" => ["i", "i", "i", 0 , "i"],
|
||||
"o" => ["o", "o", "o", "o", "o"],
|
||||
"u" => ["u", "u", "u", 0 , "u"],
|
||||
"c" => [ 0 , "c", 0 , 0 , 0 ],
|
||||
"n" => [ 0 , 0 , 0 , "n", 0 ],
|
||||
"y" => [ 0 , "y", 0 , 0 , "y"],
|
||||
}
|
||||
|
||||
@last_accent = nil
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# * Get inputed string transcoded to UTF8
|
||||
#--------------------------------------------------------------------------
|
||||
def UTF8String
|
||||
result = ""
|
||||
31.upto(255) {|key|
|
||||
if self.repeat?(key)
|
||||
c = self.get_character(key)
|
||||
if (cc = c.unpack("C")[0]) and NonCompatChars.include?(cc)
|
||||
result += cc.chr
|
||||
else
|
||||
result += UNICODE_TO_UTF8.convertc if c != ""
|
||||
end
|
||||
end
|
||||
}
|
||||
return "" if result == ""
|
||||
if @last_accent
|
||||
result = @last_accent + result
|
||||
@last_accent = nil
|
||||
end
|
||||
f_result = ""
|
||||
jump = false
|
||||
for i in 0 ... result.length
|
||||
c = result[i]
|
||||
if jump
|
||||
jump = false
|
||||
next
|
||||
end
|
||||
if Accents.include?c
|
||||
if (nc = result[i+1]) != nil
|
||||
if PssbLetters.include?(nc)
|
||||
if (ac = AccentsCharsConv[nc][Accents.indexc]) != 0
|
||||
f_result << ac
|
||||
jump = true
|
||||
else
|
||||
f_result << c
|
||||
f_result << nc
|
||||
jump = true
|
||||
end
|
||||
elsif Accents.include?(nc)
|
||||
f_result << c
|
||||
f_result << nc
|
||||
jump = true
|
||||
else
|
||||
f_result << c
|
||||
f_result << nc
|
||||
jump = true
|
||||
end
|
||||
else
|
||||
@last_accent = c
|
||||
end
|
||||
else
|
||||
f_result << c
|
||||
end
|
||||
end
|
||||
return f_result
|
||||
end
|
||||
end
|
||||
|
||||
Input.singleton_class.prepend InputExtension
|
||||
Input.const_set :KEYMAP, KEYMAP
|
||||
end
|
254
mkxp-z/Kawariki-patches/ports/Glitchfinder_Keyboard_Stub.rb
Normal file
254
mkxp-z/Kawariki-patches/ports/Glitchfinder_Keyboard_Stub.rb
Normal file
|
@ -0,0 +1,254 @@
|
|||
# Glitchfinder's Key Input MKXP stub
|
||||
# Only press? trigger? release? repeat? implemented
|
||||
# Direct forwarding to respective MKXP Input.*ex? methods
|
||||
# Key constants copied from 1.30 source
|
||||
# ANYKEY is not implemented by MKXP
|
||||
#
|
||||
# Authors: Glitchfinder, Taeyeon Mori
|
||||
# Date: 2022-01-31
|
||||
|
||||
module Keys
|
||||
# ****************************** Key names ********************************
|
||||
#--------------------------------------------------------------------------
|
||||
# * Miscellaneous Keys
|
||||
#--------------------------------------------------------------------------
|
||||
CANCEL = 0x03 # Control-Break Processing
|
||||
BACKSPACE = 0x08 # Backspace Key
|
||||
TAB = 0x09 # Tab Key
|
||||
CLEAR = 0x0C # Clear Key
|
||||
RETURN = 0x0D # Enter Key
|
||||
SHIFT = 0x10 # Shift Key
|
||||
CONTROL = 0x11 # Ctrl Key
|
||||
MENU = 0x12 # Alt Key
|
||||
PAUSE = 0x13 # Pause Key
|
||||
ESCAPE = 0x1B # Esc Key
|
||||
CONVERT = 0x1C # IME Convert Key
|
||||
NONCONVERT = 0x1D # IME Nonconvert Key
|
||||
ACCEPT = 0x1E # IME Accept Key
|
||||
SPACE = 0x20 # Space Bar Key (Space, usually blank)
|
||||
PRIOR = 0x21 # Page Up Key
|
||||
NEXT = 0x22 # Page Down Key
|
||||
ENDS = 0x23 # End Key
|
||||
HOME = 0x24 # Home Key
|
||||
LEFT = 0x25 # Left Arrow Key
|
||||
UP = 0x26 # Up Arrow Key
|
||||
RIGHT = 0x27 # Right Arrow Key
|
||||
DOWN = 0x28 # Down Arrow Key
|
||||
SELECT = 0x29 # Select Key
|
||||
PRINT = 0x2A # Print Key
|
||||
EXECUTE = 0x2B # Execute Key
|
||||
SNAPSHOT = 0x2C # Print Screen Key
|
||||
DELETE = 0x2E # Delete Key
|
||||
HELP = 0x2F # Help Key
|
||||
LSHIFT = 0xA0 # Left Shift Key
|
||||
RSHIFT = 0xA1 # Right Shift Key
|
||||
LCONTROL = 0xA2 # Left Control Key (Ctrl)
|
||||
RCONTROL = 0xA3 # Right Control Key (Ctrl)
|
||||
LMENU = 0xA4 # Left Menu Key (Alt)
|
||||
RMENU = 0xA5 # Right Menu Key (Alt)
|
||||
PACKET = 0xE7 # Used to Pass Unicode Characters as Keystrokes
|
||||
#--------------------------------------------------------------------------
|
||||
# * Number Keys
|
||||
#--------------------------------------------------------------------------
|
||||
N0 = 0x30 # 0 Key
|
||||
N1 = 0x31 # 1 Key
|
||||
N2 = 0x32 # 2 Key
|
||||
N3 = 0x33 # 3 Key
|
||||
N4 = 0x34 # 4 Key
|
||||
N5 = 0x35 # 5 Key
|
||||
N6 = 0x36 # 6 Key
|
||||
N7 = 0x37 # 7 Key
|
||||
N8 = 0x38 # 8 Key
|
||||
N9 = 0x39 # 9 Key
|
||||
#--------------------------------------------------------------------------
|
||||
# * Letter Keys
|
||||
#--------------------------------------------------------------------------
|
||||
A = 0x41 # A Key
|
||||
B = 0x42 # B Key
|
||||
C = 0x43 # C Key
|
||||
D = 0x44 # D Key
|
||||
E = 0x45 # E Key
|
||||
F = 0x46 # F Key
|
||||
G = 0x47 # G Key
|
||||
H = 0x48 # H Key
|
||||
I = 0x49 # I Key
|
||||
J = 0x4A # J Key
|
||||
K = 0x4B # K Key
|
||||
L = 0x4C # L Key
|
||||
M = 0x4D # M Key
|
||||
N = 0x4E # N Key
|
||||
O = 0x4F # O Key
|
||||
P = 0x50 # P Key
|
||||
Q = 0x51 # Q Key
|
||||
R = 0x52 # R Key
|
||||
S = 0x53 # S Key
|
||||
T = 0x54 # T Key
|
||||
U = 0x55 # U Key
|
||||
V = 0x56 # V Key
|
||||
W = 0x57 # W Key
|
||||
X = 0x58 # X Key
|
||||
Y = 0x59 # Y Key
|
||||
Z = 0x5A # Z Key
|
||||
#--------------------------------------------------------------------------
|
||||
# * Windows Keys
|
||||
#--------------------------------------------------------------------------
|
||||
LWIN = 0x5B # Left Windows Key (Natural keyboard)
|
||||
RWIN = 0x5C # Right Windows Key (Natural Keyboard)
|
||||
APPS = 0x5D # Applications Key (Natural keyboard)
|
||||
SLEEP = 0x5F # Computer Sleep Key
|
||||
BROWSER_BACK = 0xA6 # Browser Back Key
|
||||
BROWSER_FORWARD = 0xA7 # Browser Forward Key
|
||||
BROWSER_REFRESH = 0xA8 # Browser Refresh Key
|
||||
BROWSER_STOP = 0xA9 # Browser Stop Key
|
||||
BROWSER_SEARCH = 0xAA # Browser Search Key
|
||||
BROWSER_FAVORITES = 0xAB # Browser Favorites Key
|
||||
BROWSER_HOME = 0xAC # Browser Start and Home Key
|
||||
VOLUME_MUTE = 0xAD # Volume Mute Key
|
||||
VOLUME_DOWN = 0xAE # Volume Down Key
|
||||
VOLUME_UP = 0xAF # Volume Up Key
|
||||
MEDIA_NEXT_TRACK = 0xB0 # Next Track Key
|
||||
MEDIA_PREV_TRACK = 0xB1 # Previous Track Key
|
||||
MEDIA_STOP = 0xB2 # Stop Media Key
|
||||
MEDIA_PLAY_PAUSE = 0xB3 # Play/Pause Media Key
|
||||
LAUNCH_MAIL = 0xB4 # Start Mail Key
|
||||
LAUNCH_MEDIA_SELECT = 0xB5 # Select Media Key
|
||||
LAUNCH_APP1 = 0xB6 # Start Application 1 Key
|
||||
LAUNCH_APP2 = 0xB7 # Start Application 2 Key
|
||||
PROCESSKEY = 0xE5 # IME Process Key
|
||||
ATTN = 0xF6 # Attn Key
|
||||
CRSEL = 0xF7 # CrSel Key
|
||||
EXSEL = 0xF8 # ExSel Key
|
||||
EREOF = 0xF9 # Erase EOF Key
|
||||
PLAY = 0xFA # Play Key
|
||||
ZOOM = 0xFB # Zoom Key
|
||||
PA1 = 0xFD # PA1 Key
|
||||
#--------------------------------------------------------------------------
|
||||
# * Number Pad Keys
|
||||
#--------------------------------------------------------------------------
|
||||
NUMPAD0 = 0x60 # Numeric Keypad 0 Key
|
||||
NUMPAD1 = 0x61 # Numeric Keypad 1 Key
|
||||
NUMPAD2 = 0x62 # Numeric Keypad 2 Key
|
||||
NUMPAD3 = 0x63 # Numeric Keypad 3 Key
|
||||
NUMPAD4 = 0x64 # Numeric Keypad 4 Key
|
||||
NUMPAD5 = 0x65 # Numeric Keypad 5 Key
|
||||
NUMPAD6 = 0x66 # Numeric Keypad 6 Key
|
||||
NUMPAD7 = 0x67 # Numeric Keypad 7 Key
|
||||
NUMPAD8 = 0x68 # Numeric Keypad 8 Key
|
||||
NUMPAD9 = 0x69 # Numeric Keypad 9 Key
|
||||
MULTIPLY = 0x6A # Multiply Key (*)
|
||||
ADD = 0x6B # Add Key (+)
|
||||
SEPARATOR = 0x6C # Separator Key
|
||||
SUBTRACT = 0x6D # Subtract Key (-)
|
||||
DECIMAL = 0x6E # Decimal Key (.)
|
||||
DIVIDE = 0x6F # Divide Key (/)
|
||||
#--------------------------------------------------------------------------
|
||||
# * Function Keys
|
||||
#--------------------------------------------------------------------------
|
||||
F1 = 0x70 # F1 Key
|
||||
F2 = 0x71 # F2 Key
|
||||
F3 = 0x72 # F3 Key
|
||||
F4 = 0x73 # F4 Key
|
||||
F5 = 0x74 # F5 Key
|
||||
F6 = 0x75 # F6 Key
|
||||
F7 = 0x76 # F7 Key
|
||||
F8 = 0x77 # F8 Key
|
||||
F9 = 0x78 # F9 Key
|
||||
F10 = 0x79 # F10 Key
|
||||
F11 = 0x7A # F11 Key
|
||||
F12 = 0x7B # F12 Key
|
||||
F13 = 0x7C # F13 Key
|
||||
F14 = 0x7D # F14 Key
|
||||
F15 = 0x7E # F15 Key
|
||||
F16 = 0x7F # F16 Key
|
||||
F17 = 0x80 # F17 Key
|
||||
F18 = 0x81 # F18 Key
|
||||
F19 = 0x82 # F19 Key
|
||||
F20 = 0x83 # F20 Key
|
||||
F21 = 0x84 # F21 Key
|
||||
F22 = 0x85 # F22 Key
|
||||
F23 = 0x86 # F23 Key
|
||||
F24 = 0x87 # F24 Key
|
||||
#--------------------------------------------------------------------------
|
||||
# * Toggle Keys
|
||||
#--------------------------------------------------------------------------
|
||||
CAPITAL = 0x14 # Caps Lock Key
|
||||
KANA = 0x15 # IME Kana Mode Key
|
||||
HANGUL = 0x15 # IME Hangul Mode Key
|
||||
JUNJA = 0x17 # IME Junja Mode Key
|
||||
FINAL = 0x18 # IME Final Mode Key
|
||||
HANJA = 0x19 # IME Hanja Mode Key
|
||||
KANJI = 0x19 # IME Kanji Mode Key
|
||||
MODECHANGE = 0x1F # IME Mode Change Request Key
|
||||
INSERT = 0x2D # Insert Key
|
||||
NUMLOCK = 0x90 # Num Lock Key
|
||||
SCROLL = 0x91 # Scroll Lock Key
|
||||
#--------------------------------------------------------------------------
|
||||
# * OEM Keys (Vary by keyboard)
|
||||
#--------------------------------------------------------------------------
|
||||
OEM_1 = 0xBA # Misc Characters (; : in USA 101/102 Keyboards)
|
||||
OEM_SEMICOLON = 0xBA
|
||||
OEM_PLUS = 0xBB # + = Key
|
||||
OEM_COMMA = 0xBC # , < Key
|
||||
OEM_MINUS = 0xBD # - _ Key
|
||||
OEM_PERIOD = 0xBE # . > Key
|
||||
OEM_2 = 0xBF # Misc Characters (/ ? in USA 101/102 Keyboards)
|
||||
OEM_SLASH = 0xBF
|
||||
OEM_3 = 0xC0 # Misc Characters (` ~ in USA 101/102 Keyboards)
|
||||
OEM_GRAVE = 0xC0
|
||||
OEM_4 = 0xDB # Misc Characters ([ { in USA 101/102 Keyboards)
|
||||
OEM_OPENBRACKET = 0xDB
|
||||
OEM_5 = 0xDC # Misc Characters (\ | in USA 101/102 Keyboards)
|
||||
OEM_BACKSLASH = 0xDC
|
||||
OEM_6 = 0xDD # Misc Characters (] } in USA 101/102 Keyboards)
|
||||
OEM_CLOSEBRACKET = 0xDD
|
||||
OEM_7 = 0xDE # Misc Characters (' " in USA 101/102 Keyboards)
|
||||
OEM_APOSTROPHE = 0xDE
|
||||
OEM_8 = 0xDF # Misc Characters (Varies by Keyboard)
|
||||
OEM_9 = 0xE1 # OEM Specific
|
||||
OEM_10 = 0x92 # OEM Specific
|
||||
OEM_11 = 0x93 # OEM Specific
|
||||
OEM_12 = 0x94 # OEM Specific
|
||||
OEM_13 = 0x95 # OEM Specific
|
||||
OEM_14 = 0x96 # OEM Specific
|
||||
OEM_15 = 0xE3 # OEM Specific
|
||||
OEM_16 = 0xE4 # OEM Specific
|
||||
OEM_17 = 0xE6 # OEM Specific
|
||||
OEM_18 = 0xE9 # OEM Specific
|
||||
OEM_19 = 0xEA # OEM Specific
|
||||
OEM_20 = 0xEB # OEM Specific
|
||||
OEM_21 = 0xEC # OEM Specific
|
||||
OEM_22 = 0xED # OEM Specific
|
||||
OEM_23 = 0xEE # OEM Specific
|
||||
OEM_24 = 0xEF # OEM Specific
|
||||
OEM_25 = 0xF1 # OEM Specific
|
||||
OEM_26 = 0xF2 # OEM Specific
|
||||
OEM_27 = 0xF3 # OEM Specific
|
||||
OEM_28 = 0xF4 # OEM Specific
|
||||
OEM_29 = 0xF5 # OEM Specific
|
||||
OEM_102 = 0xE2 # Angle Bracket or Backslash on RT-102 Keyboards
|
||||
OEM_CLEAR = 0xFE # Clear Key
|
||||
#--------------------------------------------------------------------------
|
||||
# * Special Keys
|
||||
#--------------------------------------------------------------------------
|
||||
#ANYKEY = 0x100 # Any Key
|
||||
|
||||
# ********************************* Stub **********************************
|
||||
def self.update
|
||||
end
|
||||
|
||||
def self.press?(key)
|
||||
return Input.pressex? key
|
||||
end
|
||||
|
||||
def self.trigger?(key)
|
||||
return Input.triggerex? key
|
||||
end
|
||||
|
||||
def self.repeat?(key)
|
||||
return Input.repeatex? key
|
||||
end
|
||||
|
||||
def self.release?(key)
|
||||
return Input.releaseex? key
|
||||
end
|
||||
end
|
1052
mkxp-z/Kawariki-patches/ports/Mouse.rb
Normal file
1052
mkxp-z/Kawariki-patches/ports/Mouse.rb
Normal file
File diff suppressed because it is too large
Load diff
315
mkxp-z/Kawariki-patches/ports/TH_EventTriggerLabels.rb
Normal file
315
mkxp-z/Kawariki-patches/ports/TH_EventTriggerLabels.rb
Normal file
|
@ -0,0 +1,315 @@
|
|||
=begin
|
||||
#==============================================================================
|
||||
Title: Event Trigger Labels
|
||||
Author: Hime
|
||||
Date: Dec 22, 2014
|
||||
------------------------------------------------------------------------------
|
||||
** Change log
|
||||
Sep 09, 2022
|
||||
- Add mkxp-z 2.4 support
|
||||
Feb 13, 2022
|
||||
- MKXP(-Z) port by Taeyeon Mori
|
||||
- Replace any_key_pressed? implementation based on Win32API with
|
||||
one using System.raw_key_states
|
||||
Dec 22, 2014
|
||||
- fixed bug where page list is not properly reset after execution
|
||||
- added a flag for post-event processing for whether an event was triggered
|
||||
Nov 6, 2014
|
||||
- completely refactored code
|
||||
- implemented "any key pressed?" check
|
||||
- moved key item triggers and touch triggers into separate scripts
|
||||
Jan 30, 2014
|
||||
-refactored code
|
||||
-added compatibility with instance items
|
||||
Dec 27, 2013
|
||||
-optimized performance by not clearing out the key item variable on update
|
||||
Nov 19, 2013
|
||||
-fixed bug where stepping on event with no active page crashed the game
|
||||
Sep 26, 2013
|
||||
-added support for "player touch" trigger label
|
||||
Sep 6, 2013
|
||||
-fixed bug where trigger labels as the first command doesn't register properly
|
||||
Mar 22, 2013
|
||||
-fixed bug where you can still trigger events after they have been erased
|
||||
Dec 5, 2012
|
||||
-fixed issue where event was checked before page was setup
|
||||
Oct 20, 2012
|
||||
-fixed issue where using key item in succession crashes game
|
||||
-added support for key item triggers
|
||||
Aug 22, 2012
|
||||
-Support input names greater than one character (eg: F5 vs C)
|
||||
Aug 18, 2012
|
||||
-fixed label parsing to store all buttons
|
||||
Jun 13, 2012
|
||||
-initial release
|
||||
------------------------------------------------------------------------------
|
||||
** Terms of Use
|
||||
* Free to use in non-commercial projects
|
||||
* Contact me for commercial use
|
||||
* No real support. The script is provided as-is
|
||||
* Will do bug fixes, but no compatibility patches
|
||||
* Features may be requested but no guarantees, especially if it is non-trivial
|
||||
* Credits to Hime Works in your project
|
||||
* Preserve this header
|
||||
------------------------------------------------------------------------------
|
||||
** Description:
|
||||
|
||||
This script allows you to assign multiple action triggers to an event.
|
||||
Every page can have its own set of action triggers.
|
||||
|
||||
The action button, by default, is the C button (on keyboards, it is by default
|
||||
the Z key, Enter, or Space). So when you press the action button when you're
|
||||
standing beside an event, you will execute its action trigger and the event
|
||||
will begin running.
|
||||
|
||||
Multiple action triggers allow you to set up your event to run different
|
||||
sets of commands depending on which button you pressed. For example, you can
|
||||
press the C button to interact with the event normally, or you can press the
|
||||
X button (default A key) to initiate a mini-game.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
** Installation
|
||||
|
||||
Place this script below Materials and above Main
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
** Usage
|
||||
|
||||
Instead of treating your page as one list of commands, you should instead
|
||||
treat it as different sections of commands. Each section will have its own
|
||||
label, specified in a specific format.
|
||||
|
||||
To create a section, add a Label command and then write
|
||||
|
||||
button?(:C)
|
||||
|
||||
This means that any commands under this label will be executed when you press
|
||||
the C button (remember that the C button is the Z key on your keyboard).
|
||||
|
||||
You can create as many sections as you want, each with their own buttons.
|
||||
Press F1 in-game and then go to the keyboard tab to see which buttons are
|
||||
available.
|
||||
|
||||
#==============================================================================
|
||||
=end
|
||||
$imported = {} if $imported.nil?
|
||||
$imported[:TH_EventTriggerLabels] = true
|
||||
#==============================================================================
|
||||
# ** Configuration
|
||||
#==============================================================================
|
||||
module TH
|
||||
module Event_Trigger_Labels
|
||||
|
||||
# this is what you need to type for all your labels if you want to use
|
||||
# the input branching
|
||||
Button_Format = "button?"
|
||||
|
||||
#==============================================================================
|
||||
# ** Rest of the script
|
||||
#==============================================================================
|
||||
Button_Regex = /#{Regexp.escape(Button_Format)}\(\:(.*)\)/
|
||||
end
|
||||
end
|
||||
|
||||
module Input
|
||||
class << self
|
||||
alias :th_any_key_pressed_check_update :update
|
||||
end
|
||||
|
||||
# Not every key should be checked
|
||||
Keys_To_Check = 4.upto(99) # SDL scancodes, most standard keys, no modifiers
|
||||
|
||||
if Input.respond_to?(:raw_key_states) then # MKXP-Z 2.4 +
|
||||
def self.update
|
||||
th_any_key_pressed_check_update
|
||||
state = Input.raw_key_states
|
||||
@any_key_pressed = Keys_To_Check.any?{|key| state[key]}
|
||||
end
|
||||
else
|
||||
def self.update
|
||||
th_any_key_pressed_check_update
|
||||
state = System.raw_key_states
|
||||
@any_key_pressed = Keys_To_Check.any?{|key| state[key] != 0}
|
||||
end
|
||||
end
|
||||
|
||||
def self.any_key_pressed?
|
||||
@any_key_pressed
|
||||
end
|
||||
end
|
||||
|
||||
module RPG
|
||||
class Event::Page
|
||||
|
||||
attr_accessor :button_labels
|
||||
|
||||
def button_labels
|
||||
return @button_labels ||= []
|
||||
end
|
||||
|
||||
alias :th_event_trigger_labels_list :list
|
||||
def list
|
||||
setup_trigger_labels unless @trigger_labels_set
|
||||
th_event_trigger_labels_list
|
||||
end
|
||||
|
||||
def setup_trigger_labels
|
||||
@trigger_labels_set = true
|
||||
nulls = []
|
||||
if @trigger < 3
|
||||
@list.each_with_index do |cmd, index|
|
||||
if cmd.code == 118
|
||||
label = cmd.parameters[0]
|
||||
# Check for extra buttons
|
||||
if trigger_label?(label)
|
||||
nulls << index
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# insert "exit event processing" before each "event branch"
|
||||
nulls.reverse.each {|index|
|
||||
@list.insert(index, RPG::EventCommand.new(115))
|
||||
}
|
||||
end
|
||||
|
||||
def trigger_label?(label)
|
||||
if label =~ TH::Event_Trigger_Labels::Button_Regex
|
||||
self.button_labels << $1.to_sym
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Game_Player < Game_Character
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Alias. Try to avoid hardcoding it
|
||||
#-----------------------------------------------------------------------------
|
||||
alias :th_trigger_labels_nonmoving :update_nonmoving
|
||||
def update_nonmoving(last_moving)
|
||||
return if $game_map.interpreter.running?
|
||||
if trigger_conditions_met?
|
||||
pre_trigger_event_processing
|
||||
triggered = check_event_label_trigger
|
||||
post_trigger_event_processing(triggered)
|
||||
end
|
||||
th_trigger_labels_nonmoving(last_moving)
|
||||
end
|
||||
|
||||
def trigger_conditions_met?
|
||||
movable? && Input.any_key_pressed?
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
def pre_trigger_event_processing
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# New. Clean up.
|
||||
#-----------------------------------------------------------------------------
|
||||
def post_trigger_event_processing(triggered)
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# New. Check for any valid events in the area
|
||||
#-----------------------------------------------------------------------------
|
||||
def check_event_label_trigger
|
||||
positions_to_check_for_event.each do |x, y|
|
||||
$game_map.events_xy(x, y).each do |event|
|
||||
label = event.check_trigger_label
|
||||
|
||||
# If no label was found, check next event
|
||||
next unless label
|
||||
|
||||
# If the event can run, insert a jump to label command at
|
||||
# the beginning before running it
|
||||
if check_action_event
|
||||
text = [label]
|
||||
command = RPG::EventCommand.new(119, 0, text)
|
||||
event.list.insert(0, command)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# New. Positions to check events
|
||||
#-----------------------------------------------------------------------------
|
||||
def positions_to_check_for_event
|
||||
positions = [[@x, @y]]
|
||||
x2 = $game_map.round_x_with_direction(@x, @direction)
|
||||
y2 = $game_map.round_y_with_direction(@y, @direction)
|
||||
positions << [x2, y2]
|
||||
return positions unless $game_map.counter?(x2, y2)
|
||||
x3 = $game_map.round_x_with_direction(x2, @direction)
|
||||
y3 = $game_map.round_y_with_direction(y2, @direction)
|
||||
positions << [x3, y3]
|
||||
return positions
|
||||
end
|
||||
end
|
||||
|
||||
class Game_Event
|
||||
|
||||
attr_reader :page
|
||||
attr_reader :erased
|
||||
attr_accessor :list
|
||||
|
||||
alias :th_event_trigger_labels_setup_page_settings :setup_page_settings
|
||||
def setup_page_settings(*args)
|
||||
th_event_trigger_labels_setup_page_settings
|
||||
@list = Marshal.load(Marshal.dump(@page.list.clone))
|
||||
end
|
||||
|
||||
def check_trigger_label
|
||||
return nil if @erased
|
||||
label = get_trigger_label
|
||||
if label
|
||||
# Reset the commands (Since we maybe have inserted a jump command before)
|
||||
@needs_reset = true
|
||||
end
|
||||
return label
|
||||
end
|
||||
|
||||
def get_trigger_label
|
||||
label = check_button_trigger
|
||||
return label if label
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# New. Check whether the button triggers the event
|
||||
#-----------------------------------------------------------------------------
|
||||
def check_button_trigger
|
||||
return unless button_trigger_met?
|
||||
@page.button_labels.each do |button|
|
||||
if Input.trigger?(button)
|
||||
return "#{TH::Event_Trigger_Labels::Button_Format}(:#{button})"
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def button_trigger_met?
|
||||
return false unless @page
|
||||
return false if @page.button_labels.empty?
|
||||
return true
|
||||
end
|
||||
|
||||
alias :th_event_trigger_labels_update :update
|
||||
def update
|
||||
th_event_trigger_labels_update
|
||||
reset_page if @needs_reset
|
||||
end
|
||||
|
||||
def reset_page
|
||||
@needs_reset = false
|
||||
@list = Marshal.load(Marshal.dump(@page.list.clone))
|
||||
end
|
||||
end
|
110
mkxp-z/Kawariki-patches/ports/TH_SimpleAudioEncryption.rb
Normal file
110
mkxp-z/Kawariki-patches/ports/TH_SimpleAudioEncryption.rb
Normal file
|
@ -0,0 +1,110 @@
|
|||
=begin
|
||||
#===============================================================================
|
||||
Title: Simple Audio Encryption MKXP-Z
|
||||
Author: Taeyeon Mori
|
||||
Date: Feb 23, 2022
|
||||
Original Title: Simple Audio Encryption
|
||||
Original Author: Hime
|
||||
Original Date: Mar 22, 2014
|
||||
Original URL: http://www.himeworks.com/2014/03/21/simple-audio-encryption/
|
||||
--------------------------------------------------------------------------------
|
||||
** Original Terms of Use
|
||||
* Free to use in non-commercial projects
|
||||
* Contact me for commercial use
|
||||
* No real support. The script is provided as-is
|
||||
* Will do bug fixes, but no compatibility patches
|
||||
* Features may be requested but no guarantees, especially if it is non-trivial
|
||||
* Credits to Hime Works in your project
|
||||
* Preserve this header
|
||||
#===============================================================================
|
||||
=end
|
||||
|
||||
$imported = {} if $imported.nil?
|
||||
$imported[:TH_SimpleAudioEncryption] = true
|
||||
|
||||
module TH
|
||||
module Crypt
|
||||
@@video_extensions = [".ogv"]
|
||||
@@audio_extensions = ["", ".ogg", ".mp3", ".mid", ".wav"]
|
||||
@@cache = {}
|
||||
|
||||
def self.find_real_path(path, exts)
|
||||
# return unmodified if we can verify that it exists outside archive
|
||||
return path if exts.any? {|ext| File.exist? (path + ext)}
|
||||
exts.each do|ext|
|
||||
# There is no way to check if a file exists in the archive from Ruby
|
||||
# So we try to load it to a string and see if it fails.
|
||||
# This is expensive so make sure to cache the result of this method
|
||||
candidate = "Data/" + path + ext
|
||||
begin
|
||||
# MKXP-Z extension
|
||||
load_data candidate, true
|
||||
rescue
|
||||
next
|
||||
end
|
||||
Preload.print "TH_SAE: Found #{path} at #{candidate}"
|
||||
return candidate
|
||||
end
|
||||
# return nil if not found
|
||||
return nil
|
||||
end
|
||||
|
||||
def self.real_path(path, exts)
|
||||
# Check cache
|
||||
real_path = @@cache[path]
|
||||
return real_path unless real_path.nil?
|
||||
# Try to find
|
||||
real_path = self.find_real_path path, exts
|
||||
# Just fall back to the original path if not found
|
||||
# Otherwise, we'll repeat the expensive lookup
|
||||
# whenever this path comes up
|
||||
real_path = path if real_path.nil?
|
||||
# Save to cache
|
||||
@@cache[path] = real_path
|
||||
return real_path
|
||||
end
|
||||
|
||||
def self.real_audio_path(path)
|
||||
self.real_path path, @@audio_extensions
|
||||
end
|
||||
|
||||
def self.real_video_path(path)
|
||||
self.real_path path, @@video_extensions
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Audio
|
||||
class << self
|
||||
alias :th_simple_audio_decryption_bgm_play :bgm_play
|
||||
alias :th_simple_audio_decryption_bgs_play :bgs_play
|
||||
alias :th_simple_audio_decryption_me_play :me_play
|
||||
alias :th_simple_audio_decryption_se_play :se_play
|
||||
end
|
||||
|
||||
def self.bgm_play(name, *args)
|
||||
th_simple_audio_decryption_bgm_play(TH::Crypt::real_audio_path(name), *args)
|
||||
end
|
||||
|
||||
def self.bgs_play(name, *args)
|
||||
th_simple_audio_decryption_bgs_play(TH::Crypt::real_audio_path(name), *args)
|
||||
end
|
||||
|
||||
def self.me_play(name, *args)
|
||||
th_simple_audio_decryption_me_play(TH::Crypt::real_audio_path(name), *args)
|
||||
end
|
||||
|
||||
def self.se_play(name, *args)
|
||||
th_simple_audio_decryption_se_play(TH::Crypt::real_audio_path(name), *args)
|
||||
end
|
||||
end
|
||||
|
||||
module Graphics
|
||||
class << self
|
||||
alias :th_simple_audio_encryption_play_movie :play_movie
|
||||
end
|
||||
|
||||
def self.play_movie(name, *args)
|
||||
th_simple_audio_encryption_play_movie(TH::Crypt::real_video_path(name), *args)
|
||||
end
|
||||
end
|
815
mkxp-z/Kawariki-patches/ports/XP_CustomResolution.rb
Normal file
815
mkxp-z/Kawariki-patches/ports/XP_CustomResolution.rb
Normal file
|
@ -0,0 +1,815 @@
|
|||
#===============================================================================
|
||||
# Custom Resolution
|
||||
# Authors: ForeverZer0, KK20
|
||||
# Version: 0.96b
|
||||
# Date: 11.15.2013
|
||||
#===============================================================================
|
||||
# MKXP Port
|
||||
# Authors: Taeyeon Mori
|
||||
# Date: 01/30/2022
|
||||
#
|
||||
# Includes tilemap texture size workaround
|
||||
Preload.require 'XP_TilemapOverrideLib.rb'
|
||||
#===============================================================================
|
||||
# KK20's Notes
|
||||
#===============================================================================
|
||||
# Introduction:
|
||||
#
|
||||
# This script is intended to create screen resolutions other than 640 x 480.
|
||||
# The script comes with its own Tilemap rewrite in order to combat larger
|
||||
# screen resolutions (because anything beyond 640 x 480 is not drawn).
|
||||
#
|
||||
# Instructions:
|
||||
#
|
||||
# Place script above 'Main'. Probably best to put it below all your other
|
||||
# custom scripts.
|
||||
# You will also need 'screenshot.dll' included in your project. You can find
|
||||
# that in Fantasist's Transitions Pack linked below.
|
||||
#
|
||||
# Things to Consider:
|
||||
#
|
||||
# - Fullscreen will change the resolution back to 640 x 480. A solution is in
|
||||
# the works.
|
||||
# - Transitions do not work properly on larger resolutions. You can use a
|
||||
# Transitions Add-Ons script if you want better transitions (otherwise, all
|
||||
# you will get is the default fade in/out). Links listed below.
|
||||
# - Custom scripts that draw windows to the screen will most likely need edits.
|
||||
# - Larger resolutions = more processing power = more lag
|
||||
#
|
||||
# ***************************************************************************
|
||||
# * THIS IS STILL A WORK IN PROGRESS; IF YOU FIND ANYTHING PLEASE REPORT IT *
|
||||
# ***************************************************************************
|
||||
#
|
||||
# Links:
|
||||
# - Fantasist's Transitions Pack (w/ screenshot.dll)
|
||||
# http://forum.chaos-project.com/index.php/topic,1390.0.html
|
||||
# - ForeverZer0's Add-ons
|
||||
# http://forum.chaos-project.com/index.php/topic,7862.0.html
|
||||
# - ThallionDarkshine's Add-ons
|
||||
# http://forum.chaos-project.com/index.php/topic,12655.0.html
|
||||
# - Drago Transition Pack
|
||||
# http://forum.chaos-project.com/index.php/topic,13488.0.html
|
||||
#
|
||||
#===============================================================================
|
||||
# ForeverZer0's Notes from v0.93 (outdated information)
|
||||
#===============================================================================
|
||||
# Introduction:
|
||||
#
|
||||
# My goal in creating this script was to create a system that allowed the user
|
||||
# to set the screen size to something other than 640 x 480, but not have make
|
||||
# huge sacrifices in compatibility and performance. Although the script is
|
||||
# not simply Plug-and-Play, it is about as close as one can achieve with a
|
||||
# script of this nature.
|
||||
#
|
||||
# Instructions:
|
||||
#
|
||||
# - Place the "screenshot.dll" from Fantasist's Transition Pack script, which
|
||||
# can be found here: http://www.sendspace.com/file/yjd54h in your game folder
|
||||
# - Place this script above main, below default scripts.
|
||||
# - In my experience, unchecking "Reduce Screen Flickering" actually helps the
|
||||
# screen not to flicker. Open menu with F1 while playing and set this to what
|
||||
# you get the best results with.
|
||||
#
|
||||
# Features:
|
||||
#
|
||||
# - Totally re-written Tilemap and Plane class. Both classes were written to
|
||||
# display the map across any screen size automatically. The Tilemap class
|
||||
# is probably even more efficient than the original, which will help offset
|
||||
# any increased lag due to using a larger screen size with more sprites
|
||||
# being displayed.
|
||||
# - Every possible autotile graphic (48 per autotile) will be cached for the
|
||||
# next time that tile is used.
|
||||
# - Autotile animation has been made as efficient as possible, with a system
|
||||
# that stores their coodinates, but only if they change. This greatly reduces
|
||||
# the number of iterations at each update.
|
||||
# - System creates an external file to save pre-cached data priorities and
|
||||
# autotiles. This will decrease any loading times even more, and only takes a
|
||||
# second, depending on the number of maps you have.
|
||||
# - User defined autotile animation speed. Can change with script calls.
|
||||
# - Automatic re-sizing of Bitmaps and Viewports that are 640 x 480 to the
|
||||
# defined resolution, unless explicitely over-ridden in the method call.
|
||||
# The graphics themselves will not be resized, but any existing scripts that
|
||||
# use the normal screen size will already be configured to display different
|
||||
# sizes of graphics for transitions, battlebacks, pictures, fogs, etc.
|
||||
# - Option to have a log file ouput each time the game is ran, which can alert
|
||||
# you to possible errors with map sizes, etc.
|
||||
#
|
||||
# Issues/Bugs/Possible Bugs:
|
||||
#
|
||||
# - Graphic related scripts and your graphics will need to be customized to
|
||||
# fit the new screen size, so this script is not for everyone.
|
||||
# - The Z-axis for the Plane class, which is used for Fogs and Panoramas has
|
||||
# been altered. It is now multiplied by 1000. This will likely be a minor
|
||||
# issue for most, since this class is very rarely used except for Fogs and
|
||||
# Panoramas, which are already far above and below respectfully.
|
||||
# - Normal transitions using graphics cannot be used. With the exception of
|
||||
# a standard fade, like that used when no graphic is defined will be used.
|
||||
# Aside from that, only special transitions from Transition Pack can be
|
||||
# used.
|
||||
#===============================================================================
|
||||
# Credits/Thanks:
|
||||
# - ForeverZer0, for script.
|
||||
# - Creators of the Transition Pack and Screenshot.dll
|
||||
# - Selwyn, for base resolution script
|
||||
# - KK20, for Version 0.94 and above and the Tilemap class
|
||||
#===============================================================================
|
||||
# CONFIGURATION
|
||||
#===============================================================================
|
||||
# FIXME: need to exfiltrate this in the preload patch process
|
||||
|
||||
SCREEN = [1024, 576]
|
||||
# Define the resolution of the game screen. These values can be anything
|
||||
# within reason. Centering, viewports, etc. will all be taken care of, but it
|
||||
# is recommended that you use values divisible by 32 for best results.
|
||||
|
||||
UPDATE_COUNT = 8
|
||||
# Define the number of frames between autotile updates. The lower the number,
|
||||
# the faster the animations cycle. This can be changed in-game with the
|
||||
# following script call: $game_map.autotile_speed = SPEED
|
||||
|
||||
RESOLUTION_LOG = true
|
||||
# This will create a log in the Game directory each time the game is ran in
|
||||
# DEBUG mode, which will list possible errors with map sizes, etc.
|
||||
|
||||
#===============================================================================
|
||||
# ** Resolution
|
||||
#===============================================================================
|
||||
|
||||
class Resolution
|
||||
|
||||
attr_reader :version
|
||||
|
||||
def initialize
|
||||
# Define version.
|
||||
@version = 0.96
|
||||
# Resize screen
|
||||
Graphics.resize_screen(SCREEN[0], SCREEN[1])
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
def size
|
||||
# Returns the screen size of the machine.
|
||||
# FIXME: available in MKXP?
|
||||
return [1920, 1080]
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
def snapshot(filename = 'Data/snap', quality = 0)
|
||||
# FILENAME = Filename that the picture will be saved as.
|
||||
# FILETYPE = 0 = High Quality 1 = Low Quality (ignored)
|
||||
Graphics.screenshot(filename)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# ** RPG::Cache
|
||||
#===============================================================================
|
||||
|
||||
module RPG::Cache
|
||||
|
||||
AUTO_INDEX = [
|
||||
[27,28,33,34], [5,28,33,34], [27,6,33,34], [5,6,33,34],
|
||||
[27,28,33,12], [5,28,33,12], [27,6,33,12], [5,6,33,12],
|
||||
[27,28,11,34], [5,28,11,34], [27,6,11,34], [5,6,11,34],
|
||||
[27,28,11,12], [5,28,11,12], [27,6,11,12], [5,6,11,12],
|
||||
[25,26,31,32], [25,6,31,32], [25,26,31,12], [25,6,31,12],
|
||||
[15,16,21,22], [15,16,21,12], [15,16,11,22], [15,16,11,12],
|
||||
[29,30,35,36], [29,30,11,36], [5,30,35,36], [5,30,11,36],
|
||||
[39,40,45,46], [5,40,45,46], [39,6,45,46], [5,6,45,46],
|
||||
[25,30,31,36], [15,16,45,46], [13,14,19,20], [13,14,19,12],
|
||||
[17,18,23,24], [17,18,11,24], [41,42,47,48], [5,42,47,48],
|
||||
[37,38,43,44], [37,6,43,44], [13,18,19,24], [13,14,43,44],
|
||||
[37,42,43,48], [17,18,47,48], [13,18,43,48], [1,2,7,8]
|
||||
]
|
||||
|
||||
def self.autotile(filename)
|
||||
key = "Graphics/Autotiles/#{filename}"
|
||||
if !@cache.include?(key) || @cache[key].disposed?
|
||||
# Cache the autotile graphic.
|
||||
@cache[key] = (filename == '') ? Bitmap.new(128, 96) : Bitmap.new(key)
|
||||
# Cache each configuration of this autotile.
|
||||
new_bm = self.format_autotiles(@cache[key], filename)
|
||||
@cache[key].dispose
|
||||
@cache[key] = new_bm
|
||||
end
|
||||
return @cache[key]
|
||||
end
|
||||
|
||||
def self.format_autotiles(bitmap, filename)
|
||||
if bitmap.height > 32
|
||||
frames = bitmap.width / 96
|
||||
template = Bitmap.new(256*frames,192)
|
||||
# Create a bitmap to use as a template for creation.
|
||||
(0..frames-1).each{|frame|
|
||||
(0...6).each {|i| (0...8).each {|j| AUTO_INDEX[8*i+j].each {|number|
|
||||
number -= 1
|
||||
x, y = 16 * (number % 6), 16 * (number / 6)
|
||||
rect = Rect.new(x + (frame * 96), y, 16, 16)
|
||||
template.blt((32 * j + x % 32) + (frame * 256), 32 * i + y % 32, bitmap, rect)
|
||||
}}}}
|
||||
return template
|
||||
else
|
||||
return bitmap
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# ** Tilemap_DataTable
|
||||
#===============================================================================
|
||||
class Tilemap_DataTable
|
||||
attr_accessor :updates
|
||||
attr_accessor :table
|
||||
def initialize(table)
|
||||
@table = table
|
||||
@updates = []
|
||||
end
|
||||
|
||||
def updated
|
||||
return @updates.size >= 1
|
||||
end
|
||||
|
||||
def [](x,y=nil,z=nil)
|
||||
return @table[x,y,z] unless z.nil?
|
||||
return @table[x,y] unless y.nil?
|
||||
return @table[x]
|
||||
end
|
||||
|
||||
def []=(x,y,z=nil,t_id=nil)
|
||||
@updates.push([x,y,z,t_id]) unless t_id.nil?
|
||||
t_id.nil? ? (z.nil? ? @table[x] = y : @table[x,y] = z) : @table[x,y,z] = t_id
|
||||
end
|
||||
|
||||
def xsize; return @table.xsize; end
|
||||
def ysize; return @table.ysize; end
|
||||
def zsize; return @table.zsize; end
|
||||
|
||||
def resize(x,y=nil,z=nil); @table.resize(x,y,z); end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# ** Tilemap
|
||||
#===============================================================================
|
||||
|
||||
class Tilemap
|
||||
|
||||
attr_reader :tileset, :map_data, :ox, :oy, :viewport
|
||||
attr_accessor :autotiles, :priorities
|
||||
|
||||
# +++ MKXP +++
|
||||
def tileset=(value)
|
||||
# Need to wrap tilesets that don't fit into texture
|
||||
if value.mega?
|
||||
@tileset = TileWrap::wrapTileset(value)
|
||||
value.dispose
|
||||
else
|
||||
@tileset = value
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(viewport)
|
||||
# Initialize instance variables to store required data.
|
||||
@viewport, @autotiles, @tile_sprites, @ox, @oy = viewport, [], [], 0, 0
|
||||
@current_frame, @total_frames = [], []
|
||||
@tilemap_drawn = false
|
||||
@ox_oy_set = [false, false]
|
||||
# Get priority data for this tileset from instance of Game_Map.
|
||||
@priorities = $game_map.priorities
|
||||
# Holds all the Sprite instances of animating tiles (keys based on tile's ID)
|
||||
@animating_tiles = {}
|
||||
# Game map's x/y location of the top left corner tile
|
||||
@corner_tile_loc = [-1,-1]
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Initialize all tile sprites. Draws three sprites per (x,y).
|
||||
#-----------------------------------------------------------------------------
|
||||
def init_tiles
|
||||
# Determine how many frames of animation this autotile has
|
||||
for i in 0..6
|
||||
bm = @autotiles[i]
|
||||
if bm.nil?
|
||||
@total_frames = 1
|
||||
elsif bm.height > 32
|
||||
@total_frames[i] = bm.width / 256
|
||||
else
|
||||
@total_frames[i] = bm.width / 32
|
||||
end
|
||||
@current_frame[i] = 0
|
||||
end
|
||||
# Turn on flag that the tilemap sprites have been initialized
|
||||
@tilemap_drawn = true
|
||||
|
||||
@animating_tiles.clear
|
||||
# Create a sprite and viewport to use for each priority level.
|
||||
(0...((SCREEN[0]/32+2) * (SCREEN[1]/32+2))*3).each{|i|
|
||||
@tile_sprites[i/3] = [] if @tile_sprites[i/3].nil?
|
||||
@tile_sprites[i/3][i%3] = Sprite.new(@viewport) unless @tile_sprites[i/3][i%3].is_a?(Sprite)
|
||||
# Rename to something shorter and easier to work with for below
|
||||
tile = @tile_sprites[i/3][i%3]
|
||||
# Assign tile's respective ID value
|
||||
tile.tile_sprite_id = i
|
||||
# Draw sprite at index location (ex. ID 0 should always be the top-left sprite)
|
||||
tile.x = (i % ((SCREEN[0]/32+2)*3) / 3 * 32) - 32 + (@ox % 32)
|
||||
tile.y = (i / ((SCREEN[0]/32+2)*3) * 32) - 32 + (@oy % 32)
|
||||
|
||||
map_x, map_y = (tile.x+@ox)/32, (tile.y+@oy)/32
|
||||
@corner_tile_loc = [map_x, map_y] if i == 0
|
||||
# If the tile happens to be drawn along the outside borders of the map
|
||||
if map_x < 0 || map_x >= $game_map.width || map_y < 0 || map_y >= $game_map.height
|
||||
update_tile_id tile, 0
|
||||
else # Tile is actually on the map
|
||||
update_tile_id tile, @map_data[map_x, map_y, i%3]
|
||||
end
|
||||
}
|
||||
# Sprite ID located at top left corner (ranges from 0..map_width * map_height
|
||||
@corner_index = 0
|
||||
end
|
||||
|
||||
# Common code for setting the tile by id
|
||||
def update_tile_id(tile, tile_id)
|
||||
if tile_id == 0 # empty tile
|
||||
tile.z = 0
|
||||
tile.bitmap = RPG::Cache.picture('')#@tileset
|
||||
tile.src_rect.set(0,0,0,0)
|
||||
return
|
||||
end
|
||||
if @priorities[tile_id] == 0
|
||||
tile.z = 0
|
||||
else
|
||||
tile.z = tile.y + @priorities[tile_id] * 32 + 32
|
||||
end
|
||||
if tile_id >= 384 # non-autotile
|
||||
tile.bitmap = @tileset
|
||||
tile.src_rect.set(((tile_id - 384) % 8) * 32,
|
||||
((tile_id - 384) / 8) * 32,
|
||||
32, 32)
|
||||
# Fix rect for possibly wrapped tileset
|
||||
TileWrap.wrapRect! tile.src_rect
|
||||
else # autotile
|
||||
auto_id = tile_id/48-1
|
||||
tile.bitmap = @autotiles[auto_id]
|
||||
tile.src_rect.set(((tile_id % 48) % 8) * 32 + @current_frame[auto_id] * 256,
|
||||
((tile_id % 48) / 8) * 32,
|
||||
32, 32)
|
||||
@animating_tiles[tile.tile_sprite_id] = tile if @total_frames[auto_id] > 1
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Makes update to ox and oy. Sprites out of range will be moved based on these
|
||||
# two values.
|
||||
#-----------------------------------------------------------------------------
|
||||
def ox=(ox)
|
||||
#
|
||||
unless @tilemap_drawn
|
||||
@ox = ox
|
||||
@ox_oy_set[0] = true
|
||||
return
|
||||
end
|
||||
|
||||
return if @ox == ox
|
||||
# Shift all tiles left or right by the difference
|
||||
shift = @ox - ox
|
||||
|
||||
@tile_sprites.each {|set| set.each{|tile| tile.x += shift }}
|
||||
@ox = ox
|
||||
# Determine if columns need to be shifted
|
||||
col_num = @corner_index
|
||||
#return unless @tile_sprites[col_num][0].x <= -49 || @tile_sprites[col_num][0].x >= -17
|
||||
while @tile_sprites[col_num][0].x <= -49 || @tile_sprites[col_num][0].x >= -17
|
||||
|
||||
@corner_tile_loc[0] += (shift < 0 ? 1 : -1)
|
||||
modTileId = ((SCREEN[0]+64)*(SCREEN[1]+64))/1024
|
||||
# If new ox is greater than old ox
|
||||
if shift < 0
|
||||
# Move all sprites in left column to the right side and change bitmaps
|
||||
# and z-values
|
||||
(0...(SCREEN[1]/32+2)).each{|n|
|
||||
j = ((SCREEN[0]/32+2) * n + col_num) % modTileId
|
||||
@tile_sprites[j].each_index{|i|
|
||||
tile = @tile_sprites[j][i]
|
||||
@animating_tiles.delete(tile.tile_sprite_id)
|
||||
tile.x += 64 + SCREEN[0]
|
||||
|
||||
map_x, map_y = (tile.x+@ox)/32, (tile.y+@oy)/32
|
||||
tile_id = @map_data[map_x,map_y,i]
|
||||
|
||||
if tile_id.nil?
|
||||
tile.z = [map_y * 32, 0].max
|
||||
tile.bitmap = RPG::Cache.picture('')
|
||||
tile.src_rect.set(0,0,0,0)
|
||||
next
|
||||
end
|
||||
|
||||
update_tile_id tile, tile_id
|
||||
}
|
||||
}
|
||||
# New corner should be the tile immediately right of the previous tile
|
||||
col_num /= SCREEN[0]/32+2
|
||||
col_num *= SCREEN[0]/32+2
|
||||
@corner_index = (@corner_index + 1) % (SCREEN[0]/32+2) + col_num
|
||||
else
|
||||
# Shift right column to the left
|
||||
# Gets the right column
|
||||
row_index = col_num / (SCREEN[0]/32+2)
|
||||
row_index *= (SCREEN[0]/32+2)
|
||||
col_num = (@corner_index - 1) % (SCREEN[0]/32+2) + row_index
|
||||
|
||||
(0...(SCREEN[1]/32+2)).each{|n|
|
||||
j = ((SCREEN[0]/32+2) * n + col_num) % modTileId
|
||||
@tile_sprites[j].each_index{|i|
|
||||
tile = @tile_sprites[j][i]
|
||||
@animating_tiles.delete(tile.tile_sprite_id)
|
||||
tile.x -= 64 + SCREEN[0]
|
||||
|
||||
map_x, map_y = (tile.x+@ox)/32, (tile.y+@oy)/32
|
||||
tile_id = @map_data[map_x,map_y,i]
|
||||
if tile_id.nil?
|
||||
tile.z = [map_y * 32, 0].max
|
||||
tile.bitmap = @tileset
|
||||
tile.src_rect.set(0,0,0,0)
|
||||
next
|
||||
end
|
||||
|
||||
update_tile_id tile, tile_id
|
||||
}
|
||||
}
|
||||
col_num /= SCREEN[0]/32+2
|
||||
col_num *= SCREEN[0]/32+2
|
||||
@corner_index = (@corner_index - 1) % (SCREEN[0]/32+2) + col_num
|
||||
end
|
||||
col_num = @corner_index
|
||||
end #end of while
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def oy=(oy)
|
||||
#
|
||||
unless @tilemap_drawn
|
||||
@oy = oy
|
||||
@ox_oy_set[1] = true
|
||||
return
|
||||
end
|
||||
|
||||
return if @oy == oy
|
||||
# Shift all tiles up or down by the difference, and change z-value
|
||||
shift = @oy - oy
|
||||
|
||||
@tile_sprites.each {|set| set.each{|tile| tile.y += shift; tile.z += shift unless tile.z == 0 }}
|
||||
@oy = oy
|
||||
# Determine if rows need to be shifted
|
||||
row_num = @corner_index
|
||||
#return unless @tile_sprites[row_num][0].y <= -49 || @tile_sprites[row_num][0].y >= -17
|
||||
while @tile_sprites[row_num][0].y <= -49 || @tile_sprites[row_num][0].y >= -17
|
||||
|
||||
|
||||
# Needed for resetting the new corner index much later.
|
||||
modTileId = ((SCREEN[0]+64)*(SCREEN[1]+64))/1024
|
||||
@corner_tile_loc[1] += (shift < 0 ? 1 : -1)
|
||||
# If new oy is greater than old oy
|
||||
if shift < 0
|
||||
row_num /= SCREEN[0]/32+2
|
||||
row_num *= SCREEN[0]/32+2
|
||||
# Move all sprites in top row to the bottom side and change bitmaps
|
||||
# and z-values
|
||||
(0...(SCREEN[0]/32+2)).each{|n|
|
||||
# Run through each triad of sprites from left to right
|
||||
j = n + row_num
|
||||
@tile_sprites[j].each_index{|i|
|
||||
# Get each individual tile on each layer
|
||||
tile = @tile_sprites[j][i]
|
||||
@animating_tiles.delete(tile.tile_sprite_id)
|
||||
tile.y += 64 + SCREEN[1]
|
||||
# Determine what map coordinate this tile now resides at...
|
||||
map_x, map_y = (tile.x+@ox)/32, (tile.y+@oy)/32
|
||||
# ...and get its tile_id
|
||||
tile_id = @map_data[map_x,map_y,i]
|
||||
# If no tile exists here (effectively out of array bounds)
|
||||
if tile_id.nil?
|
||||
tile.z = [map_y * 32, 0].max
|
||||
tile.bitmap = RPG::Cache.picture('')
|
||||
tile.src_rect.set(0,0,0,0)
|
||||
next
|
||||
end
|
||||
|
||||
update_tile_id tile, tile_id
|
||||
}
|
||||
}
|
||||
|
||||
@corner_index = (@corner_index + (SCREEN[0]/32+2)) % modTileId
|
||||
else
|
||||
row_num = (@corner_index - (SCREEN[0]/32+2)) % modTileId
|
||||
row_num /= SCREEN[0]/32+2
|
||||
row_num *= SCREEN[0]/32+2
|
||||
(0...(SCREEN[0]/32+2)).each{|n|
|
||||
# Run through each triad of sprites from left to right
|
||||
j = n + row_num
|
||||
@tile_sprites[j].each_index{|i|
|
||||
# Get each individual tile on each layer
|
||||
tile = @tile_sprites[j][i]
|
||||
@animating_tiles.delete(tile.tile_sprite_id)
|
||||
tile.y -= 64 + SCREEN[1]
|
||||
# Determine what map coordinate this tile now resides at...
|
||||
map_x, map_y = (tile.x+@ox)/32, (tile.y+@oy)/32
|
||||
# ...and get its tile_id
|
||||
tile_id = @map_data[map_x,map_y,i]
|
||||
# If no tile exists here (effectively out of array bounds)
|
||||
if tile_id.nil?
|
||||
tile.z = [map_y * 32, 0].max
|
||||
tile.bitmap = RPG::Cache.picture('')
|
||||
tile.src_rect.set(0,0,0,0)
|
||||
next
|
||||
end
|
||||
|
||||
update_tile_id tile, tile_id
|
||||
}
|
||||
}
|
||||
@corner_index = (@corner_index - (SCREEN[0]/32+2)) % modTileId
|
||||
end
|
||||
row_num = @corner_index
|
||||
end # end of while
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Dispose all the tile sprites
|
||||
#-----------------------------------------------------------------------------
|
||||
def dispose
|
||||
# Dispose all of the sprites
|
||||
@tile_sprites.each {|set| set.each{|tile| tile.dispose }}
|
||||
@tile_sprites.clear
|
||||
@animating_tiles.clear
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Set map data
|
||||
#-----------------------------------------------------------------------------
|
||||
def map_data=(data)
|
||||
# Set the map data to new class
|
||||
if data.is_a?(Tilemap_DataTable)
|
||||
@map_data = data
|
||||
else
|
||||
@map_data = Tilemap_DataTable.new(data)
|
||||
end
|
||||
@map_data.table = @map_data.table.clone
|
||||
@map_data.updates = []
|
||||
|
||||
@animating_tiles.clear
|
||||
@tilemap_drawn = false
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Update the tile sprites; make changes to the map_data and update autotiles
|
||||
#-----------------------------------------------------------------------------
|
||||
def update
|
||||
# Can't update anything if the ox and oy have not yet been set
|
||||
return if @ox_oy_set != [true, true]
|
||||
# If the tilemap sprites have not been initialized, GO DO IT
|
||||
if !@tilemap_drawn
|
||||
init_tiles
|
||||
end
|
||||
|
||||
# If made any changes to $game_map.data, the proper graphics will be drawn
|
||||
if @map_data.updated
|
||||
@map_data.updates.each{|item|
|
||||
x,y,z,tile_id = item
|
||||
# If this changed tile is visible on screen
|
||||
if x.between?(@corner_tile_loc[0], @corner_tile_loc[0]+(SCREEN[0]/32 + 1)) and
|
||||
y.between?(@corner_tile_loc[1], @corner_tile_loc[1]+(SCREEN[1]/32 + 1))
|
||||
|
||||
x_dif = x - @corner_tile_loc[0]
|
||||
y_dif = y - @corner_tile_loc[1]
|
||||
|
||||
id = @corner_index + x_dif
|
||||
id -= SCREEN[0]/32+2 if id/(SCREEN[0]/32+2) > @corner_index/(SCREEN[0]/32+2)
|
||||
|
||||
id += y_dif * (SCREEN[0]/32+2)
|
||||
id -= (SCREEN[0]/32+2)*(SCREEN[1]/32+2) if id >= (SCREEN[0]/32+2)*(SCREEN[1]/32+2)
|
||||
|
||||
tile = @tile_sprites[id][z]
|
||||
@animating_tiles.delete(tile.tile_sprite_id)
|
||||
|
||||
update_tile_id tile, tile_id
|
||||
end
|
||||
}
|
||||
@map_data.updates = []
|
||||
end
|
||||
|
||||
# Update the sprites.
|
||||
if Graphics.frame_count % $game_map.autotile_speed == 0
|
||||
# Increase current frame of tile by one, looping by width.
|
||||
for i in 0..6
|
||||
@current_frame[i] = (@current_frame[i] + 1) % @total_frames[i]
|
||||
end
|
||||
@animating_tiles.each_value{|tile|
|
||||
frames = tile.bitmap.width
|
||||
tile.src_rect.set((tile.src_rect.x + 256) % frames, tile.src_rect.y, 32, 32)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Game_Map
|
||||
#===============================================================================
|
||||
|
||||
class Game_Map
|
||||
|
||||
attr_reader :tile_size, :autotile_speed, :autotile_data, :priority_data
|
||||
|
||||
alias zer0_load_autotile_data_init initialize
|
||||
def initialize
|
||||
# Call original method.
|
||||
zer0_load_autotile_data_init
|
||||
# Store the screen dimensions in tiles to save on calculations later.
|
||||
@tile_size = [SCREEN[0], SCREEN[1]].collect {|n| (n / 32.0).ceil }
|
||||
@autotile_speed = UPDATE_COUNT
|
||||
end
|
||||
|
||||
alias zer0_map_edge_setup setup
|
||||
def setup(map_id)
|
||||
# Call original method.
|
||||
zer0_map_edge_setup(map_id)
|
||||
# Change Map's data into a special Table class
|
||||
@map.data = Tilemap_DataTable.new(@map.data)
|
||||
# Find the displayed area of the map in tiles. No calcualting every step.
|
||||
@map_edge = [self.width - @tile_size[0], self.height - @tile_size[1]]
|
||||
@map_edge.collect! {|size| size * 128 }
|
||||
end
|
||||
|
||||
def scroll_down(distance)
|
||||
# Find point that the map edge meets the screen edge, using custom size.
|
||||
@display_y = [@display_y + distance, @map_edge[1]].min
|
||||
end
|
||||
|
||||
def scroll_right(distance)
|
||||
# Find point that the map edge meets the screen edge, using custom size.
|
||||
@display_x = [@display_x + distance, @map_edge[0]].min
|
||||
end
|
||||
|
||||
def autotile_speed=(speed)
|
||||
# Keep the speed above 0 to prevent the ZeroDivision Error.
|
||||
@autotile_speed = speed
|
||||
@autotile_speed = 1 if @autotile_speed < 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# ** Game_Player
|
||||
#===============================================================================
|
||||
|
||||
class Game_Player
|
||||
|
||||
CENTER_X = ((SCREEN[0] / 2) - 16) * 4 # Center screen x-coordinate * 4
|
||||
CENTER_Y = ((SCREEN[1] / 2) - 16) * 4 # Center screen y-coordinate * 4
|
||||
|
||||
def center(x, y)
|
||||
# Recalculate the screen center based on the new resolution.
|
||||
max_x = ($game_map.width - $game_map.tile_size[0]) * 128
|
||||
max_y = ($game_map.height - $game_map.tile_size[1]) * 128
|
||||
$game_map.display_x = [0, [x * 128 - CENTER_X, max_x].min].max
|
||||
$game_map.display_y = [0, [y * 128 - CENTER_Y, max_y].min].max
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# ** Sprite
|
||||
#===============================================================================
|
||||
class Sprite
|
||||
attr_accessor :tile_sprite_id
|
||||
alias tile_sprite_id_init initialize
|
||||
def initialize(view = nil)
|
||||
# No defined ID
|
||||
@tile_sprite_id = nil
|
||||
# Call original method.
|
||||
tile_sprite_id_init(view)
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# ** Viewport
|
||||
#===============================================================================
|
||||
class Viewport
|
||||
|
||||
alias zer0_viewport_resize_init initialize
|
||||
def initialize(x=0, y=0, width=SCREEN[0], height=SCREEN[1], override=false)
|
||||
if x.is_a?(Rect)
|
||||
# If first argument is a Rectangle, just use it as the argument.
|
||||
zer0_viewport_resize_init(x)
|
||||
elsif [x, y, width, height] == [0, 0, 640, 480] && !override
|
||||
# Resize fullscreen viewport, unless explicitly overridden.
|
||||
zer0_viewport_resize_init(Rect.new(0, 0, SCREEN[0], SCREEN[1]))
|
||||
else
|
||||
# Call method normally.
|
||||
zer0_viewport_resize_init(Rect.new(x, y, width, height))
|
||||
end
|
||||
end
|
||||
|
||||
def resize(*args)
|
||||
# Resize the viewport. Can call with (X, Y, WIDTH, HEIGHT) or (RECT).
|
||||
self.rect = args[0].is_a?(Rect) ? args[0] : Rect.new(*args)
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# ** Plane
|
||||
#===============================================================================
|
||||
|
||||
# class Plane < Sprite
|
||||
|
||||
# def z=(z)
|
||||
# # Change the Z value of the viewport, not the sprite.
|
||||
# super(z * 1000)
|
||||
# end
|
||||
|
||||
# def ox=(ox)
|
||||
# return if @bitmap == nil
|
||||
# # Have viewport stay in loop on X-axis.
|
||||
# super(ox % @bitmap.width)
|
||||
# end
|
||||
|
||||
# def oy=(oy)
|
||||
# return if @bitmap == nil
|
||||
# # Have viewport stay in loop on Y-axis.
|
||||
# super(oy % @bitmap.height)
|
||||
# end
|
||||
|
||||
# def bitmap
|
||||
# # Return the single bitmap, before it was tiled.
|
||||
# return @bitmap
|
||||
# end
|
||||
|
||||
# def bitmap=(tile)
|
||||
# @bitmap = tile
|
||||
# # Calculate the number of tiles it takes to span screen in both directions.
|
||||
# xx = 1 + (SCREEN[0].to_f / tile.width).ceil
|
||||
# yy = 1 + (SCREEN[1].to_f / tile.height).ceil
|
||||
# # Create appropriately sized bitmap, then tile across it with source image.
|
||||
# plane = Bitmap.new(@bitmap.width * xx, @bitmap.height * yy)
|
||||
# (0..xx).each {|x| (0..yy).each {|y|
|
||||
# plane.blt(x * @bitmap.width, y * @bitmap.height, @bitmap, @bitmap.rect)
|
||||
# }}
|
||||
# # Set the bitmap to the sprite through its super class (Sprite).
|
||||
# super(plane)
|
||||
# end
|
||||
|
||||
# # Redefine methods dealing with coordinates (defined in super) to do nothing.
|
||||
# def x; end
|
||||
# def y; end
|
||||
# def x=(x); end
|
||||
# def y=(y); end
|
||||
# end
|
||||
#===============================================================================
|
||||
# ** Integer
|
||||
#===============================================================================
|
||||
|
||||
class Integer
|
||||
|
||||
def gcd(num)
|
||||
# Returns the greatest common denominator of self and num.
|
||||
min, max = self.abs, num.abs
|
||||
while min > 0
|
||||
tmp = min
|
||||
min = max % min
|
||||
max = tmp
|
||||
end
|
||||
return max
|
||||
end
|
||||
|
||||
def lcm(num)
|
||||
# Returns the lowest common multiple of self and num.
|
||||
return [self, num].include?(0) ? 0 : (self / self.gcd(num) * num).abs
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# ** Resolution Log
|
||||
#===============================================================================
|
||||
if RESOLUTION_LOG
|
||||
undersize, mapinfo = [], load_data('Data/MapInfos.rxdata')
|
||||
# Create a text file and write the header.
|
||||
file = File.open('Resolution Log.txt', 'wb')
|
||||
file.write("[RESOLUTION LOG]\r\n\r\n")
|
||||
time = Time.now.strftime("%x at %I:%M:%S %p")
|
||||
file.write(" Logged on #{time}\r\n\r\n")
|
||||
lcm = SCREEN[0].lcm(SCREEN[1]).to_f
|
||||
aspect = [(lcm / SCREEN[1]), (lcm / SCREEN[0])].collect {|num| num.round }
|
||||
file.write("RESOLUTION:\r\n #{SCREEN[0].to_i} x #{SCREEN[1].to_i}\r\n")
|
||||
file.write("ASPECT RATIO:\r\n #{aspect[0]}:#{aspect[1]}\r\n")
|
||||
file.write("MINIMUM MAP SIZE:\r\n #{(SCREEN[0] / 32).ceil} x #{(SCREEN[1] / 32).ceil}\r\n\r\n")
|
||||
file.write("UNDERSIZED MAPS:\r\n")
|
||||
mapinfo.keys.each {|key|
|
||||
map = load_data(sprintf("Data/Map%03d.rxdata", key))
|
||||
next if map.width*32 >= SCREEN[0] && map.height*32 >= SCREEN[1]
|
||||
undersize.push(key)
|
||||
}
|
||||
unless undersize.empty?
|
||||
file.write("The following maps are too small for the defined resolution. They should be adjusted to prevent graphical errors.\r\n\r\n")
|
||||
undersize.sort.each {|id| file.write(" MAP[#{id}]: #{mapinfo[id].name}\r\n") }
|
||||
file.write("\r\n")
|
||||
else
|
||||
file.write(' All maps are sized correctly.')
|
||||
end
|
||||
file.close
|
||||
end
|
||||
|
||||
# Call the resolution, setting it to a global variable for plug-ins.
|
||||
$resolution = Resolution.new
|
61
mkxp-z/Kawariki-patches/ports/Zeus_Fullscreen++.rb
Normal file
61
mkxp-z/Kawariki-patches/ports/Zeus_Fullscreen++.rb
Normal file
|
@ -0,0 +1,61 @@
|
|||
# Zeus81 Fullscreen++ MKXP API Shim
|
||||
# Authors: Taeyeon Mori
|
||||
|
||||
Preload.require 'PreloadIni.rb'
|
||||
|
||||
# Fullscreen++ v2.2 for VX and VXace by Zeus81
|
||||
# Free for non commercial and commercial use
|
||||
# Licence : http://creativecommons.org/licenses/by-sa/3.0/
|
||||
# Contact : zeusex81@gmail.com
|
||||
# (fr) Manuel d'utilisation : http://pastebin.com/raw.php?i=1TQfMnVJ
|
||||
# (en) User Guide : http://pastebin.com/raw.php?i=EgnWt9ur
|
||||
|
||||
$imported ||= {}
|
||||
$imported[:Zeus_Fullscreen] = __FILE__
|
||||
|
||||
class << Graphics
|
||||
Disable_VX_Fullscreen = true
|
||||
|
||||
unless method_defined?(:zeus_fullscreen_update)
|
||||
alias zeus_fullscreen_update update
|
||||
end
|
||||
|
||||
def load_fullscreen_settings
|
||||
fullscreen = (Preload::Ini.readIniString('./Game.ini', 'Fullscreen++', 'Fullscreen') || '0') == '1'
|
||||
end
|
||||
def save_fullscreen_settings
|
||||
Preload::Ini.writeIniString('./Game.ini', 'Fullscreen++', 'Fullscreen', fullscreen ? '1' : '0')
|
||||
end
|
||||
|
||||
def fullscreen?
|
||||
fullscreen
|
||||
end
|
||||
def vx_fullscreen?
|
||||
false
|
||||
end
|
||||
def toggle_fullscreen
|
||||
fullscreen = !fullscreen
|
||||
end
|
||||
def toggle_vx_fullscreen
|
||||
end
|
||||
def vx_fullscreen_mode
|
||||
end
|
||||
def fullscreen_mode
|
||||
fullscreen = true
|
||||
end
|
||||
def windowed_mode
|
||||
fullscreen = false
|
||||
end
|
||||
def toggle_ratio
|
||||
end
|
||||
def ratio
|
||||
1
|
||||
end
|
||||
def ratio=(r)
|
||||
end
|
||||
def update
|
||||
zeus_fullscreen_update
|
||||
toggle_fullscreen if Input.trigger?(Input::F5)
|
||||
end
|
||||
end
|
||||
Graphics.load_fullscreen_settings
|
530
mkxp-z/Kawariki-patches/ports/Zeus_Map_Effects.rb
Normal file
530
mkxp-z/Kawariki-patches/ports/Zeus_Map_Effects.rb
Normal file
|
@ -0,0 +1,530 @@
|
|||
# Map Effects v1.4.1 for VX and VXace by Zeus81
|
||||
# €30 for commercial use
|
||||
# Licence : http://creativecommons.org/licenses/by-nc-nd/4.0/
|
||||
# Contact : zeusex81@gmail.com
|
||||
# (fr) Manuel d'utilisation : https://www.dropbox.com/s/lb1d3q9jmx53taf/Map%20Effects%20Doc%20Fr.txt
|
||||
# (en) User Guide : https://www.dropbox.com/s/sk3uwq2bleoxr7s/Map%20Effects%20Doc%20En.txt
|
||||
# Demo : https://www.dropbox.com/s/2ex6906dyehl7an/Map%20Effects.zip
|
||||
|
||||
$imported ||= {}
|
||||
$imported[:Zeus_Map_Effects] = __FILE__
|
||||
|
||||
def xp?() false end ; def vx?() false end ; def vxace?() false end
|
||||
RUBY_VERSION == '1.8.1' ? defined?(Hangup) ?
|
||||
def xp?() true end : def vx?() true end : def vxace?() true end
|
||||
|
||||
class << Graphics
|
||||
def snap_elements_to_bitmap(*elements)
|
||||
if !@snap_elements_back or @snap_elements_back.disposed?
|
||||
@snap_elements_back = Sprite.new
|
||||
@snap_elements_back.bitmap = Bitmap.new(1, 1)
|
||||
@snap_elements_back.bitmap.set_pixel(0, 0, Color.new(0, 0, 0))
|
||||
@snap_elements_back.z = 0x0FFF_FFFF
|
||||
end
|
||||
@snap_elements_back.zoom_x = width
|
||||
@snap_elements_back.zoom_y = height
|
||||
@snap_elements_back.visible = true
|
||||
elements.each {|element| element.z += 0x1FFF_FFFF}
|
||||
bmp = snap_to_bitmap rescue retry
|
||||
@snap_elements_back.visible = false
|
||||
elements.each {|element| element.z -= 0x1FFF_FFFF}
|
||||
return bmp
|
||||
end
|
||||
end
|
||||
|
||||
module Math
|
||||
module_function
|
||||
def min(x, y) x < y ? x : y end
|
||||
def max(x, y) x < y ? y : x end
|
||||
def middle(min, x, max) x < max ? x < min ? min : x : max end
|
||||
end
|
||||
|
||||
module Zeus
|
||||
module Animation
|
||||
def animate(variable, target_value, duration=0, ext=nil)
|
||||
@za_animations ||= {}
|
||||
base_value = Marshal.load(Marshal.dump(instance_variable_get(variable)))
|
||||
if duration < 1
|
||||
update_animation_value(variable, base_value, target_value, 1, 1, ext)
|
||||
@za_animations.delete(variable)
|
||||
else
|
||||
@za_animations[variable] = [base_value, target_value, 0, duration.to_i, ext]
|
||||
end
|
||||
end
|
||||
def animating?
|
||||
@za_animations and !@za_animations.empty?
|
||||
end
|
||||
def clear_animations
|
||||
@za_animations and @za_animations.clear
|
||||
end
|
||||
def memorize_animations(variables = instance_variables)
|
||||
data = {}
|
||||
variables.each {|var| data[var.to_sym] = instance_variable_get(var)}
|
||||
data.delete(:@za_memorize)
|
||||
@za_memorize = Marshal.dump(data)
|
||||
end
|
||||
def restore_animations
|
||||
return unless @za_memorize
|
||||
Marshal.load(@za_memorize).each {|var,value| instance_variable_set(var,value)}
|
||||
end
|
||||
def update_animations
|
||||
return unless @za_animations
|
||||
@za_animations.delete_if do |variable, data|
|
||||
data[2] += 1
|
||||
update_animation_value(variable, *data)
|
||||
data[2] == data[3]
|
||||
end
|
||||
end
|
||||
private
|
||||
def calculate_next_value(base_value, target_value, duration, duration_total)
|
||||
base_value + (target_value - base_value) * duration / duration_total
|
||||
end
|
||||
def update_animation_value(variable, base_value, target_value, duration, duration_total, ext)
|
||||
method_name = "update_animation_variable_#{variable.to_s[1..-1]}"
|
||||
method_name = "update_animation_#{base_value.class}" unless respond_to?(method_name)
|
||||
send(method_name, variable, base_value, target_value, duration, duration_total, ext)
|
||||
end
|
||||
def update_animation_Color(variable, base_value, target_value, duration, duration_total, ext)
|
||||
value = instance_variable_get(variable)
|
||||
value.red = calculate_next_value(base_value.red , target_value.red , duration, duration_total)
|
||||
value.green = calculate_next_value(base_value.green, target_value.green, duration, duration_total)
|
||||
value.blue = calculate_next_value(base_value.blue , target_value.blue , duration, duration_total)
|
||||
value.alpha = calculate_next_value(base_value.alpha, target_value.alpha, duration, duration_total)
|
||||
end
|
||||
def update_animation_Tone(variable, base_value, target_value, duration, duration_total, ext)
|
||||
value = instance_variable_get(variable)
|
||||
value.red = calculate_next_value(base_value.red , target_value.red , duration, duration_total)
|
||||
value.green = calculate_next_value(base_value.green, target_value.green, duration, duration_total)
|
||||
value.blue = calculate_next_value(base_value.blue , target_value.blue , duration, duration_total)
|
||||
value.gray = calculate_next_value(base_value.gray , target_value.gray , duration, duration_total)
|
||||
end
|
||||
def update_animation_Float(variable, base_value, target_value, duration, duration_total, ext)
|
||||
value = calculate_next_value(base_value, target_value, duration, duration_total)
|
||||
instance_variable_set(variable, value)
|
||||
end
|
||||
alias update_animation_Fixnum update_animation_Float
|
||||
alias update_animation_Bignum update_animation_Float
|
||||
end
|
||||
end
|
||||
|
||||
class Game_Map_Effects
|
||||
include Zeus::Animation
|
||||
attr_accessor :active, :refresh_rate, :back, :x, :y, :ox, :oy, :angle,
|
||||
:zoom_x, :zoom_y, :mirror, :opacity, :blend_type, :color, :tone,
|
||||
:hue, :wave_amp, :wave_length, :wave_speed, :wave_phase,
|
||||
:pixelize, :blur_division, :blur_fade, :blur_animation,
|
||||
:gaussian_blur_length, :linear_blur_angle, :linear_blur_length,
|
||||
:radial_blur_angle, :zoom_blur_length, :motion_blur_rate
|
||||
def initialize
|
||||
@active = true
|
||||
@refresh_rate = 30.0
|
||||
clear
|
||||
end
|
||||
def clear
|
||||
@back = false
|
||||
@x = @ox = Graphics.width / 2
|
||||
@y = @oy = Graphics.height / 2
|
||||
@zoom_x = 1.0
|
||||
@zoom_y = 1.0
|
||||
@zoom2 = Math.sqrt(100.0)
|
||||
@angle = 0.0
|
||||
@wave_amp = 0.0
|
||||
@wave_length = 180
|
||||
@wave_speed = 360
|
||||
@wave_phase = 0.0
|
||||
@mirror = false
|
||||
@opacity = 255
|
||||
@blend_type = 0
|
||||
@color ||= Color.new(0, 0, 0, 0)
|
||||
@color.set(0, 0, 0, 0)
|
||||
@tone ||= Tone.new(0, 0, 0, 0)
|
||||
@tone.set(0, 0, 0, 0)
|
||||
@hue = 0
|
||||
@pixelize = 1.0
|
||||
@pixelize2 = Math.sqrt(100.0)
|
||||
@blur_division = 4.0
|
||||
@blur_fade = 1.0
|
||||
@blur_animation = 0.0
|
||||
@gaussian_blur_length = 0.0
|
||||
@linear_blur_angle = 0.0
|
||||
@linear_blur_length = 0.0
|
||||
@radial_blur_angle = 0.0
|
||||
@zoom_blur_length = 0.0
|
||||
@motion_blur_rate = 0.0
|
||||
clear_animations
|
||||
end
|
||||
alias memorize memorize_animations
|
||||
alias restore restore_animations
|
||||
alias update update_animations
|
||||
def active?
|
||||
return false unless @active
|
||||
animating? or blur? or @mirror or @blend_type != 0 or
|
||||
@zoom_x != 1 or @zoom_y != 1 or @pixelize > 1 or
|
||||
@angle % 360 != 0 or @hue.to_i % 360 != 0 or @color.alpha != 0 or
|
||||
@tone.red != 0 or @tone.green != 0 or @tone.blue != 0 or @tone.gray != 0 or
|
||||
(@wave_amp * @zoom_x >= 1 and @wave_length * @zoom_y >= 1)
|
||||
end
|
||||
def blur?
|
||||
return false if @blur_division < 1
|
||||
@gaussian_blur_length != 0 or @linear_blur_length != 0 or
|
||||
@radial_blur_angle != 0 or @zoom_blur_length != 0 or @motion_blur_rate != 0
|
||||
end
|
||||
def refresh_bitmap?
|
||||
@refresh_rate > 0 and
|
||||
Graphics.frame_count % (Graphics.frame_rate / @refresh_rate.to_f) < 1
|
||||
end
|
||||
def tilemap_wave_sync(tilemap_oy)
|
||||
return 0 if @wave_length == 0
|
||||
tilemap_oy * @wave_speed / @wave_length.to_f
|
||||
end
|
||||
def blur_animation_offset
|
||||
return 0 if @blur_animation == 0
|
||||
1 - @blur_animation * Graphics.frame_count / Graphics.frame_rate.to_f % 1
|
||||
end
|
||||
def refresh_motion_blur?
|
||||
@blur_division >= 1 and @motion_blur_rate > 0 and
|
||||
Graphics.frame_count % @motion_blur_rate < 1
|
||||
end
|
||||
def set_origin(x, y, duration=0)
|
||||
x = x * Graphics.width / 100
|
||||
y = y * Graphics.height / 100
|
||||
animate(:@x , x, duration)
|
||||
animate(:@y , y, duration)
|
||||
animate(:@ox, x, duration)
|
||||
animate(:@oy, y, duration)
|
||||
end
|
||||
def set_zoom(zoom, duration=0, center_on_player=true)
|
||||
zoom = Math.sqrt(Math.max(1, zoom))
|
||||
animate(:@zoom2, zoom, duration, center_on_player)
|
||||
end
|
||||
def update_animation_variable_zoom2(variable, base_value, target_value, duration, duration_total, center_on_player)
|
||||
update_animation_Float(variable, base_value, target_value, duration, duration_total, nil)
|
||||
@zoom_y = @zoom_x = @zoom2 ** 2 / 100.0
|
||||
display_ratio = Game_Map::DisplayRatio.to_f
|
||||
if center_on_player
|
||||
x = $game_player.real_x / display_ratio
|
||||
y = $game_player.real_y / display_ratio
|
||||
else
|
||||
x = $game_map.display_x / display_ratio + $game_map.screen_tile_x / 2
|
||||
y = $game_map.display_y / display_ratio + $game_map.screen_tile_y / 2
|
||||
end
|
||||
$game_player.center(x, y)
|
||||
end
|
||||
def set_angle(angle, duration=0)
|
||||
animate(:@angle, angle, duration)
|
||||
end
|
||||
def set_opacity(opacity, duration=0)
|
||||
opacity = opacity * 255 / 100
|
||||
animate(:@opacity, opacity, duration)
|
||||
end
|
||||
def set_color(red, green, blue, alpha, duration=0)
|
||||
animate(:@color, Color.new(red, green, blue, alpha), duration)
|
||||
end
|
||||
def set_tone(red, green, blue, gray, duration=0)
|
||||
animate(:@tone, Tone.new(red, green, blue, gray), duration)
|
||||
end
|
||||
def set_hue(hue, duration=0)
|
||||
animate(:@hue, hue, duration)
|
||||
end
|
||||
def set_wave(amp, length, speed, duration=0)
|
||||
animate(:@wave_amp , amp , duration)
|
||||
animate(:@wave_length, length, duration)
|
||||
animate(:@wave_speed , speed , duration)
|
||||
end
|
||||
def set_pixelize(pixelize, duration=0)
|
||||
pixelize = Math.sqrt(Math.max(100, pixelize))
|
||||
animate(:@pixelize2, pixelize, duration)
|
||||
end
|
||||
def update_animation_variable_pixelize2(variable, base_value, target_value, duration, duration_total, ext)
|
||||
update_animation_Float(variable, base_value, target_value, duration, duration_total, ext)
|
||||
@pixelize = @pixelize2 ** 2 / 100.0
|
||||
end
|
||||
def setup_blur(division, fade, animation, duration=0)
|
||||
division = Math.middle(0, division, 16)
|
||||
animate(:@blur_division , division , duration)
|
||||
animate(:@blur_fade , fade , duration)
|
||||
animate(:@blur_animation, animation, duration)
|
||||
end
|
||||
def set_gaussian_blur(length, duration=0)
|
||||
animate(:@gaussian_blur_length, length, duration)
|
||||
end
|
||||
def set_linear_blur(angle, length, duration=0)
|
||||
animate(:@linear_blur_angle , angle , duration)
|
||||
animate(:@linear_blur_length, length, duration)
|
||||
end
|
||||
def set_radial_blur(angle, duration=0)
|
||||
animate(:@radial_blur_angle, angle, duration)
|
||||
end
|
||||
def set_zoom_blur(zoom, duration=0)
|
||||
length = Math.max(1, zoom) / 100.0 - 1
|
||||
animate(:@zoom_blur_length, length, duration)
|
||||
end
|
||||
def set_motion_blur(rate, duration=0)
|
||||
animate(:@motion_blur_rate, rate, duration)
|
||||
end
|
||||
end
|
||||
|
||||
class Spriteset_Map_Effects
|
||||
Blur_Offset = [[0.7,0.7], [-0.7,-0.7], [-0.7,0.7], [0.7,-0.7],
|
||||
[0,1], [0,-1], [1,0], [-1,0]]
|
||||
def initialize(*viewports)
|
||||
@map_viewports = viewports
|
||||
@viewport = Viewport.new(viewports[0].rect)
|
||||
@viewport.z = viewports[0].z
|
||||
@viewport.visible = false
|
||||
@effects_sprites = []
|
||||
@effects_bitmaps = []
|
||||
@data = $game_map.effects
|
||||
end
|
||||
def dispose(dispose_viewport=true)
|
||||
@effects_sprites.each {|sprite| sprite.dispose}
|
||||
@effects_sprites.clear
|
||||
@effects_bitmaps.each {|bitmap| bitmap.dispose if bitmap}
|
||||
@effects_bitmaps.clear
|
||||
@pixelize_bitmap.dispose if @pixelize_bitmap
|
||||
@pixelize_bitmap = nil
|
||||
@back_sprite.dispose if @back_sprite
|
||||
@back_sprite = nil
|
||||
if dispose_viewport
|
||||
@viewport.dispose
|
||||
else
|
||||
@viewport.visible = false
|
||||
@map_viewports.each {|viewport| viewport.visible = true}
|
||||
end
|
||||
end
|
||||
def update(tilemap_oy = 0)
|
||||
unless @data.active?
|
||||
dispose(false) if @viewport.visible
|
||||
return
|
||||
end
|
||||
@viewport.visible = true
|
||||
@motion_blur_refresh ||= @data.refresh_motion_blur?
|
||||
refresh_sprites
|
||||
if !@effects_bitmaps[0] or @data.refresh_bitmap?
|
||||
refresh_bitmaps
|
||||
refresh_pixelize
|
||||
end
|
||||
refresh_back
|
||||
wave_sync = @data.tilemap_wave_sync(tilemap_oy)
|
||||
blur_offset = @data.blur_animation_offset
|
||||
@effects_sprites.each_with_index do |sprite, id|
|
||||
update_effects(sprite, id, wave_sync)
|
||||
update_pixelize(sprite) if @pixelize_bitmap
|
||||
update_blur(sprite, id, blur_offset) if id > 0
|
||||
end
|
||||
@data.wave_phase = @effects_sprites[0].wave_phase - wave_sync
|
||||
end
|
||||
def refresh_sprites
|
||||
n = (@data.blur? ? @data.blur_division.to_i+1 : 1) - @effects_sprites.size
|
||||
n.times {@effects_sprites << Sprite.new(@viewport)}
|
||||
(-n).times {@effects_sprites.pop.dispose}
|
||||
end
|
||||
def refresh_bitmaps
|
||||
n = (@data.motion_blur_rate == 0 ? 1 : @effects_sprites.size) - @effects_bitmaps.size
|
||||
n.times {@effects_bitmaps << nil}
|
||||
(-n).times {bmp = @effects_bitmaps.pop and bmp.dispose}
|
||||
@map_viewports.each {|viewport| viewport.visible = true}
|
||||
@effects_bitmaps.unshift(@effects_bitmaps.pop) if @motion_blur_refresh
|
||||
@effects_bitmaps[0].dispose if @effects_bitmaps[0]
|
||||
@effects_bitmaps[0] = Graphics.snap_elements_to_bitmap(*@map_viewports)
|
||||
@effects_bitmaps[0].hue_change(@data.hue % 360) if @data.hue.to_i % 360 != 0
|
||||
@map_viewports.each {|viewport| viewport.visible = false}
|
||||
@motion_blur_refresh = false
|
||||
end
|
||||
def refresh_pixelize
|
||||
if @data.pixelize > 1
|
||||
bmp = @effects_bitmaps[0]
|
||||
@pixelize_rect ||= Rect.new(0, 0, 0, 0)
|
||||
@pixelize_rect.width = Math.max(1, bmp.width / @data.pixelize)
|
||||
@pixelize_rect.height = Math.max(1, bmp.height / @data.pixelize)
|
||||
@pixelize_bitmap ||= Bitmap.new(bmp.width, bmp.height)
|
||||
@pixelize_bitmap.clear
|
||||
@pixelize_bitmap.stretch_blt(@pixelize_rect, bmp, bmp.rect)
|
||||
elsif @pixelize_bitmap
|
||||
@pixelize_bitmap.dispose
|
||||
@pixelize_bitmap = nil
|
||||
end
|
||||
end
|
||||
def refresh_back
|
||||
if @data.back
|
||||
@back_sprite ||= Sprite.new(@viewport)
|
||||
@back_sprite.bitmap = @effects_bitmaps[0]
|
||||
elsif @back_sprite
|
||||
@back_sprite.dispose
|
||||
@back_sprite = nil
|
||||
end
|
||||
end
|
||||
def update_effects(sprite, id, wave_sync)
|
||||
sprite.bitmap = @effects_bitmaps[id] || @effects_bitmaps[0]
|
||||
sprite.x = @data.x
|
||||
sprite.y = @data.y
|
||||
sprite.z = id + 1
|
||||
sprite.ox = @data.ox
|
||||
sprite.oy = @data.oy
|
||||
sprite.zoom_x = @data.zoom_x
|
||||
sprite.zoom_y = @data.zoom_y
|
||||
sprite.angle = @data.angle % 360
|
||||
sprite.wave_amp = @data.wave_amp * @data.zoom_x
|
||||
sprite.wave_length = @data.wave_length * @data.zoom_y
|
||||
sprite.wave_speed = @data.wave_speed * @data.zoom_y
|
||||
sprite.wave_phase = @data.wave_phase + wave_sync
|
||||
sprite.mirror = @data.mirror
|
||||
sprite.opacity = @data.opacity
|
||||
sprite.blend_type = @data.blend_type
|
||||
sprite.color = @data.color
|
||||
sprite.tone = @data.tone
|
||||
sprite.update
|
||||
end
|
||||
def update_pixelize(sprite)
|
||||
pzx = @pixelize_bitmap.width / @pixelize_rect.width.to_f
|
||||
pzy = @pixelize_bitmap.height / @pixelize_rect.height.to_f
|
||||
sprite.bitmap = @pixelize_bitmap
|
||||
sprite.src_rect = @pixelize_rect
|
||||
sprite.x -= sprite.ox - (sprite.ox /= pzx).to_i * pzx
|
||||
sprite.y -= sprite.oy - (sprite.oy /= pzy).to_i * pzy
|
||||
sprite.zoom_x *= pzx
|
||||
sprite.zoom_y *= pzy
|
||||
end
|
||||
def update_blur(sprite, id, blur_offset)
|
||||
update_blur_opacity(sprite, id-blur_offset)
|
||||
update_gaussian_blur(sprite, id) if @data.gaussian_blur_length != 0
|
||||
update_linear_blur(sprite, id-blur_offset) if @data.linear_blur_length != 0
|
||||
update_radial_blur(sprite, id-blur_offset) if @data.radial_blur_angle != 0
|
||||
update_zoom_blur(sprite, id-blur_offset) if @data.zoom_blur_length != 0
|
||||
end
|
||||
def update_blur_opacity(sprite, id)
|
||||
sprite.opacity /= (id < 1 ? 2 : id+1) **
|
||||
(1 + @data.blur_fade / (@data.blur_division*20.0))
|
||||
end
|
||||
def update_gaussian_blur(sprite, id)
|
||||
box, boy = *Blur_Offset[(id-1)%8]
|
||||
offset = ((id+3)/4) / ((@data.blur_division.to_i+3)/4).to_f *
|
||||
@data.gaussian_blur_length
|
||||
sprite.x += (offset.ceil * box).round
|
||||
sprite.y += (offset.ceil * boy).round
|
||||
end
|
||||
def update_linear_blur(sprite, id)
|
||||
radian = @data.linear_blur_angle * Math::PI / 180
|
||||
offset = id * @data.linear_blur_length / @data.blur_division.to_f
|
||||
sprite.x += offset * Math.cos( radian)
|
||||
sprite.y += offset * Math.sin(-radian)
|
||||
end
|
||||
def update_zoom_blur(sprite, id)
|
||||
zoom = 1 + id * @data.zoom_blur_length / @data.blur_division.to_f
|
||||
sprite.zoom_x *= zoom
|
||||
sprite.zoom_y *= zoom
|
||||
end
|
||||
def update_radial_blur(sprite, id)
|
||||
sprite.angle += id * @data.radial_blur_angle / @data.blur_division.to_f
|
||||
sprite.angle %= 360
|
||||
end
|
||||
end
|
||||
|
||||
class Game_Map
|
||||
if vx?
|
||||
def screen_tile_x() Graphics.width / 32 end
|
||||
def screen_tile_y() Graphics.height / 32 end
|
||||
DisplayRatio = 256
|
||||
else
|
||||
DisplayRatio = 1
|
||||
end
|
||||
def zoom_ox
|
||||
return 0 unless effects.active and effects.zoom_x > 1
|
||||
(1 - 1 / effects.zoom_x) * screen_tile_x / 2
|
||||
end
|
||||
def zoom_oy
|
||||
return 0 unless effects.active and effects.zoom_y > 1
|
||||
(1 - 1 / effects.zoom_y) * screen_tile_y / 2
|
||||
end
|
||||
def limit_x(x)
|
||||
ox = zoom_ox
|
||||
min = DisplayRatio * -ox
|
||||
max = DisplayRatio * (width - screen_tile_x + ox)
|
||||
x < max ? x < min ? min : x : max
|
||||
end
|
||||
def limit_y(y)
|
||||
oy = zoom_oy
|
||||
min = DisplayRatio * -oy
|
||||
max = DisplayRatio * (height - screen_tile_y + oy)
|
||||
y < max ? y < min ? min : y : max
|
||||
end
|
||||
def set_display_x(x)
|
||||
x = loop_horizontal? ? x % (width * DisplayRatio) : limit_x(x)
|
||||
@parallax_x += x - @display_x if @parallax_loop_x or !loop_horizontal?
|
||||
@display_x = x
|
||||
end
|
||||
def set_display_y(y)
|
||||
y = loop_vertical? ? y % (height * DisplayRatio) : limit_y(y)
|
||||
@parallax_y += y - @display_y if @parallax_loop_y or !loop_vertical?
|
||||
@display_y = y
|
||||
end
|
||||
def set_display_pos(x, y) set_display_x(x); set_display_y(y) end
|
||||
def scroll_down(distance) set_display_y(@display_y + distance) end
|
||||
def scroll_left(distance) set_display_x(@display_x - distance) end
|
||||
def scroll_right(distance) set_display_x(@display_x + distance) end
|
||||
def scroll_up(distance) set_display_y(@display_y - distance) end
|
||||
def effects() @effects ||= Game_Map_Effects.new end
|
||||
alias zeus_map_effects_update update
|
||||
def update(*args)
|
||||
zeus_map_effects_update(*args)
|
||||
effects.update
|
||||
end
|
||||
end
|
||||
|
||||
class Game_Interpreter
|
||||
def map_effects
|
||||
$game_map.effects
|
||||
end
|
||||
end
|
||||
|
||||
class Game_Player
|
||||
def center(x, y)
|
||||
$game_map.set_display_pos(x*256-CENTER_X, y*256-CENTER_Y)
|
||||
end
|
||||
end if vx?
|
||||
|
||||
class Spriteset_Map
|
||||
alias zeus_map_effects_update update
|
||||
def update
|
||||
zeus_map_effects_update
|
||||
@map_effects ||= Spriteset_Map_Effects.new(@viewport1)
|
||||
@map_effects.update(@tilemap.oy)
|
||||
end
|
||||
alias zeus_map_effects_dispose dispose
|
||||
def dispose
|
||||
zeus_map_effects_dispose
|
||||
@map_effects.dispose
|
||||
end
|
||||
end
|
||||
|
||||
$imported[:Zeus_Weather_Viewport] ||= __FILE__
|
||||
if $imported[:Zeus_Weather_Viewport] == __FILE__
|
||||
|
||||
class Spriteset_Map
|
||||
alias zeus_weather_viewport_create_weather create_weather
|
||||
def create_weather
|
||||
zeus_weather_viewport_create_weather
|
||||
@weather.weather_viewport = @viewport1
|
||||
end
|
||||
end
|
||||
|
||||
class Spriteset_Weather
|
||||
if vx?
|
||||
def weather_viewport=(viewport)
|
||||
for sprite in @sprites
|
||||
sprite.viewport = viewport
|
||||
sprite.z = 0x8000
|
||||
end
|
||||
end
|
||||
else
|
||||
attr_accessor :weather_viewport
|
||||
alias zeus_weather_viewport_add_sprite add_sprite
|
||||
def add_sprite
|
||||
zeus_weather_viewport_add_sprite
|
||||
@sprites[-1].viewport = @weather_viewport
|
||||
@sprites[-1].z = 0x8000
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
386
mkxp-z/Kawariki-patches/ports/achievements.rb
Normal file
386
mkxp-z/Kawariki-patches/ports/achievements.rb
Normal file
|
@ -0,0 +1,386 @@
|
|||
# [122] 29075340: achievements
|
||||
# cyanic's Quick and Easy Steamworks Achievements Integration for Ruby
|
||||
# https://github.com/GMMan/RGSS_SteamUserStatsLite
|
||||
# r4 06/16/16
|
||||
#
|
||||
# Drop steam_api.dll into the root of your project. Requires Steamworks SDK version >= 1.37.
|
||||
#
|
||||
# "Miller complained about how hard achievements were to implement in C++, so this was born."
|
||||
#
|
||||
|
||||
$imported ||= {}
|
||||
$imported['cyanic-SteamUserStatsLite'] = 4 # Slightly unorthodox, it's a version number.
|
||||
|
||||
# A context class to get Steamworks pointers to interfaces.
|
||||
#
|
||||
# @author cyanic
|
||||
class SteamAPIContext
|
||||
STEAMCLIENT_INTERFACE_VERSION = 'SteamClient017'
|
||||
STEAMUSERSTATS_INTERFACE_VERSION = 'STEAMUSERSTATS_INTERFACE_VERSION011'
|
||||
STEAMAPPS_INTERFACE_VERSION = 'STEAMAPPS_INTERFACE_VERSION008'
|
||||
|
||||
# Instantiates a new instance of +SteamAPIContext+.
|
||||
def initialize
|
||||
# @initted = false
|
||||
# @h_steam_user = # @@dll_SteamAPI_GetHSteamUser.call
|
||||
# if (@h_steam_pipe = # @@dll_SteamAPI_GetHSteamPipe.call) != 0
|
||||
# return if (@steam_client = # @@dll_SteamInternal_CreateInterface.call(STEAMCLIENT_INTERFACE_VERSION)) == 0
|
||||
# return if (@steam_user_stats = # @@dll_SteamAPI_ISteamClient_GetISteamUserStats.call(@steam_client, @h_steam_user, @h_steam_pipe, STEAMUSERSTATS_INTERFACE_VERSION)) == 0
|
||||
# return if (@steam_apps = # @@dll_SteamAPI_ISteamClient_GetISteamApps.call(@steam_client, @h_steam_user, @h_steam_pipe, STEAMAPPS_INTERFACE_VERSION)) == 0
|
||||
#
|
||||
# @initted = true
|
||||
# end
|
||||
end
|
||||
|
||||
# Checks if context is initialized.
|
||||
#
|
||||
# @return [true, false] Whether context is initialized.
|
||||
def initted?
|
||||
@initted
|
||||
end
|
||||
|
||||
# Gets the ISteamClient pointer
|
||||
#
|
||||
# @return [Fixnum, nil] The ISteamClient pointer if context is initialized, otherwise +nil+.
|
||||
def steam_client
|
||||
@steam_client if initted?
|
||||
end
|
||||
|
||||
# Gets the ISteamUserStats pointer
|
||||
#
|
||||
# @return [Fixnum, nil] The ISteamUserStats pointer if context is initialized, otherwise +nil+.
|
||||
def steam_user_stats
|
||||
@steam_user_stats if initted?
|
||||
end
|
||||
|
||||
# Gets the ISteamApps pointer
|
||||
#
|
||||
# @return [Fixnum, nil] The ISteamUserStats pointer if context is initialized, otherwise +nil+.
|
||||
def steam_apps
|
||||
@steam_apps if initted?
|
||||
end
|
||||
|
||||
private
|
||||
def self.is_64bit?
|
||||
# Probably very bad detection of whether current runtime is 64-bit
|
||||
(/x64/ =~ RUBY_PLATFORM) != nil
|
||||
end
|
||||
|
||||
def self.steam_dll_name
|
||||
# @@dll_name ||= self.is_64bit? ? 'steam_api64' : 'steam_api'
|
||||
end
|
||||
|
||||
# @@dll_SteamAPI_GetHSteamUser = Win32API.new(self.steam_dll_name, 'SteamAPI_GetHSteamUser', '', 'I')
|
||||
# @@dll_SteamAPI_GetHSteamPipe = Win32API.new(self.steam_dll_name, 'SteamAPI_GetHSteamPipe', '', 'I')
|
||||
# @@dll_SteamInternal_CreateInterface = Win32API.new(self.steam_dll_name, 'SteamInternal_CreateInterface', 'P', 'I')
|
||||
# @@dll_SteamAPI_ISteamClient_GetISteamUserStats = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamClient_GetISteamUserStats', 'IIIP', 'I')
|
||||
# @@dll_SteamAPI_ISteamClient_GetISteamApps = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamClient_GetISteamApps', 'IIIP', 'I')
|
||||
|
||||
end
|
||||
|
||||
# A simple class for Steamworks UserStats integration.
|
||||
#
|
||||
# @author cyanic
|
||||
class SteamUserStatsLite
|
||||
|
||||
# Instantiates a new instance of +SteamUserStatsLite+.
|
||||
def initialize
|
||||
@initted = false
|
||||
api_initted = # @@dll_SteamAPI_Init.call % 256 != 0
|
||||
if api_initted
|
||||
@context = SteamAPIContext.new
|
||||
if @context.initted?
|
||||
@i_apps = @context.steam_apps
|
||||
@i_user_stats = @context.steam_user_stats
|
||||
@initted = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Shuts down Steamworks.
|
||||
#
|
||||
# @return [void]
|
||||
def shutdown
|
||||
if @initted
|
||||
@i_apps = nil
|
||||
@i_user_stats = nil
|
||||
# @@dll_SteamAPI_Shutdown.call
|
||||
@initted = false
|
||||
end
|
||||
end
|
||||
|
||||
# Checks if Steamworks is initialized.
|
||||
#
|
||||
# @return [true, false] Whether Steamworks is initialized.
|
||||
def initted?
|
||||
@initted
|
||||
end
|
||||
|
||||
# Restarts the app if Steamworks is not availble.
|
||||
#
|
||||
# @param app_id [Integer] The app ID to relaunch as.
|
||||
# @return [true, false] +true+ if current instance should exit, +false+ if not.
|
||||
def self.restart_app_if_necessary(app_id)
|
||||
# @@dll_SteamAPI_RestartAppIfNecessary.call(app_id) % 256 != 0
|
||||
end
|
||||
|
||||
# Runs Steam callbacks.
|
||||
#
|
||||
# @return [void]
|
||||
def update
|
||||
# @@dll_SteamAPI_RunCallbacks.call if initted?
|
||||
end
|
||||
|
||||
# Checks if current app is owned.
|
||||
#
|
||||
# @return [true, false, nil] Whether the current user has a license for the current app. +nil+ is returned if ownership status can't be retrieved.
|
||||
def is_subscribed
|
||||
if initted?
|
||||
# @@dll_SteamAPI_ISteamApps_BIsSubscribed.call(@i_apps) % 256 != 0
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Checks if a DLC is installed.
|
||||
#
|
||||
# @param app_id [Integer] The app ID of the DLC to check.
|
||||
# @return [true, false, nil] Whether the DLC is installed. +nil+ is returned if the installation status can't be retrieved.
|
||||
def is_dlc_installed(app_id)
|
||||
if initted?
|
||||
# @@dll_SteamAPI_ISteamApps_BIsDlcInstalled.call(@i_apps, app_id) % 256 != 0
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Pulls current user's stats from Steam.
|
||||
#
|
||||
# @return [true, false] Whether the stats have been successfully pulled.
|
||||
def request_current_stats
|
||||
if initted?
|
||||
# @@dll_SteamAPI_ISteamUserStats_RequestCurrentStats.call(@i_user_stats) % 256 != 0
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Gets the value of an INT stat.
|
||||
#
|
||||
# @param name [String] The name of the stat.
|
||||
# @return [Integer, nil] The value of the stat, or +nil+ if the stat cannot be retrieved.
|
||||
def get_stat_int(name)
|
||||
if initted?
|
||||
val = ' ' * 4
|
||||
ok = # @@dll_SteamAPI_ISteamUserStats_GetStat.call(@i_user_stats, name, val) % 256 != 0
|
||||
ok ? val.unpack('I')[0] : nil
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Gets the value of an FLOAT stat.
|
||||
#
|
||||
# @param name [String] The name of the stat.
|
||||
# @return [Float, nil] The value of the stat, or +nil+ if the stat cannot be retrieved.
|
||||
def get_stat_float(name)
|
||||
if initted?
|
||||
val = ' ' * 4
|
||||
ok = # @@dll_SteamAPI_ISteamUserStats_GetStat0.call(@i_user_stats, name, val) % 256 != 0
|
||||
ok ? val.unpack('f')[0] : nil
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the value of a stat.
|
||||
#
|
||||
# @param name [String] The name of the stat.
|
||||
# @param val [Integer, Float] The value of the stat.
|
||||
# @return [true, false] Whether the stat was successfully updated.
|
||||
# @example
|
||||
# steam = SteamUserStatsLite.instance
|
||||
# steam.set_stat 'YOUR_STAT_ID_HERE', 100
|
||||
# steam.update
|
||||
def set_stat(name, val)
|
||||
if initted?
|
||||
|
||||
# @@dll_SteamAPI_ISteamUserStats_StoreStats.call(@i_user_stats) % 256 != 0 && ok
|
||||
end
|
||||
end
|
||||
|
||||
# Updates an AVGRATE stat.
|
||||
#
|
||||
# @param name [String] The name of the stat.
|
||||
# @param count_this_session [Float] The value during this session.
|
||||
# @param session_length [Float] The length of this session.
|
||||
# @return [true, false] Whether the stat was successfully updated.
|
||||
def update_avg_rate_stat(name, count_this_session, session_length)
|
||||
if initted?
|
||||
packed = self.class.pack_double session_length
|
||||
end
|
||||
end
|
||||
|
||||
# Gets an achievement's state.
|
||||
#
|
||||
# @param name [String] The name of the achievement.
|
||||
# @return [true, false, nil] Whether the achievement has unlocked, or +nil+ if the achievement cannot be retrieved.
|
||||
def get_achievement(name)
|
||||
if initted?
|
||||
val = ' '
|
||||
ok = # @@dll_SteamAPI_ISteamUserStats_GetAchievement.call(@i_user_stats, name, val) % 256 != 0
|
||||
ok ? val.unpack('C')[0] != 0 : nil
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Sets an achievement as unlocked.
|
||||
#
|
||||
# @param name [String] The name of the achievement.
|
||||
# @return [true, false] Whether the achievement was set successfully.
|
||||
# @example
|
||||
# steam = SteamUserStatsLite.instance
|
||||
# steam.set_achievement 'YOUR_ACH_ID_HERE'
|
||||
# steam.update
|
||||
def set_achievement(name)
|
||||
# if initted?
|
||||
# ok = # @@dll_SteamAPI_ISteamUserStats_SetAchievement.call(@i_user_stats, name) % 256 != 0
|
||||
# # @@dll_SteamAPI_ISteamUserStats_StoreStats.call(@i_user_stats) % 256 != 0 && ok
|
||||
# # else
|
||||
# # false
|
||||
# end
|
||||
end
|
||||
|
||||
# Sets an achievement as locked.
|
||||
#
|
||||
# @param name [String] The name of the achievement.
|
||||
# @return [true, false] Whether the achievement was cleared successfully.
|
||||
def clear_achievement(name)
|
||||
# if initted?
|
||||
# ok = # @@dll_SteamAPI_ISteamUserStats_ClearAchievement.call(@i_user_stats, name) % 256 != 0
|
||||
# # @@dll_SteamAPI_ISteamUserStats_StoreStats.call(@i_user_stats) % 256 != 0 && ok
|
||||
# else
|
||||
# false
|
||||
# end
|
||||
end
|
||||
|
||||
# Gets an achievement's state and unlock time.
|
||||
#
|
||||
# @param name [String] The name of the achievement.
|
||||
# @return [<Object, Time>] The achievement's state (+true+ or +false+) and the time it was unlocked.
|
||||
def get_achievement_and_unlock_time(name)
|
||||
if initted?
|
||||
achieved = ' '
|
||||
unlock_time = ' ' * 4
|
||||
ok = # @@dll_SteamAPI_ISteamUserStats_GetAchievementAndUnlockTime.call(@i_user_stats, name, achieved, unlock_time) % 256 != 0
|
||||
ok ? [achieved.unpack('C')[0] != 0, Time.at(unlock_time.unpack('L')[0])] : nil
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Gets the value of an achievement's display attribute.
|
||||
#
|
||||
# @param name [String] The name of the achievement.
|
||||
# @param key [String] The key of the display attribute.
|
||||
# @return [String] The value of the display attribute.
|
||||
def get_achievement_display_attribute(name, key)
|
||||
if initted?
|
||||
# @@dll_SteamAPI_ISteamUserStats_GetAchievementDisplayAttribute.call @i_user_stats, name, key
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Gets the number of achievements.
|
||||
#
|
||||
# @return [Integer, nil] The number of achievements, or +nil+ if the number cannot be retrieved.
|
||||
def get_num_achievements
|
||||
if initted?
|
||||
# @@dll_SteamAPI_ISteamUserStats_GetNumAchievements.call @i_user_stats
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Gets the name of an achievement by its index.
|
||||
#
|
||||
# @param achievement [Integer] The index of the achievement.
|
||||
# @return [String] The name of the achievement.
|
||||
def get_achievement_name(achievement)
|
||||
if initted?
|
||||
# @@dll_SteamAPI_ISteamUserStats_GetAchievementName.call @i_user_stats, achievement
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Resets all stats.
|
||||
#
|
||||
# @param achievements_too [true, false] Whether to reset achievements as well.
|
||||
# @return [true, false] Whether achievements have been reset.
|
||||
def reset_all_stats(achievements_too)
|
||||
# if initted?
|
||||
# ok = # @@dll_SteamAPI_ISteamUserStats_ResetAllStats.call(@i_user_stats, achievements_too ? 1 : 0) % 256 != 0
|
||||
# # @@dll_SteamAPI_ISteamUserStats_StoreStats.call(@i_user_stats) % 256 != 0 && ok
|
||||
# else
|
||||
# false
|
||||
# end
|
||||
end
|
||||
|
||||
# Gets the global instance of SteamUserStatsLite.
|
||||
#
|
||||
# @return [SteamUserStatsLite] The global instance of the class.
|
||||
def self.instance
|
||||
@@instance
|
||||
end
|
||||
|
||||
private
|
||||
def self.is_64bit?
|
||||
# Probably very bad detection of whether current runtime is 64-bit
|
||||
(/x64/ =~ RUBY_PLATFORM) != nil
|
||||
end
|
||||
|
||||
def self.steam_dll_name
|
||||
# @@dll_name ||= self.is_64bit? ? 'steam_api64' : 'steam_api'
|
||||
end
|
||||
|
||||
# Function imports
|
||||
# @@dll_SteamAPI_RestartAppIfNecessary = Win32API.new(self.steam_dll_name, 'SteamAPI_RestartAppIfNecessary', 'I', 'I')
|
||||
# @@dll_SteamAPI_Init = Win32API.new(self.steam_dll_name, 'SteamAPI_Init', '', 'I')
|
||||
# @@dll_SteamAPI_Shutdown = Win32API.new(self.steam_dll_name, 'SteamAPI_Shutdown', '', 'V')
|
||||
# @@dll_SteamAPI_RunCallbacks = Win32API.new(self.steam_dll_name, 'SteamAPI_RunCallbacks', '', 'V')
|
||||
# @@dll_SteamAPI_ISteamUserStats_RequestCurrentStats = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_RequestCurrentStats', 'P', 'I')
|
||||
# @@dll_SteamAPI_ISteamUserStats_GetStat = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_GetStat', 'PPP', 'I')
|
||||
# @@dll_SteamAPI_ISteamUserStats_GetStat0 = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_GetStat0', 'PPP', 'I')
|
||||
# @@dll_SteamAPI_ISteamUserStats_SetStat = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_SetStat', 'PPL', 'I')
|
||||
# @@dll_SteamAPI_ISteamUserStats_SetStat0 = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_SetStat0', 'PPI', 'I')
|
||||
# @@dll_SteamAPI_ISteamUserStats_UpdateAvgRateStat = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_UpdateAvgRateStat', 'PPIII', 'I')
|
||||
# @@dll_SteamAPI_ISteamUserStats_GetAchievement = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_GetAchievement', 'PPP', 'I')
|
||||
# @@dll_SteamAPI_ISteamUserStats_SetAchievement = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_SetAchievement', 'PP', 'I')
|
||||
# @@dll_SteamAPI_ISteamUserStats_ClearAchievement = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_ClearAchievement', 'PP', 'I')
|
||||
# @@dll_SteamAPI_ISteamUserStats_GetAchievementAndUnlockTime = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_GetAchievementAndUnlockTime', 'PPPP', 'I')
|
||||
# @@dll_SteamAPI_ISteamUserStats_GetAchievementDisplayAttribute = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_GetAchievementDisplayAttribute', 'PPP', 'P')
|
||||
# @@dll_SteamAPI_ISteamUserStats_GetNumAchievements = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_GetNumAchievements', 'P', 'I')
|
||||
# @@dll_SteamAPI_ISteamUserStats_GetAchievementName = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_GetAchievementName', 'PI', 'P')
|
||||
# @@dll_SteamAPI_ISteamUserStats_StoreStats = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_StoreStats', 'P', 'I')
|
||||
# @@dll_SteamAPI_ISteamUserStats_ResetAllStats = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamUserStats_ResetAllStats', 'PI', 'I')
|
||||
# @@dll_SteamAPI_ISteamApps_BIsSubscribed = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamApps_BIsSubscribed', 'P', 'I')
|
||||
# @@dll_SteamAPI_ISteamApps_BIsDlcInstalled = Win32API.new(self.steam_dll_name, 'SteamAPI_ISteamApps_BIsDlcInstalled', 'PI', 'I')
|
||||
|
||||
@@instance = self.new
|
||||
|
||||
def self.pack_float(val)
|
||||
# Packs number to a string, then unpack to an int
|
||||
inter = [val].pack 'e'
|
||||
inter.unpack('I')[0]
|
||||
end
|
||||
|
||||
def self.pack_double(val)
|
||||
# Packs number to a string, then unpack to an array of two ints
|
||||
inter = [val].pack 'd'
|
||||
inter.unpack 'II'
|
||||
end
|
||||
|
||||
end
|
613
mkxp-z/Kawariki-patches/ports/debug/basewt.rb
Normal file
613
mkxp-z/Kawariki-patches/ports/debug/basewt.rb
Normal file
|
@ -0,0 +1,613 @@
|
|||
#==============================================================================
|
||||
# ■ Window_Base
|
||||
#------------------------------------------------------------------------------
|
||||
# ゲーム中の全てのウィンドウのスーパークラスです。
|
||||
#==============================================================================
|
||||
|
||||
class Window_Base < Window
|
||||
#--------------------------------------------------------------------------
|
||||
# ● オブジェクト初期化
|
||||
#--------------------------------------------------------------------------
|
||||
def initialize(x, y, width, height)
|
||||
super
|
||||
self.windowskin = Cache.system("Window")
|
||||
update_padding
|
||||
update_tone
|
||||
create_contents
|
||||
@opening = @closing = false
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 解放
|
||||
#--------------------------------------------------------------------------
|
||||
def dispose
|
||||
contents.dispose unless disposed?
|
||||
super
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 行の高さを取得
|
||||
#--------------------------------------------------------------------------
|
||||
def line_height
|
||||
return 24
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 標準パディングサイズの取得
|
||||
#--------------------------------------------------------------------------
|
||||
def standard_padding
|
||||
return 12
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● パディングの更新
|
||||
#--------------------------------------------------------------------------
|
||||
def update_padding
|
||||
self.padding = standard_padding
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● ウィンドウ内容の幅を計算
|
||||
#--------------------------------------------------------------------------
|
||||
def contents_width
|
||||
width - standard_padding * 2
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● ウィンドウ内容の高さを計算
|
||||
#--------------------------------------------------------------------------
|
||||
def contents_height
|
||||
height - standard_padding * 2
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 指定行数に適合するウィンドウの高さを計算
|
||||
#--------------------------------------------------------------------------
|
||||
def fitting_height(line_number)
|
||||
line_number * line_height + standard_padding * 2
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 色調の更新
|
||||
#--------------------------------------------------------------------------
|
||||
def update_tone
|
||||
self.tone.set($game_system.window_tone)
|
||||
end
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# ● ウィンドウ内容の作成
|
||||
#--------------------------------------------------------------------------
|
||||
def create_contents
|
||||
test5 = contents_width
|
||||
testf = contents_height
|
||||
# Debugging: Log the current types and values of contents_width and contents_height
|
||||
puts "Before disposing, contents width: #{contents_width}, height: #{contents_height}"
|
||||
puts "Before disposing, contents width type: #{contents_width.class}, height type: #{contents_height.class}"
|
||||
|
||||
contents.dispose
|
||||
|
||||
# Check for nil and ensure that contents_width and contents_height are integers
|
||||
if contents_width.nil? || contents_height.nil?
|
||||
puts "sadada disposing, contents width: #{contents_width}, height: #{contents_height}"
|
||||
puts "Warning: contents_width or contents_height is nil, setting default values."
|
||||
contents_width = 190 # Default width (you can adjust this to your needs)
|
||||
contents_height = 120 # Default height (you can adjust this to your needs)
|
||||
end
|
||||
|
||||
# Ensure contents_width and contents_height are valid integers before proceeding
|
||||
# if contents_width.is_a?(Integer) && contents_height.is_a?(Integer)
|
||||
if contents_width > 0 && contents_height > 0
|
||||
# Limit height to a maximum of 2048 pixels
|
||||
# contents_height = 2048 if contents_height > 2048
|
||||
self.contents = Bitmap.new(contents_width, contents_height)
|
||||
puts "Created new bitmap with dimensions: #{contents_width} x #{contents_height}"
|
||||
else
|
||||
puts "Invalid dimensions: creating fallback 1x1 bitmap"
|
||||
self.contents = Bitmap.new(1, 1)
|
||||
end
|
||||
# else
|
||||
# # If contents_width or contents_height are not valid integers, create a fallback 1x1 bitmap
|
||||
# puts "Warning: Invalid types for contents width or height. Creating fallback 1x1 bitmap."
|
||||
# self.contents = Bitmap.new(1, 1)
|
||||
# end
|
||||
end
|
||||
def create_contents
|
||||
# puts "vv Before disposing, contents width: #{contents_width}, height: #{contents_height}"
|
||||
# puts "vv Before disposing, contents width type: #{contents_width.class}, height type: #{contents_height.class}"
|
||||
contents.dispose
|
||||
# puts "Before disposing, contents width: #{contents_width}, height: #{contents_height}"
|
||||
# puts "Before disposing, contents width type: #{contents_width.class}, height type: #{contents_height.class}"
|
||||
|
||||
# end
|
||||
if contents_height > 10000
|
||||
self.contents = Bitmap.new(1, 1)
|
||||
elsif contents_width > 0 && contents_height > 0
|
||||
self.contents = Bitmap.new(contents_width, contents_height)
|
||||
puts "Created new bitmap with dimensions: #{contents_width} x #{contents_height}"
|
||||
else
|
||||
self.contents = Bitmap.new(1, 1)
|
||||
end
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● フレーム更新
|
||||
#--------------------------------------------------------------------------
|
||||
def update
|
||||
super
|
||||
update_tone
|
||||
update_open if @opening
|
||||
update_close if @closing
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 開く処理の更新
|
||||
#--------------------------------------------------------------------------
|
||||
def update_open
|
||||
self.openness += 48
|
||||
@opening = false if open?
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 閉じる処理の更新
|
||||
#--------------------------------------------------------------------------
|
||||
def update_close
|
||||
self.openness -= 48
|
||||
@closing = false if close?
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● ウィンドウを開く
|
||||
#--------------------------------------------------------------------------
|
||||
def open
|
||||
@opening = true unless open?
|
||||
@closing = false
|
||||
self
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● ウィンドウを閉じる
|
||||
#--------------------------------------------------------------------------
|
||||
def close
|
||||
@closing = true unless close?
|
||||
@opening = false
|
||||
self
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● ウィンドウの表示
|
||||
#--------------------------------------------------------------------------
|
||||
def show
|
||||
self.visible = true
|
||||
self
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● ウィンドウの非表示
|
||||
#--------------------------------------------------------------------------
|
||||
def hide
|
||||
self.visible = false
|
||||
self
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● ウィンドウのアクティブ化
|
||||
#--------------------------------------------------------------------------
|
||||
def activate
|
||||
self.active = true
|
||||
self
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● ウィンドウの非アクティブ化
|
||||
#--------------------------------------------------------------------------
|
||||
def deactivate
|
||||
self.active = false
|
||||
self
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 文字色取得
|
||||
# n : 文字色番号(0..31)
|
||||
#--------------------------------------------------------------------------
|
||||
def text_color(n)
|
||||
windowskin.get_pixel(64 + (n % 8) * 8, 96 + (n / 8) * 8)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 各種文字色の取得
|
||||
#--------------------------------------------------------------------------
|
||||
def normal_color; text_color(0); end; # 通常
|
||||
def system_color; text_color(16); end; # システム
|
||||
def crisis_color; text_color(17); end; # ピンチ
|
||||
def knockout_color; text_color(18); end; # 戦闘不能
|
||||
def gauge_back_color; text_color(19); end; # ゲージ背景
|
||||
def hp_gauge_color1; text_color(20); end; # HP ゲージ 1
|
||||
def hp_gauge_color2; text_color(21); end; # HP ゲージ 2
|
||||
def mp_gauge_color1; text_color(22); end; # MP ゲージ 1
|
||||
def mp_gauge_color2; text_color(23); end; # MP ゲージ 2
|
||||
def mp_cost_color; text_color(23); end; # 消費 TP
|
||||
def power_up_color; text_color(24); end; # 装備 パワーアップ
|
||||
def power_down_color; text_color(25); end; # 装備 パワーダウン
|
||||
def tp_gauge_color1; text_color(28); end; # TP ゲージ 1
|
||||
def tp_gauge_color2; text_color(29); end; # TP ゲージ 2
|
||||
def tp_cost_color; text_color(29); end; # 消費 TP
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 保留項目の背景色を取得
|
||||
#--------------------------------------------------------------------------
|
||||
def pending_color
|
||||
windowskin.get_pixel(80, 80)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 半透明描画用のアルファ値を取得
|
||||
#--------------------------------------------------------------------------
|
||||
def translucent_alpha
|
||||
return 160
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● テキスト描画色の変更
|
||||
# enabled : 有効フラグ。false のとき半透明で描画
|
||||
#--------------------------------------------------------------------------
|
||||
def change_color(color, enabled = true)
|
||||
contents.font.color.set(color)
|
||||
contents.font.color.alpha = translucent_alpha unless enabled
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● テキストの描画
|
||||
# args : Bitmap#draw_text と同じ
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_text(*args)
|
||||
contents.draw_text(*args)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● テキストサイズの取得
|
||||
#--------------------------------------------------------------------------
|
||||
def text_size(str)
|
||||
contents.text_size(str)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 制御文字つきテキストの描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_text_ex(x, y, text)
|
||||
reset_font_settings
|
||||
text = convert_escape_characters(text)
|
||||
pos = {:x => x, :y => y, :new_x => x, :height => calc_line_height(text)}
|
||||
process_character(text.slice!(0, 1), text, pos) until text.empty?
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● フォント設定のリセット
|
||||
#--------------------------------------------------------------------------
|
||||
def reset_font_settings
|
||||
change_color(normal_color)
|
||||
contents.font.size = Font.default_size
|
||||
contents.font.bold = false
|
||||
contents.font.italic = false
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 制御文字の事前変換
|
||||
# 実際の描画を始める前に、原則として文字列に変わるものだけを置き換える。
|
||||
# 文字「\」はエスケープ文字(\e)に変換。
|
||||
#--------------------------------------------------------------------------
|
||||
def convert_escape_characters(text)
|
||||
result = text.to_s.clone
|
||||
result.gsub!(/\\/) { "\e" }
|
||||
result.gsub!(/\e\e/) { "\\" }
|
||||
result.gsub!(/\eV\[(\d+)\]/i) { $game_variables[$1.to_i] }
|
||||
result.gsub!(/\eV\[(\d+)\]/i) { $game_variables[$1.to_i] }
|
||||
result.gsub!(/\eN\[(\d+)\]/i) { actor_name($1.to_i) }
|
||||
result.gsub!(/\eP\[(\d+)\]/i) { party_member_name($1.to_i) }
|
||||
result.gsub!(/\eG/i) { Vocab::currency_unit }
|
||||
result
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● アクター n 番の名前を取得
|
||||
#--------------------------------------------------------------------------
|
||||
def actor_name(n)
|
||||
actor = n >= 1 ? $game_actors[n] : nil
|
||||
actor ? actor.name : ""
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● パーティメンバー n 番の名前を取得
|
||||
#--------------------------------------------------------------------------
|
||||
def party_member_name(n)
|
||||
actor = n >= 1 ? $game_party.members[n - 1] : nil
|
||||
actor ? actor.name : ""
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 文字の処理
|
||||
# c : 文字
|
||||
# text : 描画処理中の文字列バッファ(必要なら破壊的に変更)
|
||||
# pos : 描画位置 {:x, :y, :new_x, :height}
|
||||
#--------------------------------------------------------------------------
|
||||
def process_character(c, text, pos)
|
||||
case c
|
||||
when "\n" # 改行
|
||||
process_new_line(text, pos)
|
||||
when "\f" # 改ページ
|
||||
process_new_page(text, pos)
|
||||
when "\e" # 制御文字
|
||||
process_escape_character(obtain_escape_code(text), text, pos)
|
||||
else # 普通の文字
|
||||
process_normal_character(c, pos)
|
||||
end
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 通常文字の処理
|
||||
#--------------------------------------------------------------------------
|
||||
def process_normal_character(c, pos)
|
||||
text_width = text_size(c).width
|
||||
draw_text(pos[:x], pos[:y], text_width * 2, pos[:height], c)
|
||||
pos[:x] += text_width
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 改行文字の処理
|
||||
#--------------------------------------------------------------------------
|
||||
def process_new_line(text, pos)
|
||||
pos[:x] = pos[:new_x]
|
||||
pos[:y] += pos[:height]
|
||||
pos[:height] = calc_line_height(text)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 改ページ文字の処理
|
||||
#--------------------------------------------------------------------------
|
||||
def process_new_page(text, pos)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 制御文字の本体を破壊的に取得
|
||||
#--------------------------------------------------------------------------
|
||||
def obtain_escape_code(text)
|
||||
text.slice!(/^[\$\.\|\^!><\{\}\\]|^[A-Z]+/i)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 制御文字の引数を破壊的に取得
|
||||
#--------------------------------------------------------------------------
|
||||
def obtain_escape_param(text)
|
||||
text.slice!(/^\[\d+\]/)[/\d+/].to_i rescue 0
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 制御文字の処理
|
||||
# code : 制御文字の本体部分(「\C[1]」なら「C」)
|
||||
#--------------------------------------------------------------------------
|
||||
def process_escape_character(code, text, pos)
|
||||
case code.upcase
|
||||
when 'C'
|
||||
change_color(text_color(obtain_escape_param(text)))
|
||||
when 'I'
|
||||
process_draw_icon(obtain_escape_param(text), pos)
|
||||
when '{'
|
||||
make_font_bigger
|
||||
when '}'
|
||||
make_font_smaller
|
||||
end
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 制御文字によるアイコン描画の処理
|
||||
#--------------------------------------------------------------------------
|
||||
def process_draw_icon(icon_index, pos)
|
||||
draw_icon(icon_index, pos[:x], pos[:y])
|
||||
pos[:x] += 24
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● フォントを大きくする
|
||||
#--------------------------------------------------------------------------
|
||||
def make_font_bigger
|
||||
contents.font.size += 8 if contents.font.size <= 64
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● フォントを小さくする
|
||||
#--------------------------------------------------------------------------
|
||||
def make_font_smaller
|
||||
contents.font.size -= 8 if contents.font.size >= 16
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 行の高さを計算
|
||||
# restore_font_size : 計算後にフォントサイズを元に戻す
|
||||
#--------------------------------------------------------------------------
|
||||
def calc_line_height(text, restore_font_size = true)
|
||||
result = [line_height, contents.font.size].max
|
||||
last_font_size = contents.font.size
|
||||
text.slice(/^.*$/).scan(/\e[\{\}]/).each do |esc|
|
||||
make_font_bigger if esc == "\e{"
|
||||
make_font_smaller if esc == "\e}"
|
||||
result = [result, contents.font.size].max
|
||||
end
|
||||
contents.font.size = last_font_size if restore_font_size
|
||||
result
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● ゲージの描画
|
||||
# rate : 割合(1.0 で満タン)
|
||||
# color1 : グラデーション 左端
|
||||
# color2 : グラデーション 右端
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_gauge(x, y, width, rate, color1, color2)
|
||||
fill_w = (width * rate).to_i
|
||||
gauge_y = y + line_height - 8
|
||||
contents.fill_rect(x, gauge_y, width, 6, gauge_back_color)
|
||||
contents.gradient_fill_rect(x, gauge_y, fill_w, 6, color1, color2)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● アイコンの描画
|
||||
# enabled : 有効フラグ。false のとき半透明で描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_icon(icon_index, x, y, enabled = true)
|
||||
bitmap = Cache.system("Iconset")
|
||||
rect = Rect.new(icon_index % 16 * 24, icon_index / 16 * 24, 24, 24)
|
||||
contents.blt(x, y, bitmap, rect, enabled ? 255 : translucent_alpha)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 顔グラフィックの描画
|
||||
# enabled : 有効フラグ。false のとき半透明で描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_face(face_name, face_index, x, y, enabled = true)
|
||||
bitmap = Cache.face(face_name)
|
||||
rect = Rect.new(face_index % 4 * 96, face_index / 4 * 96, 96, 96)
|
||||
contents.blt(x, y, bitmap, rect, enabled ? 255 : translucent_alpha)
|
||||
bitmap.dispose
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 歩行グラフィックの描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_character(character_name, character_index, x, y)
|
||||
return unless character_name
|
||||
bitmap = Cache.character(character_name)
|
||||
sign = character_name[/^[\!\$]./]
|
||||
if sign && sign.include?('$')
|
||||
cw = bitmap.width / 3
|
||||
ch = bitmap.height / 4
|
||||
else
|
||||
cw = bitmap.width / 12
|
||||
ch = bitmap.height / 8
|
||||
end
|
||||
n = character_index
|
||||
src_rect = Rect.new((n%4*3+1)*cw, (n/4*4)*ch, cw, ch)
|
||||
contents.blt(x - cw / 2, y - ch, bitmap, src_rect)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● HP の文字色を取得
|
||||
#--------------------------------------------------------------------------
|
||||
def hp_color(actor)
|
||||
return knockout_color if actor.hp == 0
|
||||
return crisis_color if actor.hp < actor.mhp / 4
|
||||
return normal_color
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● MP の文字色を取得
|
||||
#--------------------------------------------------------------------------
|
||||
def mp_color(actor)
|
||||
return crisis_color if actor.mp < actor.mmp / 4
|
||||
return normal_color
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● TP の文字色を取得
|
||||
#--------------------------------------------------------------------------
|
||||
def tp_color(actor)
|
||||
return normal_color
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● アクターの歩行グラフィック描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_actor_graphic(actor, x, y)
|
||||
draw_character(actor.character_name, actor.character_index, x, y)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● アクターの顔グラフィック描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_actor_face(actor, x, y, enabled = true)
|
||||
draw_face(actor.face_name, actor.face_index, x, y, enabled)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 名前の描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_actor_name(actor, x, y, width = 112)
|
||||
change_color(hp_color(actor))
|
||||
draw_text(x, y, width, line_height, actor.name)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 職業の描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_actor_class(actor, x, y, width = 112)
|
||||
change_color(normal_color)
|
||||
draw_text(x, y, width, line_height, actor.class.name)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 二つ名の描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_actor_nickname(actor, x, y, width = 180)
|
||||
change_color(normal_color)
|
||||
draw_text(x, y, width, line_height, actor.nickname)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● レベルの描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_actor_level(actor, x, y)
|
||||
change_color(system_color)
|
||||
draw_text(x, y, 32, line_height, Vocab::level_a)
|
||||
change_color(normal_color)
|
||||
draw_text(x + 32, y, 24, line_height, actor.level, 2)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● ステートおよび強化/弱体のアイコンを描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_actor_icons(actor, x, y, width = 96)
|
||||
icons = (actor.state_icons + actor.buff_icons)[0, width / 24]
|
||||
icons.each_with_index {|n, i| draw_icon(n, x + 24 * i, y) }
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 現在値/最大値を分数形式で描画
|
||||
# current : 現在値
|
||||
# max : 最大値
|
||||
# color1 : 現在値の色
|
||||
# color2 : 最大値の色
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_current_and_max_values(x, y, width, current, max, color1, color2)
|
||||
change_color(color1)
|
||||
xr = x + width
|
||||
if width < 96
|
||||
draw_text(xr - 40, y, 42, line_height, current, 2)
|
||||
else
|
||||
draw_text(xr - 92, y, 42, line_height, current, 2)
|
||||
change_color(color2)
|
||||
draw_text(xr - 52, y, 12, line_height, "/", 2)
|
||||
draw_text(xr - 42, y, 42, line_height, max, 2)
|
||||
end
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● HP の描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_actor_hp(actor, x, y, width = 124)
|
||||
draw_gauge(x, y, width, actor.hp_rate, hp_gauge_color1, hp_gauge_color2)
|
||||
change_color(system_color)
|
||||
draw_text(x, y, 30, line_height, Vocab::hp_a)
|
||||
draw_current_and_max_values(x, y, width, actor.hp, actor.mhp,
|
||||
hp_color(actor), normal_color)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● MP の描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_actor_mp(actor, x, y, width = 124)
|
||||
draw_gauge(x, y, width, actor.mp_rate, mp_gauge_color1, mp_gauge_color2)
|
||||
change_color(system_color)
|
||||
draw_text(x, y, 30, line_height, Vocab::mp_a)
|
||||
draw_current_and_max_values(x, y, width, actor.mp, actor.mmp,
|
||||
mp_color(actor), normal_color)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● TP の描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_actor_tp(actor, x, y, width = 124)
|
||||
draw_gauge(x, y, width, actor.tp_rate, tp_gauge_color1, tp_gauge_color2)
|
||||
change_color(system_color)
|
||||
draw_text(x, y, 30, line_height, Vocab::tp_a)
|
||||
change_color(tp_color(actor))
|
||||
draw_text(x + width - 42, y, 42, line_height, actor.tp.to_i, 2)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● シンプルなステータスの描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_actor_simple_status(actor, x, y)
|
||||
draw_actor_name(actor, x, y)
|
||||
draw_actor_level(actor, x, y + line_height * 1)
|
||||
draw_actor_icons(actor, x, y + line_height * 2)
|
||||
draw_actor_class(actor, x + 120, y)
|
||||
draw_actor_hp(actor, x + 120, y + line_height * 1)
|
||||
draw_actor_mp(actor, x + 120, y + line_height * 2)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 能力値の描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_actor_param(actor, x, y, param_id)
|
||||
change_color(system_color)
|
||||
draw_text(x, y, 120, line_height, Vocab::param(param_id))
|
||||
change_color(normal_color)
|
||||
draw_text(x + 120, y, 36, line_height, actor.param(param_id), 2)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● アイテム名の描画
|
||||
# enabled : 有効フラグ。false のとき半透明で描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_item_name(item, x, y, enabled = true, width = 172)
|
||||
return unless item
|
||||
draw_icon(item.icon_index, x, y, enabled)
|
||||
change_color(normal_color, enabled)
|
||||
draw_text(x + 24, y, width, line_height, item.name)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 通貨単位つき数値(所持金など)の描画
|
||||
#--------------------------------------------------------------------------
|
||||
def draw_currency_value(value, unit, x, y, width)
|
||||
cx = text_size(unit).width
|
||||
change_color(normal_color)
|
||||
draw_text(x, y, width - cx - 2, line_height, value, 2)
|
||||
change_color(system_color)
|
||||
draw_text(x, y, width, line_height, unit, 2)
|
||||
end
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 能力値変化の描画色取得
|
||||
#--------------------------------------------------------------------------
|
||||
def param_change_color(change)
|
||||
return power_up_color if change > 0
|
||||
return power_down_color if change < 0
|
||||
return normal_color
|
||||
end
|
||||
end
|
2723
mkxp-z/Kawariki-patches/ports/debug/savebitmanwin32api.rb
Normal file
2723
mkxp-z/Kawariki-patches/ports/debug/savebitmanwin32api.rb
Normal file
File diff suppressed because it is too large
Load diff
1078
mkxp-z/Kawariki-patches/ports/testencode.rb
Normal file
1078
mkxp-z/Kawariki-patches/ports/testencode.rb
Normal file
File diff suppressed because it is too large
Load diff
191
mkxp-z/Kawariki-patches/ports/wxexittest.rb
Normal file
191
mkxp-z/Kawariki-patches/ports/wxexittest.rb
Normal file
|
@ -0,0 +1,191 @@
|
|||
# ===========================================================================
|
||||
# ★ WF-RGSS Scripts ★
|
||||
# Exit-EX 終了処理スクリプト(共通実行スクリプト VXAce版)
|
||||
# バージョン : rev-2.1 (2012-1-24)
|
||||
# 作者 : A Crying Minister (WHITE-FLUTE)
|
||||
# サポート先URI: http://www.whiteflute.org/wfrgss/
|
||||
# ---------------------------------------------------------------------------
|
||||
# 機能:
|
||||
# ・VXAceの終了処理をXP/VX形式(SystemExit送出)に設定します。
|
||||
# ・VXAceに限り、共通実行スクリプトと同様に使えます。
|
||||
# ---------------------------------------------------------------------------
|
||||
# 設置場所 :Mainセクション(一番最後)に上書き
|
||||
# または、Mainセクションの直前
|
||||
# 必要スクリプト:
|
||||
# ・共通スクリプト
|
||||
# 必要DLL
|
||||
# ・WFExit.dll
|
||||
# 注意事項:
|
||||
# ▽ 共通スクリプトが必要です。
|
||||
# 改造して使用することを推奨しますが、そのまま使ってもOKです。
|
||||
# ▽ デバッグモードでエラーを記録する場合、
|
||||
# 現在のユーザで書き込みを行えることが必要になります。
|
||||
# ▽ スクリプトが実行されます。これ以降のセクションは実行されません。
|
||||
#==============================================================================
|
||||
# ◆ Main ( Execute )
|
||||
#------------------------------------------------------------------------------
|
||||
# 各クラスの定義が終わった後、ここから実際の処理が始まります。
|
||||
#==============================================================================
|
||||
#module Exit
|
||||
# # ---------------------------------------------------------------------------
|
||||
# # ◆ カスタマイズポイント セットアップ処理を記述します。
|
||||
# # ---------------------------------------------------------------------------
|
||||
# def self.setup
|
||||
# end
|
||||
# # ---------------------------------------------------------------------------
|
||||
# # ◆ カスタマイズポイント 解放処理を記述します。
|
||||
# # ---------------------------------------------------------------------------
|
||||
# def self.dispose
|
||||
# DataManager.save_system
|
||||
# end
|
||||
#end
|
||||
# ---------------------------------------------------------------------------
|
||||
# ◆ 以下の内容は変更する必要はありません。
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
#==============================================================================
|
||||
# ◆ Exit モジュール
|
||||
#------------------------------------------------------------------------------
|
||||
def hook_exit()
|
||||
# Simulate what the hookExit function might do
|
||||
# puts "Simulated hookExit called with parameter:"
|
||||
# You can add more simulated behavior here, like logging, altering global variables, etc.
|
||||
end
|
||||
module Exit
|
||||
# ---------------------------------------------------------------------------
|
||||
# ◆ 処理実行
|
||||
# ---------------------------------------------------------------------------
|
||||
begin
|
||||
@@hook = method(:hook_exit)
|
||||
@@exit = method(:hook_exit)
|
||||
@@quit = method(:hook_exit)
|
||||
@@reset = method(:hook_exit)
|
||||
@@clear = method(:hook_exit)
|
||||
|
||||
#@@hook = Win32API.new('System/WFExit','hookExit','v','l')
|
||||
#@@exit = Win32API.new('System/WFExit','getToExit','v','l')
|
||||
#@@quit = Win32API.new('System/WFExit','Quit','v','v')
|
||||
#@@reset = Win32API.new('System/WFExit','getToReset','v','l')
|
||||
#@@clear = Win32API.new('System/WFExit','clearReset','v','v')
|
||||
rescue Exception
|
||||
raise if $TEST
|
||||
raise( LoadError , "cannot read modules.(WFExit.dll)")
|
||||
end
|
||||
@@hook.call()
|
||||
# ---------------------------------------------------------------------------
|
||||
# ◆ 終了を監視する
|
||||
# ---------------------------------------------------------------------------
|
||||
def self.toexit
|
||||
raise SystemExit.new(0) if @@exit.call() == 1
|
||||
end
|
||||
# ---------------------------------------------------------------------------
|
||||
# ◆ F12リセットを監視する
|
||||
# ---------------------------------------------------------------------------
|
||||
def self.toreset
|
||||
raise RGSSReset if @duration && @duration <= 0 if @@reset.call() == 1
|
||||
if @duration && @duration > 0
|
||||
@duration -= 1
|
||||
@@clear.call()
|
||||
end
|
||||
end
|
||||
# ---------------------------------------------------------------------------
|
||||
# ◆ 本当の終了処理
|
||||
# ---------------------------------------------------------------------------
|
||||
def self.quit
|
||||
@@quit.call()
|
||||
end
|
||||
# ---------------------------------------------------------------------------
|
||||
# ◆ リセットカウントをクリア
|
||||
# ---------------------------------------------------------------------------
|
||||
def self.clearreset(wait = false)
|
||||
@@clear.call()
|
||||
@duration = wait ? 120 : 0
|
||||
end
|
||||
end
|
||||
# ---------------------------------------------------------------------------
|
||||
# ◆ 終了監視をセット
|
||||
# ---------------------------------------------------------------------------
|
||||
class << Graphics
|
||||
alias __wfexit_uodate__ update
|
||||
def Graphics.update
|
||||
__wfexit_uodate__
|
||||
Exit.toexit
|
||||
Exit.toreset
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ◆ セットアップをセット
|
||||
# ---------------------------------------------------------------------------
|
||||
class << SceneManager
|
||||
alias __wfexit_run__ run
|
||||
#--------------------------------------------------------------------------
|
||||
# ● 実行
|
||||
#--------------------------------------------------------------------------
|
||||
def SceneManager.run
|
||||
Exit.setup
|
||||
Exit.clearreset(true)
|
||||
__wfexit_run__
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ◆ 処理実行
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
begin
|
||||
rgss_main { SceneManager.run }
|
||||
# 以下、例外処理
|
||||
rescue BugDetected, InternalBugDetected => errobj
|
||||
begin
|
||||
MessageBox.fatalerror( errobj )
|
||||
raise SystemExit.new(1)
|
||||
rescue Hangup
|
||||
nil
|
||||
end
|
||||
|
||||
rescue SyntaxError => errobj
|
||||
# -------------------------------------------------------------------------
|
||||
# ◆ 例外 SyntaxError
|
||||
# -------------------------------------------------------------------------
|
||||
# この例外はバグかセットアップが適切にされていない状況で無い限り、
|
||||
# 補足されることはない
|
||||
begin
|
||||
raise( BugDetected,
|
||||
"[FATAL] The invalidated exception was detected. \n\n" +
|
||||
"Exception:\n#{errobj}")
|
||||
rescue BugDetected => errobj
|
||||
begin
|
||||
MessageBox.fatalerror( errobj )
|
||||
raise SystemExit.new(1)
|
||||
rescue Hangup
|
||||
nil
|
||||
end
|
||||
end
|
||||
rescue SystemExit
|
||||
# 終了を補足する。エラーメッセージに書き加えない。
|
||||
rescue Exception => errobj
|
||||
# -------------------------------------------------------------------------
|
||||
# ◆ 例外処理
|
||||
# 特に指定されていない例外を補足します。
|
||||
# ※ rev-2 より、Errno::ENOENT もここで補足します。
|
||||
# -------------------------------------------------------------------------
|
||||
begin
|
||||
MessageBox.fatalerror( errobj )
|
||||
raise SystemExit.new(1)
|
||||
rescue Hangup
|
||||
nil
|
||||
end
|
||||
|
||||
ensure
|
||||
# -------------------------------------------------------------------------
|
||||
# ● 後処理
|
||||
# -------------------------------------------------------------------------
|
||||
# 後処理を担当します。
|
||||
# スクリプト内容によってはここで解放処理が必要になることがあります。
|
||||
Exit.dispose
|
||||
# ★ ----------------------------------------------------------------------
|
||||
Exit.quit # フックを解放する。実行しないと終了しない危険性大
|
||||
end
|
||||
|
||||
exit # Mainセクションが後に控えている時に処理が渡らないようにする
|
602
mkxp-z/Kawariki-patches/preload.rb
Normal file
602
mkxp-z/Kawariki-patches/preload.rb
Normal file
|
@ -0,0 +1,602 @@
|
|||
# Kawariki MKXP preload infrastructure
|
||||
|
||||
module Preload
|
||||
# Kawariki mkxp resources location
|
||||
Path = File.dirname __FILE__
|
||||
|
||||
# Require common libs
|
||||
def self.require(name)
|
||||
Kernel.require File.join(Path, "libs", name)
|
||||
end
|
||||
|
||||
module Common
|
||||
# In RMXP mode, Kernel.print opens message boxes
|
||||
def print(text)
|
||||
STDOUT.puts("[preload] " + text.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
extend Common
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Patches
|
||||
# -------------------------------------------------------------------------
|
||||
class Context
|
||||
include Common
|
||||
|
||||
def initialize(scripts)
|
||||
@scripts = scripts
|
||||
@script_instances = {}
|
||||
@options = {}
|
||||
@blacklist = []
|
||||
@delay = {}
|
||||
@script_id_digits = Math.log10(scripts.size).ceil
|
||||
end
|
||||
|
||||
attr_reader :script_id_digits, :script_loc_format
|
||||
|
||||
# Scripts
|
||||
def script(i)
|
||||
@script_instances[i] ||= Script.new self, i, @scripts[i]
|
||||
end
|
||||
|
||||
def script_count
|
||||
@scripts.size
|
||||
end
|
||||
|
||||
def each_script
|
||||
(0...@scripts.size).each {|i| yield script i}
|
||||
end
|
||||
|
||||
def last_script
|
||||
script (script_count - 1)
|
||||
end
|
||||
|
||||
def script_loc(scriptid)
|
||||
return script(scriptid).loc
|
||||
end
|
||||
|
||||
def blacklisted?(script)
|
||||
@blacklist.include? script.name
|
||||
end
|
||||
|
||||
def add_script(name, code)
|
||||
@scripts.pop
|
||||
@scripts.push [name, "", nil, code]
|
||||
# TODO: Find an empty script to canibalize instead
|
||||
end
|
||||
|
||||
# Read options from environment
|
||||
FalseEnvValues = [nil, "", "0", "no"]
|
||||
def read_env(env=ENV)
|
||||
env_bool = ->(name) {!FalseEnvValues.include?(env[name])}
|
||||
env_str = ->(name) {e = env[name]; e unless e == ""}
|
||||
env_list = ->(name, delim) {e = env[name]; e.nil? ? [] : e.split(delim)}
|
||||
|
||||
set :dump_scripts_raw, env_str.("KAWARIKI_MKXP_DUMP_SCRIPTS")
|
||||
set :dump_scripts_patched, env_str.("KAWARIKI_MKXP_DUMP_PATCHED_SCRIPTS")
|
||||
mark :dont_run_game if env_bool.("KAWARIKI_MKXP_DRY_RUN")
|
||||
mark :no_font_effects if env_bool.("KAWARIKI_MKXP_NO_FONT_EFFECTS")
|
||||
@blacklist = env_list.("KAWARIKI_MKXP_FILTER_SCRIPTS", ",")
|
||||
end
|
||||
|
||||
def read_system(system=System)
|
||||
# TODO: Non mkxp-z variants
|
||||
set :mkxp_version, system::VERSION
|
||||
set :mkxp_version_tuple, (system::VERSION.split ".").map{|d| d.to_i}
|
||||
|
||||
if (self[:mkxp_version_tuple] <=> [2, 4]) >= 0 then
|
||||
mark :mkxpz_24
|
||||
_config = CFG
|
||||
else
|
||||
_config = system::CONFIG
|
||||
end
|
||||
# set :rgss_version, _config["rgssVersion"].to_i
|
||||
# puts "jj"+_config["gameFolder"].to_s
|
||||
# Preload.require "PreloadIni.rb"
|
||||
# puts "vvv"+ENV["rpgvers"]
|
||||
set :rgss_version, ENV["rpgvers"].to_i
|
||||
|
||||
# puts self[:zeusrpgver]
|
||||
# puts vcode
|
||||
if defined?(RGSS_VERSION) && RGSS_VERSION == "3.0.1" then
|
||||
# See mkxp-z/mri-binding.cpp
|
||||
# puts "vvv"+RGSS_VERSION
|
||||
set :rgss_version, 3
|
||||
end
|
||||
|
||||
# FIXME: can this be reliably retrieved from MKXP if set to 0 in config?
|
||||
if self[:rgss_version] == 0 then
|
||||
print "Warning: rgssVersion not set in MKXP config. Are you running mkxp directly?"
|
||||
if RGSS_VERSION == "3.0.1" then
|
||||
# See mkxp-z/mri-binding.cpp
|
||||
set :rgss_version, 3
|
||||
else
|
||||
print "Warning: Cannot guess RGSS version. Kawariki should automatically set it correctly."
|
||||
end
|
||||
end
|
||||
if self[:mkxp_version] == "MKXPZ_VERSION" then
|
||||
print "Note: Using mkxp-z with broken System::VERSION reporting. Cannot detect real mkxp-z version"
|
||||
set :mkxp_version, "mkxp-z"
|
||||
end
|
||||
end
|
||||
|
||||
# Options
|
||||
def set(sym, value=true)
|
||||
@options.store sym, value unless value.nil?
|
||||
end
|
||||
|
||||
def [](sym)
|
||||
@options[sym]
|
||||
end
|
||||
|
||||
def mark(*flags)
|
||||
flags.each{|flag| set flag, true}
|
||||
end
|
||||
|
||||
def flag?(flag)
|
||||
@options.key? flag
|
||||
end
|
||||
|
||||
# Delay
|
||||
DelaySlots = [:after_patches]
|
||||
|
||||
def delay(slot, &p)
|
||||
raise "Unknown delay slot #{slot}" unless DelaySlots.include? slot
|
||||
@delay[slot] = [] unless @delay.key? slot
|
||||
@delay[slot].push p
|
||||
end
|
||||
|
||||
def run_delay_slot(slot, *args)
|
||||
raise "Unknown delay slot #{slot}" unless DelaySlots.include? slot
|
||||
if @delay[slot] then
|
||||
@delay[slot].each {|p| p.call(self, *args)}
|
||||
@delay.delete slot
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Script
|
||||
|
||||
def initialize(context, i, script)
|
||||
@context = context
|
||||
@index = i
|
||||
@script = script
|
||||
@log = []
|
||||
end
|
||||
|
||||
attr_reader :context
|
||||
attr_reader :index
|
||||
|
||||
def log(msg=nil)
|
||||
@log.push msg unless msg.nil? || @log.last == msg
|
||||
@log
|
||||
end
|
||||
|
||||
def loc
|
||||
"##{index.to_s.rjust @context.script_id_digits} '#{name}'"
|
||||
end
|
||||
|
||||
def [](i)
|
||||
@script[i]
|
||||
end
|
||||
|
||||
def name
|
||||
@script[1]
|
||||
end
|
||||
|
||||
|
||||
def source
|
||||
@script[3]
|
||||
end
|
||||
|
||||
def sub!(*p)
|
||||
@script[3].gsub!(*p)
|
||||
end
|
||||
|
||||
def source=(code)
|
||||
@script[3] = code
|
||||
end
|
||||
|
||||
def load_file(path)
|
||||
log "replaced with #{File.basename path}"
|
||||
@script[3] = File.read(path)
|
||||
end
|
||||
|
||||
def remove
|
||||
log "removed"
|
||||
@script[3] = ""
|
||||
end
|
||||
|
||||
# Extract $imported key only once
|
||||
# $imported['Hello'] = 1
|
||||
# $imported[:Hello] = true
|
||||
# ($imported ||= {})["Hello"] = true
|
||||
# Type (String/Symbol) is preserved
|
||||
ImportedKeyExpr = /^\s*(?:\$imported|\(\s*\$imported(?:\s*\|\|=\s*\{\s*\})?\s*\))\[(:\w+|'[^']+'|"[^"]+")\]\s*=\s*(.+)\s*$/
|
||||
|
||||
def _extract_imported
|
||||
match = ImportedKeyExpr.match(source)
|
||||
@imported_entry = !match.nil?
|
||||
return unless @imported_entry
|
||||
@imported_key = match[1][0] == ':' ? match[1][1..].to_sym : match[1][1...-1]
|
||||
@imported_value = match[2]
|
||||
end
|
||||
|
||||
def imported_entry?
|
||||
_extract_imported if @imported_entry.nil?
|
||||
@imported_entry
|
||||
end
|
||||
|
||||
def imported_key
|
||||
_extract_imported if @imported_entry.nil?
|
||||
@imported_key
|
||||
end
|
||||
|
||||
def imported_value
|
||||
_extract_imported if @imported_entry.nil?
|
||||
@imported_value
|
||||
end
|
||||
end
|
||||
|
||||
class Patch
|
||||
include Common
|
||||
|
||||
def initialize(desc=nil)
|
||||
@description = desc
|
||||
@conditions = []
|
||||
@actions = []
|
||||
@terminal = false
|
||||
end
|
||||
|
||||
def is_applicable(script)
|
||||
return @conditions.all? {|cond| cond.call(script)}
|
||||
end
|
||||
|
||||
def apply(script)
|
||||
print "Patch #{script.loc}: #{@description}"
|
||||
@actions.each {|action| action.call script}
|
||||
@terminal
|
||||
end
|
||||
|
||||
def eval(script)
|
||||
apply script if is_applicable script
|
||||
end
|
||||
|
||||
# --- Conditions ---
|
||||
# Arbitrary condition
|
||||
def if?(&p)
|
||||
@conditions.push p
|
||||
self
|
||||
end
|
||||
|
||||
# Source code contains text
|
||||
def include?(str)
|
||||
# XXX: maybe should restrict this to the start of the script for performance?
|
||||
if? {|script| script.source.include? str}
|
||||
end
|
||||
|
||||
# Source code matches (any) pattern
|
||||
def match?(*ps)
|
||||
pattern = Regexp.union(*ps)
|
||||
if? {|script| script.source.match? pattern}
|
||||
end
|
||||
|
||||
# Script sets $imported[key]
|
||||
def imported?(key)
|
||||
if? {|script| script.imported_key == key}
|
||||
end
|
||||
|
||||
# Global flag set
|
||||
def flag?(flag)
|
||||
if? {|script| script.context.flag? flag}
|
||||
end
|
||||
|
||||
# --- Actions ---
|
||||
# Arbitrary action
|
||||
def then!(&p)
|
||||
@actions.push p
|
||||
self
|
||||
end
|
||||
|
||||
# Run arbitrary action later
|
||||
def delay!(slot, &p)
|
||||
@actions.push proc{|script|script.context.delay(slot, &p)}
|
||||
self
|
||||
end
|
||||
|
||||
# Substitute text
|
||||
def sub!(pattern, replacement)
|
||||
@actions.push proc{|script| script.source.gsub! pattern, replacement}
|
||||
self
|
||||
end
|
||||
|
||||
# Set a global flag for later reference
|
||||
def flag!(*flags)
|
||||
@actions.push proc{|script| script.context.mark *flags}
|
||||
self
|
||||
end
|
||||
|
||||
# Remove the script (terminal)
|
||||
def remove!
|
||||
@actions.push proc{|script| script.remove }
|
||||
@terminal = true
|
||||
self
|
||||
end
|
||||
|
||||
# Replace the whole script with a file from ports/ (terminal)
|
||||
def replace!(filename)
|
||||
puts filename
|
||||
@actions.push proc{|script| script.load_file File.join(Path, "ports", filename)}
|
||||
@terminal = true
|
||||
self
|
||||
end
|
||||
|
||||
# Stop processing this script if patch is applicable (terminal)
|
||||
def next!
|
||||
@terminal = true
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Apply Patches
|
||||
# -------------------------------------------------------------------------
|
||||
class ClassInfo
|
||||
include Common
|
||||
|
||||
def initialize(name, script, supername)
|
||||
@name = name
|
||||
@defs = [[script, supername]]
|
||||
@superdef = 0
|
||||
end
|
||||
|
||||
attr_reader :name
|
||||
attr_reader :defs
|
||||
|
||||
def first_script
|
||||
return @defs[0][0]
|
||||
end
|
||||
|
||||
def super_name
|
||||
return @defs[@superdef][1]
|
||||
end
|
||||
|
||||
def super_script
|
||||
return @defs[@superdef][0]
|
||||
end
|
||||
|
||||
def first_loc
|
||||
return first_script.loc
|
||||
end
|
||||
|
||||
def super_loc
|
||||
return super_script.loc
|
||||
end
|
||||
|
||||
def add_definition(script, supername)
|
||||
if !supername.nil? && super_name != supername then
|
||||
print "Warning: Redefinition of class '#{name}' in #{script.loc} with inconsistent superclass '#{supername}'. Previous definition in #{super_loc} has superclass '#{super_name}'"
|
||||
@superdef = @defs.size
|
||||
end
|
||||
@defs.push [script, supername]
|
||||
end
|
||||
|
||||
def inconsistent?
|
||||
return @superdef > 0
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_class_defs(ctx)
|
||||
classes = {}
|
||||
expr = /^class\s+(\w+)\s*(?:<\s*(\w+)\s*)?$/
|
||||
ctx.each_script do |script|
|
||||
# Encoding is all kinds of messed up in RM
|
||||
e = script.source.encoding
|
||||
script.source.force_encoding Encoding.find("ASCII-8BIT")
|
||||
script.source.scan(expr) do |groups|
|
||||
name, supername = *groups
|
||||
if !classes.include? name then
|
||||
classes[name] = ClassInfo.new name, script, supername
|
||||
else
|
||||
classes[name].add_definition script, supername
|
||||
end
|
||||
end
|
||||
script.source.force_encoding e
|
||||
end
|
||||
return classes
|
||||
end
|
||||
|
||||
def self.overwrite_redefinitions(ctx)
|
||||
classes = get_class_defs ctx
|
||||
classes.each_pair do |name, cls|
|
||||
if cls.inconsistent? then
|
||||
print "Eliminating definitions of class '#{name}' before #{cls.super_loc}. First in #{cls.first_loc}"
|
||||
cls.super_script.sub!(Regexp.new("^(class\\s+#{name}\\s*<\\s*#{cls.super_name}\\s*)$"),
|
||||
"Object.remove_const :#{name}\n\\1")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.patch_scripts(ctx)
|
||||
ctx.each_script do |script|
|
||||
# Remove blacklisted scripts
|
||||
if ctx.blacklisted? script then
|
||||
print "Removed #{script.loc}: Blacklisted"
|
||||
script.remove
|
||||
next
|
||||
end
|
||||
# Encodings are a mess in RGSS. Can break Regexp matching
|
||||
e = script.source.encoding
|
||||
script.source.force_encoding "ASCII-8BIT"
|
||||
# Apply patches
|
||||
Patches.each do |patch|
|
||||
break if patch.eval script
|
||||
end
|
||||
print "Patched #{script.loc}: #{script.log.join(', ')}" if script.log.size > 0
|
||||
# Warn if Win32API references in source
|
||||
if script.source.include? "Win32API.new" then
|
||||
print "Warning: Script #{script.loc} uses Win32API."
|
||||
require "Win32API.rb"
|
||||
end
|
||||
# Restore encoding
|
||||
script.source.force_encoding e
|
||||
end
|
||||
ctx.run_delay_slot :after_patches
|
||||
end
|
||||
|
||||
NoFilenameChars = "/$|*#="
|
||||
|
||||
def self.dump_scripts(ctx, opt)
|
||||
# Dump all scripts to a folder specified by opt
|
||||
if ctx.flag? opt then
|
||||
dump = ctx[opt]
|
||||
print "Dumping all scripts to %s" % dump
|
||||
Dir.mkdir dump unless Dir.exist? dump
|
||||
fn_format = "%0#{ctx.script_id_digits}d%s%s%s"
|
||||
ctx.each_script do |script|
|
||||
filename = fn_format % [script.index,
|
||||
script.name.empty? ? "" : " ",
|
||||
script.name.tr(NoFilenameChars, "_"),
|
||||
script.source.empty? ? "" : ".rb"]
|
||||
File.write File.join(dump, filename), script.source
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Logic
|
||||
# -------------------------------------------------------------------------
|
||||
RgssVersionNames = ["Unknown", "XP", "VX", "VX Ace"]
|
||||
|
||||
|
||||
|
||||
@on_preload = []
|
||||
@on_load = []
|
||||
@on_boot = []
|
||||
@ctx = nil
|
||||
|
||||
def self._run_preload
|
||||
# Initialize
|
||||
@ctx = ctx = Context.new $RGSS_SCRIPTS
|
||||
ctx.read_system
|
||||
ctx.read_env
|
||||
|
||||
# Preload[:vcode] = vcode
|
||||
# Preload.Context.set(:vscode, vcode)
|
||||
# puts vcode
|
||||
# set :zeusrpgver, vcode
|
||||
# set :zeusrpgver, vcode
|
||||
# puts vcode
|
||||
# set :zeusrpgver, vcode
|
||||
# print "#{ctx[:zeusrpgver]}"
|
||||
print "MKXP mkxp-z #{ctx[:mkxp_version]} RGSS #{ctx[:rgss_version]} (#{RgssVersionNames[ctx[:rgss_version]]})\n"
|
||||
# Run preload hooks
|
||||
@on_preload.each{|p| p.call ctx}
|
||||
ctx.each_script do |script|
|
||||
print "Script ##{script.index}: #{script.name}#{"\t[#{script.imported_key}]" if script.imported_key}"
|
||||
end
|
||||
# Patch Scripts
|
||||
dump_scripts ctx, :dump_scripts_raw
|
||||
patch_scripts ctx
|
||||
overwrite_redefinitions ctx if ctx.flag? :redefinitions_overwrite_class
|
||||
dump_scripts ctx, :dump_scripts_patched
|
||||
# Try to inject hook after most (plugin) scripts are loaded but before game starts
|
||||
ctx.last_script.source= "Preload._run_boot\n\n" + ctx.last_script.source
|
||||
# Done
|
||||
if ctx.flag? :dont_run_game then
|
||||
print "KAWARIKI_MKXP_DRY_RUN is set, not continuing to game code"
|
||||
exit 123
|
||||
end
|
||||
end
|
||||
|
||||
def self._run_load
|
||||
@on_load.each {|p| p.call @ctx}
|
||||
end
|
||||
|
||||
def self._run_boot
|
||||
@on_boot.each {|p| p.call @ctx}
|
||||
end
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Callbacks for user-scripts
|
||||
# -------------------------------------------------------------------------
|
||||
# Register block to be called with preload context
|
||||
def self.on_preload(&p)
|
||||
@on_preload.push p
|
||||
end
|
||||
|
||||
# Register block to be called after patches are applied
|
||||
def self.on_load(&p)
|
||||
@on_load.push p
|
||||
end
|
||||
|
||||
# Register block to be called on RGSS boot
|
||||
def self.on_boot(&p)
|
||||
@on_boot.push p
|
||||
end
|
||||
end
|
||||
_config = CFG
|
||||
|
||||
# puts "hhh"
|
||||
def find_game_ini_in_directory(directory)
|
||||
# Search for "game.ini" within the specified directory, case-insensitive
|
||||
files = Dir.glob("#{directory}/Game.ini", File::FNM_CASEFOLD)
|
||||
|
||||
# If the file exists, return the full path
|
||||
if files.any?
|
||||
return files.first # Return the full path of the first match
|
||||
else
|
||||
return nil # Return nil if no file is found
|
||||
end
|
||||
end
|
||||
game_ini_path = find_game_ini_in_directory(_config["gameFolder"].to_s)
|
||||
# puts Dir.pwd
|
||||
|
||||
|
||||
|
||||
def checkini(file_path)
|
||||
# Check if the file exists
|
||||
if File.exist?(file_path)
|
||||
# Read the content of the file
|
||||
input_string = File.read(file_path, encoding: 'ASCII-8BIT')
|
||||
|
||||
# Match the content of the file and return the appropriate value
|
||||
# Match the pattern in the input string and return corresponding values
|
||||
if input_string =~ /rvdata2/
|
||||
return 3
|
||||
elsif input_string =~ /rvdata/
|
||||
return 2
|
||||
elsif input_string =~ /rxdata/
|
||||
return 1
|
||||
else
|
||||
return 0 # Return nil if none of the patterns match
|
||||
end
|
||||
else
|
||||
puts "File does not exist!"
|
||||
return nil
|
||||
end
|
||||
end
|
||||
vers = checkini(game_ini_path)
|
||||
|
||||
rgssversioncodes = ["Unknown", ":xp", ":vx", ":vxace"]
|
||||
|
||||
# vcode =
|
||||
# set :zeusrpgver, vcode
|
||||
ENV["vcode"] = rgssversioncodes[vers]
|
||||
puts ENV["vcode"]
|
||||
ENV["rpgvers"] = vers.to_s
|
||||
# puts "nbnn"+ENV["vcode"]
|
||||
# Ensure Zlib is loaded
|
||||
Kernel.require 'zlib' unless Kernel.const_defined? :Zlib
|
||||
# Load patch definitions
|
||||
Kernel.require File.join(Preload::Path, 'patches.rb')
|
||||
# Inject user scripts
|
||||
Dir['*.kawariki.rb'].each do |filename|
|
||||
Preload.print "Loading user script #{filename}"
|
||||
Kernel.require filename
|
||||
end
|
||||
# Apply patches to scripts
|
||||
Preload._run_preload
|
||||
# Run load hooks just before control returns to MKXP to run the scripts
|
||||
Preload._run_load
|
31
mkxp-z/Kawariki-patches/versions.json
Normal file
31
mkxp-z/Kawariki-patches/versions.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"$schema": "../versions.schema.json",
|
||||
"format": 2,
|
||||
"name": "mkxp",
|
||||
"common": {
|
||||
"slug": "{variant}-{version!v}-{platform}"
|
||||
},
|
||||
"versions": [
|
||||
{
|
||||
"variant": "mkxp-z",
|
||||
"version": [2, 4, 0],
|
||||
"platforms": ["linux-x86_64"],
|
||||
"binary": "mkxp-z",
|
||||
"url": "https://github.com/Orochimarufan/Kawariki/releases/download/mkxp-2.3.0-kk/mkxp-z-{version!v}-{platform}.tar.xz"
|
||||
},
|
||||
{
|
||||
"variant": "mkxp-z",
|
||||
"version": [2, 3, 1],
|
||||
"platforms": ["linux-x86_64"],
|
||||
"binary": "mkxp-z.x86_64",
|
||||
"url": "https://github.com/Orochimarufan/Kawariki/releases/download/mkxp-2.3.0-kk/mkxp-z_2.3.1_x64.tar.xz"
|
||||
},
|
||||
{
|
||||
"variant": "mkxp-z",
|
||||
"version": [2, 3, 0],
|
||||
"platforms": ["linux-x86_64"],
|
||||
"binary": "mkxp-z.x86_64",
|
||||
"url": "https://github.com/Orochimarufan/Kawariki/releases/download/mkxp-2.3.0-kk/mkxp-z_2.3.0_x64.tar.xz"
|
||||
}
|
||||
]
|
||||
}
|
529
mkxp-z/mkxp.json
Normal file
529
mkxp-z/mkxp.json
Normal file
|
@ -0,0 +1,529 @@
|
|||
{
|
||||
// Lines starting with '//' are comments.
|
||||
//
|
||||
// About filesystem paths specified in this config:
|
||||
// to the directory containing the mkxp executable
|
||||
// (the default behavior), or relative to the current
|
||||
// working directory (when compiled with
|
||||
// -DWORKDIR_CURRENT). All other paths are resolved
|
||||
"gameFolder": "ggg",
|
||||
// encrypted archives. Since this is JSON, any
|
||||
// backslashes in paths need to be escaped (i.e. a
|
||||
// single backslash becomes a double backslash). If
|
||||
// that's too much hassle, you can use a single forward
|
||||
// slash instead (even on Windows).
|
||||
|
||||
// Some influential environment variables, set them to either "1" or "0":
|
||||
// "MKXPZ_WINDOWS_CONSOLE"
|
||||
// - Enables/disables the extra console window on Windows. It appears by
|
||||
// default whenever mkxp-z is started in debug mode.
|
||||
// "MKXPZ_MACOS_METAL"
|
||||
// - Setting this will influence the rendering backend used.
|
||||
// Probably not a good idea to mess with it unless you have some kind of issue.
|
||||
// OpenGL is default on x86, and Metal is the default on Apple Silicon.
|
||||
// This takes priority over the config option if it's set.
|
||||
// "MKXPZ_FOLDER_SELECT"
|
||||
// - Allows the manual selection of the game's folder at startup.
|
||||
// Only works on macOS at the moment.
|
||||
// "MTL_HUD_ENABLED"
|
||||
// - On macOS 13 (Ventura) and over, provided the Metal backend is used,
|
||||
// this will enable a full performance HUD containing more details than
|
||||
// the built-in framerate display.
|
||||
|
||||
|
||||
// Specify the RGSS version to run under.
|
||||
// Possible values are 0, 1, 2, 3. If set to 0,
|
||||
// mkxp will try to guess the required version
|
||||
// If this fails, the version defaults to 1.
|
||||
// (default: 0)
|
||||
//
|
||||
// "rgssVersion": 1,
|
||||
|
||||
|
||||
// Continuously display average FPS in window title.
|
||||
// This can always be toggled with F2 at runtime.
|
||||
// (default: disabled)
|
||||
//
|
||||
// "displayFPS": false,
|
||||
|
||||
|
||||
// Continuously print average FPS to console.
|
||||
// This setting does not affect the window title
|
||||
// FPS display toggled via F2
|
||||
// (default: disabled)
|
||||
//
|
||||
// "printFPS": false,
|
||||
|
||||
|
||||
// Game window is resizable
|
||||
// (default: enabled)
|
||||
//
|
||||
// "winResizable": true,
|
||||
|
||||
|
||||
// Start game in fullscreen (this can
|
||||
// always be toggled with Alt-Enter at runtime)
|
||||
// (default: disabled)
|
||||
//
|
||||
// "fullscreen": false,
|
||||
|
||||
|
||||
// Preserve game screen aspect ratio,
|
||||
// as opposed to stretch-to-fill
|
||||
// (default: enabled)
|
||||
//
|
||||
// "fixedAspectRatio": true,
|
||||
|
||||
|
||||
// Apply smooth interpolation when game screen
|
||||
// is upscaled
|
||||
// 0: Nearest-Neighbor
|
||||
// 1: Bilinear
|
||||
// 2: Bicubic
|
||||
// 3: Lanczos3
|
||||
// 4: xBRZ
|
||||
// (default: 0)
|
||||
//
|
||||
// "smoothScaling": 0,
|
||||
|
||||
|
||||
// Apply smooth interpolation when game screen
|
||||
// is downscaled (same values as smoothScaling)
|
||||
// (default: 0)
|
||||
//
|
||||
// "smoothScalingDown": 0,
|
||||
|
||||
|
||||
// Apply smooth interpolation when bitmaps
|
||||
// are upscaled (same values as smoothScaling)
|
||||
// (default: 0)
|
||||
//
|
||||
// "bitmapSmoothScaling": 0,
|
||||
|
||||
|
||||
// Apply smooth interpolation when bitmaps
|
||||
// are downscaled (same values as smoothScaling)
|
||||
// (default: 0)
|
||||
//
|
||||
// "bitmapSmoothScalingDown": 0,
|
||||
|
||||
|
||||
// Apply mipmap interpolation when game screen
|
||||
// or bitmaps are downscaled (requires
|
||||
// "smoothScalingDown": 1 or "bitmapSmoothScalingDown": 1)
|
||||
// (default: false)
|
||||
//
|
||||
// "smoothScalingMipmaps": false,
|
||||
|
||||
|
||||
// Sharpness when using Bicubic scaling.
|
||||
// A good starting range is 0 to 100,
|
||||
// but you may wish to go outside that range in either direction.
|
||||
// (default: 100)
|
||||
//
|
||||
// "bicubicSharpness": 100,
|
||||
|
||||
|
||||
// Scaling factor for xBRZ interpolation
|
||||
// (set to at least the ratio of your window size
|
||||
// to the game's native resolution)
|
||||
// (default: 1.0)
|
||||
//
|
||||
// "xbrzScalingFactor": 4.0,
|
||||
|
||||
|
||||
// Replace the game's Bitmap files with external high-res files
|
||||
// provided in the "Hires" directory.
|
||||
// (You'll also need to set the below Scaling Factors.)
|
||||
// (default: disabled)
|
||||
//
|
||||
// "enableHires": false,
|
||||
|
||||
|
||||
// Scaling factor for textures (e.g. Bitmaps)
|
||||
// (higher values will look better if you use high-res textures)
|
||||
// (default: 1.0)
|
||||
//
|
||||
// "textureScalingFactor": 4.0,
|
||||
|
||||
|
||||
// Scaling factor for screen framebuffer
|
||||
// (higher values will look better if you use high-res textures)
|
||||
// (default: 1.0)
|
||||
//
|
||||
// "framebufferScalingFactor": 4.0,
|
||||
|
||||
|
||||
// Scaling factor for tileset atlas
|
||||
// (higher values will look better if you use high-res textures)
|
||||
// (default: 1.0)
|
||||
//
|
||||
// "atlasScalingFactor": 4.0,
|
||||
|
||||
|
||||
// Sync screen redraws to the monitor refresh rate
|
||||
// (default: disabled)
|
||||
//
|
||||
// "vsync": false,
|
||||
|
||||
|
||||
// Specify the window width on startup. If set to 0,
|
||||
// it will default to the default resolution width
|
||||
// specific to the RGSS version (640 in RGSS1, 544
|
||||
// in RGSS2 or higher).
|
||||
// (default: 0)
|
||||
//
|
||||
// "defScreenW": 640,
|
||||
|
||||
|
||||
// Specify the window height on startup. If set to 0,
|
||||
// it will default to the default resolution height
|
||||
// specific to the RGSS version (480 in RGSS1, 416
|
||||
// in RGSS2 or higher).
|
||||
// (default: 0)
|
||||
//
|
||||
// "defScreenH": 480,
|
||||
|
||||
|
||||
// Override the game window title
|
||||
// (default: none)
|
||||
//
|
||||
// "windowTitle": "Custom Title",
|
||||
|
||||
|
||||
// Enforce a static frame rate
|
||||
// (0 = disabled)
|
||||
//
|
||||
// "fixedFramerate": 0,
|
||||
|
||||
|
||||
// Skip (don't draw) frames when behind.
|
||||
// Can be changed at runtime, but this is the
|
||||
// default value when the game starts.
|
||||
// (default: disabled)
|
||||
//
|
||||
// "frameSkip": false,
|
||||
|
||||
|
||||
// Use a fixed framerate that is approx. equal to the
|
||||
// native screen refresh rate. This is different from
|
||||
// "fixedFramerate" because the actual frame rate is
|
||||
// reported back to the game, ensuring correct timers.
|
||||
// If the screen refresh rate cannot be determined,
|
||||
// this option is force-disabled.
|
||||
// This option may be force-disabled at build time.
|
||||
// (default: disabled)
|
||||
//
|
||||
// "syncToRefreshrate": false,
|
||||
|
||||
|
||||
// A list of fonts to render without alpha blending.
|
||||
// (default: none)
|
||||
//
|
||||
// "solidFonts": [
|
||||
// "Arial",
|
||||
// "Times New Roman",
|
||||
// ],
|
||||
|
||||
|
||||
// Prefer the use of Metal over OpenGL on macOS.
|
||||
// This defaults to false under Intel machines,
|
||||
// and true under ARM/Apple Silicon ones (which
|
||||
// merely emulate OpenGL anyway)
|
||||
//
|
||||
// Try changing this if you have graphics problems.
|
||||
// Metal is far better, but ANGLE may not initialize correctly
|
||||
// on some Intel machines.
|
||||
//
|
||||
// On Apple Silicon it's probably better to not touch it.
|
||||
// Emulated OpenGL is buggy, and it will also break things like
|
||||
// the Steam overlay.
|
||||
// (default: true if Apple Silicon, false if Intel)
|
||||
//
|
||||
// "preferMetalRenderer": true,
|
||||
|
||||
|
||||
// Work around buggy graphics drivers which don't
|
||||
// properly synchronize texture access, most
|
||||
// apparent when text doesn't show up or the map
|
||||
// tileset doesn't render at all
|
||||
// (default: disabled)
|
||||
//
|
||||
// "subImageFix": false,
|
||||
|
||||
|
||||
// Enable framebuffer blitting if the driver is
|
||||
// capable of it. Some drivers carry buggy
|
||||
// implementations of this functionality, so
|
||||
// disabling it can be used as a workaround.
|
||||
// Does nothing on macOS. Force-disabled when
|
||||
// smoothScaling or smoothScalingDown isn't
|
||||
// Nearest-Neighbor or Bilinear.
|
||||
// (default: disabled)
|
||||
//
|
||||
// "enableBlitting": false,
|
||||
|
||||
|
||||
// Limit the maximum size (width, height) of
|
||||
// most textures mkxp will create (exceptions are
|
||||
// rendering backbuffers and similar).
|
||||
// If set to 0, the hardware maximum is used.
|
||||
// This is useful for recording traces that can
|
||||
// be played back on machines with lower specs.
|
||||
// (default: 0)
|
||||
//
|
||||
// "maxTextureSize": 0,
|
||||
|
||||
// Scale up the game screen by an integer amount,
|
||||
// as large as the current window size allows, before
|
||||
// doing any last additional scalings to fill part or
|
||||
// all of the remaining window space (or none at all
|
||||
// if lastMileScaling is disabled).
|
||||
// If fixedAspectRatio is disabled, the integer scale
|
||||
// factors in horizontal and vertical direction can differ
|
||||
// depending on how much space is available, otherwise
|
||||
// they are forced to the smaller of the two.
|
||||
// (default: disabled)
|
||||
//
|
||||
// "integerScalingActive": false,
|
||||
|
||||
|
||||
// When integer scaling is enabled, this option controls
|
||||
// whether the scaled game screen is further scaled
|
||||
// (with linear interpolation when smoothScaling is enabled)
|
||||
// to fill the rest of the game window.
|
||||
// Note that this option still respects fixedAspectRatio.
|
||||
// (default: enabled)
|
||||
//
|
||||
// "integerScalingLastMile": true,
|
||||
|
||||
|
||||
// Set the base path of the game to '/path/to/game'
|
||||
// (default: executable directory)
|
||||
//
|
||||
|
||||
|
||||
// Use either right or left Alt + Enter to toggle
|
||||
// fullscreen
|
||||
// (default: disabled)
|
||||
//
|
||||
// "anyAltToggleFS": false,
|
||||
|
||||
|
||||
// Enable F12 game reset
|
||||
// (default: enabled)
|
||||
//
|
||||
// "enableReset": true,
|
||||
|
||||
// Enable F1/keybinding menu
|
||||
// (default: enabled)
|
||||
//
|
||||
// "enableSettings": true,
|
||||
|
||||
|
||||
// Allow symlinks for game assets to be followed
|
||||
// (default: disabled)
|
||||
//
|
||||
// "allowSymlinks": false,
|
||||
|
||||
|
||||
// Organisation / company and application / game
|
||||
// name to build the directory path where mkxp
|
||||
// will store game specific data (eg. key bindings).
|
||||
// If not specified, mkxp-z will use a folder based
|
||||
// on the name of the game, if possible, defaulting
|
||||
// to "." for Org and "mkxp-z" for App otherwise.
|
||||
// (default: none)
|
||||
//
|
||||
// "dataPathOrg": "mycompany",
|
||||
// "dataPathApp": "mygame",
|
||||
|
||||
|
||||
// Set the game window icon to 'path/to/icon.png'
|
||||
// Only functions on Linux.
|
||||
// (default: none)
|
||||
//
|
||||
// "iconPath": "/path/to/icon.png",
|
||||
|
||||
|
||||
// Instead of playing an RPG Maker game,
|
||||
// execute a single plain text script instead
|
||||
// (default: none)
|
||||
//
|
||||
// "customScript": "/path/to/script.rb",
|
||||
|
||||
|
||||
// Define raw scripts (e.g. compatibility wrappers)
|
||||
// to be executed before the actual Scripts.rxdata
|
||||
// execution starts
|
||||
// (default: none)
|
||||
//
|
||||
// "preloadScript": [
|
||||
// "scripts/preload/ruby_classic_wrap.rb",
|
||||
// "scripts/preload/mkxp_wrap.rb",
|
||||
// "scripts/preload/win32_wrap.rb",
|
||||
// ],
|
||||
"preloadScript": [
|
||||
"Kawariki-patches/preload.rb",
|
||||
],
|
||||
|
||||
|
||||
// Index all accesible assets via their lower case path
|
||||
// (emulates windows case insensitivity)
|
||||
// (default: enabled)
|
||||
//
|
||||
// "pathCache": true,
|
||||
|
||||
// Add 'rtp1', 'rtp2.zip' and 'game.rgssad' to the asset search path
|
||||
// (multiple allowed). You can use folders, RGSS archives, and any archive
|
||||
// formats supported by PhysicsFS; see the compatibility list at:
|
||||
// https://www.icculus.org/physfs/docs/html/
|
||||
// (default: none)
|
||||
//
|
||||
"RTP": [
|
||||
"RGSS3/RPGVXAce",
|
||||
"RGSS2/RPGVX",
|
||||
"RGSS/Standard"],
|
||||
|
||||
// Similar to the RTP option, except items are loaded before
|
||||
// the game archive and folder, for incremental game updates
|
||||
// or modding.
|
||||
// (default: none)
|
||||
//
|
||||
// "patches": [
|
||||
// "/path/to/patch1.zip",
|
||||
// "/path/to/patch2",
|
||||
// ],
|
||||
|
||||
|
||||
// Use the script's name as filename in warnings and error messages
|
||||
// (default: enabled)
|
||||
//
|
||||
// "useScriptNames": true,
|
||||
|
||||
|
||||
// Font substitutions allow drop-in replacements of fonts
|
||||
// to be used without changing the RGSS scripts,
|
||||
// eg. providing 'Open Sans' when the game thinkgs it's
|
||||
// using 'Arial'. Font family to be substituted and
|
||||
// replacement family are separated by one sole '>'.
|
||||
// Be careful not to include any spaces.
|
||||
// This is not connected to the built-in font, which is
|
||||
// always used when a non-existing font family is
|
||||
// requested by RGSS.
|
||||
// (default: none)
|
||||
//
|
||||
// "fontSub": [
|
||||
// "Arial>Open Sans",
|
||||
// "Times New Roman>Liberation Serif",
|
||||
// ],
|
||||
|
||||
|
||||
// Because mkxp is usually distributed as a stand alone
|
||||
// build, no predefined load paths are initialized
|
||||
// ($:, $LOAD_PATH) in the MRI backend. With this option,
|
||||
// they can be specified manually (eg. when using a system
|
||||
// libruby.so). It is however recommended to statically
|
||||
// link all required gems into libruby.so.
|
||||
// (default: none)
|
||||
//
|
||||
// "rubyLoadpath": [
|
||||
// "/usr/lib64/ruby/",
|
||||
// "/usr/local/share/ruby/site_ruby",
|
||||
// ],
|
||||
|
||||
// Determines whether MJIT is enabled. This probably
|
||||
// won't work unless you also have the header file
|
||||
// that it needs. Only works with Ruby 2.6 or higher.
|
||||
// This Ruby feature is experimental.
|
||||
// (default: false)
|
||||
//
|
||||
// "JITEnable": false,
|
||||
|
||||
// Determines what level of verbosity to use when
|
||||
// logging MJIT events. Starts at 0, which is next
|
||||
// to nothing. Set it higher to see more.
|
||||
// (default: 0)
|
||||
//
|
||||
// "JITVerboseLevel": 0,
|
||||
|
||||
// Determines how many compiled methods that Ruby
|
||||
// will keep in its MJIT cache.
|
||||
// (default: 100)
|
||||
//
|
||||
// "JITMaxCache": 100,
|
||||
|
||||
// Determines how many times a function has to be
|
||||
// called before it is compiled by MJIT.
|
||||
// (default: 10000)
|
||||
//
|
||||
// "JITMinCalls": 10000,
|
||||
|
||||
// Determines whether YJIT is enabled.
|
||||
// Only works with Ruby 3.1 or higher.
|
||||
// This Ruby feature is experimental.
|
||||
// (default: false)
|
||||
//
|
||||
// "YJITEnable": false,
|
||||
|
||||
// SoundFont to use for midi playback (via fluidsynth)
|
||||
// (default: none)
|
||||
//
|
||||
// "midiSoundFont": "Audio/BGM/GMGSx.sf2",
|
||||
|
||||
|
||||
// Activate "chorus" effect for midi playback
|
||||
//
|
||||
// "midiChorus": false,
|
||||
|
||||
|
||||
// Activate "reverb" effect for midi playback
|
||||
//
|
||||
// "midiReverb": false,
|
||||
|
||||
|
||||
// Number of OpenAL sources to allocate for SE playback.
|
||||
// If there are a lot of sounds playing at the same time
|
||||
// and audibly cutting each other off, try increasing
|
||||
// this number. Maximum: 64.
|
||||
//
|
||||
// "SESourceCount": 6,
|
||||
|
||||
// Number of streams to open for BGM tracks. If the game
|
||||
// needs multitrack audio, this should be set to as many
|
||||
// available tracks as the game needs. Maximum: 16.
|
||||
//
|
||||
// "BGMTrackCount": 1,
|
||||
|
||||
|
||||
// The Windows game executable name minus ".exe". By default
|
||||
// this is "Game", but some developers manually rename it.
|
||||
// mkxp needs this name because both the .ini (game
|
||||
// configuration) and .rgssad (encrypted data archive) must
|
||||
// carry the same name minus their extension, and we cannot
|
||||
// guess the executable's name.
|
||||
// You could just as well rename them both to "Game.ini" and
|
||||
// "Game.rgssad", but specifying the executable name here
|
||||
// is a tiny bit less intrusive.
|
||||
//
|
||||
// "execName": "Game",
|
||||
|
||||
// You can define alternate terminology for the different
|
||||
// inputs recognized by RPG Maker. A, B, C, X, Y, Z, L, and R
|
||||
// can all be set using this dictionary, and will be displayed
|
||||
// on the F1 menu. This is only a cosmetic effect, so it will
|
||||
// have no effect on the game's scripts.
|
||||
//
|
||||
// "bindingNames": {
|
||||
// "c": "Confirm",
|
||||
// "b": "Cancel",
|
||||
// "x": ...,
|
||||
// },
|
||||
|
||||
|
||||
// Dump tile atlas (for debugging purposes)
|
||||
// (default: false)
|
||||
//
|
||||
// "dumpAtlas": false,
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue