Compare commits
134 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb9c72d1db | ||
|
|
7a455dcad5 | ||
|
|
cacbecb324 | ||
|
|
c521dcaf57 | ||
|
|
b89c06008b | ||
|
|
c20e40652d | ||
|
|
2fe74627bd | ||
|
|
9864a2551d | ||
|
|
dea8c98399 | ||
|
|
108a20ef27 | ||
|
|
0adc65054c | ||
|
|
d72a74f6c3 | ||
|
|
1d05bac7a1 | ||
|
|
980b40dcdd | ||
|
|
b1a8707fb2 | ||
|
|
382de999cc | ||
|
|
06618d9e21 | ||
|
|
1b6e29acc0 | ||
|
|
e5992779f3 | ||
|
|
d7bc8e4176 | ||
|
|
629978d7a6 | ||
|
|
039ad65557 | ||
|
|
26e5104a96 | ||
|
|
d39276fe3a | ||
|
|
2a17a07784 | ||
|
|
56d35bef0d | ||
|
|
676098dc5f | ||
|
|
857d3902bb | ||
|
|
7803378d82 | ||
|
|
893a116fb4 | ||
|
|
916bf40602 | ||
|
|
40d6348b09 | ||
|
|
1e5047cd48 | ||
|
|
7750006127 | ||
|
|
1b69c97ce4 | ||
|
|
b3431fadf7 | ||
|
|
2a0d0633f1 | ||
|
|
4ed86be78e | ||
|
|
db13317613 | ||
|
|
8deb855b12 | ||
|
|
24277424d2 | ||
|
|
c593eceaaf | ||
|
|
e3a811c83d | ||
|
|
89fd83012a | ||
|
|
e71447a3d3 | ||
|
|
b89d6dfd72 | ||
|
|
3878be0d09 | ||
|
|
21d550ad1e | ||
|
|
134ab451e3 | ||
|
|
25fc67fec1 | ||
|
|
a41780caa2 | ||
|
|
4eb5e39946 | ||
|
|
354b0812c9 | ||
|
|
bee34bfdf4 | ||
|
|
d31e367870 | ||
|
|
16f0be1a45 | ||
|
|
ebba548206 | ||
|
|
c9fa9a4765 | ||
|
|
cfca07f7f2 | ||
|
|
0f60556b73 | ||
|
|
a1521049b5 | ||
|
|
1128813bf0 | ||
|
|
1f6339b3b3 | ||
|
|
79f5e00f6e | ||
|
|
957c5af66b | ||
|
|
c5c5ecd499 | ||
|
|
df4382f2e0 | ||
|
|
8700d0c601 | ||
|
|
27c5beea01 | ||
|
|
52af5cfc1f | ||
|
|
5a47f74023 | ||
|
|
c35ea77c59 | ||
|
|
b10c580d6f | ||
|
|
7096116296 | ||
|
|
330edde003 | ||
|
|
cac96bfc13 | ||
|
|
31edb19379 | ||
|
|
d482f0e610 | ||
|
|
c3bffa6777 | ||
|
|
140234f40e | ||
|
|
13b76287f8 | ||
|
|
a55feb9301 | ||
|
|
d86a887cf9 | ||
|
|
5b2a1d13a1 | ||
|
|
1ca08cb97a | ||
|
|
ca78b94a7d | ||
|
|
dcb53393c1 | ||
|
|
4ece7d1188 | ||
|
|
87289a34c0 | ||
|
|
2859410d4b | ||
|
|
9d53496521 | ||
|
|
4a8d5b13a8 | ||
|
|
8ba4fa309d | ||
|
|
0cab26227a | ||
|
|
1694c68ebc | ||
|
|
6c74c461c2 | ||
|
|
0ec5306de5 | ||
|
|
ba2ae3c303 | ||
|
|
019dbbb56e | ||
|
|
a47918a83c | ||
|
|
25e07fb597 | ||
|
|
43ad927817 | ||
|
|
d7966cdab2 | ||
|
|
33bda1612c | ||
|
|
f3eef3fe6c | ||
|
|
d8ae5fbd32 | ||
|
|
02e83a1989 | ||
|
|
5c8f7c4b00 | ||
|
|
3592a7232c | ||
|
|
ef067cd954 | ||
|
|
17382d7c7e | ||
|
|
5170948588 | ||
|
|
3ccb087d20 | ||
|
|
3f9145b745 | ||
|
|
5b79d8ca79 | ||
|
|
25c1eeee5c | ||
|
|
f5060c301b | ||
|
|
8a2ca4b733 | ||
|
|
9610de0a66 | ||
|
|
64627ddde9 | ||
|
|
63bcb2d009 | ||
|
|
df5bceaf2a | ||
|
|
66d46bd8a5 | ||
|
|
28a433ea76 | ||
|
|
2c69834a12 | ||
|
|
00ee53efca | ||
|
|
4989cf6d5a | ||
|
|
0d5aa705f0 | ||
|
|
307b032118 | ||
|
|
ab8279078e | ||
|
|
b7ac80e684 | ||
|
|
6064a4bc79 | ||
|
|
e41a4b8e16 | ||
|
|
39057fd1fb |
11
.gitattributes
vendored
@@ -2,14 +2,23 @@
|
||||
*.c text eol=lf
|
||||
*.cc text eol=lf
|
||||
*.cmake text eol=lf
|
||||
*.gradle text eol=lf
|
||||
*.h text eol=lf
|
||||
*.md text eol=lf
|
||||
*.java text eol=lf
|
||||
*.json text eol=lf
|
||||
*.md text eol=lf
|
||||
*.plist text eol=lf
|
||||
*.pro text eol=lf
|
||||
*.properties text eol=lf
|
||||
*.xml text eol=lf
|
||||
*.yml text eol=lf
|
||||
.clang-format text eol=lf
|
||||
.editorconfig text eol=lf
|
||||
.gitattributes text eol=lf
|
||||
.gitignore text eol=lf
|
||||
gradlew text eol=lf
|
||||
CMakeLists.txt text eol=lf
|
||||
LICENSE text eol=lf
|
||||
|
||||
# Force CRLF
|
||||
*.bat text eol=crlf
|
||||
|
||||
61
.github/workflows/ci-build.yml
vendored
@@ -2,19 +2,12 @@ name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/ci-build.yml'
|
||||
- 'src/**.cc'
|
||||
- 'src/**.h'
|
||||
- '**/CMakeLists.txt'
|
||||
- '**/*.cmake'
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/ci-build.yml'
|
||||
- 'src/**.cc'
|
||||
- 'src/**.h'
|
||||
- '**/CMakeLists.txt'
|
||||
- '**/*.cmake'
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -38,6 +31,50 @@ jobs:
|
||||
- name: cppcheck
|
||||
run: cppcheck --std=c++17 src/
|
||||
|
||||
android:
|
||||
name: Android
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 11
|
||||
cache: gradle
|
||||
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: os/android/app/.cxx
|
||||
key: android-cmake-v1
|
||||
|
||||
- name: Setup signing config
|
||||
if: env.KEYSTORE_FILE_BASE64 != '' && env.KEYSTORE_PROPERTIES_FILE_BASE64 != ''
|
||||
run: |
|
||||
cd os/android
|
||||
echo "$KEYSTORE_FILE_BASE64" | base64 --decode > debug.keystore
|
||||
echo "$KEYSTORE_PROPERTIES_FILE_BASE64" | base64 --decode > debug-keystore.properties
|
||||
env:
|
||||
KEYSTORE_FILE_BASE64: ${{ secrets.ANDROID_DEBUG_KEYSTORE_FILE_BASE64 }}
|
||||
KEYSTORE_PROPERTIES_FILE_BASE64: ${{ secrets.ANDROID_DEBUG_KEYSTORE_PROPERTIES_FILE_BASE64 }}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd os/android
|
||||
./gradlew assembleDebug
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: fallout2-ce-debug.apk
|
||||
path: os/android/app/build/outputs/apk/debug/app-debug.apk
|
||||
retention-days: 7
|
||||
|
||||
linux:
|
||||
name: Linux (${{ matrix.arch }})
|
||||
|
||||
|
||||
46
.github/workflows/release.yml
vendored
@@ -10,6 +10,52 @@ defaults:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
android:
|
||||
name: Android
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 11
|
||||
cache: gradle
|
||||
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: os/android/app/.cxx
|
||||
key: android-cmake-v1
|
||||
|
||||
- name: Setup signing config
|
||||
if: env.KEYSTORE_FILE_BASE64 != '' && env.KEYSTORE_PROPERTIES_FILE_BASE64 != ''
|
||||
run: |
|
||||
cd os/android
|
||||
echo "$KEYSTORE_FILE_BASE64" | base64 --decode > release.keystore
|
||||
echo "$KEYSTORE_PROPERTIES_FILE_BASE64" | base64 --decode > release-keystore.properties
|
||||
env:
|
||||
KEYSTORE_FILE_BASE64: ${{ secrets.ANDROID_RELEASE_KEYSTORE_FILE_BASE64 }}
|
||||
KEYSTORE_PROPERTIES_FILE_BASE64: ${{ secrets.ANDROID_RELEASE_KEYSTORE_PROPERTIES_FILE_BASE64 }}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd os/android
|
||||
./gradlew assembleRelease
|
||||
|
||||
- name: Upload
|
||||
run: |
|
||||
cd os/android/app/build/outputs/apk/release
|
||||
cp app-release.apk fallout2-ce-android.apk
|
||||
gh release upload ${{ github.ref_name }} fallout2-ce-android.apk
|
||||
rm fallout2-ce-android.apk
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
linux:
|
||||
name: Linux (${{ matrix.arch }})
|
||||
|
||||
|
||||
@@ -170,6 +170,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/palette.h"
|
||||
"src/party_member.cc"
|
||||
"src/party_member.h"
|
||||
"src/pcx.cc"
|
||||
"src/pcx.h"
|
||||
"src/perk_defs.h"
|
||||
"src/perk.cc"
|
||||
"src/perk.h"
|
||||
@@ -237,8 +239,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/window.h"
|
||||
"src/word_wrap.cc"
|
||||
"src/word_wrap.h"
|
||||
"src/world_map.cc"
|
||||
"src/world_map.h"
|
||||
"src/worldmap.cc"
|
||||
"src/worldmap.h"
|
||||
"src/xfile.cc"
|
||||
"src/xfile.h"
|
||||
)
|
||||
@@ -274,11 +276,24 @@ if(WIN32)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"os/windows/fallout2-ce.ico"
|
||||
"os/windows/fallout2-ce.rc"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
target_sources(${EXECUTABLE_NAME} PUBLIC "os/macos/fallout2-ce.icns")
|
||||
set_source_files_properties("os/macos/fallout2-ce.icns" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||
|
||||
set_target_properties(${EXECUTABLE_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/os/macos/Info.plist")
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.alexbatalov.fallout2-ce")
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME "${EXECUTABLE_NAME}")
|
||||
set(MACOSX_BUNDLE_ICON_FILE "fallout2-ce.icns")
|
||||
set(MACOSX_BUNDLE_DISPLAY_NAME "Fallout 2")
|
||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "1.1.0")
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "1.1.0")
|
||||
endif()
|
||||
|
||||
add_subdirectory("third_party/fpattern")
|
||||
|
||||
51
LICENSE.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Sustainable Use License
|
||||
|
||||
Version 1.0
|
||||
|
||||
## Acceptance
|
||||
|
||||
By using the software, you agree to all of the terms and conditions below.
|
||||
|
||||
## Copyright License
|
||||
|
||||
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations below.
|
||||
|
||||
## Limitations
|
||||
|
||||
You may use or modify the software only for your own internal business purposes or for non-commercial or personal use. You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes. You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law.
|
||||
|
||||
## Patents
|
||||
|
||||
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
||||
|
||||
## Notices
|
||||
|
||||
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. If you modify the software, you must include in any modified copies of the software a prominent notice stating that you have modified the software.
|
||||
|
||||
## No Other Rights
|
||||
|
||||
These terms do not imply any licenses other than those expressly granted in these terms.
|
||||
|
||||
## Termination
|
||||
|
||||
If you use the software in violation of these terms, such use is not licensed, and your license will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your license will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your license to terminate automatically and permanently.
|
||||
|
||||
## No Liability
|
||||
|
||||
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
|
||||
|
||||
## Definitions
|
||||
|
||||
The "licensor" is the entity offering these terms.
|
||||
|
||||
The "software" is the software the licensor makes available under these terms, including any portion of it.
|
||||
|
||||
"You" refers to the individual or entity agreeing to these terms.
|
||||
|
||||
"Your company" is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
||||
|
||||
"Your license" is the license granted to you for the software under these terms.
|
||||
|
||||
"Use" means anything you do with the software requiring your license.
|
||||
|
||||
"Trademark" means trademarks, service marks, and similar rights.
|
||||
14
README.md
@@ -34,6 +34,16 @@ $ sudo apt install libsdl2-2.0-0
|
||||
|
||||
- Run `fallout2-ce.app`.
|
||||
|
||||
### Android
|
||||
|
||||
> **NOTE**: Fallout 2 was designed with mouse in mind. There are many controls that require precise cursor positioning, which is not possible with fingers. When playing on Android you'll use fingers to move mouse cursor, not a character, or a map. Double tap to "click" left mouse button in the current cursor position, triple tap to "click" right mouse button. It might feel awkward at first, but it's super handy - you can play with just a thumb. This is not set in stone and might change in the future.
|
||||
|
||||
- Use Windows installation as a base - it contains data assets needed to play. Copy `Fallout2` folder to your device, for example to `Downloads`. You need `master.dat`, `critter.dat`, `patch000.dat`, and `data` folder.
|
||||
|
||||
- Download `fallout2-ce.apk` and copy it to your device. Open it with file explorer, follow instructions (install from unknown source).
|
||||
|
||||
- When you run the game for the first time it will immediately present file picker. Select the folder from the first step. Wait until this data is copied. A loading dialog will appear, just wait for about 30 seconds. The game will start automatically.
|
||||
|
||||
## Contributing
|
||||
|
||||
Integrating Sfall goodies is the top priority. Quality of life updates are OK too. Please no large scale refactorings at this time as we need to reconcile changes from Reference Edition, which will make this process slow and error-prone. In any case open up an issue with your suggestion or to notify other people that something is being worked on.
|
||||
@@ -42,6 +52,6 @@ Integrating Sfall goodies is the top priority. Quality of life updates are OK to
|
||||
|
||||
There are literally hundreds if not thousands of fixes and features in sfall. I guess not all of them are needed in Community Edition, but for the sake of compatibility with big mods out there, let's integrate them all.
|
||||
|
||||
## Legal & License
|
||||
## License
|
||||
|
||||
See [Fallout 2 Reference Edition](https://github.com/alexbatalov/fallout2-re). Same conditions apply until the source code in this repository is changed significantly.
|
||||
The source code is this repository is available under the [Sustainable Use License](LICENSE.md).
|
||||
|
||||
4
os/android/.gitignore
vendored
@@ -7,3 +7,7 @@
|
||||
/.idea/navEditor.xml
|
||||
/.idea/workspace.xml
|
||||
/local.properties
|
||||
/debug-keystore.properties
|
||||
/debug.keystore
|
||||
/release-keystore.properties
|
||||
/release.keystore
|
||||
|
||||
3
os/android/app/.gitignore
vendored
@@ -1,2 +1,5 @@
|
||||
/.cxx
|
||||
/build
|
||||
|
||||
# TODO: Cleanup root .gitignore
|
||||
!/src/debug
|
||||
|
||||
@@ -9,8 +9,8 @@ android {
|
||||
applicationId 'com.alexbatalov.fallout2ce'
|
||||
minSdk 21
|
||||
targetSdk 32
|
||||
versionCode 1
|
||||
versionName '1.0'
|
||||
versionCode 2
|
||||
versionName '1.1.0'
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments '-DANDROID_STL=c++_static'
|
||||
@@ -26,10 +26,49 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
// Override default debug signing config to make sure every CI runner
|
||||
// uses the same key for painless updates.
|
||||
def debugKeystorePropertiesFile = rootProject.file('debug-keystore.properties')
|
||||
if (debugKeystorePropertiesFile.exists()) {
|
||||
def debugKeystoreProperties = new Properties()
|
||||
debugKeystoreProperties.load(new FileInputStream(debugKeystorePropertiesFile))
|
||||
|
||||
debug {
|
||||
storeFile rootProject.file(debugKeystoreProperties.getProperty('storeFile'))
|
||||
storePassword debugKeystoreProperties.getProperty('storePassword')
|
||||
keyAlias debugKeystoreProperties.getProperty('keyAlias')
|
||||
keyPassword debugKeystoreProperties.getProperty('keyPassword')
|
||||
}
|
||||
}
|
||||
|
||||
def releaseKeystoreProperties = new Properties()
|
||||
def releaseKeystorePropertiesFile = rootProject.file('release-keystore.properties')
|
||||
if (releaseKeystorePropertiesFile.exists()) {
|
||||
releaseKeystoreProperties.load(new FileInputStream(releaseKeystorePropertiesFile))
|
||||
|
||||
release {
|
||||
storeFile rootProject.file(releaseKeystoreProperties.getProperty('storeFile'))
|
||||
storePassword releaseKeystoreProperties.getProperty('storePassword')
|
||||
keyAlias releaseKeystoreProperties.getProperty('keyAlias')
|
||||
keyPassword releaseKeystoreProperties.getProperty('keyPassword')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
// Prevents signing keys clashes between debug and release versions
|
||||
// for painless development.
|
||||
applicationIdSuffix '.debug'
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
|
||||
// Release signing config is optional and might not be present in CI
|
||||
// builds, hence `findByName`.
|
||||
signingConfig signingConfigs.findByName('release')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,4 +96,5 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||
}
|
||||
|
||||
3
os/android/app/src/debug/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Fallout 2 (Debug)</string>
|
||||
</resources>
|
||||
@@ -58,6 +58,7 @@
|
||||
An example Java class can be found in README-android.md
|
||||
-->
|
||||
<application android:label="@string/app_name"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:allowBackup="true"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
android:hardwareAccelerated="true" >
|
||||
@@ -92,6 +93,10 @@
|
||||
</intent-filter>
|
||||
-->
|
||||
</activity>
|
||||
|
||||
<activity android:name=".ImportActivity"
|
||||
android:theme="@style/AppTheme">
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.alexbatalov.fallout2ce;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
static boolean copyRecursively(ContentResolver contentResolver, DocumentFile src, File dest) {
|
||||
final DocumentFile[] documentFiles = src.listFiles();
|
||||
for (final DocumentFile documentFile : documentFiles) {
|
||||
if (documentFile.isFile()) {
|
||||
if (!copyFile(contentResolver, documentFile, new File(dest, documentFile.getName()))) {
|
||||
return false;
|
||||
}
|
||||
} else if (documentFile.isDirectory()) {
|
||||
final File subdirectory = new File(dest, documentFile.getName());
|
||||
if (!subdirectory.exists()) {
|
||||
subdirectory.mkdir();
|
||||
}
|
||||
|
||||
if (!copyRecursively(contentResolver, documentFile, subdirectory)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean copyFile(ContentResolver contentResolver, DocumentFile src, File dest) {
|
||||
try {
|
||||
final InputStream inputStream = contentResolver.openInputStream(src.getUri());
|
||||
final OutputStream outputStream = new FileOutputStream(dest);
|
||||
|
||||
final byte[] buffer = new byte[16384];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
inputStream.close();
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.alexbatalov.fallout2ce;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class ImportActivity extends Activity {
|
||||
private static final int IMPORT_REQUEST_CODE = 1;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
startActivityForResult(intent, IMPORT_REQUEST_CODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent resultData) {
|
||||
if (requestCode == IMPORT_REQUEST_CODE) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
final Uri treeUri = resultData.getData();
|
||||
if (treeUri != null) {
|
||||
final DocumentFile treeDocument = DocumentFile.fromTreeUri(this, treeUri);
|
||||
if (treeDocument != null) {
|
||||
copyFiles(treeDocument);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finish();
|
||||
} else {
|
||||
super.onActivityResult(requestCode, resultCode, resultData);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyFiles(DocumentFile treeDocument) {
|
||||
ProgressDialog dialog = createProgressDialog();
|
||||
dialog.show();
|
||||
|
||||
new Thread(() -> {
|
||||
ContentResolver contentResolver = getContentResolver();
|
||||
File externalFilesDir = getExternalFilesDir(null);
|
||||
FileUtils.copyRecursively(contentResolver, treeDocument, externalFilesDir);
|
||||
|
||||
startMainActivity();
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void startMainActivity() {
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private ProgressDialog createProgressDialog() {
|
||||
ProgressDialog progressDialog = new ProgressDialog(this,
|
||||
android.R.style.Theme_Material_Light_Dialog);
|
||||
progressDialog.setTitle(R.string.loading_dialog_title);
|
||||
progressDialog.setMessage(getString(R.string.loading_dialog_message));
|
||||
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
progressDialog.setCancelable(false);
|
||||
|
||||
return progressDialog;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,47 @@
|
||||
package com.alexbatalov.fallout2ce;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.libsdl.app.SDLActivity;
|
||||
|
||||
public class MainActivity extends SDLActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
// Needed to initialize `files` folder (and make it publicly accessible
|
||||
// for file managers) for user to upload assets.
|
||||
getExternalFilesDir(null);
|
||||
import java.io.File;
|
||||
|
||||
public class MainActivity extends SDLActivity {
|
||||
private boolean noExit = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final File externalFilesDir = getExternalFilesDir(null);
|
||||
|
||||
final File configFile = new File(externalFilesDir, "fallout2.cfg");
|
||||
if (!configFile.exists()) {
|
||||
final File masterDatFile = new File(externalFilesDir, "master.dat");
|
||||
final File critterDatFile = new File(externalFilesDir, "critter.dat");
|
||||
if (!masterDatFile.exists() || !critterDatFile.exists()) {
|
||||
final Intent intent = new Intent(this, ImportActivity.class);
|
||||
startActivity(intent);
|
||||
|
||||
noExit = true;
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
if (!noExit) {
|
||||
// Needed to make sure libc calls exit handlers, which releases
|
||||
// in-game resources.
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getLibraries() {
|
||||
return new String[]{
|
||||
"fallout2-ce",
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
BIN
os/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 26 KiB |
BIN
os/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
os/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 12 KiB |
BIN
os/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
os/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 43 KiB |
BIN
os/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
os/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 90 KiB |
BIN
os/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
os/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 148 KiB |
BIN
os/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#000000</color>
|
||||
</resources>
|
||||
@@ -1,3 +1,5 @@
|
||||
<resources>
|
||||
<string name="app_name">Fallout 2 Community Edition</string>
|
||||
<string name="app_name">Fallout 2</string>
|
||||
<string name="loading_dialog_title">PLEASE STAND BY</string>
|
||||
<string name="loading_dialog_message">Copying files…</string>
|
||||
</resources>
|
||||
|
||||
BIN
os/macos/fallout2-ce.icns
Normal file
BIN
os/windows/fallout2-ce.ico
Normal file
|
After Width: | Height: | Size: 97 KiB |
1
os/windows/fallout2-ce.rc
Normal file
@@ -0,0 +1 @@
|
||||
IDI_ICON1 ICON DISCARDABLE "fallout2-ce.ico"
|
||||
666
src/actions.cc
@@ -16,7 +16,7 @@ bool _can_see(Object* a1, Object* a2);
|
||||
bool _action_explode_running();
|
||||
int actionExplode(int tile, int elevation, int minDamage, int maxDamage, Object* a5, bool a6);
|
||||
int actionTalk(Object* a1, Object* a2);
|
||||
void _action_dmg(int tile, int elevation, int minDamage, int maxDamage, int damageType, bool animated, bool bypassArmor);
|
||||
void actionDamage(int tile, int elevation, int minDamage, int maxDamage, int damageType, bool animated, bool bypassArmor);
|
||||
bool actionCheckPush(Object* a1, Object* a2);
|
||||
int actionPush(Object* a1, Object* a2);
|
||||
int _action_can_talk_to(Object* a1, Object* a2);
|
||||
|
||||
1446
src/animation.cc
@@ -3,36 +3,14 @@
|
||||
|
||||
#include "combat_defs.h"
|
||||
#include "obj_types.h"
|
||||
#include "sound.h"
|
||||
|
||||
typedef enum AnimKind {
|
||||
ANIM_KIND_OBJ_MOVE_TO_OBJ = 0,
|
||||
ANIM_KIND_OBJ_MOVE_TO_TILE = 1,
|
||||
ANIM_KIND_2 = 2,
|
||||
ANIM_KIND_KNOCKDOWN = 3,
|
||||
ANIM_KIND_ANIMATE = 4,
|
||||
ANIM_KIND_ANIMATE_REVERSE = 5,
|
||||
ANIM_KIND_6 = 6,
|
||||
ANIM_KIND_SET_ROTATION_TO_TILE = 7,
|
||||
ANIM_KIND_ROTATE_CLOCKWISE = 8,
|
||||
ANIM_KIND_ROTATE_COUNTER_CLOCKWISE = 9,
|
||||
ANIM_KIND_HIDE = 10,
|
||||
ANIM_KIND_EXEC = 11,
|
||||
ANIM_KIND_EXEC_2 = 12,
|
||||
ANIM_KIND_14 = 14,
|
||||
ANIM_KIND_15 = 15,
|
||||
ANIM_KIND_16 = 16,
|
||||
ANIM_KIND_17 = 17,
|
||||
ANIM_KIND_18 = 18,
|
||||
ANIM_KIND_19 = 19,
|
||||
ANIM_KIND_20 = 20,
|
||||
ANIM_KIND_23 = 23,
|
||||
ANIM_KIND_24 = 24,
|
||||
ANIM_KIND_ANIMATE_FOREVER = 25,
|
||||
ANIM_KIND_26 = 26,
|
||||
ANIM_KIND_27 = 27,
|
||||
ANIM_KIND_28 = 28,
|
||||
} AnimKind;
|
||||
typedef enum AnimationRequestOptions {
|
||||
ANIMATION_REQUEST_UNRESERVED = 0x01,
|
||||
ANIMATION_REQUEST_RESERVED = 0x02,
|
||||
ANIMATION_REQUEST_NO_STAND = 0x04,
|
||||
ANIMATION_REQUEST_0x100 = 0x100,
|
||||
ANIMATION_REQUEST_INSIGNIFICANT = 0x200,
|
||||
} AnimationRequestOptions;
|
||||
|
||||
// Basic animations: 0-19
|
||||
// Knockdown and death: 20-35
|
||||
@@ -112,9 +90,13 @@ typedef enum AnimationType {
|
||||
LAST_SF_DEATH_ANIM = ANIM_FALL_FRONT_BLOOD_SF,
|
||||
} AnimationType;
|
||||
|
||||
typedef int AnimationProc(Object*, Object*);
|
||||
typedef int AnimationSoundProc(Sound*);
|
||||
typedef int AnimationProc2(Object*, Object*, void*);
|
||||
#define FID_ANIM_TYPE(value) ((value) & 0xFF0000) >> 16
|
||||
|
||||
// Signature of animation callback accepting 2 parameters.
|
||||
typedef int(AnimationCallback)(void* a1, void* a2);
|
||||
|
||||
// Signature of animation callback accepting 3 parameters.
|
||||
typedef int(AnimationCallback3)(void* a1, void* a2, void* a3);
|
||||
|
||||
typedef struct STRUCT_530014_28 {
|
||||
int tile;
|
||||
@@ -133,28 +115,31 @@ int _register_priority(int a1);
|
||||
int reg_anim_clear(Object* a1);
|
||||
int reg_anim_end();
|
||||
int animationIsBusy(Object* a1);
|
||||
int reg_anim_obj_move_to_obj(Object* a1, Object* a2, int actionPoints, int delay);
|
||||
int reg_anim_obj_run_to_obj(Object* owner, Object* destination, int actionPoints, int delay);
|
||||
int reg_anim_obj_move_to_tile(Object* obj, int tile_num, int elev, int actionPoints, int delay);
|
||||
int reg_anim_obj_run_to_tile(Object* obj, int tile_num, int elev, int actionPoints, int delay);
|
||||
int reg_anim_2(Object* obj, int tile_num, int elev, int a4, int a5);
|
||||
int reg_anim_knockdown(Object* obj, int tile, int elev, int anim, int delay);
|
||||
int reg_anim_animate(Object* obj, int anim, int delay);
|
||||
int reg_anim_animate_reverse(Object* obj, int anim, int delay);
|
||||
int reg_anim_6(Object* obj, int anim, int delay);
|
||||
int reg_anim_set_rotation_to_tile(Object* owner, int tile);
|
||||
int reg_anim_rotate_clockwise(Object* obj);
|
||||
int reg_anim_rotate_counter_clockwise(Object* obj);
|
||||
int reg_anim_hide(Object* obj);
|
||||
int reg_anim_11_0(Object* a1, Object* a2, AnimationProc* proc, int delay);
|
||||
int reg_anim_12(Object* a1, Object* a2, void* a3, AnimationProc2* proc, int delay);
|
||||
int reg_anim_11_1(Object* a1, Object* a2, AnimationProc* proc, int delay);
|
||||
int reg_anim_15(Object* obj, int a2, int a3);
|
||||
int reg_anim_17(Object* obj, int fid, int a3);
|
||||
int reg_anim_18(Object* obj, int a2, int a3);
|
||||
int reg_anim_update_light(Object* obj, int fid, int a3);
|
||||
int reg_anim_play_sfx(Object* obj, const char* a2, int a3);
|
||||
int reg_anim_animate_forever(Object* obj, int a2, int a3);
|
||||
int animationRegisterMoveToObject(Object* owner, Object* destination, int actionPoints, int delay);
|
||||
int animationRegisterRunToObject(Object* owner, Object* destination, int actionPoints, int delay);
|
||||
int animationRegisterMoveToTile(Object* owner, int tile, int elevation, int actionPoints, int delay);
|
||||
int animationRegisterRunToTile(Object* owner, int tile, int elevation, int actionPoints, int delay);
|
||||
int animationRegisterMoveToTileStraight(Object* object, int tile, int elevation, int anim, int delay);
|
||||
int animationRegisterMoveToTileStraightAndWaitForComplete(Object* owner, int tile, int elev, int anim, int delay);
|
||||
int animationRegisterAnimate(Object* owner, int anim, int delay);
|
||||
int animationRegisterAnimateReversed(Object* owner, int anim, int delay);
|
||||
int animationRegisterAnimateAndHide(Object* owner, int anim, int delay);
|
||||
int animationRegisterRotateToTile(Object* owner, int tile);
|
||||
int animationRegisterRotateClockwise(Object* owner);
|
||||
int animationRegisterRotateCounterClockwise(Object* owner);
|
||||
int animationRegisterHideObject(Object* object);
|
||||
int animationRegisterHideObjectForced(Object* object);
|
||||
int animationRegisterCallback(void* a1, void* a2, AnimationCallback* proc, int delay);
|
||||
int animationRegisterCallback3(void* a1, void* a2, void* a3, AnimationCallback3* proc, int delay);
|
||||
int animationRegisterCallbackForced(void* a1, void* a2, AnimationCallback* proc, int delay);
|
||||
int animationRegisterSetFlag(Object* object, int flag, int delay);
|
||||
int animationRegisterUnsetFlag(Object* object, int flag, int delay);
|
||||
int animationRegisterSetFid(Object* owner, int fid, int delay);
|
||||
int animationRegisterTakeOutWeapon(Object* owner, int weaponAnimationCode, int delay);
|
||||
int animationRegisterSetLightDistance(Object* owner, int lightDistance, int delay);
|
||||
int animationRegisterToggleOutline(Object* object, bool outline, int delay);
|
||||
int animationRegisterPlaySoundEffect(Object* owner, const char* soundEffectName, int delay);
|
||||
int animationRegisterAnimateForever(Object* owner, int anim, int delay);
|
||||
int reg_anim_26(int a1, int a2);
|
||||
int _make_path(Object* object, int from, int to, unsigned char* a4, int a5);
|
||||
int pathfinderFindPath(Object* object, int from, int to, unsigned char* rotations, int a5, PathBuilderCallback* callback);
|
||||
@@ -169,4 +154,6 @@ void _dude_stand(Object* obj, int rotation, int fid);
|
||||
void _dude_standup(Object* a1);
|
||||
void animationStop();
|
||||
|
||||
int animationRegisterSetLightIntensity(Object* owner, int lightDistance, int lightIntensity, int delay);
|
||||
|
||||
#endif /* ANIMATION_H */
|
||||
|
||||
514
src/art.cc
@@ -1,18 +1,19 @@
|
||||
#include "art.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "animation.h"
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "game_config.h"
|
||||
#include "memory.h"
|
||||
#include "object.h"
|
||||
#include "proto.h"
|
||||
#include "sfall_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct ArtListDescription {
|
||||
int flags;
|
||||
char name[16];
|
||||
@@ -126,10 +127,8 @@ static int* gArtCritterFidShoudRunData;
|
||||
int artInit()
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
int i;
|
||||
File* stream;
|
||||
char str[200];
|
||||
char *ptr, *curr;
|
||||
char string[200];
|
||||
|
||||
int cacheSize;
|
||||
if (!configGetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_ART_CACHE_SIZE_KEY, &cacheSize)) {
|
||||
@@ -147,20 +146,36 @@ int artInit()
|
||||
gArtLanguageInitialized = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < 11; i++) {
|
||||
gArtListDescriptions[i].flags = 0;
|
||||
sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[i].name, gArtListDescriptions[i].name);
|
||||
bool critterDbSelected = false;
|
||||
for (int objectType = 0; objectType < OBJ_TYPE_COUNT; objectType++) {
|
||||
gArtListDescriptions[objectType].flags = 0;
|
||||
sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[objectType].name, gArtListDescriptions[objectType].name);
|
||||
|
||||
if (artReadList(path, &(gArtListDescriptions[i].fileNames), &(gArtListDescriptions[i].fileNamesLength)) != 0) {
|
||||
int oldDb;
|
||||
if (objectType == OBJ_TYPE_CRITTER) {
|
||||
oldDb = _db_current();
|
||||
critterDbSelected = true;
|
||||
_db_select(_critter_db_handle);
|
||||
}
|
||||
|
||||
if (artReadList(path, &(gArtListDescriptions[objectType].fileNames), &(gArtListDescriptions[objectType].fileNamesLength)) != 0) {
|
||||
debugPrint("art_read_lst failed in art_init\n");
|
||||
if (critterDbSelected) {
|
||||
_db_select(oldDb);
|
||||
}
|
||||
cacheFree(&gArtCache);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (objectType == OBJ_TYPE_CRITTER) {
|
||||
critterDbSelected = false;
|
||||
_db_select(oldDb);
|
||||
}
|
||||
}
|
||||
|
||||
_anon_alias = (int*)internal_malloc(sizeof(*_anon_alias) * gArtListDescriptions[1].fileNamesLength);
|
||||
_anon_alias = (int*)internal_malloc(sizeof(*_anon_alias) * gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength);
|
||||
if (_anon_alias == NULL) {
|
||||
gArtListDescriptions[1].fileNamesLength = 0;
|
||||
gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength = 0;
|
||||
debugPrint("Out of memory for anon_alias in art_init\n");
|
||||
cacheFree(&gArtCache);
|
||||
return -1;
|
||||
@@ -168,17 +183,17 @@ int artInit()
|
||||
|
||||
gArtCritterFidShoudRunData = (int*)internal_malloc(sizeof(*gArtCritterFidShoudRunData) * gArtListDescriptions[1].fileNamesLength);
|
||||
if (gArtCritterFidShoudRunData == NULL) {
|
||||
gArtListDescriptions[1].fileNamesLength = 0;
|
||||
gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength = 0;
|
||||
debugPrint("Out of memory for artCritterFidShouldRunData in art_init\n");
|
||||
cacheFree(&gArtCache);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < gArtListDescriptions[1].fileNamesLength; i++) {
|
||||
gArtCritterFidShoudRunData[i] = 0;
|
||||
for (int critterIndex = 0; critterIndex < gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength; critterIndex++) {
|
||||
gArtCritterFidShoudRunData[critterIndex] = 0;
|
||||
}
|
||||
|
||||
sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[1].name, gArtListDescriptions[1].name);
|
||||
sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[OBJ_TYPE_CRITTER].name, gArtListDescriptions[OBJ_TYPE_CRITTER].name);
|
||||
|
||||
stream = fileOpen(path, "rt");
|
||||
if (stream == NULL) {
|
||||
@@ -206,75 +221,70 @@ int artInit()
|
||||
tribalMaleFileName = gDefaultTribalMaleFileName;
|
||||
}
|
||||
|
||||
char *tribalFemaleFileName = NULL;
|
||||
char* tribalFemaleFileName = NULL;
|
||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_FEMALE_KEY, &tribalFemaleFileName);
|
||||
if (tribalFemaleFileName == NULL || tribalFemaleFileName[0] == '\0') {
|
||||
tribalFemaleFileName = gDefaultTribalFemaleFileName;
|
||||
}
|
||||
|
||||
ptr = gArtListDescriptions[1].fileNames;
|
||||
for (i = 0; i < gArtListDescriptions[1].fileNamesLength; i++) {
|
||||
if (compat_stricmp(ptr, jumpsuitMaleFileName) == 0) {
|
||||
_art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_MALE] = i;
|
||||
} else if (compat_stricmp(ptr, jumpsuitFemaleFileName) == 0) {
|
||||
_art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_FEMALE] = i;
|
||||
char* critterFileNames = gArtListDescriptions[OBJ_TYPE_CRITTER].fileNames;
|
||||
for (int critterIndex = 0; critterIndex < gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength; critterIndex++) {
|
||||
if (compat_stricmp(critterFileNames, "hmjmps") == 0) {
|
||||
_art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_MALE] = critterIndex;
|
||||
} else if (compat_stricmp(critterFileNames, "hfjmps") == 0) {
|
||||
_art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_FEMALE] = critterIndex;
|
||||
}
|
||||
|
||||
if (compat_stricmp(ptr, tribalMaleFileName) == 0) {
|
||||
_art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_MALE] = i;
|
||||
_art_vault_guy_num = i;
|
||||
} else if (compat_stricmp(ptr, tribalFemaleFileName) == 0) {
|
||||
_art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_FEMALE] = i;
|
||||
if (compat_stricmp(critterFileNames, "hmwarr") == 0) {
|
||||
_art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_MALE] = critterIndex;
|
||||
_art_vault_guy_num = critterIndex;
|
||||
} else if (compat_stricmp(critterFileNames, "hfprim") == 0) {
|
||||
_art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_FEMALE] = critterIndex;
|
||||
}
|
||||
|
||||
ptr += 13;
|
||||
critterFileNames += 13;
|
||||
}
|
||||
|
||||
for (i = 0; i < gArtListDescriptions[1].fileNamesLength; i++) {
|
||||
if (!fileReadString(str, sizeof(str), stream)) {
|
||||
for (int critterIndex = 0; critterIndex < gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength; critterIndex++) {
|
||||
if (!fileReadString(string, sizeof(string), stream)) {
|
||||
break;
|
||||
}
|
||||
|
||||
ptr = str;
|
||||
curr = ptr;
|
||||
while (*curr != '\0' && *curr != ',') {
|
||||
curr++;
|
||||
}
|
||||
char* sep1 = strchr(string, ',');
|
||||
if (sep1 != NULL) {
|
||||
_anon_alias[critterIndex] = atoi(sep1 + 1);
|
||||
|
||||
if (*curr != '\0') {
|
||||
_anon_alias[i] = atoi(curr + 1);
|
||||
|
||||
ptr = curr + 1;
|
||||
curr = ptr;
|
||||
while (*curr != '\0' && *curr != ',') {
|
||||
curr++;
|
||||
char* sep2 = strchr(sep1 + 1, ',');
|
||||
if (sep2 != NULL) {
|
||||
gArtCritterFidShoudRunData[critterIndex] = atoi(sep2 + 1);
|
||||
} else {
|
||||
gArtCritterFidShoudRunData[critterIndex] = 0;
|
||||
}
|
||||
|
||||
gArtCritterFidShoudRunData[i] = *curr != '\0' ? atoi(ptr) : 0;
|
||||
} else {
|
||||
_anon_alias[i] = _art_vault_guy_num;
|
||||
gArtCritterFidShoudRunData[i] = 1;
|
||||
_anon_alias[critterIndex] = _art_vault_guy_num;
|
||||
gArtCritterFidShoudRunData[critterIndex] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
fileClose(stream);
|
||||
|
||||
ptr = gArtListDescriptions[4].fileNames;
|
||||
for (i = 0; i < gArtListDescriptions[4].fileNamesLength; i++) {
|
||||
if (compat_stricmp(ptr, "grid001.frm") == 0) {
|
||||
_art_mapper_blank_tile = i;
|
||||
char* tileFileNames = gArtListDescriptions[OBJ_TYPE_TILE].fileNames;
|
||||
for (int tileIndex = 0; tileIndex < gArtListDescriptions[OBJ_TYPE_TILE].fileNamesLength; tileIndex++) {
|
||||
if (compat_stricmp(tileFileNames, "grid001.frm") == 0) {
|
||||
_art_mapper_blank_tile = tileIndex;
|
||||
}
|
||||
tileFileNames += 13;
|
||||
}
|
||||
|
||||
gHeadDescriptions = (HeadDescription*)internal_malloc(sizeof(HeadDescription) * gArtListDescriptions[8].fileNamesLength);
|
||||
gHeadDescriptions = (HeadDescription*)internal_malloc(sizeof(*gHeadDescriptions) * gArtListDescriptions[OBJ_TYPE_HEAD].fileNamesLength);
|
||||
if (gHeadDescriptions == NULL) {
|
||||
gArtListDescriptions[8].fileNamesLength = 0;
|
||||
gArtListDescriptions[OBJ_TYPE_HEAD].fileNamesLength = 0;
|
||||
debugPrint("Out of memory for head_info in art_init\n");
|
||||
cacheFree(&gArtCache);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[8].name, gArtListDescriptions[8].name);
|
||||
sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[OBJ_TYPE_HEAD].name, gArtListDescriptions[OBJ_TYPE_HEAD].name);
|
||||
|
||||
stream = fileOpen(path, "rt");
|
||||
if (stream == NULL) {
|
||||
@@ -283,46 +293,42 @@ int artInit()
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < gArtListDescriptions[8].fileNamesLength; i++) {
|
||||
if (!fileReadString(str, sizeof(str), stream)) {
|
||||
for (int headIndex = 0; headIndex < gArtListDescriptions[OBJ_TYPE_HEAD].fileNamesLength; headIndex++) {
|
||||
if (!fileReadString(string, sizeof(string), stream)) {
|
||||
break;
|
||||
}
|
||||
|
||||
ptr = str;
|
||||
curr = ptr;
|
||||
while (*curr != '\0' && *curr != ',') {
|
||||
curr++;
|
||||
char* sep1 = strchr(string, ',');
|
||||
if (sep1 != NULL) {
|
||||
*sep1 = '\0';
|
||||
} else {
|
||||
sep1 = string;
|
||||
}
|
||||
|
||||
if (*curr != '\0') {
|
||||
ptr = curr + 1;
|
||||
curr = ptr;
|
||||
while (*curr != '\0' && *curr != ',') {
|
||||
curr++;
|
||||
}
|
||||
|
||||
if (*curr != '\0') {
|
||||
gHeadDescriptions[i].goodFidgetCount = atoi(ptr);
|
||||
|
||||
ptr = curr + 1;
|
||||
curr = ptr;
|
||||
while (*curr != '\0' && *curr != ',') {
|
||||
curr++;
|
||||
}
|
||||
|
||||
if (*curr != '\0') {
|
||||
gHeadDescriptions[i].neutralFidgetCount = atoi(ptr);
|
||||
|
||||
ptr = curr + 1;
|
||||
curr = strpbrk(ptr, " ,;\t\n");
|
||||
if (curr != NULL) {
|
||||
*curr = '\0';
|
||||
}
|
||||
|
||||
gHeadDescriptions[i].badFidgetCount = atoi(ptr);
|
||||
}
|
||||
}
|
||||
char* sep2 = strchr(sep1, ',');
|
||||
if (sep2 != NULL) {
|
||||
*sep2 = '\0';
|
||||
} else {
|
||||
sep2 = sep1;
|
||||
}
|
||||
|
||||
gHeadDescriptions[headIndex].goodFidgetCount = atoi(sep1 + 1);
|
||||
|
||||
char* sep3 = strchr(sep2, ',');
|
||||
if (sep3 != NULL) {
|
||||
*sep3 = '\0';
|
||||
} else {
|
||||
sep3 = sep2;
|
||||
}
|
||||
|
||||
gHeadDescriptions[headIndex].neutralFidgetCount = atoi(sep2 + 1);
|
||||
|
||||
char* sep4 = strpbrk(sep3 + 1, " ,;\t\n");
|
||||
if (sep4 != NULL) {
|
||||
*sep4 = '\0';
|
||||
}
|
||||
|
||||
gHeadDescriptions[headIndex].badFidgetCount = atoi(sep3 + 1);
|
||||
}
|
||||
|
||||
fileClose(stream);
|
||||
@@ -357,19 +363,19 @@ void artExit()
|
||||
// 0x418F1C
|
||||
char* artGetObjectTypeName(int objectType)
|
||||
{
|
||||
return objectType >= 0 && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].name : NULL;
|
||||
return objectType >= OBJ_TYPE_ITEM && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].name : NULL;
|
||||
}
|
||||
|
||||
// 0x418F34
|
||||
int artIsObjectTypeHidden(int objectType)
|
||||
{
|
||||
return objectType >= 0 && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].flags & 1 : 0;
|
||||
return objectType >= OBJ_TYPE_ITEM && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].flags & 1 : 0;
|
||||
}
|
||||
|
||||
// 0x418F7C
|
||||
int artGetFidgetCount(int headFid)
|
||||
{
|
||||
if ((headFid & 0xF000000) >> 24 != OBJ_TYPE_HEAD) {
|
||||
if (FID_TYPE(headFid) != OBJ_TYPE_HEAD) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -522,15 +528,15 @@ int artCacheFlush()
|
||||
}
|
||||
|
||||
// 0x4192B0
|
||||
int artCopyFileName(int type, int id, char* dest)
|
||||
int artCopyFileName(int objectType, int id, char* dest)
|
||||
{
|
||||
ArtListDescription* ptr;
|
||||
|
||||
if (type < 0 && type >= 11) {
|
||||
if (objectType < OBJ_TYPE_ITEM && objectType >= OBJ_TYPE_COUNT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr = &(gArtListDescriptions[type]);
|
||||
ptr = &(gArtListDescriptions[objectType]);
|
||||
|
||||
if (id >= ptr->fileNamesLength) {
|
||||
return -1;
|
||||
@@ -622,7 +628,7 @@ char* artBuildFilePath(int fid)
|
||||
|
||||
v10 = (fid & 0x70000000) >> 28;
|
||||
|
||||
v1 = _art_alias_fid(fid);
|
||||
v1 = artAliasFid(fid);
|
||||
if (v1 != -1) {
|
||||
v2 = v1;
|
||||
}
|
||||
@@ -630,15 +636,15 @@ char* artBuildFilePath(int fid)
|
||||
*_art_name = '\0';
|
||||
|
||||
v3 = v2 & 0xFFF;
|
||||
v4 = (v2 & 0xFF0000) >> 16;
|
||||
v4 = FID_ANIM_TYPE(v2);
|
||||
v5 = (v2 & 0xF000) >> 12;
|
||||
type = (v2 & 0xF000000) >> 24;
|
||||
type = FID_TYPE(v2);
|
||||
|
||||
if (v3 >= gArtListDescriptions[type].fileNamesLength) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (type < 0 || type >= 11) {
|
||||
if (type < OBJ_TYPE_ITEM || type >= OBJ_TYPE_COUNT) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -669,55 +675,45 @@ char* artBuildFilePath(int fid)
|
||||
|
||||
// art_read_lst
|
||||
// 0x419664
|
||||
static int artReadList(const char* path, char** out_arr, int* out_count)
|
||||
static int artReadList(const char* path, char** artListPtr, int* artListSizePtr)
|
||||
{
|
||||
File* stream;
|
||||
char str[200];
|
||||
char* arr;
|
||||
int count;
|
||||
char* brk;
|
||||
|
||||
stream = fileOpen(path, "rt");
|
||||
File* stream = fileOpen(path, "rt");
|
||||
if (stream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
while (fileReadString(str, sizeof(str), stream)) {
|
||||
int count = 0;
|
||||
char string[200];
|
||||
while (fileReadString(string, sizeof(string), stream)) {
|
||||
count++;
|
||||
}
|
||||
|
||||
fileSeek(stream, 0, SEEK_SET);
|
||||
|
||||
*out_count = count;
|
||||
*artListSizePtr = count;
|
||||
|
||||
arr = (char*)internal_malloc(13 * count);
|
||||
*out_arr = arr;
|
||||
if (arr == NULL) {
|
||||
goto err;
|
||||
char* artList = (char*)internal_malloc(13 * count);
|
||||
*artListPtr = artList;
|
||||
if (artList == NULL) {
|
||||
fileClose(stream);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fileReadString(str, sizeof(str), stream)) {
|
||||
brk = strpbrk(str, " ,;\r\t\n");
|
||||
while (fileReadString(string, sizeof(string), stream)) {
|
||||
char* brk = strpbrk(string, " ,;\r\t\n");
|
||||
if (brk != NULL) {
|
||||
*brk = '\0';
|
||||
}
|
||||
|
||||
strncpy(arr, str, 12);
|
||||
arr[12] = '\0';
|
||||
strncpy(artList, string, 12);
|
||||
artList[12] = '\0';
|
||||
|
||||
arr += 13;
|
||||
artList += 13;
|
||||
}
|
||||
|
||||
fileClose(stream);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
||||
fileClose(stream);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x419760
|
||||
@@ -864,54 +860,55 @@ ArtFrame* artGetFrame(Art* art, int frame, int rotation)
|
||||
// 0x4198C8
|
||||
bool artExists(int fid)
|
||||
{
|
||||
int v3;
|
||||
bool result;
|
||||
bool result = false;
|
||||
int oldDb = -1;
|
||||
|
||||
v3 = -1;
|
||||
result = false;
|
||||
|
||||
if ((fid & 0xF000000) >> 24 == 1) {
|
||||
v3 = _db_current(1);
|
||||
// _db_current(_critter_db_handle);
|
||||
_db_current(0);
|
||||
if (FID_TYPE(fid) == OBJ_TYPE_CRITTER) {
|
||||
oldDb = _db_current();
|
||||
_db_select(_critter_db_handle);
|
||||
}
|
||||
|
||||
char* filePath = artBuildFilePath(fid);
|
||||
if (filePath == NULL) {
|
||||
goto out;
|
||||
if (filePath != NULL) {
|
||||
int fileSize;
|
||||
if (dbGetFileSize(filePath, &fileSize) != -1) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
int fileSize;
|
||||
if (dbGetFileSize(filePath, &fileSize) == -1) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = true;
|
||||
|
||||
out:
|
||||
|
||||
if (v3 != -1) {
|
||||
_db_current(v3);
|
||||
if (oldDb != -1) {
|
||||
_db_select(oldDb);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: Exactly the same implementation as `artExists`.
|
||||
//
|
||||
// 0x419930
|
||||
bool _art_fid_valid(int fid)
|
||||
{
|
||||
// NOTE: Original Code involves calling some unknown function. Check in debugger in mapper.
|
||||
bool result = false;
|
||||
int oldDb = -1;
|
||||
|
||||
if (FID_TYPE(fid) == OBJ_TYPE_CRITTER) {
|
||||
oldDb = _db_current();
|
||||
_db_select(_critter_db_handle);
|
||||
}
|
||||
|
||||
char* filePath = artBuildFilePath(fid);
|
||||
if (filePath == NULL) {
|
||||
return false;
|
||||
if (filePath != NULL) {
|
||||
int fileSize;
|
||||
if (dbGetFileSize(filePath, &fileSize) != -1) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
int fileSize;
|
||||
if (dbGetFileSize(filePath, &fileSize) == -1) {
|
||||
return false;
|
||||
if (oldDb != -1) {
|
||||
_db_select(oldDb);
|
||||
}
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 0x419998
|
||||
@@ -923,7 +920,7 @@ int _art_alias_num(int index)
|
||||
// 0x4199AC
|
||||
int artCritterFidShouldRun(int fid)
|
||||
{
|
||||
if ((fid & 0xF000000) >> 24 == 1) {
|
||||
if (FID_TYPE(fid) == OBJ_TYPE_CRITTER) {
|
||||
return gArtCritterFidShoudRunData[fid & 0xFFF];
|
||||
}
|
||||
|
||||
@@ -931,64 +928,61 @@ int artCritterFidShouldRun(int fid)
|
||||
}
|
||||
|
||||
// 0x4199D4
|
||||
int _art_alias_fid(int fid)
|
||||
int artAliasFid(int fid)
|
||||
{
|
||||
int v2;
|
||||
int v3;
|
||||
int result;
|
||||
int type = FID_TYPE(fid);
|
||||
int anim = FID_ANIM_TYPE(fid);
|
||||
if (type == OBJ_TYPE_CRITTER) {
|
||||
if (anim == ANIM_ELECTRIFY
|
||||
|| anim == ANIM_BURNED_TO_NOTHING
|
||||
|| anim == ANIM_ELECTRIFIED_TO_NOTHING
|
||||
|| anim == ANIM_ELECTRIFY_SF
|
||||
|| anim == ANIM_BURNED_TO_NOTHING_SF
|
||||
|| anim == ANIM_ELECTRIFIED_TO_NOTHING_SF
|
||||
|| anim == ANIM_FIRE_DANCE
|
||||
|| anim == ANIM_CALLED_SHOT_PIC) {
|
||||
// NOTE: Original code is slightly different. It uses many mutually
|
||||
// mirrored bitwise operators. Probably result of some macros for
|
||||
// getting/setting individual bits on fid.
|
||||
return (fid & 0x70000000) | ((anim << 16) & 0xFF0000) | 0x1000000 | (fid & 0xF000) | (_anon_alias[fid & 0xFFF] & 0xFFF);
|
||||
}
|
||||
}
|
||||
|
||||
v2 = (fid & 0xF000000) >> 24;
|
||||
v3 = (fid & 0xFF0000) >> 16;
|
||||
|
||||
if (v2 != 1 || v3 != 27 && v3 != 29 && v3 != 30 && v3 != 55 && v3 != 57 && v3 != 58 && v3 != 33 && v3 != 64)
|
||||
result = -1;
|
||||
else
|
||||
result = ((fid & 0x70000000) >> 28 << 28) & 0x70000000 | (v3 << 16) & 0xFF0000 | 0x1000000 | (((fid & 0xF000) >> 12) << 12) & 0xF000 | _anon_alias[fid & 0xFFF] & 0xFFF;
|
||||
|
||||
return result;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x419A78
|
||||
static int artCacheGetFileSizeImpl(int fid, int* sizePtr)
|
||||
{
|
||||
int v4;
|
||||
char* str;
|
||||
char* ptr;
|
||||
int result;
|
||||
char path[COMPAT_MAX_PATH];
|
||||
bool loaded;
|
||||
int fileSize;
|
||||
int oldDb = -1;
|
||||
int result = -1;
|
||||
|
||||
v4 = -1;
|
||||
result = -1;
|
||||
|
||||
if ((fid & 0xF000000) >> 24 == 1) {
|
||||
v4 = _db_current(1);
|
||||
// _db_current(_critter_db_handle);
|
||||
_db_current(0);
|
||||
if (FID_TYPE(fid) == OBJ_TYPE_CRITTER) {
|
||||
oldDb = _db_current();
|
||||
_db_select(_critter_db_handle);
|
||||
}
|
||||
|
||||
str = artBuildFilePath(fid);
|
||||
if (str != NULL) {
|
||||
loaded = false;
|
||||
char* artFilePath = artBuildFilePath(fid);
|
||||
if (artFilePath != NULL) {
|
||||
int fileSize;
|
||||
bool loaded = false;
|
||||
|
||||
if (gArtLanguageInitialized) {
|
||||
ptr = str;
|
||||
while (*ptr != '\0' && *ptr != '\\') {
|
||||
ptr++;
|
||||
char* pch = strchr(artFilePath, '\\');
|
||||
if (pch == NULL) {
|
||||
pch = artFilePath;
|
||||
}
|
||||
|
||||
if (*ptr == '\0') {
|
||||
ptr = str;
|
||||
}
|
||||
char localizedPath[COMPAT_MAX_PATH];
|
||||
sprintf(localizedPath, "art\\%s\\%s", gArtLanguage, pch);
|
||||
|
||||
sprintf(path, "art\\%s\\%s", gArtLanguage, ptr);
|
||||
if (dbGetFileSize(path, &fileSize) == 0) {
|
||||
if (dbGetFileSize(localizedPath, &fileSize) == 0) {
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!loaded) {
|
||||
if (dbGetFileSize(str, &fileSize) == 0) {
|
||||
if (dbGetFileSize(artFilePath, &fileSize) == 0) {
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
@@ -999,8 +993,8 @@ static int artCacheGetFileSizeImpl(int fid, int* sizePtr)
|
||||
}
|
||||
}
|
||||
|
||||
if (v4 != -1) {
|
||||
_db_current(v4);
|
||||
if (oldDb != -1) {
|
||||
_db_select(oldDb);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1009,43 +1003,33 @@ static int artCacheGetFileSizeImpl(int fid, int* sizePtr)
|
||||
// 0x419B78
|
||||
static int artCacheReadDataImpl(int fid, int* sizePtr, unsigned char* data)
|
||||
{
|
||||
int v4;
|
||||
char* str;
|
||||
char* ptr;
|
||||
int result;
|
||||
char path[COMPAT_MAX_PATH];
|
||||
bool loaded;
|
||||
int oldDb = -1;
|
||||
int result = -1;
|
||||
|
||||
v4 = -1;
|
||||
result = -1;
|
||||
|
||||
if ((fid & 0xF000000) >> 24 == 1) {
|
||||
v4 = _db_current(1);
|
||||
// _db_current(_critter_db_handle);
|
||||
_db_current(0);
|
||||
if (FID_TYPE(fid) == OBJ_TYPE_CRITTER) {
|
||||
oldDb = _db_current();
|
||||
_db_select(_critter_db_handle);
|
||||
}
|
||||
|
||||
str = artBuildFilePath(fid);
|
||||
if (str != NULL) {
|
||||
loaded = false;
|
||||
char* artFileName = artBuildFilePath(fid);
|
||||
if (artFileName != NULL) {
|
||||
bool loaded = false;
|
||||
if (gArtLanguageInitialized) {
|
||||
ptr = str;
|
||||
while (*ptr != '\0' && *ptr != '\\') {
|
||||
ptr++;
|
||||
char* pch = strchr(artFileName, '\\');
|
||||
if (pch == NULL) {
|
||||
pch = artFileName;
|
||||
}
|
||||
|
||||
if (*ptr == '\0') {
|
||||
ptr = str;
|
||||
}
|
||||
char localizedPath[COMPAT_MAX_PATH];
|
||||
sprintf(localizedPath, "art\\%s\\%s", gArtLanguage, pch);
|
||||
|
||||
sprintf(path, "art\\%s\\%s", gArtLanguage, ptr);
|
||||
if (artRead(str, data) == 0) {
|
||||
if (artRead(localizedPath, data) == 0) {
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!loaded) {
|
||||
if (artRead(str, data) == 0) {
|
||||
if (artRead(artFileName, data) == 0) {
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
@@ -1057,8 +1041,8 @@ static int artCacheReadDataImpl(int fid, int* sizePtr, unsigned char* data)
|
||||
}
|
||||
}
|
||||
|
||||
if (v4 != -1) {
|
||||
_db_current(v4);
|
||||
if (oldDb != -1) {
|
||||
_db_select(oldDb);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1071,7 +1055,7 @@ static void artCacheFreeImpl(void* ptr)
|
||||
}
|
||||
|
||||
// 0x419C88
|
||||
int buildFid(int objectType, int a2, int anim, int a3, int rotation)
|
||||
int buildFid(int objectType, int frmId, int animType, int a3, int rotation)
|
||||
{
|
||||
int v7, v8, v9, v10;
|
||||
|
||||
@@ -1081,13 +1065,13 @@ int buildFid(int objectType, int a2, int anim, int a3, int rotation)
|
||||
goto zero;
|
||||
}
|
||||
|
||||
if (anim == 33 || anim < 20 || anim > 35) {
|
||||
if (animType == ANIM_FIRE_DANCE || animType < ANIM_FALL_BACK || animType > ANIM_FALL_FRONT_BLOOD) {
|
||||
goto zero;
|
||||
}
|
||||
|
||||
v7 = ((a3 << 12) & 0xF000) | (anim << 16) & 0xFF0000 | 0x1000000;
|
||||
v8 = (rotation << 28) & 0x70000000 | v7;
|
||||
v9 = a2 & 0xFFF;
|
||||
v7 = ((a3 << 12) & 0xF000) | ((animType << 16) & 0xFF0000) | 0x1000000;
|
||||
v8 = ((rotation << 28) & 0x70000000) | v7;
|
||||
v9 = frmId & 0xFFF;
|
||||
|
||||
if (artExists(v9 | v8) != 0) {
|
||||
goto out;
|
||||
@@ -1108,7 +1092,7 @@ zero:
|
||||
|
||||
out:
|
||||
|
||||
return (v10 << 28) & 0x70000000 | (objectType << 24) | (anim << 16) & 0xFF0000 | (a3 << 12) & 0xF000 | a2 & 0xFFF;
|
||||
return ((v10 << 28) & 0x70000000) | (objectType << 24) | ((animType << 16) & 0xFF0000) | ((a3 << 12) & 0xF000) | (frmId & 0xFFF);
|
||||
}
|
||||
|
||||
// 0x419D60
|
||||
@@ -1172,3 +1156,75 @@ int artRead(const char* path, unsigned char* data)
|
||||
fileClose(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x41A070
|
||||
int artWriteFrameData(unsigned char* data, File* stream, int count)
|
||||
{
|
||||
unsigned char* ptr = data;
|
||||
for (int index = 0; index < count; index++) {
|
||||
ArtFrame* frame = (ArtFrame*)ptr;
|
||||
|
||||
if (fileWriteInt16(stream, frame->width) == -1) return -1;
|
||||
if (fileWriteInt16(stream, frame->height) == -1) return -1;
|
||||
if (fileWriteInt32(stream, frame->size) == -1) return -1;
|
||||
if (fileWriteInt16(stream, frame->x) == -1) return -1;
|
||||
if (fileWriteInt16(stream, frame->y) == -1) return -1;
|
||||
if (fileWrite(ptr + sizeof(ArtFrame), frame->size, 1, stream) != 1) return -1;
|
||||
|
||||
ptr += sizeof(ArtFrame) + frame->size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x41A138
|
||||
int artWriteHeader(Art* art, File* stream)
|
||||
{
|
||||
if (fileWriteInt32(stream, art->field_0) == -1) return -1;
|
||||
if (fileWriteInt16(stream, art->framesPerSecond) == -1) return -1;
|
||||
if (fileWriteInt16(stream, art->actionFrame) == -1) return -1;
|
||||
if (fileWriteInt16(stream, art->frameCount) == -1) return -1;
|
||||
if (fileWriteInt16List(stream, art->xOffsets, ROTATION_COUNT) == -1) return -1;
|
||||
if (fileWriteInt16List(stream, art->yOffsets, ROTATION_COUNT) == -1) return -1;
|
||||
if (fileWriteInt32List(stream, art->dataOffsets, ROTATION_COUNT) == -1) return -1;
|
||||
if (fileWriteInt32(stream, art->field_3A) == -1) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x41A1E8
|
||||
int artWrite(const char* path, unsigned char* data)
|
||||
{
|
||||
if (data == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
File* stream = fileOpen(path, "wb");
|
||||
if (stream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Art* art = (Art*)data;
|
||||
if (artWriteHeader(art, stream) == -1) {
|
||||
fileClose(stream);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int index = 0; index < ROTATION_COUNT; index++) {
|
||||
if (index == 0 || art->dataOffsets[index - 1] != art->dataOffsets[index]) {
|
||||
if (artWriteFrameData(data + sizeof(Art) + art->dataOffsets[index], stream, art->frameCount) != 0) {
|
||||
fileClose(stream);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileClose(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ unsigned char* artLockFrameData(int fid, int frame, int direction, CacheEntry**
|
||||
unsigned char* artLockFrameDataReturningSize(int fid, CacheEntry** out_cache_entry, int* widthPtr, int* heightPtr);
|
||||
int artUnlock(CacheEntry* cache_entry);
|
||||
int artCacheFlush();
|
||||
int artCopyFileName(int a1, int a2, char* a3);
|
||||
int artCopyFileName(int objectType, int a2, char* a3);
|
||||
int _art_get_code(int a1, int a2, char* a3, char* a4);
|
||||
char* artBuildFilePath(int a1);
|
||||
int artGetFramesPerSecond(Art* art);
|
||||
@@ -144,8 +144,9 @@ bool artExists(int fid);
|
||||
bool _art_fid_valid(int fid);
|
||||
int _art_alias_num(int a1);
|
||||
int artCritterFidShouldRun(int a1);
|
||||
int _art_alias_fid(int a1);
|
||||
int buildFid(int a1, int a2, int a3, int a4, int a5);
|
||||
int artAliasFid(int fid);
|
||||
int buildFid(int objectType, int frmId, int animType, int a4, int rotation);
|
||||
int artRead(const char* path, unsigned char* data);
|
||||
int artWrite(const char* path, unsigned char* data);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#include "audio.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "debug.h"
|
||||
#include "memory_manager.h"
|
||||
#include "pointer_registry.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static bool _defaultCompressionFunc(char* filePath);
|
||||
static int audioSoundDecoderReadHandler(int fileHandle, void* buf, unsigned int size);
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#include "audio_file.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "memory_manager.h"
|
||||
#include "platform_compat.h"
|
||||
#include "pointer_registry.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static bool _defaultCompressionFunc__(char* filePath);
|
||||
static int audioFileSoundDecoderReadHandler(int fileHandle, void* buffer, unsigned int size);
|
||||
|
||||
@@ -103,7 +103,7 @@ int audioFileOpen(const char* fname, int flags, ...)
|
||||
audioFile->soundDecoder = soundDecoderInit(audioFileSoundDecoderReadHandler, audioFile->fileHandle, &(audioFile->field_14), &(audioFile->field_10), &(audioFile->fileSize));
|
||||
audioFile->fileSize *= 2;
|
||||
} else {
|
||||
audioFile->fileSize = compat_filelength(fileno(stream));
|
||||
audioFile->fileSize = getFileSize(stream);
|
||||
}
|
||||
|
||||
audioFile->position = 0;
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include "automap.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "config.h"
|
||||
@@ -20,11 +25,6 @@
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define AUTOMAP_OFFSET_COUNT (AUTOMAP_MAP_COUNT * ELEVATION_COUNT)
|
||||
|
||||
#define AUTOMAP_WINDOW_WIDTH (519)
|
||||
@@ -66,7 +66,7 @@ static const int _defam[AUTOMAP_MAP_COUNT][ELEVATION_COUNT] = {
|
||||
};
|
||||
|
||||
// 0x41B560
|
||||
static const int _displayMapList[AUTOMAP_MAP_COUNT] = {
|
||||
static int _displayMapList[AUTOMAP_MAP_COUNT] = {
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
@@ -302,7 +302,7 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
unsigned char* frmData[AUTOMAP_FRM_COUNT];
|
||||
CacheEntry* frmHandle[AUTOMAP_FRM_COUNT];
|
||||
for (int index = 0; index < AUTOMAP_FRM_COUNT; index++) {
|
||||
int fid = buildFid(6, frmIds[index], 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, frmIds[index], 0, 0, 0);
|
||||
frmData[index] = artLockFrameData(fid, 0, 0, &(frmHandle[index]));
|
||||
if (frmData[index] == NULL) {
|
||||
while (--index >= 0) {
|
||||
@@ -482,7 +482,7 @@ static void automapRenderInMapWindow(int window, int elevation, unsigned char* b
|
||||
continue;
|
||||
}
|
||||
|
||||
int objectType = (object->fid & 0xF000000) >> 24;
|
||||
int objectType = FID_TYPE(object->fid);
|
||||
unsigned char objectColor;
|
||||
|
||||
if ((flags & AUTOMAP_IN_GAME) != 0) {
|
||||
@@ -1048,7 +1048,7 @@ static void _decode_map_data(int elevation)
|
||||
if (object->tile != -1 && (object->flags & OBJECT_SEEN) != 0) {
|
||||
int contentType;
|
||||
|
||||
int objectType = (object->fid & 0xF000000) >> 24;
|
||||
int objectType = FID_TYPE(object->fid);
|
||||
if (objectType == OBJ_TYPE_SCENERY && object->pid != PROTO_ID_0x2000158) {
|
||||
contentType = 2;
|
||||
} else if (objectType == OBJ_TYPE_WALL) {
|
||||
@@ -1153,3 +1153,10 @@ int automapGetHeader(AutomapHeader** automapHeaderPtr)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void automapSetDisplayMap(int map, bool available)
|
||||
{
|
||||
if (map >= 0 && map < AUTOMAP_MAP_COUNT) {
|
||||
_displayMapList[map] = available ? 0 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,4 +54,6 @@ int automapRenderInPipboyWindow(int win, int map, int elevation);
|
||||
int automapSaveCurrent();
|
||||
int automapGetHeader(AutomapHeader** automapHeaderPtr);
|
||||
|
||||
void automapSetDisplayMap(int map, bool available);
|
||||
|
||||
#endif /* AUTOMAP_H */
|
||||
|
||||
10
src/cache.cc
@@ -1,14 +1,14 @@
|
||||
#include "cache.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "memory.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// The initial number of cache entries in new cache.
|
||||
#define CACHE_ENTRIES_INITIAL_CAPACITY (100)
|
||||
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
#include "character_editor.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "combat.h"
|
||||
#include "core.h"
|
||||
#include "critter.h"
|
||||
#include "cycle.h"
|
||||
@@ -32,14 +40,7 @@
|
||||
#include "trait.h"
|
||||
#include "window_manager.h"
|
||||
#include "word_wrap.h"
|
||||
#include "world_map.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vector>
|
||||
#include "worldmap.h"
|
||||
|
||||
#define RENDER_ALL_STATS 7
|
||||
|
||||
@@ -292,6 +293,9 @@ static void customKarmaFolderInit();
|
||||
static void customKarmaFolderFree();
|
||||
static int customKarmaFolderGetFrmId();
|
||||
|
||||
static void customTownReputationInit();
|
||||
static void customTownReputationFree();
|
||||
|
||||
// 0x431C40
|
||||
static int gCharacterEditorFrmIds[EDITOR_GRAPHIC_COUNT] = {
|
||||
170,
|
||||
@@ -792,6 +796,7 @@ struct CustomKarmaFolderDescription {
|
||||
};
|
||||
|
||||
static std::vector<CustomKarmaFolderDescription> gCustomKarmaFolderDescriptions;
|
||||
static std::vector<TownReputationEntry> gCustomTownReputationEntries;
|
||||
|
||||
// 0x431DF8
|
||||
int characterEditorShow(bool isCreationMode)
|
||||
@@ -826,6 +831,8 @@ int characterEditorShow(bool isCreationMode)
|
||||
_frame_time = _get_time();
|
||||
int keyCode = _get_input();
|
||||
|
||||
convertMouseWheelToArrowKey(&keyCode);
|
||||
|
||||
bool done = false;
|
||||
if (keyCode == 500) {
|
||||
done = true;
|
||||
@@ -1275,7 +1282,7 @@ static int characterEditorWindowInit()
|
||||
return -1;
|
||||
}
|
||||
|
||||
fid = buildFid(6, (gCharacterEditorIsCreationMode ? 169 : 177), 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, (gCharacterEditorIsCreationMode ? 169 : 177), 0, 0, 0);
|
||||
gCharacterEditorWindowBackgroundBuffer = artLockFrameDataReturningSize(fid, &gCharacterEditorWindowBackgroundHandle, &(gCharacterEditorFrmSize[0].width), &(gCharacterEditorFrmSize[0].height));
|
||||
if (gCharacterEditorWindowBackgroundBuffer == NULL) {
|
||||
messageListFree(&gCharacterEditorMessageList);
|
||||
@@ -1293,10 +1300,13 @@ static int characterEditorWindowInit()
|
||||
// SFALL: Custom karma folder.
|
||||
customKarmaFolderInit();
|
||||
|
||||
// SFALL: Custom town reputation.
|
||||
customTownReputationInit();
|
||||
|
||||
soundContinueAll();
|
||||
|
||||
for (i = 0; i < EDITOR_GRAPHIC_COUNT; i++) {
|
||||
fid = buildFid(6, gCharacterEditorFrmIds[i], 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, gCharacterEditorFrmIds[i], 0, 0, 0);
|
||||
gCharacterEditorFrmData[i] = artLockFrameDataReturningSize(fid, &(gCharacterEditorFrmHandle[i]), &(gCharacterEditorFrmSize[i].width), &(gCharacterEditorFrmSize[i].height));
|
||||
if (gCharacterEditorFrmData[i] == NULL) {
|
||||
break;
|
||||
@@ -1855,6 +1865,9 @@ static void characterEditorWindowFree()
|
||||
// SFALL: Custom karma folder.
|
||||
customKarmaFolderFree();
|
||||
|
||||
// SFALL: Custom town reputation.
|
||||
customTownReputationFree();
|
||||
|
||||
messageListFree(&gCharacterEditorMessageList);
|
||||
|
||||
interfaceBarRefresh();
|
||||
@@ -1913,7 +1926,7 @@ static int _get_input_str(int win, int cancelKeyCode, char* text, int maxLength,
|
||||
char copy[257];
|
||||
strcpy(copy, text);
|
||||
|
||||
int nameLength = strlen(text);
|
||||
size_t nameLength = strlen(text);
|
||||
copy[nameLength] = ' ';
|
||||
copy[nameLength + 1] = '\0';
|
||||
|
||||
@@ -1999,8 +2012,8 @@ bool _isdoschar(int ch)
|
||||
return true;
|
||||
}
|
||||
|
||||
int length = strlen(punctuations);
|
||||
for (int index = 0; index < length; index++) {
|
||||
size_t length = strlen(punctuations);
|
||||
for (size_t index = 0; index < length; index++) {
|
||||
if (punctuations[index] == ch) {
|
||||
return true;
|
||||
}
|
||||
@@ -2789,7 +2802,13 @@ static void characterEditorDrawDerivedStats()
|
||||
sprintf(t, "%s", messageListItemText);
|
||||
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
||||
|
||||
compat_itoa(critterGetStat(gDude, STAT_MELEE_DAMAGE), t, 10);
|
||||
// SFALL: Display melee damage without "Bonus HtH Damage" bonus.
|
||||
int meleeDamage = critterGetStat(gDude, STAT_MELEE_DAMAGE);
|
||||
if (!damageModGetDisplayBonusDamage()) {
|
||||
meleeDamage -= 2 * perkGetRank(gDude, PERK_BONUS_HTH_DAMAGE);
|
||||
}
|
||||
|
||||
compat_itoa(meleeDamage, t, 10);
|
||||
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 288, t, 640, 640, color);
|
||||
|
||||
// Damage Resistance
|
||||
@@ -2898,7 +2917,7 @@ static void characterEditorDrawSkills(int a1)
|
||||
int color;
|
||||
int y;
|
||||
int value;
|
||||
char valueString[12]; // TODO: Size might be wrong.
|
||||
char valueString[32];
|
||||
|
||||
if (characterEditorSelectedItem >= EDITOR_FIRST_SKILL && characterEditorSelectedItem < 79) {
|
||||
selectedSkill = characterEditorSelectedItem - EDITOR_FIRST_SKILL;
|
||||
@@ -2931,7 +2950,6 @@ static void characterEditorDrawSkills(int a1)
|
||||
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 138);
|
||||
fontDrawText(gCharacterEditorWindowBuffer + 640 * 233 + 422, str, 640, 640, _colorTable[18979]);
|
||||
|
||||
// TODO: Check.
|
||||
if (a1 == 2 && !gCharacterEditorIsSkillsFirstDraw) {
|
||||
characterEditorDrawBigNumber(522, 228, ANIMATE, gCharacterEditorTaggedSkillCount, gCharacterEditorOldTaggedSkillCount, gCharacterEditorWindow);
|
||||
} else {
|
||||
@@ -2966,7 +2984,6 @@ static void characterEditorDrawSkills(int a1)
|
||||
value = skillGetValue(gDude, i);
|
||||
sprintf(valueString, "%d%%", value);
|
||||
|
||||
// TODO: Check text position.
|
||||
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 573, valueString, 640, 640, color);
|
||||
|
||||
y += fontGetLineHeight() + 1;
|
||||
@@ -4253,7 +4270,7 @@ static int characterPrintToFile(const char* fileName)
|
||||
|
||||
// NOTE: Uninline.
|
||||
padding[0] = '\0';
|
||||
_AddSpaces(padding, (80 - strlen(title1)) / 2 - 2);
|
||||
_AddSpaces(padding, (80 - static_cast<int>(strlen(title1))) / 2 - 2);
|
||||
|
||||
strcat(padding, title1);
|
||||
strcat(padding, "\n");
|
||||
@@ -4264,7 +4281,7 @@ static int characterPrintToFile(const char* fileName)
|
||||
|
||||
// NOTE: Uninline.
|
||||
padding[0] = '\0';
|
||||
_AddSpaces(padding, (80 - strlen(title1)) / 2 - 2);
|
||||
_AddSpaces(padding, (80 - static_cast<int>(strlen(title1))) / 2 - 2);
|
||||
|
||||
strcat(padding, title1);
|
||||
strcat(padding, "\n");
|
||||
@@ -4284,7 +4301,7 @@ static int characterPrintToFile(const char* fileName)
|
||||
|
||||
// NOTE: Uninline.
|
||||
padding[0] = '\0';
|
||||
_AddSpaces(padding, (80 - strlen(title1)) / 2 - 2);
|
||||
_AddSpaces(padding, (80 - static_cast<int>(strlen(title1))) / 2 - 2);
|
||||
|
||||
strcat(padding, title1);
|
||||
strcat(padding, "\n");
|
||||
@@ -4299,7 +4316,7 @@ static int characterPrintToFile(const char* fileName)
|
||||
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 642),
|
||||
critterGetName(gDude));
|
||||
|
||||
int paddingLength = 27 - strlen(title1);
|
||||
int paddingLength = 27 - static_cast<int>(strlen(title1));
|
||||
if (paddingLength > 0) {
|
||||
// NOTE: Uninline.
|
||||
padding[0] = '\0';
|
||||
@@ -4332,7 +4349,7 @@ static int characterPrintToFile(const char* fileName)
|
||||
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 648),
|
||||
_itostndn(pcGetStat(PC_STAT_EXPERIENCE), title3));
|
||||
|
||||
paddingLength = 12 - strlen(title3);
|
||||
paddingLength = 12 - static_cast<int>(strlen(title3));
|
||||
if (paddingLength > 0) {
|
||||
// NOTE: Uninline.
|
||||
padding[0] = '\0';
|
||||
@@ -4392,13 +4409,19 @@ static int characterPrintToFile(const char* fileName)
|
||||
fileWriteString(title1, stream);
|
||||
fileWriteString("\n", stream);
|
||||
|
||||
// SFALL: Display melee damage without "Bonus HtH Damage" bonus.
|
||||
int meleeDamage = critterGetStat(gDude, STAT_MELEE_DAMAGE);
|
||||
if (!damageModGetDisplayBonusDamage()) {
|
||||
meleeDamage -= 2 * perkGetRank(gDude, PERK_BONUS_HTH_DAMAGE);
|
||||
}
|
||||
|
||||
// Charisma / Melee Damage / Carry Weight
|
||||
sprintf(title1,
|
||||
"%s %.2d %s %.2d %s %.3d lbs.",
|
||||
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 633),
|
||||
critterGetStat(gDude, STAT_CHARISMA),
|
||||
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 634),
|
||||
critterGetStat(gDude, STAT_MELEE_DAMAGE),
|
||||
meleeDamage,
|
||||
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 635),
|
||||
critterGetStat(gDude, STAT_CARRY_WEIGHT));
|
||||
fileWriteString(title1, stream);
|
||||
@@ -4516,9 +4539,10 @@ static int characterPrintToFile(const char* fileName)
|
||||
}
|
||||
|
||||
bool hasTownReputationHeading = false;
|
||||
for (int index = 0; index < TOWN_REPUTATION_COUNT; index++) {
|
||||
const TownReputationEntry* pair = &(gTownReputationEntries[index]);
|
||||
if (_wmAreaIsKnown(pair->city)) {
|
||||
// SFALL
|
||||
for (int index = 0; index < gCustomTownReputationEntries.size(); index++) {
|
||||
const TownReputationEntry* pair = &(gCustomTownReputationEntries[index]);
|
||||
if (wmAreaIsKnown(pair->city)) {
|
||||
if (!hasTownReputationHeading) {
|
||||
fileWriteString("\n", stream);
|
||||
|
||||
@@ -4528,7 +4552,7 @@ static int characterPrintToFile(const char* fileName)
|
||||
hasTownReputationHeading = true;
|
||||
}
|
||||
|
||||
_wmGetAreaIdxName(pair->city, title2);
|
||||
wmGetAreaIdxName(pair->city, title2);
|
||||
|
||||
int townReputation = gGameGlobalVars[pair->gvar];
|
||||
|
||||
@@ -4590,7 +4614,7 @@ static int characterPrintToFile(const char* fileName)
|
||||
sprintf(title1, "%s ", skillGetName(skill));
|
||||
|
||||
// NOTE: Uninline.
|
||||
_AddDots(title1 + strlen(title1), 16 - strlen(title1));
|
||||
_AddDots(title1 + strlen(title1), 16 - static_cast<int>(strlen(title1)));
|
||||
|
||||
bool hasKillType = false;
|
||||
|
||||
@@ -4600,7 +4624,7 @@ static int characterPrintToFile(const char* fileName)
|
||||
sprintf(title2, "%s ", killTypeGetName(killType));
|
||||
|
||||
// NOTE: Uninline.
|
||||
_AddDots(title2 + strlen(title2), 16 - strlen(title2));
|
||||
_AddDots(title2 + strlen(title2), 16 - static_cast<int>(strlen(title2)));
|
||||
|
||||
sprintf(title3,
|
||||
" %s %.3d%% %s %.3d\n",
|
||||
@@ -4645,7 +4669,7 @@ static int characterPrintToFile(const char* fileName)
|
||||
_itostndn(inventoryItem->quantity, title3),
|
||||
objectGetName(inventoryItem->item));
|
||||
|
||||
int length = 25 - strlen(title2);
|
||||
int length = 25 - static_cast<int>(strlen(title2));
|
||||
if (length < 0) {
|
||||
length = 0;
|
||||
}
|
||||
@@ -4892,7 +4916,7 @@ static int characterEditorDrawCardWithOptions(int graphicId, const char* name, c
|
||||
short beginnings[WORD_WRAP_MAX_COUNT];
|
||||
short beginningsCount;
|
||||
|
||||
fid = buildFid(10, graphicId, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_SKILLDEX, graphicId, 0, 0, 0);
|
||||
buf = artLockFrameDataReturningSize(fid, &graphicHandle, &(size.width), &(size.height));
|
||||
if (buf == NULL) {
|
||||
return -1;
|
||||
@@ -5504,9 +5528,10 @@ static void characterEditorDrawKarmaFolder()
|
||||
}
|
||||
|
||||
bool hasTownReputationHeading = false;
|
||||
for (int index = 0; index < TOWN_REPUTATION_COUNT; index++) {
|
||||
const TownReputationEntry* pair = &(gTownReputationEntries[index]);
|
||||
if (_wmAreaIsKnown(pair->city)) {
|
||||
// SFALL
|
||||
for (int index = 0; index < gCustomTownReputationEntries.size(); index++) {
|
||||
const TownReputationEntry* pair = &(gCustomTownReputationEntries[index]);
|
||||
if (wmAreaIsKnown(pair->city)) {
|
||||
if (!hasTownReputationHeading) {
|
||||
msg = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 4000);
|
||||
if (characterEditorFolderViewDrawHeading(msg)) {
|
||||
@@ -5519,7 +5544,7 @@ static void characterEditorDrawKarmaFolder()
|
||||
}
|
||||
|
||||
char cityShortName[40];
|
||||
_wmGetAreaIdxName(pair->city, cityShortName);
|
||||
wmGetAreaIdxName(pair->city, cityShortName);
|
||||
|
||||
int townReputation = gGameGlobalVars[pair->gvar];
|
||||
|
||||
@@ -5744,7 +5769,7 @@ static int perkDialogShow()
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
int backgroundWidth;
|
||||
int backgroundHeight;
|
||||
int fid = buildFid(6, 86, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, 86, 0, 0, 0);
|
||||
gPerkDialogBackgroundBuffer = artLockFrameDataReturningSize(fid, &backgroundFrmHandle, &backgroundWidth, &backgroundHeight);
|
||||
if (gPerkDialogBackgroundBuffer == NULL) {
|
||||
debugPrint("\n *** Error running perks dialog window ***\n");
|
||||
@@ -5950,13 +5975,15 @@ static int perkDialogHandleInput(int count, void (*refreshProc)())
|
||||
int keyCode = _get_input();
|
||||
int v19 = 0;
|
||||
|
||||
convertMouseWheelToArrowKey(&keyCode);
|
||||
|
||||
if (keyCode == 500) {
|
||||
rc = 1;
|
||||
} else if (keyCode == KEY_RETURN) {
|
||||
soundPlayFile("ib1p1xx1");
|
||||
rc = 1;
|
||||
} else if (keyCode == 501) {
|
||||
mouseGetPositionInWindow(gPerkDialogWindow , &gCharacterEditorMouseX, &gCharacterEditorMouseY);
|
||||
mouseGetPositionInWindow(gPerkDialogWindow, &gCharacterEditorMouseX, &gCharacterEditorMouseY);
|
||||
gPerkDialogCurrentLine = (gCharacterEditorMouseY - PERK_WINDOW_LIST_Y) / v16;
|
||||
if (gPerkDialogCurrentLine >= 0) {
|
||||
if (count - 1 < gPerkDialogCurrentLine)
|
||||
@@ -6526,7 +6553,7 @@ static int perkDialogOptionCompare(const void* a1, const void* a2)
|
||||
// 0x43DB54
|
||||
static int perkDialogDrawCard(int frmId, const char* name, const char* rank, char* description)
|
||||
{
|
||||
int fid = buildFid(10, frmId, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_SKILLDEX, frmId, 0, 0, 0);
|
||||
|
||||
CacheEntry* handle;
|
||||
int width;
|
||||
@@ -6611,7 +6638,7 @@ static int perkDialogDrawCard(int frmId, const char* name, const char* rank, cha
|
||||
strcpy(gPerkDialogCardTitle, name);
|
||||
gPerkDialogCardFrmId = frmId;
|
||||
gPerkDialogCardDrawn = true;
|
||||
|
||||
|
||||
artUnlock(handle);
|
||||
|
||||
return 0;
|
||||
@@ -7162,3 +7189,53 @@ static int customKarmaFolderGetFrmId()
|
||||
}
|
||||
return gCustomKarmaFolderDescriptions.end()->frmId;
|
||||
}
|
||||
|
||||
static void customTownReputationInit()
|
||||
{
|
||||
char* reputationList = NULL;
|
||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_CITY_REPUTATION_LIST_KEY, &reputationList);
|
||||
if (reputationList != NULL && *reputationList == '\0') {
|
||||
reputationList = NULL;
|
||||
}
|
||||
|
||||
char* curr = reputationList;
|
||||
while (curr != NULL) {
|
||||
char* next = strchr(curr, ',');
|
||||
if (next != NULL) {
|
||||
*next = '\0';
|
||||
}
|
||||
|
||||
char* sep = strchr(curr, ':');
|
||||
if (sep != NULL) {
|
||||
*sep = '\0';
|
||||
|
||||
TownReputationEntry entry;
|
||||
entry.city = atoi(curr);
|
||||
entry.gvar = atoi(sep + 1);
|
||||
gCustomTownReputationEntries.push_back(std::move(entry));
|
||||
|
||||
*sep = ':';
|
||||
}
|
||||
|
||||
if (next != NULL) {
|
||||
*next = ',';
|
||||
curr = next + 1;
|
||||
} else {
|
||||
curr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (gCustomTownReputationEntries.empty()) {
|
||||
gCustomTownReputationEntries.resize(TOWN_REPUTATION_COUNT);
|
||||
|
||||
for (int index = 0; index < TOWN_REPUTATION_COUNT; index++) {
|
||||
gCustomTownReputationEntries[index].gvar = gTownReputationEntries[index].gvar;
|
||||
gCustomTownReputationEntries[index].city = gTownReputationEntries[index].city;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void customTownReputationFree()
|
||||
{
|
||||
gCustomTownReputationEntries.clear();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#include "character_selector.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "art.h"
|
||||
#include "character_editor.h"
|
||||
#include "color.h"
|
||||
@@ -9,6 +15,7 @@
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "game_config.h"
|
||||
#include "game_sound.h"
|
||||
#include "memory.h"
|
||||
#include "message.h"
|
||||
@@ -17,15 +24,13 @@
|
||||
#include "palette.h"
|
||||
#include "platform_compat.h"
|
||||
#include "proto.h"
|
||||
#include "sfall_config.h"
|
||||
#include "skill.h"
|
||||
#include "stat.h"
|
||||
#include "text_font.h"
|
||||
#include "trait.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CS_WINDOW_WIDTH (640)
|
||||
#define CS_WINDOW_HEIGHT (480)
|
||||
|
||||
@@ -57,6 +62,19 @@
|
||||
#define CS_WINDOW_SECONDARY_STAT_MID_X (379)
|
||||
#define CS_WINDOW_BIO_X (438)
|
||||
|
||||
typedef enum PremadeCharacter {
|
||||
PREMADE_CHARACTER_NARG,
|
||||
PREMADE_CHARACTER_CHITSA,
|
||||
PREMADE_CHARACTER_MINGUN,
|
||||
PREMADE_CHARACTER_COUNT,
|
||||
} PremadeCharacter;
|
||||
|
||||
typedef struct PremadeCharacterDescription {
|
||||
char fileName[20];
|
||||
int face;
|
||||
char field_18[20];
|
||||
} PremadeCharacterDescription;
|
||||
|
||||
static bool characterSelectorWindowInit();
|
||||
static void characterSelectorWindowFree();
|
||||
static bool characterSelectorWindowRefresh();
|
||||
@@ -64,6 +82,8 @@ static bool characterSelectorWindowRenderFace();
|
||||
static bool characterSelectorWindowRenderStats();
|
||||
static bool characterSelectorWindowRenderBio();
|
||||
|
||||
static void premadeCharactersLocalizePath(char* path);
|
||||
|
||||
// 0x51C84C
|
||||
static int gCurrentPremadeCharacter = PREMADE_CHARACTER_NARG;
|
||||
|
||||
@@ -75,7 +95,7 @@ static PremadeCharacterDescription gPremadeCharacterDescriptions[PREMADE_CHARACT
|
||||
};
|
||||
|
||||
// 0x51C8D4
|
||||
static const int gPremadeCharacterCount = PREMADE_CHARACTER_COUNT;
|
||||
static int gPremadeCharacterCount = PREMADE_CHARACTER_COUNT;
|
||||
|
||||
// 0x51C7F8
|
||||
static int gCharacterSelectorWindow = -1;
|
||||
@@ -176,6 +196,8 @@ static unsigned char* gCharacterSelectorWindowPreviousButtonUpFrmData;
|
||||
// 0x667790
|
||||
static unsigned char* gCharacterSelectorWindowPreviousButtonDownFrmData;
|
||||
|
||||
static std::vector<PremadeCharacterDescription> gCustomPremadeCharacterDescriptions;
|
||||
|
||||
// 0x4A71D0
|
||||
int characterSelectorOpen()
|
||||
{
|
||||
@@ -221,6 +243,8 @@ int characterSelectorOpen()
|
||||
if (characterEditorShow(1) == 0) {
|
||||
rc = 2;
|
||||
done = true;
|
||||
} else {
|
||||
characterSelectorWindowRefresh();
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -229,6 +253,8 @@ int characterSelectorOpen()
|
||||
if (!characterEditorShow(1)) {
|
||||
rc = 2;
|
||||
done = true;
|
||||
} else {
|
||||
characterSelectorWindowRefresh();
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -299,7 +325,7 @@ static bool characterSelectorWindowInit()
|
||||
}
|
||||
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
backgroundFid = buildFid(6, 174, 0, 0, 0);
|
||||
backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 174, 0, 0, 0);
|
||||
backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle);
|
||||
if (backgroundFrmData == NULL) {
|
||||
goto err;
|
||||
@@ -328,13 +354,13 @@ static bool characterSelectorWindowInit()
|
||||
int fid;
|
||||
|
||||
// Setup "Previous" button.
|
||||
fid = buildFid(6, 122, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 122, 0, 0, 0);
|
||||
gCharacterSelectorWindowPreviousButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowPreviousButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowPreviousButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
fid = buildFid(6, 123, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 123, 0, 0, 0);
|
||||
gCharacterSelectorWindowPreviousButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowPreviousButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowPreviousButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
@@ -360,13 +386,13 @@ static bool characterSelectorWindowInit()
|
||||
buttonSetCallbacks(gCharacterSelectorWindowPreviousButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
||||
|
||||
// Setup "Next" button.
|
||||
fid = buildFid(6, 124, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 124, 0, 0, 0);
|
||||
gCharacterSelectorWindowNextButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowNextButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowNextButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
fid = buildFid(6, 125, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 125, 0, 0, 0);
|
||||
gCharacterSelectorWindowNextButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowNextButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowNextButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
@@ -392,13 +418,13 @@ static bool characterSelectorWindowInit()
|
||||
buttonSetCallbacks(gCharacterSelectorWindowNextButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
||||
|
||||
// Setup "Take" button.
|
||||
fid = buildFid(6, 8, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowTakeButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowTakeButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowTakeButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
fid = buildFid(6, 9, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowTakeButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowTakeButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowTakeButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
@@ -424,12 +450,12 @@ static bool characterSelectorWindowInit()
|
||||
buttonSetCallbacks(gCharacterSelectorWindowTakeButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
|
||||
// Setup "Modify" button.
|
||||
fid = buildFid(6, 8, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowModifyButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowModifyButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowModifyButtonUpFrmData == NULL)
|
||||
goto err;
|
||||
|
||||
fid = buildFid(6, 9, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowModifyButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowModifyButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowModifyButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
@@ -455,13 +481,13 @@ static bool characterSelectorWindowInit()
|
||||
buttonSetCallbacks(gCharacterSelectorWindowModifyButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
|
||||
// Setup "Create" button.
|
||||
fid = buildFid(6, 8, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowCreateButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowCreateButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowCreateButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
fid = buildFid(6, 9, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowCreateButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowCreateButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowCreateButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
@@ -487,13 +513,13 @@ static bool characterSelectorWindowInit()
|
||||
buttonSetCallbacks(gCharacterSelectorWindowCreateButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
|
||||
// Setup "Back" button.
|
||||
fid = buildFid(6, 8, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowBackButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowBackButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowBackButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
fid = buildFid(6, 9, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowBackButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowBackButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowBackButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
@@ -657,7 +683,9 @@ static void characterSelectorWindowFree()
|
||||
static bool characterSelectorWindowRefresh()
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
sprintf(path, "%s.gcd", gPremadeCharacterDescriptions[gCurrentPremadeCharacter].fileName);
|
||||
sprintf(path, "%s.gcd", gCustomPremadeCharacterDescriptions[gCurrentPremadeCharacter].fileName);
|
||||
premadeCharactersLocalizePath(path);
|
||||
|
||||
if (_proto_dude_init(path) == -1) {
|
||||
debugPrint("\n ** Error in dude init! **\n");
|
||||
return false;
|
||||
@@ -688,7 +716,7 @@ static bool characterSelectorWindowRenderFace()
|
||||
bool success = false;
|
||||
|
||||
CacheEntry* faceFrmHandle;
|
||||
int faceFid = buildFid(6, gPremadeCharacterDescriptions[gCurrentPremadeCharacter].face, 0, 0, 0);
|
||||
int faceFid = buildFid(OBJ_TYPE_INTERFACE, gCustomPremadeCharacterDescriptions[gCurrentPremadeCharacter].face, 0, 0, 0);
|
||||
Art* frm = artLock(faceFid, &faceFrmHandle);
|
||||
if (frm != NULL) {
|
||||
unsigned char* data = artGetFrameData(frm, 0, 0);
|
||||
@@ -963,7 +991,8 @@ static bool characterSelectorWindowRenderBio()
|
||||
fontSetCurrent(101);
|
||||
|
||||
char path[COMPAT_MAX_PATH];
|
||||
sprintf(path, "%s.bio", gPremadeCharacterDescriptions[gCurrentPremadeCharacter].fileName);
|
||||
sprintf(path, "%s.bio", gCustomPremadeCharacterDescriptions[gCurrentPremadeCharacter].fileName);
|
||||
premadeCharactersLocalizePath(path);
|
||||
|
||||
File* stream = fileOpen(path, "rt");
|
||||
if (stream != NULL) {
|
||||
@@ -983,3 +1012,113 @@ static bool characterSelectorWindowRenderBio()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void premadeCharactersInit()
|
||||
{
|
||||
char* fileNamesString;
|
||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PREMADE_CHARACTERS_FILE_NAMES_KEY, &fileNamesString);
|
||||
if (fileNamesString != NULL && *fileNamesString == '\0') {
|
||||
fileNamesString = NULL;
|
||||
}
|
||||
|
||||
char* faceFidsString;
|
||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PREMADE_CHARACTERS_FACE_FIDS_KEY, &faceFidsString);
|
||||
if (faceFidsString != NULL && *faceFidsString == '\0') {
|
||||
faceFidsString = NULL;
|
||||
}
|
||||
|
||||
if (fileNamesString != NULL && faceFidsString != NULL) {
|
||||
int fileNamesLength = 0;
|
||||
for (char* pch = fileNamesString; pch != NULL; pch = strchr(pch + 1, ',')) {
|
||||
fileNamesLength++;
|
||||
}
|
||||
|
||||
int faceFidsLength = 0;
|
||||
for (char* pch = faceFidsString; pch != NULL; pch = strchr(pch + 1, ',')) {
|
||||
faceFidsLength++;
|
||||
}
|
||||
|
||||
int premadeCharactersCount = std::min(fileNamesLength, faceFidsLength);
|
||||
gCustomPremadeCharacterDescriptions.resize(premadeCharactersCount);
|
||||
|
||||
for (int index = 0; index < premadeCharactersCount; index++) {
|
||||
char* pch;
|
||||
|
||||
pch = strchr(fileNamesString, ',');
|
||||
if (pch != NULL) {
|
||||
*pch = '\0';
|
||||
}
|
||||
|
||||
if (strlen(fileNamesString) > 11) {
|
||||
// Sfall fails here.
|
||||
continue;
|
||||
}
|
||||
|
||||
sprintf(gCustomPremadeCharacterDescriptions[index].fileName, "premade\\%s", fileNamesString);
|
||||
|
||||
if (pch != NULL) {
|
||||
*pch = ',';
|
||||
}
|
||||
|
||||
fileNamesString = pch + 1;
|
||||
|
||||
pch = strchr(faceFidsString, ',');
|
||||
if (pch != NULL) {
|
||||
*pch = '\0';
|
||||
}
|
||||
|
||||
gCustomPremadeCharacterDescriptions[index].face = atoi(faceFidsString);
|
||||
|
||||
if (pch != NULL) {
|
||||
*pch = ',';
|
||||
}
|
||||
|
||||
faceFidsString = pch + 1;
|
||||
|
||||
gCustomPremadeCharacterDescriptions[index].field_18[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (gCustomPremadeCharacterDescriptions.empty()) {
|
||||
gCustomPremadeCharacterDescriptions.resize(PREMADE_CHARACTER_COUNT);
|
||||
|
||||
for (int index = 0; index < PREMADE_CHARACTER_COUNT; index++) {
|
||||
strcpy(gCustomPremadeCharacterDescriptions[index].fileName, gPremadeCharacterDescriptions[index].fileName);
|
||||
gCustomPremadeCharacterDescriptions[index].face = gPremadeCharacterDescriptions[index].face;
|
||||
strcpy(gCustomPremadeCharacterDescriptions[index].field_18, gPremadeCharacterDescriptions[index].field_18);
|
||||
}
|
||||
}
|
||||
|
||||
gPremadeCharacterCount = gCustomPremadeCharacterDescriptions.size();
|
||||
}
|
||||
|
||||
void premadeCharactersExit()
|
||||
{
|
||||
gCustomPremadeCharacterDescriptions.clear();
|
||||
}
|
||||
|
||||
static void premadeCharactersLocalizePath(char* path)
|
||||
{
|
||||
if (compat_strnicmp(path, "premade\\", 8) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
char* language;
|
||||
if (!configGetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_LANGUAGE_KEY, &language)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (compat_stricmp(language, ENGLISH) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
char localizedPath[COMPAT_MAX_PATH];
|
||||
strncpy(localizedPath, path, 8);
|
||||
strcpy(localizedPath + 8, language);
|
||||
strcpy(localizedPath + 8 + strlen(language), path + 7);
|
||||
|
||||
int fileSize;
|
||||
if (dbGetFileSize(localizedPath, &fileSize) == 0) {
|
||||
strcpy(path, localizedPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
#ifndef CHARACTER_SELECTOR_H
|
||||
#define CHARACTER_SELECTOR_H
|
||||
|
||||
typedef enum PremadeCharacter {
|
||||
PREMADE_CHARACTER_NARG,
|
||||
PREMADE_CHARACTER_CHITSA,
|
||||
PREMADE_CHARACTER_MINGUN,
|
||||
PREMADE_CHARACTER_COUNT,
|
||||
} PremadeCharacter;
|
||||
|
||||
typedef struct PremadeCharacterDescription {
|
||||
char fileName[20];
|
||||
int face;
|
||||
char field_18[20];
|
||||
} PremadeCharacterDescription;
|
||||
|
||||
int characterSelectorOpen();
|
||||
|
||||
void premadeCharactersInit();
|
||||
void premadeCharactersExit();
|
||||
|
||||
#endif /* CHARACTER_SELECTOR_H */
|
||||
|
||||
86
src/color.cc
@@ -1,11 +1,19 @@
|
||||
#include "color.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#define COLOR_PALETTE_STACK_CAPACITY 16
|
||||
|
||||
#include <algorithm>
|
||||
typedef struct ColorPaletteStackEntry {
|
||||
unsigned char mappedColors[256];
|
||||
unsigned char cmap[768];
|
||||
unsigned char colorTable[32768];
|
||||
} ColorPaletteStackEntry;
|
||||
|
||||
static int colorPaletteFileOpen(const char* filePath, int flags);
|
||||
static int colorPaletteFileRead(int fd, void* buffer, size_t size);
|
||||
@@ -25,6 +33,12 @@ static char _aColor_cNoError[] = "color.c: No errors\n";
|
||||
// 0x50F95C
|
||||
static char _aColor_cColorTa[] = "color.c: color table not found\n";
|
||||
|
||||
// 0x50F984
|
||||
static char _aColor_cColorpa[] = "color.c: colorpalettestack overflow";
|
||||
|
||||
// 0x50F9AC
|
||||
static char aColor_cColor_0[] = "color.c: colorpalettestack underflow";
|
||||
|
||||
// 0x51DF10
|
||||
static char* _errorStr = _aColor_cNoError;
|
||||
|
||||
@@ -54,6 +68,9 @@ unsigned char _cmap[768] = {
|
||||
0x3F, 0x3F, 0x3F
|
||||
};
|
||||
|
||||
// 0x673050
|
||||
static ColorPaletteStackEntry* gColorPaletteStack[COLOR_PALETTE_STACK_CAPACITY];
|
||||
|
||||
// 0x673090
|
||||
unsigned char _systemCmap[256 * 3];
|
||||
|
||||
@@ -78,6 +95,9 @@ unsigned char _colorMixMulTable[65536];
|
||||
// 0x6A38D0
|
||||
unsigned char _colorTable[32768];
|
||||
|
||||
// 0x6AB8D0
|
||||
static int gColorPaletteStackSize;
|
||||
|
||||
// 0x6AB928
|
||||
static ColorPaletteFileReadProc* gColorPaletteFileReadProc;
|
||||
|
||||
@@ -572,6 +592,60 @@ void colorSetBrightness(double value)
|
||||
_setSystemPalette(_systemCmap);
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4C8828
|
||||
bool colorPushColorPalette()
|
||||
{
|
||||
if (gColorPaletteStackSize >= COLOR_PALETTE_STACK_CAPACITY) {
|
||||
_errorStr = _aColor_cColorpa;
|
||||
return false;
|
||||
}
|
||||
|
||||
ColorPaletteStackEntry* entry = (ColorPaletteStackEntry*)malloc(sizeof(*entry));
|
||||
gColorPaletteStack[gColorPaletteStackSize] = entry;
|
||||
|
||||
memcpy(entry->mappedColors, _mappedColor, sizeof(_mappedColor));
|
||||
memcpy(entry->cmap, _cmap, sizeof(_cmap));
|
||||
memcpy(entry->colorTable, _colorTable, sizeof(_colorTable));
|
||||
|
||||
gColorPaletteStackSize++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4C88E0
|
||||
bool colorPopColorPalette()
|
||||
{
|
||||
if (gColorPaletteStackSize == 0) {
|
||||
_errorStr = aColor_cColor_0;
|
||||
return false;
|
||||
}
|
||||
|
||||
gColorPaletteStackSize--;
|
||||
|
||||
ColorPaletteStackEntry* entry = gColorPaletteStack[gColorPaletteStackSize];
|
||||
|
||||
memcpy(_mappedColor, entry->mappedColors, sizeof(_mappedColor));
|
||||
memcpy(_cmap, entry->cmap, sizeof(_cmap));
|
||||
memcpy(_colorTable, entry->colorTable, sizeof(_colorTable));
|
||||
|
||||
free(entry);
|
||||
gColorPaletteStack[gColorPaletteStackSize] = NULL;
|
||||
|
||||
_setIntensityTables();
|
||||
|
||||
for (int index = 0; index < 256; index++) {
|
||||
_setMixTableColor(index);
|
||||
}
|
||||
|
||||
_rebuildColorBlendTables();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4C89CC
|
||||
bool _initColors()
|
||||
{
|
||||
@@ -599,5 +673,9 @@ void _colorsClose()
|
||||
_freeColorBlendTable(index);
|
||||
}
|
||||
|
||||
// TODO: Incomplete.
|
||||
for (int index = 0; index < gColorPaletteStackSize; index++) {
|
||||
free(gColorPaletteStack[index]);
|
||||
}
|
||||
|
||||
gColorPaletteStackSize = 0;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ unsigned char* _getColorBlendTable(int ch);
|
||||
void _freeColorBlendTable(int a1);
|
||||
void colorPaletteSetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc);
|
||||
void colorSetBrightness(double value);
|
||||
bool colorPushColorPalette();
|
||||
bool colorPopColorPalette();
|
||||
bool _initColors();
|
||||
void _colorsClose();
|
||||
|
||||
|
||||
1538
src/combat.cc
36
src/combat.h
@@ -1,8 +1,8 @@
|
||||
#ifndef COMBAT_H
|
||||
#define COMBAT_H
|
||||
|
||||
#include "db.h"
|
||||
#include "combat_defs.h"
|
||||
#include "db.h"
|
||||
#include "obj_types.h"
|
||||
#include "proto_types.h"
|
||||
|
||||
@@ -21,12 +21,12 @@ bool _combat_safety_invalidate_weapon(Object* a1, Object* a2, int hitMode, Objec
|
||||
bool _combatTestIncidentalHit(Object* a1, Object* a2, Object* a3, Object* a4);
|
||||
Object* _combat_whose_turn();
|
||||
void _combat_data_init(Object* obj);
|
||||
Object* _combatAIInfoGetFriendlyDead(Object* obj);
|
||||
int _combatAIInfoSetFriendlyDead(Object* a1, Object* a2);
|
||||
Object* _combatAIInfoGetLastTarget(Object* obj);
|
||||
int _combatAIInfoSetLastTarget(Object* a1, Object* a2);
|
||||
Object* _combatAIInfoGetLastItem(Object* obj);
|
||||
int _combatAIInfoSetLastItem(Object* obj, Object* a2);
|
||||
Object* aiInfoGetFriendlyDead(Object* obj);
|
||||
int aiInfoSetFriendlyDead(Object* a1, Object* a2);
|
||||
Object* aiInfoGetLastTarget(Object* obj);
|
||||
int aiInfoSetLastTarget(Object* a1, Object* a2);
|
||||
Object* aiInfoGetLastItem(Object* obj);
|
||||
int aiInfoSetLastItem(Object* obj, Object* a2);
|
||||
void _combat_update_critter_outline_for_los(Object* critter, bool a2);
|
||||
void _combat_over_from_load();
|
||||
void _combat_give_exps(int exp_points);
|
||||
@@ -35,7 +35,7 @@ void _combat(STRUCT_664980* attack);
|
||||
void attackInit(Attack* attack, Object* a2, Object* a3, int a4, int a5);
|
||||
int _combat_attack(Object* a1, Object* a2, int a3, int a4);
|
||||
int _combat_bullet_start(const Object* a1, const Object* a2);
|
||||
void _compute_explosion_on_extras(Attack* attack, int a2, int a3, int a4);
|
||||
void _compute_explosion_on_extras(Attack* attack, int a2, bool isGrenade, int a4);
|
||||
int _determine_to_hit(Object* a1, Object* a2, int hitLocation, int hitMode);
|
||||
int _determine_to_hit_no_range(Object* a1, Object* a2, int a3, int a4, unsigned char* a5);
|
||||
int _determine_to_hit_from_tile(Object* a1, int a2, Object* a3, int a4, int a5);
|
||||
@@ -56,9 +56,29 @@ int _combat_explode_scenery(Object* a1, Object* a2);
|
||||
void _combat_delete_critter(Object* obj);
|
||||
void _combatKillCritterOutsideCombat(Object* critter_obj, char* msg);
|
||||
|
||||
int criticalsGetValue(int killType, int hitLocation, int effect, int dataMember);
|
||||
void criticalsSetValue(int killType, int hitLocation, int effect, int dataMember, int value);
|
||||
void criticalsResetValue(int killType, int hitLocation, int effect, int dataMember);
|
||||
int unarmedGetDamage(int hitMode, int* minDamagePtr, int* maxDamagePtr);
|
||||
int unarmedGetBonusCriticalChance(int hitMode);
|
||||
int unarmedGetActionPointCost(int hitMode);
|
||||
bool unarmedIsPenetrating(int hitMode);
|
||||
int unarmedGetPunchHitMode(bool isSecondary);
|
||||
int unarmedGetKickHitMode(bool isSecondary);
|
||||
bool unarmedIsPenetrating(int hitMode);
|
||||
bool damageModGetBonusHthDamageFix();
|
||||
bool damageModGetDisplayBonusDamage();
|
||||
|
||||
static inline bool isInCombat()
|
||||
{
|
||||
return (gCombatState & COMBAT_STATE_0x01) != 0;
|
||||
}
|
||||
|
||||
static inline bool isUnarmedHitMode(int hitMode)
|
||||
{
|
||||
return hitMode == HIT_MODE_PUNCH
|
||||
|| hitMode == HIT_MODE_KICK
|
||||
|| (hitMode >= FIRST_ADVANCED_UNARMED_HIT_MODE && hitMode <= LAST_ADVANCED_UNARMED_HIT_MODE);
|
||||
}
|
||||
|
||||
#endif /* COMBAT_H */
|
||||
|
||||
504
src/combat_ai.cc
@@ -48,7 +48,7 @@ void _caiTeamCombatExit();
|
||||
Object* _ai_search_inven_weap(Object* critter, int a2, Object* a3);
|
||||
Object* _ai_search_inven_armor(Object* critter);
|
||||
int _cAIPrepWeaponItem(Object* critter, Object* item);
|
||||
void _cai_attempt_w_reload(Object* critter_obj, int a2);
|
||||
void aiAttemptWeaponReload(Object* critter, int animate);
|
||||
void _combat_ai_begin(int a1, void* a2);
|
||||
void _combat_ai_over();
|
||||
int _cai_perform_distance_prefs(Object* a1, Object* a2);
|
||||
|
||||
@@ -84,13 +84,6 @@ typedef enum HitLocation {
|
||||
HIT_LOCATION_SPECIFIC_COUNT = HIT_LOCATION_COUNT - 1,
|
||||
} HitLocation;
|
||||
|
||||
typedef struct STRUCT_510948 {
|
||||
Object* field_0;
|
||||
Object* field_4;
|
||||
Object* field_8;
|
||||
int field_C;
|
||||
} STRUCT_510948;
|
||||
|
||||
typedef struct STRUCT_664980 {
|
||||
Object* attacker;
|
||||
Object* defender;
|
||||
@@ -128,25 +121,52 @@ typedef struct Attack {
|
||||
int extrasKnockback[EXPLOSION_TARGET_COUNT];
|
||||
} Attack;
|
||||
|
||||
typedef enum CriticalHitDescriptionDataMember {
|
||||
CRIT_DATA_MEMBER_DAMAGE_MULTIPLIER,
|
||||
CRIT_DATA_MEMBER_FLAGS,
|
||||
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_STAT,
|
||||
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_STAT_MODIFIER,
|
||||
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_FLAGS,
|
||||
CRIT_DATA_MEMBER_MESSAGE_ID,
|
||||
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_MESSAGE_ID,
|
||||
CRIT_DATA_MEMBER_COUNT,
|
||||
} CriticalHitDescriptionDataMember;
|
||||
|
||||
// Provides metadata about critical hit effect.
|
||||
typedef struct CriticalHitDescription {
|
||||
int damageMultiplier;
|
||||
typedef union CriticalHitDescription {
|
||||
struct {
|
||||
int damageMultiplier;
|
||||
|
||||
// Damage flags that will be applied to defender.
|
||||
int flags;
|
||||
// Damage flags that will be applied to defender.
|
||||
int flags;
|
||||
|
||||
// Stat to check to upgrade this critical hit to massive critical hit or
|
||||
// -1 if there is no massive critical hit.
|
||||
int massiveCriticalStat;
|
||||
// Stat to check to upgrade this critical hit to massive critical hit or
|
||||
// -1 if there is no massive critical hit.
|
||||
int massiveCriticalStat;
|
||||
|
||||
// Bonus/penalty to massive critical stat.
|
||||
int massiveCriticalStatModifier;
|
||||
// Bonus/penalty to massive critical stat.
|
||||
int massiveCriticalStatModifier;
|
||||
|
||||
// Additional damage flags if this critical hit become massive critical.
|
||||
int massiveCriticalFlags;
|
||||
// Additional damage flags if this critical hit become massive critical.
|
||||
int massiveCriticalFlags;
|
||||
|
||||
int messageId;
|
||||
int massiveCriticalMessageId;
|
||||
int messageId;
|
||||
int massiveCriticalMessageId;
|
||||
};
|
||||
|
||||
// SFALL: Allow indexed access to the data above.
|
||||
int values[CRIT_DATA_MEMBER_COUNT];
|
||||
} CriticalHitDescription;
|
||||
|
||||
typedef enum CombatBadShot {
|
||||
COMBAT_BAD_SHOT_OK = 0,
|
||||
COMBAT_BAD_SHOT_NO_AMMO = 1,
|
||||
COMBAT_BAD_SHOT_OUT_OF_RANGE = 2,
|
||||
COMBAT_BAD_SHOT_NOT_ENOUGH_AP = 3,
|
||||
COMBAT_BAD_SHOT_ALREADY_DEAD = 4,
|
||||
COMBAT_BAD_SHOT_AIM_BLOCKED = 5,
|
||||
COMBAT_BAD_SHOT_ARM_CRIPPLED = 6,
|
||||
COMBAT_BAD_SHOT_BOTH_ARMS_CRIPPLED = 7,
|
||||
} CombatBadShot;
|
||||
|
||||
#endif /* COMBAT_DEFS_H */
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "db.h"
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
@@ -11,6 +7,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
#define CONFIG_FILE_MAX_LINE_LENGTH (256)
|
||||
|
||||
// The initial number of sections (or key-value) pairs in the config.
|
||||
@@ -81,25 +81,20 @@ bool configParseCommandLineArguments(Config* config, int argc, char** argv)
|
||||
}
|
||||
|
||||
for (int arg = 0; arg < argc; arg++) {
|
||||
char* pch = argv[arg];
|
||||
char* pch;
|
||||
char* string = argv[arg];
|
||||
|
||||
// Find opening bracket.
|
||||
while (*pch != '\0' && *pch != '[') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == '\0') {
|
||||
pch = strchr(string, '[');
|
||||
if (pch == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char* sectionKey = pch + 1;
|
||||
|
||||
// Find closing bracket.
|
||||
while (*pch != '\0' && *pch != ']') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == '\0') {
|
||||
pch = strchr(sectionKey, ']');
|
||||
if (pch == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -189,7 +184,7 @@ bool configSetString(Config* config, const char* sectionKey, const char* key, co
|
||||
}
|
||||
|
||||
// 0x42C05C
|
||||
bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr, unsigned char base /* = 0 */ )
|
||||
bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr, unsigned char base /* = 0 */)
|
||||
{
|
||||
if (valuePtr == NULL) {
|
||||
return false;
|
||||
@@ -233,36 +228,30 @@ bool configGetIntList(Config* config, const char* sectionKey, const char* key, i
|
||||
}
|
||||
|
||||
char temp[CONFIG_FILE_MAX_LINE_LENGTH];
|
||||
strncpy(temp, string, CONFIG_FILE_MAX_LINE_LENGTH - 1);
|
||||
string = strncpy(temp, string, CONFIG_FILE_MAX_LINE_LENGTH - 1);
|
||||
|
||||
char* beginning = temp;
|
||||
char* pch = beginning;
|
||||
while (*pch != '\0') {
|
||||
if (*pch == ',') {
|
||||
*pch = '\0';
|
||||
|
||||
*arr++ = atoi(beginning);
|
||||
|
||||
*pch = ',';
|
||||
|
||||
pch++;
|
||||
beginning = pch;
|
||||
|
||||
count--;
|
||||
|
||||
if (count < 0) {
|
||||
break;
|
||||
}
|
||||
while (1) {
|
||||
char* pch = strchr(string, ',');
|
||||
if (pch == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
pch++;
|
||||
count--;
|
||||
if (count == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
*pch = '\0';
|
||||
*arr++ = atoi(string);
|
||||
string = pch + 1;
|
||||
}
|
||||
|
||||
if (count <= 1) {
|
||||
*arr = atoi(beginning);
|
||||
*arr = atoi(string);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x42C160
|
||||
@@ -383,30 +372,19 @@ static bool configParseLine(Config* config, char* string)
|
||||
char* pch;
|
||||
|
||||
// Find comment marker and truncate the string.
|
||||
pch = string;
|
||||
while (*pch != '\0' && *pch != ';') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch != '\0') {
|
||||
pch = strchr(string, ';');
|
||||
if (pch != NULL) {
|
||||
*pch = '\0';
|
||||
}
|
||||
|
||||
// Find opening bracket.
|
||||
pch = string;
|
||||
while (*pch != '\0' && *pch != '[') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == '[') {
|
||||
pch = strchr(string, '[');
|
||||
if (pch != NULL) {
|
||||
char* sectionKey = pch + 1;
|
||||
|
||||
// Find closing bracket.
|
||||
while (*pch != '\0' && *pch != ']') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == ']') {
|
||||
pch = strchr(sectionKey, ']');
|
||||
if (pch != NULL) {
|
||||
*pch = '\0';
|
||||
strcpy(gConfigLastSectionKey, sectionKey);
|
||||
return configTrimString(gConfigLastSectionKey);
|
||||
@@ -435,12 +413,8 @@ static bool configParseKeyValue(char* string, char* key, char* value)
|
||||
}
|
||||
|
||||
// Find equals character.
|
||||
char* pch = string;
|
||||
while (*pch != '\0' && *pch != '=') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == '\0') {
|
||||
char* pch = strchr(string, '=');
|
||||
if (pch == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
650
src/core.cc
@@ -1,8 +1,13 @@
|
||||
#include "core.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "audio_engine.h"
|
||||
#include "config.h"
|
||||
#include "color.h"
|
||||
#include "config.h"
|
||||
#include "dinput.h"
|
||||
#include "draw.h"
|
||||
#include "interface.h"
|
||||
@@ -13,15 +18,13 @@
|
||||
#include "window_manager.h"
|
||||
#include "window_manager_private.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <SDL.h>
|
||||
static void idleImpl();
|
||||
|
||||
// NOT USED.
|
||||
void (*_idle_func)() = NULL;
|
||||
// 0x51E234
|
||||
IdleFunc* _idle_func = NULL;
|
||||
|
||||
// NOT USED.
|
||||
void (*_focus_func)(int) = NULL;
|
||||
// 0x51E238
|
||||
FocusFunc* _focus_func = NULL;
|
||||
|
||||
// 0x51E23C
|
||||
int gKeyboardKeyRepeatRate = 80;
|
||||
@@ -116,39 +119,48 @@ int gModifierKeysState = 0;
|
||||
int (*_kb_scan_to_ascii)() = keyboardDequeueLogicalKeyCode;
|
||||
|
||||
// 0x51E2F0
|
||||
STRUCT_51E2F0* _vcr_buffer = NULL;
|
||||
VcrEntry* _vcr_buffer = NULL;
|
||||
|
||||
// number of entries in _vcr_buffer
|
||||
// 0x51E2F4
|
||||
int _vcr_buffer_index = 0;
|
||||
|
||||
// 0x51E2F8
|
||||
int _vcr_state = 2;
|
||||
unsigned int gVcrState = VCR_STATE_TURNED_OFF;
|
||||
|
||||
// 0x51E2FC
|
||||
int _vcr_time = 0;
|
||||
unsigned int _vcr_time = 0;
|
||||
|
||||
// 0x51E300
|
||||
int _vcr_counter = 0;
|
||||
unsigned int _vcr_counter = 0;
|
||||
|
||||
// 0x51E304
|
||||
int _vcr_terminate_flags = 0;
|
||||
unsigned int gVcrTerminateFlags = 0;
|
||||
|
||||
// 0x51E308
|
||||
int _vcr_terminated_condition = 0;
|
||||
int gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_NONE;
|
||||
|
||||
// 0x51E30C
|
||||
int _vcr_start_time = 0;
|
||||
unsigned int _vcr_start_time = 0;
|
||||
|
||||
// 0x51E310
|
||||
int _vcr_registered_atexit = 0;
|
||||
|
||||
// 0x51E314
|
||||
File* _vcr_file = NULL;
|
||||
File* gVcrFile = NULL;
|
||||
|
||||
// 0x51E318
|
||||
int _vcr_buffer_end = 0;
|
||||
|
||||
// 0x51E31C
|
||||
VcrPlaybackCompletionCallback* gVcrPlaybackCompletionCallback = NULL;
|
||||
|
||||
// 0x51E320
|
||||
unsigned int gVcrRequestedTerminationFlags = 0;
|
||||
|
||||
// 0x51E324
|
||||
int gVcrOldKeyboardLayout = 0;
|
||||
|
||||
// A map of SDL_SCANCODE_* constants normalized for QWERTY keyboard.
|
||||
//
|
||||
// 0x6ABC70
|
||||
@@ -355,12 +367,18 @@ int gKeyboardLayout;
|
||||
// 0x6AD93C
|
||||
unsigned char gPressedPhysicalKeysCount;
|
||||
|
||||
// 0x6AD940
|
||||
VcrEntry stru_6AD940;
|
||||
|
||||
SDL_Window* gSdlWindow = NULL;
|
||||
SDL_Surface* gSdlSurface = NULL;
|
||||
SDL_Renderer* gSdlRenderer = NULL;
|
||||
SDL_Texture* gSdlTexture = NULL;
|
||||
SDL_Surface* gSdlTextureSurface = NULL;
|
||||
|
||||
static int gMouseWheelX = 0;
|
||||
static int gMouseWheelY = 0;
|
||||
|
||||
// 0x4C8A70
|
||||
int coreInit(int a1)
|
||||
{
|
||||
@@ -396,6 +414,10 @@ int coreInit(int a1)
|
||||
gTickerListHead = NULL;
|
||||
gScreenshotKeyCode = KEY_ALT_C;
|
||||
|
||||
// SFALL: Set idle function.
|
||||
// CE: Prevents frying CPU when window is not focused.
|
||||
inputSetIdleFunc(idleImpl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -446,7 +468,7 @@ void _process_bk()
|
||||
|
||||
tickersExecute();
|
||||
|
||||
if (_vcr_update() != 3) {
|
||||
if (vcrUpdate() != 3) {
|
||||
_mouse_info();
|
||||
}
|
||||
|
||||
@@ -629,31 +651,37 @@ void pauseGame()
|
||||
// 0x4C8E38
|
||||
int pauseHandlerDefaultImpl()
|
||||
{
|
||||
int len;
|
||||
int v1;
|
||||
int v2;
|
||||
int win;
|
||||
unsigned char* buf;
|
||||
int v6;
|
||||
int v7;
|
||||
int windowWidth = fontGetStringWidth("Paused") + 32;
|
||||
int windowHeight = 3 * fontGetLineHeight() + 16;
|
||||
|
||||
len = fontGetStringWidth("Paused") + 32;
|
||||
v1 = fontGetLineHeight();
|
||||
v2 = 3 * v1 + 16;
|
||||
|
||||
win = windowCreate((_scr_size.right - _scr_size.left + 1 - len) / 2, (_scr_size.bottom - _scr_size.top + 1 - v2) / 2, len, v2, 256, 20);
|
||||
int win = windowCreate((rectGetWidth(&_scr_size) - windowWidth) / 2,
|
||||
(rectGetHeight(&_scr_size) - windowHeight) / 2,
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
256,
|
||||
WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
|
||||
if (win == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
windowDrawBorder(win);
|
||||
buf = windowGetBuffer(win);
|
||||
fontDrawText(buf + 8 * len + 16, "Paused", len, len, _colorTable[31744]);
|
||||
|
||||
v6 = v2 - 8 - v1;
|
||||
v7 = fontGetStringWidth("Done");
|
||||
// TODO: Incomplete.
|
||||
// _win_register_text_button(win, (len - v7 - 16) / 2, v6 - 6, -1, -1, -1, 27, "Done", 0);
|
||||
unsigned char* windowBuffer = windowGetBuffer(win);
|
||||
fontDrawText(windowBuffer + 8 * windowWidth + 16,
|
||||
"Paused",
|
||||
windowWidth,
|
||||
windowWidth,
|
||||
_colorTable[31744]);
|
||||
|
||||
_win_register_text_button(win,
|
||||
(windowWidth - fontGetStringWidth("Done") - 16) / 2,
|
||||
windowHeight - 8 - fontGetLineHeight() - 6,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
KEY_ESCAPE,
|
||||
"Done",
|
||||
0);
|
||||
|
||||
windowRefresh(win);
|
||||
|
||||
@@ -720,7 +748,7 @@ int screenshotHandlerDefaultImpl(int width, int height, unsigned char* data, uns
|
||||
|
||||
for (index = 0; index < 100000; index++) {
|
||||
sprintf(fileName, "scr%.5d.bmp", index);
|
||||
|
||||
|
||||
stream = compat_fopen(fileName, "rb");
|
||||
if (stream == NULL) {
|
||||
break;
|
||||
@@ -784,7 +812,7 @@ int screenshotHandlerDefaultImpl(int width, int height, unsigned char* data, uns
|
||||
// biCompression
|
||||
intValue = 0;
|
||||
fwrite(&intValue, sizeof(intValue), 1, stream);
|
||||
|
||||
|
||||
// biSizeImage
|
||||
intValue = 0;
|
||||
fwrite(&intValue, sizeof(intValue), 1, stream);
|
||||
@@ -901,6 +929,70 @@ unsigned int _get_bk_time()
|
||||
return gTickerLastTimestamp;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4C9418
|
||||
void inputSetKeyboardKeyRepeatRate(int value)
|
||||
{
|
||||
gKeyboardKeyRepeatRate = value;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4C9420
|
||||
int inputGetKeyboardKeyRepeatRate()
|
||||
{
|
||||
return gKeyboardKeyRepeatRate;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4C9428
|
||||
void inputSetKeyboardKeyRepeatDelay(int value)
|
||||
{
|
||||
gKeyboardKeyRepeatDelay = value;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4C9430
|
||||
int inputGetKeyboardKeyRepeatDelay()
|
||||
{
|
||||
return gKeyboardKeyRepeatDelay;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4C9438
|
||||
void inputSetFocusFunc(FocusFunc* func)
|
||||
{
|
||||
_focus_func = func;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4C9440
|
||||
FocusFunc* inputGetFocusFunc()
|
||||
{
|
||||
return _focus_func;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4C9448
|
||||
void inputSetIdleFunc(IdleFunc* func)
|
||||
{
|
||||
_idle_func = func;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4C9450
|
||||
IdleFunc* inputGetIdleFunc()
|
||||
{
|
||||
return _idle_func;
|
||||
}
|
||||
|
||||
// 0x4C9490
|
||||
void buildNormalizedQwertyKeys()
|
||||
{
|
||||
@@ -1251,8 +1343,13 @@ void _GNW95_process_message()
|
||||
case SDL_MOUSEMOTION:
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
// The data is accumulated in SDL itself and will be processed
|
||||
// in `_mouse_info`.
|
||||
case SDL_MOUSEWHEEL:
|
||||
handleMouseEvent(&e);
|
||||
break;
|
||||
case SDL_FINGERDOWN:
|
||||
case SDL_FINGERMOTION:
|
||||
case SDL_FINGERUP:
|
||||
handleTouchEvent(&e);
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
@@ -1324,10 +1421,10 @@ void _GNW95_process_key(KeyboardData* data)
|
||||
{
|
||||
data->key = gNormalizedQwertyKeys[data->key];
|
||||
|
||||
if (_vcr_state == 1) {
|
||||
if (_vcr_terminate_flags & 1) {
|
||||
_vcr_terminated_condition = 2;
|
||||
_vcr_stop();
|
||||
if (gVcrState == VCR_STATE_PLAYING) {
|
||||
if ((gVcrTerminateFlags & VCR_TERMINATE_ON_KEY_PRESS) != 0) {
|
||||
gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_TERMINATED;
|
||||
vcrStop();
|
||||
}
|
||||
} else {
|
||||
STRUCT_6ABF50* ptr = &(_GNW95_key_time_stamps[data->key]);
|
||||
@@ -1346,7 +1443,7 @@ void _GNW95_process_key(KeyboardData* data)
|
||||
void _GNW95_lost_focus()
|
||||
{
|
||||
if (_focus_func != NULL) {
|
||||
_focus_func(0);
|
||||
_focus_func(false);
|
||||
}
|
||||
|
||||
while (!gProgramIsActive) {
|
||||
@@ -1358,7 +1455,7 @@ void _GNW95_lost_focus()
|
||||
}
|
||||
|
||||
if (_focus_func != NULL) {
|
||||
_focus_func(1);
|
||||
_focus_func(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1643,10 +1740,11 @@ void _mouse_info()
|
||||
x = (int)(x * gMouseSensitivity);
|
||||
y = (int)(y * gMouseSensitivity);
|
||||
|
||||
if (_vcr_state == 1) {
|
||||
if (((_vcr_terminate_flags & 4) && buttons) || ((_vcr_terminate_flags & 2) && (x || y))) {
|
||||
_vcr_terminated_condition = 2;
|
||||
_vcr_stop();
|
||||
if (gVcrState == VCR_STATE_PLAYING) {
|
||||
if (((gVcrTerminateFlags & VCR_TERMINATE_ON_MOUSE_PRESS) != 0 && buttons != 0)
|
||||
|| ((gVcrTerminateFlags & VCR_TERMINATE_ON_MOUSE_MOVE) != 0 && (x != 0 || y != 0))) {
|
||||
gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_TERMINATED;
|
||||
vcrStop();
|
||||
return;
|
||||
}
|
||||
x = 0;
|
||||
@@ -1655,6 +1753,16 @@ void _mouse_info()
|
||||
}
|
||||
|
||||
_mouse_simulate_input(x, y, buttons);
|
||||
|
||||
// TODO: Move to `_mouse_simulate_input`.
|
||||
// TODO: Record wheel event in VCR.
|
||||
gMouseWheelX = mouseData.wheelX;
|
||||
gMouseWheelY = mouseData.wheelY;
|
||||
|
||||
if (gMouseWheelX != 0 || gMouseWheelY != 0) {
|
||||
gMouseEvent |= MOUSE_EVENT_WHEEL;
|
||||
_raw_buttons |= MOUSE_EVENT_WHEEL;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4CA698
|
||||
@@ -1665,18 +1773,18 @@ void _mouse_simulate_input(int delta_x, int delta_y, int buttons)
|
||||
}
|
||||
|
||||
if (delta_x || delta_y || buttons != gMouseButtonsState) {
|
||||
if (_vcr_state == 0) {
|
||||
if (_vcr_buffer_index == 4095) {
|
||||
_vcr_dump_buffer();
|
||||
if (gVcrState == 0) {
|
||||
if (_vcr_buffer_index == VCR_BUFFER_CAPACITY - 1) {
|
||||
vcrDump();
|
||||
}
|
||||
|
||||
STRUCT_51E2F0* ptr = &(_vcr_buffer[_vcr_buffer_index]);
|
||||
ptr->type = 3;
|
||||
ptr->field_4 = _vcr_time;
|
||||
ptr->field_8 = _vcr_counter;
|
||||
ptr->dx = delta_x;
|
||||
ptr->dy = delta_y;
|
||||
ptr->buttons = buttons;
|
||||
VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]);
|
||||
vcrEntry->type = VCR_ENTRY_TYPE_MOUSE_EVENT;
|
||||
vcrEntry->time = _vcr_time;
|
||||
vcrEntry->counter = _vcr_counter;
|
||||
vcrEntry->mouseEvent.dx = delta_x;
|
||||
vcrEntry->mouseEvent.dy = delta_y;
|
||||
vcrEntry->mouseEvent.buttons = buttons;
|
||||
|
||||
_vcr_buffer_index++;
|
||||
}
|
||||
@@ -1996,10 +2104,10 @@ int _GNW95_init_mode_ex(int width, int height, int bpp)
|
||||
_zero_mem = _GNW95_zero_vid_mem;
|
||||
_mouse_blit = _GNW95_ShowRect;
|
||||
} else {
|
||||
_zero_mem = NULL;
|
||||
_mouse_blit = _GNW95_MouseShowRect16;
|
||||
_mouse_blit_trans = _GNW95_MouseShowTransRect16;
|
||||
_scr_blit = _GNW95_ShowRect16;
|
||||
_zero_mem = NULL;
|
||||
_mouse_blit = _GNW95_MouseShowRect16;
|
||||
_mouse_blit_trans = _GNW95_MouseShowTransRect16;
|
||||
_scr_blit = _GNW95_ShowRect16;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2036,7 +2144,7 @@ int _GNW95_init_window(int width, int height, bool fullscreen)
|
||||
if (gSdlRenderer == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
if (SDL_RenderSetLogicalSize(gSdlRenderer, width, height) != 0) {
|
||||
goto err;
|
||||
}
|
||||
@@ -2214,7 +2322,7 @@ void directDrawSetPaletteInRange(unsigned char* palette, int start, int count)
|
||||
void directDrawSetPalette(unsigned char* palette)
|
||||
{
|
||||
if (gSdlSurface != NULL && gSdlSurface->format->palette != NULL) {
|
||||
SDL_Color colors[256];
|
||||
SDL_Color colors[256];
|
||||
|
||||
for (int index = 0; index < 256; index++) {
|
||||
colors[index].r = palette[index * 3] << 2;
|
||||
@@ -2251,7 +2359,6 @@ void directDrawSetPalette(unsigned char* palette)
|
||||
windowRefreshAll(&_scr_size);
|
||||
}
|
||||
|
||||
|
||||
if (_update_palette_func != NULL) {
|
||||
_update_palette_func();
|
||||
}
|
||||
@@ -2555,13 +2662,14 @@ int keyboardGetLayout()
|
||||
// TODO: Key type is likely short.
|
||||
void _kb_simulate_key(KeyboardData* data)
|
||||
{
|
||||
if (_vcr_state == 0) {
|
||||
if (_vcr_buffer_index != 4095) {
|
||||
STRUCT_51E2F0* ptr = &(_vcr_buffer[_vcr_buffer_index]);
|
||||
ptr->type = 2;
|
||||
ptr->type_2_field_C = data->key & 0xFFFF;
|
||||
ptr->field_4 = _vcr_time;
|
||||
ptr->field_8 = _vcr_counter;
|
||||
if (gVcrState == 0) {
|
||||
if (_vcr_buffer_index != VCR_BUFFER_CAPACITY - 1) {
|
||||
VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]);
|
||||
vcrEntry->type = VCR_ENTRY_TYPE_KEYBOARD_EVENT;
|
||||
vcrEntry->keyboardEvent.key = data->key & 0xFFFF;
|
||||
vcrEntry->time = _vcr_time;
|
||||
vcrEntry->counter = _vcr_counter;
|
||||
|
||||
_vcr_buffer_index++;
|
||||
}
|
||||
}
|
||||
@@ -4359,9 +4467,9 @@ int keyboardPeekEvent(int index, KeyboardEvent** keyboardEventPtr)
|
||||
}
|
||||
|
||||
// 0x4D2680
|
||||
bool _vcr_record(const char* fileName)
|
||||
bool vcrRecord(const char* fileName)
|
||||
{
|
||||
if (_vcr_state != 2) {
|
||||
if (gVcrState != VCR_STATE_TURNED_OFF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4369,77 +4477,260 @@ bool _vcr_record(const char* fileName)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_vcr_buffer != NULL) {
|
||||
// NOTE: Uninline.
|
||||
if (!vcrInitBuffer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_vcr_buffer = (STRUCT_51E2F0*)internal_malloc(sizeof(*_vcr_buffer) * 4096);
|
||||
if (_vcr_buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_vcr_clear_buffer();
|
||||
|
||||
_vcr_file = fileOpen(fileName, "wb");
|
||||
if (_vcr_file == NULL) {
|
||||
if (_vcr_buffer != NULL) {
|
||||
_vcr_clear_buffer();
|
||||
internal_free(_vcr_buffer);
|
||||
_vcr_buffer = NULL;
|
||||
}
|
||||
gVcrFile = fileOpen(fileName, "wb");
|
||||
if (gVcrFile == NULL) {
|
||||
// NOTE: Uninline.
|
||||
vcrFreeBuffer();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_vcr_registered_atexit == 0) {
|
||||
_vcr_registered_atexit = atexit(_vcr_stop);
|
||||
_vcr_registered_atexit = atexit(vcrStop);
|
||||
}
|
||||
|
||||
STRUCT_51E2F0* entry = &(_vcr_buffer[_vcr_buffer_index]);
|
||||
entry->type = 1;
|
||||
entry->field_4 = 0;
|
||||
entry->field_8 = 0;
|
||||
entry->type_1_field_14 = keyboardGetLayout();
|
||||
VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]);
|
||||
vcrEntry->type = VCR_ENTRY_TYPE_INITIAL_STATE;
|
||||
vcrEntry->time = 0;
|
||||
vcrEntry->counter = 0;
|
||||
vcrEntry->initial.keyboardLayout = keyboardGetLayout();
|
||||
|
||||
while (mouseGetEvent() != 0) {
|
||||
_mouse_info();
|
||||
}
|
||||
|
||||
mouseGetPosition(&(entry->type_1_field_C), &(entry->type_1_field_10));
|
||||
mouseGetPosition(&(vcrEntry->initial.mouseX), &(vcrEntry->initial.mouseY));
|
||||
|
||||
_vcr_counter = 1;
|
||||
_vcr_buffer_index++;
|
||||
_vcr_start_time = _get_time();
|
||||
keyboardReset();
|
||||
_vcr_state = 0;
|
||||
|
||||
gVcrState = VCR_STATE_RECORDING;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4D27EC
|
||||
bool vcrPlay(const char* fileName, unsigned int terminationFlags, VcrPlaybackCompletionCallback* callback)
|
||||
{
|
||||
if (gVcrState != VCR_STATE_TURNED_OFF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fileName == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
if (!vcrInitBuffer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gVcrFile = fileOpen(fileName, "rb");
|
||||
if (gVcrFile == NULL) {
|
||||
// NOTE: Uninline.
|
||||
vcrFreeBuffer();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vcrLoad()) {
|
||||
fileClose(gVcrFile);
|
||||
// NOTE: Uninline.
|
||||
vcrFreeBuffer();
|
||||
return false;
|
||||
}
|
||||
|
||||
while (mouseGetEvent() != 0) {
|
||||
_mouse_info();
|
||||
}
|
||||
|
||||
keyboardReset();
|
||||
|
||||
gVcrRequestedTerminationFlags = terminationFlags;
|
||||
gVcrPlaybackCompletionCallback = callback;
|
||||
gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_COMPLETED;
|
||||
gVcrTerminateFlags = 0;
|
||||
_vcr_counter = 0;
|
||||
_vcr_time = 0;
|
||||
_vcr_start_time = _get_time();
|
||||
gVcrState = VCR_STATE_PLAYING;
|
||||
stru_6AD940.time = 0;
|
||||
stru_6AD940.counter = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4D28F4
|
||||
void _vcr_stop()
|
||||
void vcrStop()
|
||||
{
|
||||
if (_vcr_state == 0 || _vcr_state == 1) {
|
||||
_vcr_state |= 0x80000000;
|
||||
if (gVcrState == VCR_STATE_RECORDING || gVcrState == VCR_STATE_PLAYING) {
|
||||
gVcrState |= VCR_STATE_STOP_REQUESTED;
|
||||
}
|
||||
|
||||
keyboardReset();
|
||||
}
|
||||
|
||||
// 0x4D2918
|
||||
int _vcr_status()
|
||||
int vcrGetState()
|
||||
{
|
||||
return _vcr_state;
|
||||
return gVcrState;
|
||||
}
|
||||
|
||||
// 0x4D2930
|
||||
int _vcr_update()
|
||||
int vcrUpdate()
|
||||
{
|
||||
// TODO: Incomplete.
|
||||
if ((gVcrState & VCR_STATE_STOP_REQUESTED) != 0) {
|
||||
gVcrState &= ~VCR_STATE_STOP_REQUESTED;
|
||||
|
||||
switch (gVcrState) {
|
||||
case VCR_STATE_RECORDING:
|
||||
vcrDump();
|
||||
|
||||
fileClose(gVcrFile);
|
||||
gVcrFile = NULL;
|
||||
|
||||
// NOTE: Uninline.
|
||||
vcrFreeBuffer();
|
||||
|
||||
break;
|
||||
case VCR_STATE_PLAYING:
|
||||
fileClose(gVcrFile);
|
||||
gVcrFile = NULL;
|
||||
|
||||
// NOTE: Uninline.
|
||||
vcrFreeBuffer();
|
||||
|
||||
keyboardSetLayout(gVcrOldKeyboardLayout);
|
||||
|
||||
if (gVcrPlaybackCompletionCallback != NULL) {
|
||||
gVcrPlaybackCompletionCallback(gVcrPlaybackCompletionReason);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
gVcrState = VCR_STATE_TURNED_OFF;
|
||||
}
|
||||
|
||||
switch (gVcrState) {
|
||||
case VCR_STATE_RECORDING:
|
||||
_vcr_counter++;
|
||||
_vcr_time = getTicksSince(_vcr_start_time);
|
||||
if (_vcr_buffer_index == VCR_BUFFER_CAPACITY - 1) {
|
||||
vcrDump();
|
||||
}
|
||||
break;
|
||||
case VCR_STATE_PLAYING:
|
||||
if (_vcr_buffer_index < _vcr_buffer_end || vcrLoad()) {
|
||||
VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]);
|
||||
if (stru_6AD940.counter < vcrEntry->counter) {
|
||||
if (vcrEntry->time > stru_6AD940.time) {
|
||||
unsigned int delay = stru_6AD940.time;
|
||||
delay += (_vcr_counter - stru_6AD940.counter)
|
||||
* (vcrEntry->time - stru_6AD940.time)
|
||||
/ (vcrEntry->counter - stru_6AD940.counter);
|
||||
|
||||
while (getTicksSince(_vcr_start_time) < delay) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_vcr_counter++;
|
||||
|
||||
int rc = 0;
|
||||
while (_vcr_counter >= _vcr_buffer[_vcr_buffer_index].counter) {
|
||||
_vcr_time = getTicksSince(_vcr_start_time);
|
||||
if (_vcr_time > _vcr_buffer[_vcr_buffer_index].time + 5
|
||||
|| _vcr_time < _vcr_buffer[_vcr_buffer_index].time - 5) {
|
||||
_vcr_start_time += _vcr_time - _vcr_buffer[_vcr_buffer_index].time;
|
||||
}
|
||||
|
||||
switch (_vcr_buffer[_vcr_buffer_index].type) {
|
||||
case VCR_ENTRY_TYPE_INITIAL_STATE:
|
||||
gVcrState = VCR_STATE_TURNED_OFF;
|
||||
gVcrOldKeyboardLayout = keyboardGetLayout();
|
||||
keyboardSetLayout(_vcr_buffer[_vcr_buffer_index].initial.keyboardLayout);
|
||||
while (mouseGetEvent() != 0) {
|
||||
_mouse_info();
|
||||
}
|
||||
gVcrState = VCR_ENTRY_TYPE_INITIAL_STATE;
|
||||
mouseHideCursor();
|
||||
_mouse_set_position(_vcr_buffer[_vcr_buffer_index].initial.mouseX, _vcr_buffer[_vcr_buffer_index].initial.mouseY);
|
||||
mouseShowCursor();
|
||||
keyboardReset();
|
||||
gVcrTerminateFlags = gVcrRequestedTerminationFlags;
|
||||
_vcr_start_time = _get_time();
|
||||
_vcr_counter = 0;
|
||||
break;
|
||||
case VCR_ENTRY_TYPE_KEYBOARD_EVENT:
|
||||
if (1) {
|
||||
KeyboardData keyboardData;
|
||||
keyboardData.key = _vcr_buffer[_vcr_buffer_index].keyboardEvent.key;
|
||||
_kb_simulate_key(&keyboardData);
|
||||
}
|
||||
break;
|
||||
case VCR_ENTRY_TYPE_MOUSE_EVENT:
|
||||
rc = 3;
|
||||
_mouse_simulate_input(_vcr_buffer[_vcr_buffer_index].mouseEvent.dx, _vcr_buffer[_vcr_buffer_index].mouseEvent.dy, _vcr_buffer[_vcr_buffer_index].mouseEvent.buttons);
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(&stru_6AD940, &(_vcr_buffer[_vcr_buffer_index]), sizeof(stru_6AD940));
|
||||
_vcr_buffer_index++;
|
||||
}
|
||||
|
||||
return rc;
|
||||
} else {
|
||||
// NOTE: Uninline.
|
||||
vcrStop();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4D2C64
|
||||
bool vcrInitBuffer()
|
||||
{
|
||||
if (_vcr_buffer == NULL) {
|
||||
_vcr_buffer = (VcrEntry*)internal_malloc(sizeof(*_vcr_buffer) * VCR_BUFFER_CAPACITY);
|
||||
if (_vcr_buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
vcrClear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4D2C98
|
||||
bool vcrFreeBuffer()
|
||||
{
|
||||
if (_vcr_buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
vcrClear();
|
||||
|
||||
internal_free(_vcr_buffer);
|
||||
_vcr_buffer = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4D2CD0
|
||||
bool _vcr_clear_buffer()
|
||||
bool vcrClear()
|
||||
{
|
||||
if (_vcr_buffer == NULL) {
|
||||
return false;
|
||||
@@ -4451,81 +4742,104 @@ bool _vcr_clear_buffer()
|
||||
}
|
||||
|
||||
// 0x4D2CF0
|
||||
int _vcr_dump_buffer()
|
||||
bool vcrDump()
|
||||
{
|
||||
if (!_vcr_buffer || !_vcr_file) {
|
||||
return 0;
|
||||
if (_vcr_buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gVcrFile == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int index = 0; index < _vcr_buffer_index; index++) {
|
||||
if (_vcr_save_record(&(_vcr_buffer[index]), _vcr_file)) {
|
||||
_vcr_buffer_index = 0;
|
||||
return 1;
|
||||
if (!vcrWriteEntry(&(_vcr_buffer[index]), gVcrFile)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
// NOTE: Uninline.
|
||||
if (!vcrClear()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4D2D74
|
||||
bool vcrLoad()
|
||||
{
|
||||
if (gVcrFile == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
if (!vcrClear()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (_vcr_buffer_end = 0; _vcr_buffer_end < VCR_BUFFER_CAPACITY; _vcr_buffer_end++) {
|
||||
if (!vcrReadEntry(&(_vcr_buffer[_vcr_buffer_end]), gVcrFile)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_vcr_buffer_end == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4D2E00
|
||||
bool _vcr_save_record(STRUCT_51E2F0* ptr, File* stream)
|
||||
bool vcrWriteEntry(VcrEntry* vcrEntry, File* stream)
|
||||
{
|
||||
if (_db_fwriteLong(stream, ptr->type) == -1) goto err;
|
||||
if (_db_fwriteLong(stream, ptr->field_4) == -1) goto err;
|
||||
if (_db_fwriteLong(stream, ptr->field_8) == -1) goto err;
|
||||
|
||||
switch (ptr->type) {
|
||||
case 1:
|
||||
if (_db_fwriteLong(stream, ptr->type_1_field_C) == -1) goto err;
|
||||
if (_db_fwriteLong(stream, ptr->type_1_field_10) == -1) goto err;
|
||||
if (_db_fwriteLong(stream, ptr->type_1_field_14) == -1) goto err;
|
||||
if (fileWriteUInt32(stream, vcrEntry->type) == -1) return false;
|
||||
if (fileWriteUInt32(stream, vcrEntry->time) == -1) return false;
|
||||
if (fileWriteUInt32(stream, vcrEntry->counter) == -1) return false;
|
||||
|
||||
switch (vcrEntry->type) {
|
||||
case VCR_ENTRY_TYPE_INITIAL_STATE:
|
||||
if (fileWriteInt32(stream, vcrEntry->initial.mouseX) == -1) return false;
|
||||
if (fileWriteInt32(stream, vcrEntry->initial.mouseY) == -1) return false;
|
||||
if (fileWriteInt32(stream, vcrEntry->initial.keyboardLayout) == -1) return false;
|
||||
return true;
|
||||
case 2:
|
||||
if (fileWriteInt16(stream, ptr->type_2_field_C) == -1) goto err;
|
||||
|
||||
case VCR_ENTRY_TYPE_KEYBOARD_EVENT:
|
||||
if (fileWriteInt16(stream, vcrEntry->keyboardEvent.key) == -1) return false;
|
||||
return true;
|
||||
case 3:
|
||||
if (_db_fwriteLong(stream, ptr->dx) == -1) goto err;
|
||||
if (_db_fwriteLong(stream, ptr->dy) == -1) goto err;
|
||||
if (_db_fwriteLong(stream, ptr->buttons) == -1) goto err;
|
||||
|
||||
case VCR_ENTRY_TYPE_MOUSE_EVENT:
|
||||
if (fileWriteInt32(stream, vcrEntry->mouseEvent.dx) == -1) return false;
|
||||
if (fileWriteInt32(stream, vcrEntry->mouseEvent.dy) == -1) return false;
|
||||
if (fileWriteInt32(stream, vcrEntry->mouseEvent.buttons) == -1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
err:
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x4D2EE4
|
||||
bool _vcr_load_record(STRUCT_51E2F0* ptr, File* stream)
|
||||
bool vcrReadEntry(VcrEntry* vcrEntry, File* stream)
|
||||
{
|
||||
if (_db_freadInt(stream, &(ptr->type)) == -1) goto err;
|
||||
if (_db_freadInt(stream, &(ptr->field_4)) == -1) goto err;
|
||||
if (_db_freadInt(stream, &(ptr->field_8)) == -1) goto err;
|
||||
|
||||
switch (ptr->type) {
|
||||
case 1:
|
||||
if (_db_freadInt(stream, &(ptr->type_1_field_C)) == -1) goto err;
|
||||
if (_db_freadInt(stream, &(ptr->type_1_field_10)) == -1) goto err;
|
||||
if (_db_freadInt(stream, &(ptr->type_1_field_14)) == -1) goto err;
|
||||
if (fileReadUInt32(stream, &(vcrEntry->type)) == -1) return false;
|
||||
if (fileReadUInt32(stream, &(vcrEntry->time)) == -1) return false;
|
||||
if (fileReadUInt32(stream, &(vcrEntry->counter)) == -1) return false;
|
||||
|
||||
switch (vcrEntry->type) {
|
||||
case VCR_ENTRY_TYPE_INITIAL_STATE:
|
||||
if (fileReadInt32(stream, &(vcrEntry->initial.mouseX)) == -1) return false;
|
||||
if (fileReadInt32(stream, &(vcrEntry->initial.mouseY)) == -1) return false;
|
||||
if (fileReadInt32(stream, &(vcrEntry->initial.keyboardLayout)) == -1) return false;
|
||||
return true;
|
||||
case 2:
|
||||
if (fileReadInt16(stream, &(ptr->type_2_field_C)) == -1) goto err;
|
||||
|
||||
case VCR_ENTRY_TYPE_KEYBOARD_EVENT:
|
||||
if (fileReadInt16(stream, &(vcrEntry->keyboardEvent.key)) == -1) return false;
|
||||
return true;
|
||||
case 3:
|
||||
if (_db_freadInt(stream, &(ptr->dx)) == -1) goto err;
|
||||
if (_db_freadInt(stream, &(ptr->dy)) == -1) goto err;
|
||||
if (_db_freadInt(stream, &(ptr->buttons)) == -1) goto err;
|
||||
|
||||
case VCR_ENTRY_TYPE_MOUSE_EVENT:
|
||||
if (fileReadInt32(stream, &(vcrEntry->mouseEvent.dx)) == -1) return false;
|
||||
if (fileReadInt32(stream, &(vcrEntry->mouseEvent.dy)) == -1) return false;
|
||||
if (fileReadInt32(stream, &(vcrEntry->mouseEvent.buttons)) == -1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
err:
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4574,3 +4888,31 @@ bool mouseHitTestInWindow(int win, int left, int top, int right, int bottom)
|
||||
|
||||
return _mouse_click_in(left, top, right, bottom);
|
||||
}
|
||||
|
||||
void mouseGetWheel(int* x, int* y)
|
||||
{
|
||||
*x = gMouseWheelX;
|
||||
*y = gMouseWheelY;
|
||||
}
|
||||
|
||||
void convertMouseWheelToArrowKey(int* keyCodePtr)
|
||||
{
|
||||
if (*keyCodePtr == -1) {
|
||||
if ((mouseGetEvent() & MOUSE_EVENT_WHEEL) != 0) {
|
||||
int wheelX;
|
||||
int wheelY;
|
||||
mouseGetWheel(&wheelX, &wheelY);
|
||||
|
||||
if (wheelY > 0) {
|
||||
*keyCodePtr = KEY_ARROW_UP;
|
||||
} else if (wheelY < 0) {
|
||||
*keyCodePtr = KEY_ARROW_DOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void idleImpl()
|
||||
{
|
||||
SDL_Delay(125);
|
||||
}
|
||||
|
||||
126
src/core.h
@@ -1,13 +1,13 @@
|
||||
#ifndef CORE_H
|
||||
#define CORE_H
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "dinput.h"
|
||||
#include "geometry.h"
|
||||
#include "window.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#define MOUSE_DEFAULT_CURSOR_WIDTH 8
|
||||
#define MOUSE_DEFAULT_CURSOR_HEIGHT 8
|
||||
#define MOUSE_DEFAULT_CURSOR_SIZE (MOUSE_DEFAULT_CURSOR_WIDTH * MOUSE_DEFAULT_CURSOR_HEIGHT)
|
||||
@@ -26,6 +26,7 @@
|
||||
#define MOUSE_EVENT_ANY_BUTTON_UP (MOUSE_EVENT_LEFT_BUTTON_UP | MOUSE_EVENT_RIGHT_BUTTON_UP)
|
||||
#define MOUSE_EVENT_LEFT_BUTTON_DOWN_REPEAT (MOUSE_EVENT_LEFT_BUTTON_DOWN | MOUSE_EVENT_LEFT_BUTTON_REPEAT)
|
||||
#define MOUSE_EVENT_RIGHT_BUTTON_DOWN_REPEAT (MOUSE_EVENT_RIGHT_BUTTON_DOWN | MOUSE_EVENT_RIGHT_BUTTON_REPEAT)
|
||||
#define MOUSE_EVENT_WHEEL 0x40
|
||||
|
||||
#define BUTTON_REPEAT_TIME 250
|
||||
|
||||
@@ -360,6 +361,44 @@ typedef enum KeyboardLayout {
|
||||
KEYBOARD_LAYOUT_SPANISH,
|
||||
} KeyboardLayout;
|
||||
|
||||
#define VCR_BUFFER_CAPACITY 4096
|
||||
|
||||
typedef enum VcrState {
|
||||
VCR_STATE_RECORDING,
|
||||
VCR_STATE_PLAYING,
|
||||
VCR_STATE_TURNED_OFF,
|
||||
} VcrState;
|
||||
|
||||
#define VCR_STATE_STOP_REQUESTED 0x80000000
|
||||
|
||||
typedef enum VcrTerminationFlags {
|
||||
// Specifies that VCR playback should stop if any key is pressed.
|
||||
VCR_TERMINATE_ON_KEY_PRESS = 0x01,
|
||||
|
||||
// Specifies that VCR playback should stop if mouse is mouved.
|
||||
VCR_TERMINATE_ON_MOUSE_MOVE = 0x02,
|
||||
|
||||
// Specifies that VCR playback should stop if any mouse button is pressed.
|
||||
VCR_TERMINATE_ON_MOUSE_PRESS = 0x04,
|
||||
} VcrTerminationFlags;
|
||||
|
||||
typedef enum VcrPlaybackCompletionReason {
|
||||
VCR_PLAYBACK_COMPLETION_REASON_NONE = 0,
|
||||
|
||||
// Indicates that VCR playback completed normally.
|
||||
VCR_PLAYBACK_COMPLETION_REASON_COMPLETED = 1,
|
||||
|
||||
// Indicates that VCR playback terminated according to termination flags.
|
||||
VCR_PLAYBACK_COMPLETION_REASON_TERMINATED = 2,
|
||||
} VcrPlaybackCompletionReason;
|
||||
|
||||
typedef enum VcrEntryType {
|
||||
VCR_ENTRY_TYPE_NONE = 0,
|
||||
VCR_ENTRY_TYPE_INITIAL_STATE = 1,
|
||||
VCR_ENTRY_TYPE_KEYBOARD_EVENT = 2,
|
||||
VCR_ENTRY_TYPE_MOUSE_EVENT = 3,
|
||||
} VcrEntryType;
|
||||
|
||||
typedef struct STRUCT_6ABF50 {
|
||||
// Time when appropriate key was pressed down or -1 if it's up.
|
||||
int tick;
|
||||
@@ -375,7 +414,9 @@ typedef struct InputEvent {
|
||||
int mouseY;
|
||||
} InputEvent;
|
||||
|
||||
typedef void TickerProc();
|
||||
typedef void(IdleFunc)();
|
||||
typedef void(FocusFunc)(bool focus);
|
||||
typedef void(TickerProc)();
|
||||
|
||||
typedef struct TickerListNode {
|
||||
int flags;
|
||||
@@ -383,26 +424,26 @@ typedef struct TickerListNode {
|
||||
struct TickerListNode* next;
|
||||
} TickerListNode;
|
||||
|
||||
typedef struct STRUCT_51E2F0 {
|
||||
int type;
|
||||
int field_4;
|
||||
int field_8;
|
||||
typedef struct VcrEntry {
|
||||
unsigned int type;
|
||||
unsigned int time;
|
||||
unsigned int counter;
|
||||
union {
|
||||
struct {
|
||||
int type_1_field_C; // mouse x
|
||||
int type_1_field_10; // mouse y
|
||||
int type_1_field_14; // keyboard layout
|
||||
};
|
||||
int mouseX;
|
||||
int mouseY;
|
||||
int keyboardLayout;
|
||||
} initial;
|
||||
struct {
|
||||
short type_2_field_C;
|
||||
};
|
||||
short key;
|
||||
} keyboardEvent;
|
||||
struct {
|
||||
int dx;
|
||||
int dy;
|
||||
int buttons;
|
||||
};
|
||||
} mouseEvent;
|
||||
};
|
||||
} STRUCT_51E2F0;
|
||||
} VcrEntry;
|
||||
|
||||
typedef struct LogicalKeyEntry {
|
||||
short field_0;
|
||||
@@ -420,9 +461,10 @@ typedef struct KeyboardEvent {
|
||||
|
||||
typedef int(PauseHandler)();
|
||||
typedef int(ScreenshotHandler)(int width, int height, unsigned char* buffer, unsigned char* palette);
|
||||
typedef void(VcrPlaybackCompletionCallback)(int reason);
|
||||
|
||||
extern void (*_idle_func)();
|
||||
extern void (*_focus_func)(int);
|
||||
extern IdleFunc* _idle_func;
|
||||
extern FocusFunc* _focus_func;
|
||||
extern int gKeyboardKeyRepeatRate;
|
||||
extern int gKeyboardKeyRepeatDelay;
|
||||
extern bool _keyboard_hooked;
|
||||
@@ -448,17 +490,20 @@ extern int gKeyboardEventQueueReadIndex;
|
||||
extern short word_51E2E8;
|
||||
extern int gModifierKeysState;
|
||||
extern int (*_kb_scan_to_ascii)();
|
||||
extern STRUCT_51E2F0* _vcr_buffer;
|
||||
extern VcrEntry* _vcr_buffer;
|
||||
extern int _vcr_buffer_index;
|
||||
extern int _vcr_state;
|
||||
extern int _vcr_time;
|
||||
extern int _vcr_counter;
|
||||
extern int _vcr_terminate_flags;
|
||||
extern int _vcr_terminated_condition;
|
||||
extern int _vcr_start_time;
|
||||
extern unsigned int gVcrState;
|
||||
extern unsigned int _vcr_time;
|
||||
extern unsigned int _vcr_counter;
|
||||
extern unsigned int gVcrTerminateFlags;
|
||||
extern int gVcrPlaybackCompletionReason;
|
||||
extern unsigned int _vcr_start_time;
|
||||
extern int _vcr_registered_atexit;
|
||||
extern File* _vcr_file;
|
||||
extern File* gVcrFile;
|
||||
extern int _vcr_buffer_end;
|
||||
extern VcrPlaybackCompletionCallback* gVcrPlaybackCompletionCallback;
|
||||
extern unsigned int gVcrRequestedTerminationFlags;
|
||||
extern int gVcrOldKeyboardLayout;
|
||||
|
||||
extern int gNormalizedQwertyKeys[SDL_NUM_SCANCODES];
|
||||
extern InputEvent gInputEventQueue[40];
|
||||
@@ -520,6 +565,7 @@ extern unsigned int _kb_idle_start_time;
|
||||
extern KeyboardEvent gLastKeyboardEvent;
|
||||
extern int gKeyboardLayout;
|
||||
extern unsigned char gPressedPhysicalKeysCount;
|
||||
extern VcrEntry stru_6AD940;
|
||||
|
||||
extern SDL_Window* gSdlWindow;
|
||||
extern SDL_Surface* gSdlSurface;
|
||||
@@ -552,6 +598,14 @@ void coreDelay(unsigned int ms);
|
||||
unsigned int getTicksSince(unsigned int a1);
|
||||
unsigned int getTicksBetween(unsigned int a1, unsigned int a2);
|
||||
unsigned int _get_bk_time();
|
||||
void inputSetKeyboardKeyRepeatRate(int value);
|
||||
int inputGetKeyboardKeyRepeatRate();
|
||||
void inputSetKeyboardKeyRepeatDelay(int value);
|
||||
int inputGetKeyboardKeyRepeatDelay();
|
||||
void inputSetFocusFunc(FocusFunc* func);
|
||||
FocusFunc* inputGetFocusFunc();
|
||||
void inputSetIdleFunc(IdleFunc* func);
|
||||
IdleFunc* inputGetIdleFunc();
|
||||
void buildNormalizedQwertyKeys();
|
||||
int _GNW95_input_init();
|
||||
void _GNW95_process_message();
|
||||
@@ -621,19 +675,25 @@ void keyboardBuildItalianConfiguration();
|
||||
void keyboardBuildSpanishConfiguration();
|
||||
void _kb_init_lock_status();
|
||||
int keyboardPeekEvent(int index, KeyboardEvent** keyboardEventPtr);
|
||||
bool _vcr_record(const char* fileName);
|
||||
void _vcr_stop();
|
||||
int _vcr_status();
|
||||
int _vcr_update();
|
||||
bool _vcr_clear_buffer();
|
||||
int _vcr_dump_buffer();
|
||||
bool _vcr_save_record(STRUCT_51E2F0* ptr, File* stream);
|
||||
bool _vcr_load_record(STRUCT_51E2F0* ptr, File* stream);
|
||||
bool vcrRecord(const char* fileName);
|
||||
bool vcrPlay(const char* fileName, unsigned int terminationFlags, VcrPlaybackCompletionCallback* callback);
|
||||
void vcrStop();
|
||||
int vcrGetState();
|
||||
int vcrUpdate();
|
||||
bool vcrInitBuffer();
|
||||
bool vcrFreeBuffer();
|
||||
bool vcrClear();
|
||||
bool vcrDump();
|
||||
bool vcrLoad();
|
||||
bool vcrWriteEntry(VcrEntry* ptr, File* stream);
|
||||
bool vcrReadEntry(VcrEntry* ptr, File* stream);
|
||||
|
||||
int screenGetWidth();
|
||||
int screenGetHeight();
|
||||
int screenGetVisibleHeight();
|
||||
void mouseGetPositionInWindow(int win, int* x, int* y);
|
||||
bool mouseHitTestInWindow(int win, int left, int top, int right, int bottom);
|
||||
void mouseGetWheel(int* x, int* y);
|
||||
void convertMouseWheelToArrowKey(int* keyCodePtr);
|
||||
|
||||
#endif /* CORE_H */
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "credits.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
@@ -16,8 +18,6 @@
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define CREDITS_WINDOW_WIDTH (640)
|
||||
#define CREDITS_WINDOW_HEIGHT (480)
|
||||
#define CREDITS_WINDOW_SCROLLING_DELAY (38)
|
||||
|
||||
130
src/critter.cc
@@ -1,5 +1,8 @@
|
||||
#include "critter.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "animation.h"
|
||||
#include "art.h"
|
||||
#include "character_editor.h"
|
||||
@@ -26,10 +29,7 @@
|
||||
#include "stat.h"
|
||||
#include "tile.h"
|
||||
#include "trait.h"
|
||||
#include "world_map.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "worldmap.h"
|
||||
|
||||
// Maximum length of dude's name length.
|
||||
#define DUDE_NAME_MAX_LENGTH (32)
|
||||
@@ -68,6 +68,7 @@ typedef enum RadiationLevel {
|
||||
} RadiationLevel;
|
||||
|
||||
static int _get_rad_damage_level(Object* obj, void* data);
|
||||
static int critter_kill_count_clear();
|
||||
static int _critterClearObjDrugs(Object* obj, void* data);
|
||||
|
||||
// 0x50141C
|
||||
@@ -159,7 +160,8 @@ int critterInit()
|
||||
{
|
||||
dudeResetName();
|
||||
|
||||
memset(gKillsByType, 0, sizeof(gKillsByType));
|
||||
// NOTE: Uninline;
|
||||
critter_kill_count_clear();
|
||||
|
||||
if (!messageListInit(&gCritterMessageList)) {
|
||||
debugPrint("\nError: Initing critter name message file!");
|
||||
@@ -181,7 +183,9 @@ int critterInit()
|
||||
void critterReset()
|
||||
{
|
||||
dudeResetName();
|
||||
memset(gKillsByType, 0, sizeof(gKillsByType));
|
||||
|
||||
// NOTE: Uninline;
|
||||
critter_kill_count_clear();
|
||||
}
|
||||
|
||||
// 0x42D004
|
||||
@@ -276,18 +280,18 @@ void dudeResetName()
|
||||
// 0x42D18C
|
||||
int critterGetHitPoints(Object* critter)
|
||||
{
|
||||
return (critter->pid >> 24) == OBJ_TYPE_CRITTER ? critter->data.critter.hp : 0;
|
||||
return PID_TYPE(critter->pid) == OBJ_TYPE_CRITTER ? critter->data.critter.hp : 0;
|
||||
}
|
||||
|
||||
// 0x42D1A4
|
||||
int critterAdjustHitPoints(Object* critter, int a2)
|
||||
int critterAdjustHitPoints(Object* critter, int hp)
|
||||
{
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int maximumHp = critterGetStat(critter, STAT_MAXIMUM_HIT_POINTS);
|
||||
int newHp = critter->data.critter.hp + a2;
|
||||
int newHp = critter->data.critter.hp + hp;
|
||||
|
||||
critter->data.critter.hp = newHp;
|
||||
if (maximumHp >= newHp) {
|
||||
@@ -304,7 +308,7 @@ int critterAdjustHitPoints(Object* critter, int a2)
|
||||
// 0x42D1F8
|
||||
int critterGetPoison(Object* critter)
|
||||
{
|
||||
return (critter->pid >> 24) == OBJ_TYPE_CRITTER ? critter->data.critter.poison : 0;
|
||||
return PID_TYPE(critter->pid) == OBJ_TYPE_CRITTER ? critter->data.critter.poison : 0;
|
||||
}
|
||||
|
||||
// Adjust critter's current poison by specified amount.
|
||||
@@ -396,7 +400,7 @@ int poisonEventProcess(Object* obj, void* data)
|
||||
// 0x42D38C
|
||||
int critterGetRadiation(Object* obj)
|
||||
{
|
||||
return (obj->pid >> 24) == OBJ_TYPE_CRITTER ? obj->data.critter.radiation : 0;
|
||||
return PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER ? obj->data.critter.radiation : 0;
|
||||
}
|
||||
|
||||
// 0x42D3A4
|
||||
@@ -416,7 +420,7 @@ int critterAdjustRadiation(Object* obj, int amount)
|
||||
}
|
||||
|
||||
if (amount > 0) {
|
||||
proto->critter.data.flags |= 0x02;
|
||||
proto->critter.data.flags |= CRITTER_FLAG_0x2;
|
||||
}
|
||||
|
||||
if (amount > 0) {
|
||||
@@ -483,7 +487,7 @@ int _critter_check_rads(Object* obj)
|
||||
|
||||
Proto* proto;
|
||||
protoGetProto(obj->pid, &proto);
|
||||
if ((proto->critter.data.flags & 0x02) == 0) {
|
||||
if ((proto->critter.data.flags & CRITTER_FLAG_0x2) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -521,10 +525,10 @@ int _critter_check_rads(Object* obj)
|
||||
|
||||
radiationEvent->radiationLevel = radiationLevel;
|
||||
radiationEvent->isHealing = 0;
|
||||
queueAddEvent(36000 * randomBetween(4, 18), obj, radiationEvent, EVENT_TYPE_RADIATION);
|
||||
queueAddEvent(GAME_TIME_TICKS_PER_HOUR * randomBetween(4, 18), obj, radiationEvent, EVENT_TYPE_RADIATION);
|
||||
}
|
||||
|
||||
proto->critter.data.flags &= ~(0x02);
|
||||
proto->critter.data.flags &= ~(CRITTER_FLAG_0x2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -568,6 +572,13 @@ void _process_rads(Object* obj, int radiationLevel, bool isHealing)
|
||||
if (obj == gDude) {
|
||||
// Radiation level message, higher is worse.
|
||||
messageListItem.num = 1000 + radiationLevelIndex;
|
||||
|
||||
// SFALL: Fix radiation message when removing radiation effects.
|
||||
if (isHealing) {
|
||||
// You feel better.
|
||||
messageListItem.num = 3003;
|
||||
}
|
||||
|
||||
if (messageListGetItem(&gMiscMessageList, &messageListItem)) {
|
||||
displayMonitorAddMessage(messageListItem.text);
|
||||
}
|
||||
@@ -579,15 +590,18 @@ void _process_rads(Object* obj, int radiationLevel, bool isHealing)
|
||||
critterSetBonusStat(obj, gRadiationEffectStats[effect], value);
|
||||
}
|
||||
|
||||
if ((obj->data.critter.combat.results & DAM_DEAD) == 0) {
|
||||
// Loop thru effects affecting primary stats. If any of the primary stat
|
||||
// dropped below minimal value, kill it.
|
||||
for (int effect = 0; effect < RADIATION_EFFECT_PRIMARY_STAT_COUNT; effect++) {
|
||||
int base = critterGetBaseStatWithTraitModifier(obj, gRadiationEffectStats[effect]);
|
||||
int bonus = critterGetBonusStat(obj, gRadiationEffectStats[effect]);
|
||||
if (base + bonus < PRIMARY_STAT_MIN) {
|
||||
critterKill(obj, -1, 1);
|
||||
break;
|
||||
// SFALL: Prevent death when removing radiation effects.
|
||||
if (!isHealing) {
|
||||
if ((obj->data.critter.combat.results & DAM_DEAD) == 0) {
|
||||
// Loop thru effects affecting primary stats. If any of the primary stat
|
||||
// dropped below minimal value, kill it.
|
||||
for (int effect = 0; effect < RADIATION_EFFECT_PRIMARY_STAT_COUNT; effect++) {
|
||||
int base = critterGetBaseStatWithTraitModifier(obj, gRadiationEffectStats[effect]);
|
||||
int bonus = critterGetBonusStat(obj, gRadiationEffectStats[effect]);
|
||||
if (base + bonus < PRIMARY_STAT_MIN) {
|
||||
critterKill(obj, -1, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -597,7 +611,8 @@ void _process_rads(Object* obj, int radiationLevel, bool isHealing)
|
||||
// You have died from radiation sickness.
|
||||
messageListItem.num = 1006;
|
||||
if (messageListGetItem(&gMiscMessageList, &messageListItem)) {
|
||||
displayMonitorAddMessage(messageListItem.text);
|
||||
// SFALL: Display a pop-up message box about death from radiation.
|
||||
gameShowDeathDialog(messageListItem.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -657,7 +672,7 @@ int radiationEventWrite(File* stream, void* data)
|
||||
// 0x42D82C
|
||||
int critterGetDamageType(Object* obj)
|
||||
{
|
||||
if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -669,6 +684,15 @@ int critterGetDamageType(Object* obj)
|
||||
return proto->critter.data.damageType;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x42D860
|
||||
static int critter_kill_count_clear()
|
||||
{
|
||||
memset(gKillsByType, 0, sizeof(gKillsByType));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x42D878
|
||||
int killsIncByType(int killType)
|
||||
{
|
||||
@@ -723,7 +747,7 @@ int critterGetKillType(Object* obj)
|
||||
return KILL_TYPE_MAN;
|
||||
}
|
||||
|
||||
if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -766,7 +790,7 @@ char* killTypeGetDescription(int killType)
|
||||
// 0x42D9F4
|
||||
int _critter_heal_hours(Object* critter, int a2)
|
||||
{
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -788,7 +812,7 @@ static int _critterClearObjDrugs(Object* obj, void* data)
|
||||
// 0x42DA64
|
||||
void critterKill(Object* critter, int anim, bool a3)
|
||||
{
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -800,20 +824,20 @@ void critterKill(Object* critter, int anim, bool a3)
|
||||
bool shouldChangeFid = false;
|
||||
int fid;
|
||||
if (_critter_is_prone(critter)) {
|
||||
int current = (critter->fid & 0xFF0000) >> 16;
|
||||
int current = FID_ANIM_TYPE(critter->fid);
|
||||
if (current == ANIM_FALL_BACK || current == ANIM_FALL_FRONT) {
|
||||
bool back = false;
|
||||
if (current == ANIM_FALL_BACK) {
|
||||
back = true;
|
||||
} else {
|
||||
fid = buildFid(1, critter->fid & 0xFFF, ANIM_FALL_FRONT_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, ANIM_FALL_FRONT_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
if (!artExists(fid)) {
|
||||
back = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (back) {
|
||||
fid = buildFid(1, critter->fid & 0xFFF, ANIM_FALL_BACK_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, ANIM_FALL_BACK_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
}
|
||||
|
||||
shouldChangeFid = true;
|
||||
@@ -828,12 +852,12 @@ void critterKill(Object* critter, int anim, bool a3)
|
||||
anim = LAST_SF_DEATH_ANIM;
|
||||
}
|
||||
|
||||
fid = buildFid(1, critter->fid & 0xFFF, anim, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, anim, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
_obj_fix_violence_settings(&fid);
|
||||
if (!artExists(fid)) {
|
||||
debugPrint("\nError: Critter Kill: Can't match fid!");
|
||||
|
||||
fid = buildFid(1, critter->fid & 0xFFF, ANIM_FALL_BACK_BLOOD_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, ANIM_FALL_BACK_BLOOD_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
_obj_fix_violence_settings(&fid);
|
||||
}
|
||||
|
||||
@@ -850,7 +874,7 @@ void critterKill(Object* critter, int anim, bool a3)
|
||||
rectUnion(&updatedRect, &tempRect, &updatedRect);
|
||||
}
|
||||
|
||||
if (!_critter_flag_check(critter->pid, 2048)) {
|
||||
if (!_critter_flag_check(critter->pid, CRITTER_FLAG_0x800)) {
|
||||
critter->flags |= OBJECT_NO_BLOCK;
|
||||
_obj_toggle_flat(critter, &tempRect);
|
||||
}
|
||||
@@ -873,7 +897,7 @@ void critterKill(Object* critter, int anim, bool a3)
|
||||
_critterClearObj = critter;
|
||||
_queue_clear_type(EVENT_TYPE_DRUG, _critterClearObjDrugs);
|
||||
|
||||
_item_destroy_all_hidden(critter);
|
||||
itemDestroyAllHidden(critter);
|
||||
|
||||
if (a3) {
|
||||
tileWindowRefreshRect(&updatedRect, elevation);
|
||||
@@ -902,7 +926,7 @@ bool critterIsActive(Object* critter)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -924,7 +948,7 @@ bool critterIsDead(Object* critter)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -946,7 +970,7 @@ bool critterIsCrippled(Object* critter)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -960,15 +984,15 @@ bool _critter_is_prone(Object* critter)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int anim = (critter->fid & 0xFF0000) >> 16;
|
||||
int anim = FID_ANIM_TYPE(critter->fid);
|
||||
|
||||
return (critter->data.critter.combat.results & (DAM_KNOCKED_OUT | DAM_KNOCKED_DOWN)) != 0
|
||||
|| anim >= FIRST_KNOCKDOWN_AND_DEATH_ANIM && anim <= LAST_KNOCKDOWN_AND_DEATH_ANIM
|
||||
|| anim >= FIRST_SF_DEATH_ANIM && anim <= LAST_SF_DEATH_ANIM;
|
||||
|| (anim >= FIRST_KNOCKDOWN_AND_DEATH_ANIM && anim <= LAST_KNOCKDOWN_AND_DEATH_ANIM)
|
||||
|| (anim >= FIRST_SF_DEATH_ANIM && anim <= LAST_SF_DEATH_ANIM);
|
||||
}
|
||||
|
||||
// critter_body_type
|
||||
@@ -980,7 +1004,7 @@ int critterGetBodyType(Object* critter)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1236,7 +1260,7 @@ int knockoutEventProcess(Object* obj, void* data)
|
||||
// 0x42E460
|
||||
int _critter_wake_clear(Object* obj, void* data)
|
||||
{
|
||||
if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1246,7 +1270,7 @@ int _critter_wake_clear(Object* obj, void* data)
|
||||
|
||||
obj->data.critter.combat.results &= ~(DAM_KNOCKED_OUT | DAM_KNOCKED_DOWN);
|
||||
|
||||
int fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, ANIM_STAND, (obj->fid & 0xF000) >> 12, obj->rotation + 1);
|
||||
int fid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, ANIM_STAND, (obj->fid & 0xF000) >> 12, obj->rotation + 1);
|
||||
objectSetFid(obj, fid, 0);
|
||||
|
||||
return 0;
|
||||
@@ -1259,12 +1283,12 @@ int _critter_set_who_hit_me(Object* a1, Object* a2)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a2 != NULL && ((a2->fid & 0xF000000) >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (a2 != NULL && FID_TYPE(a2->fid) != OBJ_TYPE_CRITTER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((a1->pid >> 24) == OBJ_TYPE_CRITTER) {
|
||||
if (a2 == NULL || a1->data.critter.combat.team != a2->data.critter.combat.team || statRoll(a1, STAT_INTELLIGENCE, -1, NULL) < 2 && (!objectIsPartyMember(a1) || !objectIsPartyMember(a2))) {
|
||||
if (PID_TYPE(a1->pid) == OBJ_TYPE_CRITTER) {
|
||||
if (a2 == NULL || a1->data.critter.combat.team != a2->data.critter.combat.team || (statRoll(a1, STAT_INTELLIGENCE, -1, NULL) < 2 && (!objectIsPartyMember(a1) || !objectIsPartyMember(a2)))) {
|
||||
a1->data.critter.combat.whoHitMe = a2;
|
||||
if (a2 == gDude) {
|
||||
reactionSetValue(a1, -3);
|
||||
@@ -1279,7 +1303,7 @@ int _critter_set_who_hit_me(Object* a1, Object* a2)
|
||||
bool _critter_can_obj_dude_rest()
|
||||
{
|
||||
bool v1 = false;
|
||||
if (!_wmMapCanRestHere(gElevation)) {
|
||||
if (!wmMapCanRestHere(gElevation)) {
|
||||
v1 = true;
|
||||
}
|
||||
|
||||
@@ -1319,7 +1343,7 @@ bool _critter_can_obj_dude_rest()
|
||||
// 0x42E62C
|
||||
int critterGetMovementPointCostAdjustedForCrippledLegs(Object* critter, int actionPoints)
|
||||
{
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1358,7 +1382,7 @@ bool _critter_flag_check(int pid, int flag)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(pid) != OBJ_TYPE_CRITTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ void critterProtoDataCopy(CritterProtoData* dest, CritterProtoData* src);
|
||||
int dudeSetName(const char* name);
|
||||
void dudeResetName();
|
||||
int critterGetHitPoints(Object* critter);
|
||||
int critterAdjustHitPoints(Object* critter, int amount);
|
||||
int critterAdjustHitPoints(Object* critter, int hp);
|
||||
int critterGetPoison(Object* critter);
|
||||
int critterAdjustPoison(Object* obj, int amount);
|
||||
int poisonEventProcess(Object* obj, void* data);
|
||||
|
||||
191
src/datafile.cc
@@ -1,10 +1,195 @@
|
||||
#include "datafile.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "color.h"
|
||||
#include "db.h"
|
||||
#include "memory_manager.h"
|
||||
#include "pcx.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
// 0x5184AC
|
||||
DatafileLoader* gDatafileLoader = NULL;
|
||||
|
||||
// 0x5184B0
|
||||
DatafileNameMangler* gDatafileNameMangler = datafileDefaultNameManglerImpl;
|
||||
|
||||
// 0x56D7E0
|
||||
unsigned char _pal[768];
|
||||
unsigned char gDatafilePalette[768];
|
||||
|
||||
// 0x42EE70
|
||||
char* datafileDefaultNameManglerImpl(char* path)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x42EE74
|
||||
void datafileSetNameMangler(DatafileNameMangler* mangler)
|
||||
{
|
||||
gDatafileNameMangler = mangler;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x42EE7C
|
||||
void datafileSetLoader(DatafileLoader* loader)
|
||||
{
|
||||
gDatafileLoader = loader;
|
||||
}
|
||||
|
||||
// 0x42EE84
|
||||
void sub_42EE84(unsigned char* data, unsigned char* palette, int width, int height)
|
||||
{
|
||||
unsigned char indexedPalette[256];
|
||||
|
||||
indexedPalette[0] = 0;
|
||||
for (int index = 1; index < 256; index++) {
|
||||
// TODO: Check.
|
||||
int r = palette[index * 3 + 2] >> 3;
|
||||
int g = palette[index * 3 + 1] >> 3;
|
||||
int b = palette[index * 3] >> 3;
|
||||
int colorTableIndex = (r << 10) | (g << 5) | b;
|
||||
indexedPalette[index] = _colorTable[colorTableIndex];
|
||||
}
|
||||
|
||||
int size = width * height;
|
||||
for (int index = 0; index < size; index++) {
|
||||
data[index] = indexedPalette[data[index]];
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x42EEF8
|
||||
void sub_42EEF8(unsigned char* data, unsigned char* palette, int width, int height)
|
||||
{
|
||||
unsigned char indexedPalette[256];
|
||||
|
||||
indexedPalette[0] = 0;
|
||||
for (int index = 1; index < 256; index++) {
|
||||
// TODO: Check.
|
||||
int r = palette[index * 3 + 2] >> 1;
|
||||
int g = palette[index * 3 + 1] >> 1;
|
||||
int b = palette[index * 3] >> 1;
|
||||
int colorTableIndex = (r << 10) | (g << 5) | b;
|
||||
indexedPalette[index] = _colorTable[colorTableIndex];
|
||||
}
|
||||
|
||||
int size = width * height;
|
||||
for (int index = 0; index < size; index++) {
|
||||
data[index] = indexedPalette[data[index]];
|
||||
}
|
||||
}
|
||||
|
||||
// 0x42EF60
|
||||
unsigned char* datafileReadRaw(char* path, int* widthPtr, int* heightPtr)
|
||||
{
|
||||
char* mangledPath = gDatafileNameMangler(path);
|
||||
char* dot = strrchr(mangledPath, '.');
|
||||
if (dot != NULL) {
|
||||
if (compat_stricmp(dot + 1, "pcx") == 0) {
|
||||
return pcxRead(mangledPath, widthPtr, heightPtr, gDatafilePalette);
|
||||
}
|
||||
}
|
||||
|
||||
if (gDatafileLoader != NULL) {
|
||||
return gDatafileLoader(mangledPath, gDatafilePalette, widthPtr, heightPtr);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 0x42EFCC
|
||||
unsigned char* datafileRead(char* path, int* widthPtr, int* heightPtr)
|
||||
{
|
||||
unsigned char* v1 = datafileReadRaw(path, widthPtr, heightPtr);
|
||||
if (v1 != NULL) {
|
||||
sub_42EE84(v1, gDatafilePalette, *widthPtr, *heightPtr);
|
||||
}
|
||||
return v1;
|
||||
}
|
||||
|
||||
// NOTE: Unused
|
||||
//
|
||||
// 0x42EFF4
|
||||
unsigned char* sub_42EFF4(char* path)
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
unsigned char* v3 = datafileReadRaw(path, &width, &height);
|
||||
if (v3 != NULL) {
|
||||
internal_free_safe(v3, __FILE__, __LINE__); // "..\\int\\DATAFILE.C", 148
|
||||
return gDatafilePalette;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x42F024
|
||||
void sub_42F024(unsigned char* data, int* widthPtr, int* heightPtr)
|
||||
{
|
||||
int width = *widthPtr;
|
||||
int height = *heightPtr;
|
||||
unsigned char* temp = (unsigned char*)internal_malloc_safe(width * height, __FILE__, __LINE__); // "..\\int\\DATAFILE.C", 157
|
||||
|
||||
// NOTE: Original code does not initialize `x`.
|
||||
int y = 0;
|
||||
int x = 0;
|
||||
unsigned char* src1 = data;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
if (*src1 == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned char* src2 = src1;
|
||||
for (x = 0; x < width; x++) {
|
||||
if (*src2 == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
*temp++ = *src2++;
|
||||
}
|
||||
|
||||
src1 += width;
|
||||
}
|
||||
|
||||
memcpy(data, temp, x * y);
|
||||
internal_free_safe(temp, __FILE__, __LINE__); // // "..\\int\\DATAFILE.C", 171
|
||||
}
|
||||
|
||||
// 0x42F0E4
|
||||
unsigned char* _datafileGetPalette()
|
||||
unsigned char* datafileGetPalette()
|
||||
{
|
||||
return _pal;
|
||||
return gDatafilePalette;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x42F0EC
|
||||
unsigned char* datafileLoad(char* path, int* sizePtr)
|
||||
{
|
||||
const char* mangledPath = gDatafileNameMangler(path);
|
||||
File* stream = fileOpen(mangledPath, "rb");
|
||||
if (stream == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int size = fileGetSize(stream);
|
||||
unsigned char* data = (unsigned char*)internal_malloc_safe(size, __FILE__, __LINE__); // "..\\int\\DATAFILE.C", 185
|
||||
if (data == NULL) {
|
||||
// NOTE: This code is unreachable, internal_malloc_safe never fails.
|
||||
// Otherwise it leaks stream.
|
||||
*sizePtr = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fileRead(data, 1, size, stream);
|
||||
fileClose(stream);
|
||||
*sizePtr = size;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,24 @@
|
||||
#ifndef DATAFILE_H
|
||||
#define DATAFILE_H
|
||||
|
||||
extern unsigned char _pal[768];
|
||||
typedef unsigned char*(DatafileLoader)(char* path, unsigned char* palette, int* widthPtr, int* heightPtr);
|
||||
typedef char*(DatafileNameMangler)(char* path);
|
||||
|
||||
unsigned char* _datafileGetPalette();
|
||||
extern DatafileLoader* gDatafileLoader;
|
||||
extern DatafileNameMangler* gDatafileNameMangler;
|
||||
|
||||
extern unsigned char gDatafilePalette[768];
|
||||
|
||||
char* datafileDefaultNameManglerImpl(char* path);
|
||||
void datafileSetNameMangler(DatafileNameMangler* mangler);
|
||||
void datafileSetLoader(DatafileLoader* loader);
|
||||
void sub_42EE84(unsigned char* data, unsigned char* palette, int width, int height);
|
||||
void sub_42EEF8(unsigned char* data, unsigned char* palette, int width, int height);
|
||||
unsigned char* datafileReadRaw(char* path, int* widthPtr, int* heightPtr);
|
||||
unsigned char* datafileRead(char* path, int* widthPtr, int* heightPtr);
|
||||
unsigned char* sub_42EFF4(char* path);
|
||||
void sub_42F024(unsigned char* data, int* widthPtr, int* heightPtr);
|
||||
unsigned char* datafileGetPalette();
|
||||
unsigned char* datafileLoad(char* path, int* sizePtr);
|
||||
|
||||
#endif /* DATAFILE_H */
|
||||
|
||||
37
src/db.cc
@@ -1,12 +1,12 @@
|
||||
#include "db.h"
|
||||
|
||||
#include "platform_compat.h"
|
||||
#include "xfile.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "platform_compat.h"
|
||||
#include "xfile.h"
|
||||
|
||||
typedef struct FileList {
|
||||
XList xlist;
|
||||
struct FileList* next;
|
||||
@@ -61,20 +61,22 @@ int dbOpen(const char* filePath1, int a2, const char* filePath2, int a4)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: This function simply returns 0, but it definitely accept one parameter
|
||||
// via eax, as seen at every call site. This value is ignored. It's impossible
|
||||
// to guess it's name.
|
||||
//
|
||||
// 0x4C5D54
|
||||
int _db_current(int a1)
|
||||
int _db_select(int dbHandle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Uncollapsed 0x4C5D54.
|
||||
int _db_current()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4C5D58
|
||||
bool _db_total()
|
||||
int _db_total()
|
||||
{
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4C5D60
|
||||
@@ -638,7 +640,7 @@ int fileNameListInit(const char* pattern, char*** fileNameListPtr, int a3, int a
|
||||
}
|
||||
}
|
||||
|
||||
bool v1 = *pattern == '*';
|
||||
bool isWildcard = *pattern == '*';
|
||||
|
||||
for (int index = 0; index < fileNamesLength; index += 1) {
|
||||
const char* name = xlist->fileNames[index];
|
||||
@@ -647,22 +649,13 @@ int fileNameListInit(const char* pattern, char*** fileNameListPtr, int a3, int a
|
||||
char extension[COMPAT_MAX_EXT];
|
||||
compat_splitpath(name, NULL, dir, fileName, extension);
|
||||
|
||||
bool v2 = false;
|
||||
if (v1) {
|
||||
char* pch = dir;
|
||||
while (*pch != '\0' && *pch != '\\') {
|
||||
pch++;
|
||||
}
|
||||
v2 = *pch != '\0';
|
||||
}
|
||||
|
||||
if (!v2) {
|
||||
if (!isWildcard || *dir == '\0' || strchr(dir, '\\') == NULL) {
|
||||
// NOTE: Quick and dirty fix to buffer overflow. See RE to
|
||||
// understand the problem.
|
||||
char path[COMPAT_MAX_PATH];
|
||||
sprintf(path, "%s%s", fileName, extension);
|
||||
free(xlist->fileNames[length]);
|
||||
xlist->fileNames[length] = strdup(path);
|
||||
xlist->fileNames[length] = compat_strdup(path);
|
||||
length++;
|
||||
}
|
||||
}
|
||||
|
||||
9
src/db.h
@@ -1,18 +1,19 @@
|
||||
#ifndef DB_H
|
||||
#define DB_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "memory_defs.h"
|
||||
#include "xfile.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef XFile File;
|
||||
typedef void FileReadProgressHandler();
|
||||
typedef char* StrdupProc(const char* string);
|
||||
|
||||
int dbOpen(const char* filePath1, int a2, const char* filePath2, int a4);
|
||||
int _db_current(int a1);
|
||||
bool _db_total();
|
||||
int _db_select(int dbHandle);
|
||||
int _db_current();
|
||||
int _db_total();
|
||||
void dbExit();
|
||||
int dbGetFileSize(const char* filePath, int* sizePtr);
|
||||
int dbGetFileContents(const char* filePath, void* ptr);
|
||||
|
||||
37
src/dbox.cc
@@ -1,5 +1,10 @@
|
||||
#include "dbox.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "art.h"
|
||||
#include "character_editor.h"
|
||||
#include "color.h"
|
||||
@@ -14,11 +19,6 @@
|
||||
#include "window_manager.h"
|
||||
#include "word_wrap.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define FILE_DIALOG_LINE_COUNT 12
|
||||
|
||||
#define FILE_DIALOG_DOUBLE_CLICK_DELAY 32
|
||||
@@ -196,7 +196,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
CacheEntry* backgroundHandle;
|
||||
int backgroundWidth;
|
||||
int backgroundHeight;
|
||||
int fid = buildFid(6, gDialogBoxBackgroundFrmIds[dialogType], 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, gDialogBoxBackgroundFrmIds[dialogType], 0, 0, 0);
|
||||
unsigned char* background = artLockFrameDataReturningSize(fid, &backgroundHandle, &backgroundWidth, &backgroundHeight);
|
||||
if (background == NULL) {
|
||||
fontSetCurrent(savedFont);
|
||||
@@ -230,7 +230,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
unsigned char* upButton = NULL;
|
||||
|
||||
if ((flags & DIALOG_BOX_0x20) == 0) {
|
||||
int doneBoxFid = buildFid(6, 209, 0, 0, 0);
|
||||
int doneBoxFid = buildFid(OBJ_TYPE_INTERFACE, 209, 0, 0, 0);
|
||||
doneBox = artLockFrameDataReturningSize(doneBoxFid, &doneBoxHandle, &doneBoxWidth, &doneBoxHeight);
|
||||
if (doneBox == NULL) {
|
||||
artUnlock(backgroundHandle);
|
||||
@@ -239,7 +239,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
return -1;
|
||||
}
|
||||
|
||||
int downButtonFid = buildFid(6, 9, 0, 0, 0);
|
||||
int downButtonFid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
downButton = artLockFrameDataReturningSize(downButtonFid, &downButtonHandle, &downButtonWidth, &downButtonHeight);
|
||||
if (downButton == NULL) {
|
||||
artUnlock(doneBoxHandle);
|
||||
@@ -249,7 +249,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
return -1;
|
||||
}
|
||||
|
||||
int upButtonFid = buildFid(6, 8, 0, 0, 0);
|
||||
int upButtonFid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
upButton = artLockFrameData(upButtonFid, 0, 0, &upButtonHandle);
|
||||
if (upButton == NULL) {
|
||||
artUnlock(downButtonHandle);
|
||||
@@ -331,7 +331,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
} else {
|
||||
int doneBoxFid = buildFid(6, 209, 0, 0, 0);
|
||||
int doneBoxFid = buildFid(OBJ_TYPE_INTERFACE, 209, 0, 0, 0);
|
||||
unsigned char* doneBox = artLockFrameDataReturningSize(doneBoxFid, &doneBoxHandle, &doneBoxWidth, &doneBoxHeight);
|
||||
if (doneBox == NULL) {
|
||||
artUnlock(backgroundHandle);
|
||||
@@ -340,7 +340,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
return -1;
|
||||
}
|
||||
|
||||
int downButtonFid = buildFid(6, 9, 0, 0, 0);
|
||||
int downButtonFid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
unsigned char* downButton = artLockFrameDataReturningSize(downButtonFid, &downButtonHandle, &downButtonWidth, &downButtonHeight);
|
||||
if (downButton == NULL) {
|
||||
artUnlock(doneBoxHandle);
|
||||
@@ -350,7 +350,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
return -1;
|
||||
}
|
||||
|
||||
int upButtonFid = buildFid(6, 8, 0, 0, 0);
|
||||
int upButtonFid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
unsigned char* upButton = artLockFrameData(upButtonFid, 0, 0, &upButtonHandle);
|
||||
if (upButton == NULL) {
|
||||
artUnlock(downButtonHandle);
|
||||
@@ -517,7 +517,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
}
|
||||
|
||||
// 0x41DE90
|
||||
int showLoadFileDialog(char *title, char** fileList, char* dest, int fileListLength, int x, int y, int flags)
|
||||
int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLength, int x, int y, int flags)
|
||||
{
|
||||
int oldFont = fontGetCurrent();
|
||||
|
||||
@@ -541,7 +541,7 @@ int showLoadFileDialog(char *title, char** fileList, char* dest, int fileListLen
|
||||
Size frmSizes[FILE_DIALOG_FRM_COUNT];
|
||||
|
||||
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
|
||||
int fid = buildFid(6, gLoadFileDialogFrmIds[index], 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, gLoadFileDialogFrmIds[index], 0, 0, 0);
|
||||
frmBuffers[index] = artLockFrameDataReturningSize(fid, &(frmHandles[index]), &(frmSizes[index].width), &(frmSizes[index].height));
|
||||
if (frmBuffers[index] == NULL) {
|
||||
while (--index >= 0) {
|
||||
@@ -551,7 +551,6 @@ int showLoadFileDialog(char *title, char** fileList, char* dest, int fileListLen
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int backgroundWidth = frmSizes[FILE_DIALOG_FRM_BACKGROUND].width;
|
||||
int backgroundHeight = frmSizes[FILE_DIALOG_FRM_BACKGROUND].height;
|
||||
|
||||
@@ -708,6 +707,8 @@ int showLoadFileDialog(char *title, char** fileList, char* dest, int fileListLen
|
||||
int scrollCounter = 0;
|
||||
bool isScrolling = false;
|
||||
|
||||
convertMouseWheelToArrowKey(&keyCode);
|
||||
|
||||
if (keyCode == 500) {
|
||||
if (fileListLength != 0) {
|
||||
strncpy(dest, fileList[selectedFileIndex + pageOffset], 16);
|
||||
@@ -922,7 +923,7 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
Size frmSizes[FILE_DIALOG_FRM_COUNT];
|
||||
|
||||
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
|
||||
int fid = buildFid(6, gSaveFileDialogFrmIds[index], 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, gSaveFileDialogFrmIds[index], 0, 0, 0);
|
||||
frmBuffers[index] = artLockFrameDataReturningSize(fid, &(frmHandles[index]), &(frmSizes[index].width), &(frmSizes[index].height));
|
||||
if (frmBuffers[index] == NULL) {
|
||||
while (--index >= 0) {
|
||||
@@ -1090,7 +1091,7 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
|
||||
char fileNameCopy[32];
|
||||
strncpy(fileNameCopy, dest, 32);
|
||||
|
||||
|
||||
int fileNameCopyLength = strlen(fileNameCopy);
|
||||
fileNameCopy[fileNameCopyLength + 1] = '\0';
|
||||
fileNameCopy[fileNameCopyLength] = ' ';
|
||||
@@ -1116,6 +1117,8 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
int scrollCounter = 0;
|
||||
bool isScrolling = false;
|
||||
|
||||
convertMouseWheelToArrowKey(&keyCode);
|
||||
|
||||
if (keyCode == 500) {
|
||||
rc = 0;
|
||||
} else if (keyCode == KEY_RETURN) {
|
||||
|
||||
99
src/debug.cc
@@ -1,9 +1,5 @@
|
||||
#include "debug.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
#include "window_manager_private.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -14,12 +10,17 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
#include "window_manager_private.h"
|
||||
|
||||
static int _debug_puts(char* string);
|
||||
static void _debug_clear();
|
||||
static int _debug_mono(char* string);
|
||||
static int _debug_log(char* string);
|
||||
static int _debug_screen(char* string);
|
||||
static void _debug_putc(char ch);
|
||||
static void _debug_putc(int ch);
|
||||
static void _debug_scroll();
|
||||
|
||||
// 0x51DEF8
|
||||
static FILE* _fd = NULL;
|
||||
@@ -174,7 +175,28 @@ static int _debug_puts(char* string)
|
||||
// 0x4C6FAC
|
||||
static void _debug_clear()
|
||||
{
|
||||
// TODO: Something with segments.
|
||||
char* buffer;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
buffer = NULL;
|
||||
|
||||
if (gDebugPrintProc == _debug_mono) {
|
||||
buffer = (char*)0xB0000;
|
||||
} else if (gDebugPrintProc == _debug_screen) {
|
||||
buffer = (char*)0xB8000;
|
||||
}
|
||||
|
||||
if (buffer != NULL) {
|
||||
for (y = 0; y < 25; y++) {
|
||||
for (x = 0; x < 80; x++) {
|
||||
*buffer++ = ' ';
|
||||
*buffer++ = 7;
|
||||
}
|
||||
}
|
||||
_cury = 0;
|
||||
_curx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C7004
|
||||
@@ -220,15 +242,72 @@ static int _debug_screen(char* string)
|
||||
}
|
||||
|
||||
// 0x4C709C
|
||||
static void _debug_putc(char ch)
|
||||
static void _debug_putc(int ch)
|
||||
{
|
||||
// TODO: Something with segments.
|
||||
char* buffer;
|
||||
|
||||
buffer = (char*)0xB0000;
|
||||
|
||||
switch (ch) {
|
||||
case 7:
|
||||
printf("\x07");
|
||||
return;
|
||||
case 8:
|
||||
if (_curx > 0) {
|
||||
_curx--;
|
||||
buffer += 2 * _curx + 2 * 80 * _cury;
|
||||
*buffer++ = ' ';
|
||||
*buffer = 7;
|
||||
}
|
||||
return;
|
||||
case 9:
|
||||
do {
|
||||
_debug_putc(' ');
|
||||
} while ((_curx - 1) % 4 != 0);
|
||||
return;
|
||||
case 13:
|
||||
_curx = 0;
|
||||
return;
|
||||
default:
|
||||
buffer += 2 * _curx + 2 * 80 * _cury;
|
||||
*buffer++ = ch;
|
||||
*buffer = 7;
|
||||
_curx++;
|
||||
if (_curx < 80) {
|
||||
return;
|
||||
}
|
||||
// FALLTHROUGH
|
||||
case 10:
|
||||
_curx = 0;
|
||||
_cury++;
|
||||
if (_cury > 24) {
|
||||
_cury = 24;
|
||||
_debug_scroll();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C71AC
|
||||
void _debug_scroll()
|
||||
static void _debug_scroll()
|
||||
{
|
||||
// TODO: Something with segments.
|
||||
char* buffer;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
buffer = (char*)0xB0000;
|
||||
|
||||
for (y = 0; y < 24; y++) {
|
||||
for (x = 0; x < 80 * 2; x++) {
|
||||
buffer[0] = buffer[80 * 2];
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; x < 80; x++) {
|
||||
*buffer++ = ' ';
|
||||
*buffer++ = 7;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C71E8
|
||||
|
||||
12
src/dfile.cc
@@ -1,14 +1,14 @@
|
||||
#include "dfile.h"
|
||||
|
||||
#include "platform_compat.h"
|
||||
|
||||
#include <fpattern.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fpattern.h>
|
||||
|
||||
#include "platform_compat.h"
|
||||
|
||||
// The size of decompression buffer for reading compressed [DFile]s.
|
||||
#define DFILE_DECOMPRESSION_BUFFER_SIZE (0x400)
|
||||
|
||||
@@ -61,7 +61,7 @@ DBase* dbaseOpen(const char* filePath)
|
||||
|
||||
// Get file size, and reposition stream to read footer, which contains two
|
||||
// 32-bits ints.
|
||||
int fileSize = compat_filelength(fileno(stream));
|
||||
int fileSize = getFileSize(stream);
|
||||
if (fseek(stream, fileSize - sizeof(int) * 2, SEEK_SET) != 0) {
|
||||
goto err;
|
||||
}
|
||||
@@ -141,7 +141,7 @@ DBase* dbaseOpen(const char* filePath)
|
||||
goto err;
|
||||
}
|
||||
|
||||
dbase->path = strdup(filePath);
|
||||
dbase->path = compat_strdup(filePath);
|
||||
dbase->dataOffset = fileSize - dbaseDataSize;
|
||||
|
||||
fclose(stream);
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#ifndef DFILE_H
|
||||
#define DFILE_H
|
||||
|
||||
#include "platform_compat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include "platform_compat.h"
|
||||
|
||||
typedef struct DBase DBase;
|
||||
typedef struct DBaseEntry DBaseEntry;
|
||||
typedef struct DFile DFile;
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
#include "dialog.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "memory_manager.h"
|
||||
#include "movie.h"
|
||||
#include "platform_compat.h"
|
||||
#include "text_font.h"
|
||||
#include "widget.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// 0x501623
|
||||
const float flt_501623 = 31.0;
|
||||
|
||||
@@ -76,7 +75,7 @@ int dword_56DB6C;
|
||||
int dword_56DB70;
|
||||
|
||||
// 0x56DB74
|
||||
int _rand2plus;
|
||||
char* off_56DB74;
|
||||
|
||||
// 0x56DB7C
|
||||
int dword_56DB7C;
|
||||
@@ -91,7 +90,7 @@ int dword_56DB84;
|
||||
int dword_56DB88;
|
||||
|
||||
// 0x56DB8C
|
||||
int dword_56DB8C;
|
||||
char* off_56DB8C;
|
||||
|
||||
// 0x56DB90
|
||||
int _replyPlaying;
|
||||
@@ -127,16 +126,16 @@ int dword_56DBB8;
|
||||
int dword_56DBBC;
|
||||
|
||||
// 0x56DBC0
|
||||
void* off_56DBC0;
|
||||
char* off_56DBC0;
|
||||
|
||||
// 0x56DBC4
|
||||
void* off_56DBC4;
|
||||
char* off_56DBC4;
|
||||
|
||||
// 0x56DBC8
|
||||
void* off_56DBC8;
|
||||
char* off_56DBC8;
|
||||
|
||||
// 0x56DBCC
|
||||
void* off_56DBCC;
|
||||
char* off_56DBCC;
|
||||
|
||||
// 0x56DBD0
|
||||
char* gDialogReplyTitle;
|
||||
@@ -151,16 +150,16 @@ int dword_56DBD8;
|
||||
int dword_56DBDC;
|
||||
|
||||
// 0x56DBE0
|
||||
void* off_56DBE0;
|
||||
char* off_56DBE0;
|
||||
|
||||
// 0x56DBE4
|
||||
void* off_56DBE4;
|
||||
char* off_56DBE4;
|
||||
|
||||
// 0x56DBE8
|
||||
void* off_56DBE8;
|
||||
char* off_56DBE8;
|
||||
|
||||
// 0x56DBEC
|
||||
void* off_56DBEC;
|
||||
char* off_56DBEC;
|
||||
|
||||
// 0x42F434
|
||||
STRUCT_56DAE0_FIELD_4* _getReply()
|
||||
@@ -191,7 +190,7 @@ void _replyAddOption(const char* a1, const char* a2, int a3)
|
||||
|
||||
v18 = _getReply();
|
||||
v17 = v18->field_14 - 1;
|
||||
v18->field_C[v17].field_8 = 2;
|
||||
v18->field_C[v17].kind = 2;
|
||||
|
||||
if (a1 != NULL) {
|
||||
v14 = (char*)internal_malloc_safe(strlen(a1) + 1, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 805
|
||||
@@ -204,18 +203,18 @@ void _replyAddOption(const char* a1, const char* a2, int a3)
|
||||
if (a2 != NULL) {
|
||||
v15 = (char*)internal_malloc_safe(strlen(a2) + 1, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 810
|
||||
strcpy(v15, a2);
|
||||
v18->field_C[v17].field_4 = v15;
|
||||
v18->field_C[v17].string = v15;
|
||||
} else {
|
||||
v18->field_C[v17].field_4 = NULL;
|
||||
v18->field_C[v17].string = NULL;
|
||||
}
|
||||
|
||||
v18->field_C[v17].field_18 = widgetGetFont();
|
||||
v18->field_C[v17].field_18 = windowGetFont();
|
||||
v18->field_C[v17].field_1A = word_56DB60;
|
||||
v18->field_C[v17].field_14 = a3;
|
||||
}
|
||||
|
||||
// 0x42F624
|
||||
void _replyAddOptionProc(const char* a1, const char* a2, int a3)
|
||||
void _replyAddOptionProc(const char* a1, int a2, int a3)
|
||||
{
|
||||
STRUCT_56DAE0_FIELD_4* v5;
|
||||
int v13;
|
||||
@@ -224,7 +223,7 @@ void _replyAddOptionProc(const char* a1, const char* a2, int a3)
|
||||
v5 = _getReply();
|
||||
v13 = v5->field_14 - 1;
|
||||
|
||||
v5->field_C[v13].field_8 = 1;
|
||||
v5->field_C[v13].kind = 1;
|
||||
|
||||
if (a1 != NULL) {
|
||||
v11 = (char*)internal_malloc_safe(strlen(a1) + 1, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 830
|
||||
@@ -234,9 +233,9 @@ void _replyAddOptionProc(const char* a1, const char* a2, int a3)
|
||||
v5->field_C[v13].field_0 = NULL;
|
||||
}
|
||||
|
||||
v5->field_C[v13].field_4 = (char*)a2;
|
||||
v5->field_C[v13].proc = a2;
|
||||
|
||||
v5->field_C[v13].field_18 = widgetGetFont();
|
||||
v5->field_C[v13].field_18 = windowGetFont();
|
||||
v5->field_C[v13].field_1A = word_56DB60;
|
||||
v5->field_C[v13].field_14 = a3;
|
||||
}
|
||||
@@ -248,9 +247,9 @@ void _optionFree(STRUCT_56DAE0_FIELD_4_FIELD_C* a1)
|
||||
internal_free_safe(a1->field_0, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 844
|
||||
}
|
||||
|
||||
if (a1->field_8 == 2) {
|
||||
if (a1->field_4 != NULL) {
|
||||
internal_free_safe(a1->field_4, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 846
|
||||
if (a1->kind == 2) {
|
||||
if (a1->string != NULL) {
|
||||
internal_free_safe(a1->string, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 846
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -388,8 +387,8 @@ void _drawStr(int win, char* str, int font, int width, int height, int left, int
|
||||
int old_font;
|
||||
Rect rect;
|
||||
|
||||
old_font = widgetGetFont();
|
||||
widgetSetFont(font);
|
||||
old_font = windowGetFont();
|
||||
windowSetFont(font);
|
||||
|
||||
_printStr(win, str, width, height, left, top, a8, a9, a10);
|
||||
|
||||
@@ -398,7 +397,7 @@ void _drawStr(int win, char* str, int font, int width, int height, int left, int
|
||||
rect.right = width + left;
|
||||
rect.bottom = height + top;
|
||||
windowRefreshRect(win, &rect);
|
||||
widgetSetFont(old_font);
|
||||
windowSetFont(old_font);
|
||||
}
|
||||
|
||||
// 0x430D40
|
||||
@@ -503,7 +502,7 @@ int _dialogOption(const char* a1, const char* a2)
|
||||
}
|
||||
|
||||
// 0x430F38
|
||||
int _dialogOptionProc(const char* a1, const char* a2)
|
||||
int _dialogOptionProc(const char* a1, int a2)
|
||||
{
|
||||
if (_dialog[_tods].field_C == -1) {
|
||||
return 1;
|
||||
@@ -514,6 +513,20 @@ int _dialogOptionProc(const char* a1, const char* a2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x430FD4
|
||||
int sub_430FD4(const char* a1, const char* a2, int timeout)
|
||||
{
|
||||
// TODO: Incomplete.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x431088
|
||||
int sub_431088(int a1)
|
||||
{
|
||||
// TODO: Incomplete.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x431184
|
||||
int _dialogGetExitPoint()
|
||||
{
|
||||
@@ -533,24 +546,24 @@ int _dialogQuit()
|
||||
}
|
||||
|
||||
// 0x4311B8
|
||||
int dialogSetOptionWindow(int a1, int a2, int a3, int a4, int a5)
|
||||
int dialogSetOptionWindow(int a1, int a2, int a3, int a4, char* a5)
|
||||
{
|
||||
dword_56DB6C = a1;
|
||||
dword_56DB70 = a2;
|
||||
dword_56DB64 = a3;
|
||||
dword_56DB68 = a4;
|
||||
_rand2plus = a5;
|
||||
off_56DB74 = a5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4311E0
|
||||
int dialogSetReplyWindow(int a1, int a2, int a3, int a4, int a5)
|
||||
int dialogSetReplyWindow(int a1, int a2, int a3, int a4, char* a5)
|
||||
{
|
||||
dword_56DB84 = a1;
|
||||
dword_56DB88 = a2;
|
||||
dword_56DB7C = a3;
|
||||
dword_56DB80 = a4;
|
||||
dword_56DB8C = a5;
|
||||
off_56DB8C = a5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -565,7 +578,7 @@ int dialogSetBorder(int a1, int a2)
|
||||
}
|
||||
|
||||
// 0x431218
|
||||
int _dialogSetScrollUp(int a1, int a2, void* a3, void* a4, void* a5, void* a6, int a7)
|
||||
int _dialogSetScrollUp(int a1, int a2, char* a3, char* a4, char* a5, char* a6, int a7)
|
||||
{
|
||||
_upButton = a1;
|
||||
dword_56DBD8 = a2;
|
||||
@@ -596,7 +609,7 @@ int _dialogSetScrollUp(int a1, int a2, void* a3, void* a4, void* a5, void* a6, i
|
||||
}
|
||||
|
||||
// 0x4312C0
|
||||
int _dialogSetScrollDown(int a1, int a2, void* a3, void* a4, void* a5, void* a6, int a7)
|
||||
int _dialogSetScrollDown(int a1, int a2, char* a3, char* a4, char* a5, char* a6, int a7)
|
||||
{
|
||||
_downButton = a1;
|
||||
dword_56DBB8 = a2;
|
||||
@@ -666,6 +679,11 @@ int _dialogSetOptionFlags(int flags)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 0x431430
|
||||
void dialogInit()
|
||||
{
|
||||
}
|
||||
|
||||
// 0x431434
|
||||
void _dialogClose()
|
||||
{
|
||||
|
||||
42
src/dialog.h
@@ -8,8 +8,11 @@ typedef void DialogFunc2(int win);
|
||||
|
||||
typedef struct STRUCT_56DAE0_FIELD_4_FIELD_C {
|
||||
char* field_0;
|
||||
char* field_4;
|
||||
int field_8;
|
||||
union {
|
||||
int proc;
|
||||
char* string;
|
||||
};
|
||||
int kind;
|
||||
int field_C;
|
||||
int field_10;
|
||||
int field_14;
|
||||
@@ -60,12 +63,12 @@ extern int dword_56DB64;
|
||||
extern int dword_56DB68;
|
||||
extern int dword_56DB6C;
|
||||
extern int dword_56DB70;
|
||||
extern int _rand2plus;
|
||||
extern char* off_56DB74;
|
||||
extern int dword_56DB7C;
|
||||
extern int dword_56DB80;
|
||||
extern int dword_56DB84;
|
||||
extern int dword_56DB88;
|
||||
extern int dword_56DB8C;
|
||||
extern char* off_56DB8C;
|
||||
extern int _replyPlaying;
|
||||
extern int _replyWin;
|
||||
extern int gDialogReplyColorG;
|
||||
@@ -77,22 +80,22 @@ extern int gDialogOptionColorR;
|
||||
extern int _downButton;
|
||||
extern int dword_56DBB8;
|
||||
extern int dword_56DBBC;
|
||||
extern void* off_56DBC0;
|
||||
extern void* off_56DBC4;
|
||||
extern void* off_56DBC8;
|
||||
extern void* off_56DBCC;
|
||||
extern char* off_56DBC0;
|
||||
extern char* off_56DBC4;
|
||||
extern char* off_56DBC8;
|
||||
extern char* off_56DBCC;
|
||||
extern char* gDialogReplyTitle;
|
||||
extern int _upButton;
|
||||
extern int dword_56DBD8;
|
||||
extern int dword_56DBDC;
|
||||
extern void* off_56DBE0;
|
||||
extern void* off_56DBE4;
|
||||
extern void* off_56DBE8;
|
||||
extern void* off_56DBEC;
|
||||
extern char* off_56DBE0;
|
||||
extern char* off_56DBE4;
|
||||
extern char* off_56DBE8;
|
||||
extern char* off_56DBEC;
|
||||
|
||||
STRUCT_56DAE0_FIELD_4* _getReply();
|
||||
void _replyAddOption(const char* a1, const char* a2, int a3);
|
||||
void _replyAddOptionProc(const char* a1, const char* a2, int a3);
|
||||
void _replyAddOptionProc(const char* a1, int a2, int a3);
|
||||
void _optionFree(STRUCT_56DAE0_FIELD_4_FIELD_C* a1);
|
||||
void _replyFree();
|
||||
int _endDialog();
|
||||
@@ -107,18 +110,21 @@ int _dialogGotoReply(const char* a1);
|
||||
int dialogSetReplyTitle(const char* a1);
|
||||
int _dialogReply(const char* a1, const char* a2);
|
||||
int _dialogOption(const char* a1, const char* a2);
|
||||
int _dialogOptionProc(const char* a1, const char* a2);
|
||||
int _dialogOptionProc(const char* a1, int a2);
|
||||
int sub_430FD4(const char* a1, const char* a2, int timeout);
|
||||
int sub_431088(int a1);
|
||||
int _dialogGetExitPoint();
|
||||
int _dialogQuit();
|
||||
int dialogSetOptionWindow(int a1, int a2, int a3, int a4, int a5);
|
||||
int dialogSetReplyWindow(int a1, int a2, int a3, int a4, int a5);
|
||||
int dialogSetOptionWindow(int a1, int a2, int a3, int a4, char* a5);
|
||||
int dialogSetReplyWindow(int a1, int a2, int a3, int a4, char* a5);
|
||||
int dialogSetBorder(int a1, int a2);
|
||||
int _dialogSetScrollUp(int a1, int a2, void* a3, void* a4, void* a5, void* a6, int a7);
|
||||
int _dialogSetScrollDown(int a1, int a2, void* a3, void* a4, void* a5, void* a6, int a7);
|
||||
int _dialogSetScrollUp(int a1, int a2, char* a3, char* a4, char* a5, char* a6, int a7);
|
||||
int _dialogSetScrollDown(int a1, int a2, char* a3, char* a4, char* a5, char* a6, int a7);
|
||||
int dialogSetOptionSpacing(int value);
|
||||
int dialogSetOptionColor(float a1, float a2, float a3);
|
||||
int dialogSetReplyColor(float a1, float a2, float a3);
|
||||
int _dialogSetOptionFlags(int flags);
|
||||
void dialogInit();
|
||||
void _dialogClose();
|
||||
int _dialogGetDialogDepth();
|
||||
void _dialogRegisterWinDrawCallbacks(DialogFunc1* a1, DialogFunc2* a2);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "dictionary.h"
|
||||
|
||||
#include "platform_compat.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "platform_compat.h"
|
||||
|
||||
// NOTE: I guess this marker is used as a type discriminator for implementing
|
||||
// nested dictionaries. That's why every dictionary-related function starts
|
||||
// with a check for this value.
|
||||
@@ -44,24 +44,19 @@ static void dictionaryFreeDefaultImpl(void* ptr)
|
||||
}
|
||||
|
||||
// 0x4D9BA8
|
||||
int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize, void* a4)
|
||||
int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize, DictionaryIO* io)
|
||||
{
|
||||
dictionary->entriesCapacity = initialCapacity;
|
||||
dictionary->valueSize = valueSize;
|
||||
dictionary->entriesLength = 0;
|
||||
|
||||
if (a4 != NULL) {
|
||||
// NOTE: There is some structure pointed by [a4] with 5 fields. They are
|
||||
// either memcopied or assigned one by one into field_10 - field_20
|
||||
// respectively. This parameter is always NULL, so I doubt it's possible
|
||||
// to understand it's meaning. There are some hints in the unused
|
||||
// functions though.
|
||||
assert(false && "Not implemented");
|
||||
if (io != NULL) {
|
||||
memcpy(&(dictionary->io), io, sizeof(*io));
|
||||
} else {
|
||||
dictionary->field_10 = 0;
|
||||
dictionary->field_14 = 0;
|
||||
dictionary->field_18 = 0;
|
||||
dictionary->field_1C = 0;
|
||||
dictionary->io.readProc = NULL;
|
||||
dictionary->io.writeProc = NULL;
|
||||
dictionary->io.field_8 = 0;
|
||||
dictionary->io.field_C = 0;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
@@ -302,6 +297,248 @@ int dictionaryRemoveValue(Dictionary* dictionary, const char* key)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4D9F84
|
||||
int dictionaryCopy(Dictionary* dest, Dictionary* src)
|
||||
{
|
||||
if (src->marker != DICTIONARY_MARKER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dictionaryInit(dest, src->entriesCapacity, src->valueSize, &(src->io)) != 0) {
|
||||
// FIXME: Should return -1, as we were unable to initialize dictionary.
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int index = 0; index < src->entriesLength; index++) {
|
||||
DictionaryEntry* entry = &(src->entries[index]);
|
||||
if (dictionaryAddValue(dest, entry->key, entry->value) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4DA090
|
||||
int dictionaryReadInt(FILE* stream, int* valuePtr)
|
||||
{
|
||||
int ch;
|
||||
int value;
|
||||
|
||||
ch = fgetc(stream);
|
||||
if (ch == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = (ch & 0xFF);
|
||||
|
||||
ch = fgetc(stream);
|
||||
if (ch == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = (value << 8) | (ch & 0xFF);
|
||||
|
||||
ch = fgetc(stream);
|
||||
if (ch == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = (value << 8) | (ch & 0xFF);
|
||||
|
||||
ch = fgetc(stream);
|
||||
if (ch == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = (value << 8) | (ch & 0xFF);
|
||||
|
||||
*valuePtr = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4DA0F4
|
||||
int dictionaryReadHeader(FILE* stream, Dictionary* dictionary)
|
||||
{
|
||||
int value;
|
||||
|
||||
if (dictionaryReadInt(stream, &value) != 0) return -1;
|
||||
dictionary->entriesLength = value;
|
||||
|
||||
if (dictionaryReadInt(stream, &value) != 0) return -1;
|
||||
dictionary->entriesCapacity = value;
|
||||
|
||||
if (dictionaryReadInt(stream, &value) != 0) return -1;
|
||||
dictionary->valueSize = value;
|
||||
|
||||
// NOTE: Originally reads `values` pointer.
|
||||
if (dictionaryReadInt(stream, &value) != 0) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4DA158
|
||||
int dictionaryLoad(FILE* stream, Dictionary* dictionary, int a3)
|
||||
{
|
||||
if (dictionary->marker != DICTIONARY_MARKER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int index = 0; index < dictionary->entriesLength; index++) {
|
||||
DictionaryEntry* entry = &(dictionary->entries[index]);
|
||||
if (entry->key != NULL) {
|
||||
gDictionaryFreeProc(entry->key);
|
||||
}
|
||||
|
||||
if (entry->value != NULL) {
|
||||
gDictionaryFreeProc(entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionary->entries != NULL) {
|
||||
gDictionaryFreeProc(dictionary->entries);
|
||||
}
|
||||
|
||||
if (dictionaryReadHeader(stream, dictionary) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dictionary->entries = NULL;
|
||||
|
||||
if (dictionary->entriesCapacity <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
dictionary->entries = (DictionaryEntry*)gDictionaryMallocProc(sizeof(*dictionary->entries) * dictionary->entriesCapacity);
|
||||
if (dictionary->entries == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int index = 0; index < dictionary->entriesLength; index++) {
|
||||
DictionaryEntry* entry = &(dictionary->entries[index]);
|
||||
entry->key = NULL;
|
||||
entry->value = NULL;
|
||||
}
|
||||
|
||||
if (dictionary->entriesLength <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int index = 0; index < dictionary->entriesLength; index++) {
|
||||
DictionaryEntry* entry = &(dictionary->entries[index]);
|
||||
int keyLength = fgetc(stream);
|
||||
if (keyLength == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
entry->key = (char*)gDictionaryMallocProc(keyLength + 1);
|
||||
if (entry->key == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fgets(entry->key, keyLength, stream) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dictionary->valueSize != 0) {
|
||||
entry->value = gDictionaryMallocProc(dictionary->valueSize);
|
||||
if (entry->value == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dictionary->io.readProc != NULL) {
|
||||
if (dictionary->io.readProc(stream, entry->value, dictionary->valueSize, a3) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (fread(entry->value, dictionary->valueSize, 1, stream) != 1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4DA2EC
|
||||
int dictionaryWriteInt(FILE* stream, int value)
|
||||
{
|
||||
if (fputc((value >> 24) & 0xFF, stream) == -1) return -1;
|
||||
if (fputc((value >> 16) & 0xFF, stream) == -1) return -1;
|
||||
if (fputc((value >> 8) & 0xFF, stream) == -1) return -1;
|
||||
if (fputc(value & 0xFF, stream) == -1) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4DA360
|
||||
int dictionaryWriteHeader(FILE* stream, Dictionary* dictionary)
|
||||
{
|
||||
if (dictionaryWriteInt(stream, dictionary->entriesLength) != 0) return -1;
|
||||
if (dictionaryWriteInt(stream, dictionary->entriesCapacity) != 0) return -1;
|
||||
if (dictionaryWriteInt(stream, dictionary->valueSize) != 0) return -1;
|
||||
// NOTE: Originally writes `entries` pointer.
|
||||
if (dictionaryWriteInt(stream, 0) != 0) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4DA3A4
|
||||
int dictionaryWrite(FILE* stream, Dictionary* dictionary, int a3)
|
||||
{
|
||||
if (dictionary->marker != DICTIONARY_MARKER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dictionaryWriteHeader(stream, dictionary) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int index = 0; index < dictionary->entriesLength; index++) {
|
||||
DictionaryEntry* entry = &(dictionary->entries[index]);
|
||||
int keyLength = strlen(entry->key);
|
||||
if (fputc(keyLength, stream) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fputs(entry->key, stream) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dictionary->io.writeProc != NULL) {
|
||||
if (dictionary->valueSize != 0) {
|
||||
if (dictionary->io.writeProc(stream, entry->value, dictionary->valueSize, a3) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (dictionary->valueSize != 0) {
|
||||
if (fwrite(entry->value, dictionary->valueSize, 1, stream) != 1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4DA498
|
||||
void dictionarySetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,22 @@
|
||||
#ifndef DICTIONARY_H
|
||||
#define DICTIONARY_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "memory_defs.h"
|
||||
|
||||
typedef int(DictionaryReadProc)(FILE* stream, void* buffer, unsigned int size, int a4);
|
||||
typedef int(DictionaryWriteProc)(FILE* stream, void* buffer, unsigned int size, int a4);
|
||||
|
||||
// NOTE: Last unnamed fields are likely seek, tell, and filelength.
|
||||
typedef struct DictionaryIO {
|
||||
DictionaryReadProc* readProc;
|
||||
DictionaryWriteProc* writeProc;
|
||||
int field_8;
|
||||
int field_C;
|
||||
int field_10;
|
||||
} DictionaryIO;
|
||||
|
||||
// A tuple containing individual key-value pair of a dictionary.
|
||||
typedef struct DictionaryEntry {
|
||||
char* key;
|
||||
@@ -27,22 +41,26 @@ typedef struct Dictionary {
|
||||
// The size of the dictionary values in bytes.
|
||||
size_t valueSize;
|
||||
|
||||
int field_10;
|
||||
int field_14;
|
||||
int field_18;
|
||||
int field_1C;
|
||||
int field_20;
|
||||
// IO callbacks.
|
||||
DictionaryIO io;
|
||||
|
||||
// The array of key-value pairs.
|
||||
DictionaryEntry* entries;
|
||||
} Dictionary;
|
||||
|
||||
int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize, void* a4);
|
||||
int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize, DictionaryIO* io);
|
||||
int dictionarySetCapacity(Dictionary* dictionary, int newCapacity);
|
||||
int dictionaryFree(Dictionary* dictionary);
|
||||
int dictionaryGetIndexByKey(Dictionary* dictionary, const char* key);
|
||||
int dictionaryAddValue(Dictionary* dictionary, const char* key, const void* value);
|
||||
int dictionaryRemoveValue(Dictionary* dictionary, const char* key);
|
||||
int dictionaryCopy(Dictionary* dest, Dictionary* src);
|
||||
int dictionaryReadInt(FILE* stream, int* valuePtr);
|
||||
int dictionaryReadHeader(FILE* stream, Dictionary* dictionary);
|
||||
int dictionaryLoad(FILE* stream, Dictionary* dictionary, int a3);
|
||||
int dictionaryWriteInt(FILE* stream, int value);
|
||||
int dictionaryWriteHeader(FILE* stream, Dictionary* dictionary);
|
||||
int dictionaryWrite(FILE* stream, Dictionary* dictionary, int a3);
|
||||
void dictionarySetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc);
|
||||
|
||||
#endif /* DICTIONARY_H */
|
||||
|
||||
145
src/dinput.cc
@@ -1,6 +1,28 @@
|
||||
#include "dinput.h"
|
||||
|
||||
#include <SDL.h>
|
||||
enum InputType {
|
||||
INPUT_TYPE_MOUSE,
|
||||
INPUT_TYPE_TOUCH,
|
||||
} InputType;
|
||||
|
||||
static int gLastInputType = INPUT_TYPE_MOUSE;
|
||||
|
||||
static int gTouchMouseLastX = 0;
|
||||
static int gTouchMouseLastY = 0;
|
||||
static int gTouchMouseDeltaX = 0;
|
||||
static int gTouchMouseDeltaY = 0;
|
||||
|
||||
static int gTouchFingers = 0;
|
||||
static unsigned int gTouchGestureLastTouchDownTimestamp = 0;
|
||||
static unsigned int gTouchGestureLastTouchUpTimestamp = 0;
|
||||
static int gTouchGestureTaps = 0;
|
||||
static bool gTouchGestureHandled = false;
|
||||
|
||||
static int gMouseWheelDeltaX = 0;
|
||||
static int gMouseWheelDeltaY = 0;
|
||||
|
||||
extern int screenGetWidth();
|
||||
extern int screenGetHeight();
|
||||
|
||||
// 0x4E0400
|
||||
bool directInputInit()
|
||||
@@ -47,9 +69,49 @@ bool mouseDeviceUnacquire()
|
||||
// 0x4E053C
|
||||
bool mouseDeviceGetData(MouseData* mouseState)
|
||||
{
|
||||
Uint32 buttons = SDL_GetRelativeMouseState(&(mouseState->x), &(mouseState->y));
|
||||
mouseState->buttons[0] = (buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;
|
||||
mouseState->buttons[1] = (buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
|
||||
if (gLastInputType == INPUT_TYPE_TOUCH) {
|
||||
mouseState->x = gTouchMouseDeltaX;
|
||||
mouseState->y = gTouchMouseDeltaY;
|
||||
mouseState->buttons[0] = 0;
|
||||
mouseState->buttons[1] = 0;
|
||||
mouseState->wheelX = 0;
|
||||
mouseState->wheelY = 0;
|
||||
gTouchMouseDeltaX = 0;
|
||||
gTouchMouseDeltaY = 0;
|
||||
|
||||
if (gTouchFingers == 0) {
|
||||
if (SDL_GetTicks() - gTouchGestureLastTouchUpTimestamp > 150) {
|
||||
if (!gTouchGestureHandled) {
|
||||
if (gTouchGestureTaps == 2) {
|
||||
mouseState->buttons[0] = 1;
|
||||
gTouchGestureHandled = true;
|
||||
} else if (gTouchGestureTaps == 3) {
|
||||
mouseState->buttons[1] = 1;
|
||||
gTouchGestureHandled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (gTouchFingers == 1) {
|
||||
if (SDL_GetTicks() - gTouchGestureLastTouchDownTimestamp > 150) {
|
||||
if (gTouchGestureTaps == 1) {
|
||||
mouseState->buttons[0] = 1;
|
||||
gTouchGestureHandled = true;
|
||||
} else if (gTouchGestureTaps == 2) {
|
||||
mouseState->buttons[1] = 1;
|
||||
gTouchGestureHandled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Uint32 buttons = SDL_GetRelativeMouseState(&(mouseState->x), &(mouseState->y));
|
||||
mouseState->buttons[0] = (buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;
|
||||
mouseState->buttons[1] = (buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
|
||||
mouseState->wheelX = gMouseWheelDeltaX;
|
||||
mouseState->wheelY = gMouseWheelDeltaY;
|
||||
|
||||
gMouseWheelDeltaX = 0;
|
||||
gMouseWheelDeltaY = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -100,3 +162,78 @@ bool keyboardDeviceInit()
|
||||
void keyboardDeviceFree()
|
||||
{
|
||||
}
|
||||
|
||||
void handleMouseEvent(SDL_Event* event)
|
||||
{
|
||||
// Mouse movement and buttons are accumulated in SDL itself and will be
|
||||
// processed later in `mouseDeviceGetData` via `SDL_GetRelativeMouseState`.
|
||||
|
||||
if (event->type == SDL_MOUSEWHEEL) {
|
||||
gMouseWheelDeltaX += event->wheel.x;
|
||||
gMouseWheelDeltaY += event->wheel.y;
|
||||
}
|
||||
|
||||
if (gLastInputType != INPUT_TYPE_MOUSE) {
|
||||
// Reset touch data.
|
||||
gTouchMouseLastX = 0;
|
||||
gTouchMouseLastY = 0;
|
||||
gTouchMouseDeltaX = 0;
|
||||
gTouchMouseDeltaY = 0;
|
||||
|
||||
gTouchFingers = 0;
|
||||
gTouchGestureLastTouchDownTimestamp = 0;
|
||||
gTouchGestureLastTouchUpTimestamp = 0;
|
||||
gTouchGestureTaps = 0;
|
||||
gTouchGestureHandled = false;
|
||||
|
||||
gLastInputType = INPUT_TYPE_MOUSE;
|
||||
}
|
||||
}
|
||||
|
||||
void handleTouchEvent(SDL_Event* event)
|
||||
{
|
||||
int windowWidth = screenGetWidth();
|
||||
int windowHeight = screenGetHeight();
|
||||
|
||||
if (event->tfinger.type == SDL_FINGERDOWN) {
|
||||
gTouchFingers++;
|
||||
|
||||
gTouchMouseLastX = (int)(event->tfinger.x * windowWidth);
|
||||
gTouchMouseLastY = (int)(event->tfinger.y * windowHeight);
|
||||
gTouchMouseDeltaX = 0;
|
||||
gTouchMouseDeltaY = 0;
|
||||
|
||||
if (event->tfinger.timestamp - gTouchGestureLastTouchDownTimestamp > 250) {
|
||||
gTouchGestureTaps = 0;
|
||||
gTouchGestureHandled = false;
|
||||
}
|
||||
|
||||
gTouchGestureLastTouchDownTimestamp = event->tfinger.timestamp;
|
||||
} else if (event->tfinger.type == SDL_FINGERMOTION) {
|
||||
int prevX = gTouchMouseLastX;
|
||||
int prevY = gTouchMouseLastY;
|
||||
gTouchMouseLastX = (int)(event->tfinger.x * windowWidth);
|
||||
gTouchMouseLastY = (int)(event->tfinger.y * windowHeight);
|
||||
gTouchMouseDeltaX += gTouchMouseLastX - prevX;
|
||||
gTouchMouseDeltaY += gTouchMouseLastY - prevY;
|
||||
} else if (event->tfinger.type == SDL_FINGERUP) {
|
||||
gTouchFingers--;
|
||||
|
||||
int prevX = gTouchMouseLastX;
|
||||
int prevY = gTouchMouseLastY;
|
||||
gTouchMouseLastX = (int)(event->tfinger.x * windowWidth);
|
||||
gTouchMouseLastY = (int)(event->tfinger.y * windowHeight);
|
||||
gTouchMouseDeltaX += gTouchMouseLastX - prevX;
|
||||
gTouchMouseDeltaY += gTouchMouseLastY - prevY;
|
||||
|
||||
gTouchGestureTaps++;
|
||||
gTouchGestureLastTouchUpTimestamp = event->tfinger.timestamp;
|
||||
}
|
||||
|
||||
if (gLastInputType != INPUT_TYPE_TOUCH) {
|
||||
// Reset mouse data.
|
||||
SDL_GetRelativeMouseState(NULL, NULL);
|
||||
|
||||
gLastInputType = INPUT_TYPE_TOUCH;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
#ifndef DINPUT_H
|
||||
#define DINPUT_H
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
typedef struct MouseData {
|
||||
int x;
|
||||
int y;
|
||||
unsigned char buttons[2];
|
||||
int wheelX;
|
||||
int wheelY;
|
||||
} MouseData;
|
||||
|
||||
typedef struct KeyboardData {
|
||||
@@ -26,4 +30,7 @@ void mouseDeviceFree();
|
||||
bool keyboardDeviceInit();
|
||||
void keyboardDeviceFree();
|
||||
|
||||
void handleMouseEvent(SDL_Event* event);
|
||||
void handleTouchEvent(SDL_Event* event);
|
||||
|
||||
#endif /* DINPUT_H */
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include "display_monitor.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "combat.h"
|
||||
@@ -10,11 +14,10 @@
|
||||
#include "geometry.h"
|
||||
#include "interface.h"
|
||||
#include "memory.h"
|
||||
#include "sfall_config.h"
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// The maximum number of lines display monitor can hold. Once this value
|
||||
// is reached earlier messages are thrown away.
|
||||
#define DISPLAY_MONITOR_LINES_CAPACITY (100)
|
||||
@@ -33,6 +36,7 @@
|
||||
|
||||
#define DISPLAY_MONITOR_BEEP_DELAY (500U)
|
||||
|
||||
static void display_clear();
|
||||
static void displayMonitorRefresh();
|
||||
static void displayMonitorScrollUpOnMouseDown(int btn, int keyCode);
|
||||
static void displayMonitorScrollDownOnMouseDown(int btn, int keyCode);
|
||||
@@ -40,6 +44,12 @@ static void displayMonitorScrollUpOnMouseEnter(int btn, int keyCode);
|
||||
static void displayMonitorScrollDownOnMouseEnter(int btn, int keyCode);
|
||||
static void displayMonitorOnMouseExit(int btn, int keyCode);
|
||||
|
||||
static void consoleFileInit();
|
||||
static void consoleFileReset();
|
||||
static void consoleFileExit();
|
||||
static void consoleFileAddMessage(const char* message);
|
||||
static void consoleFileFlush();
|
||||
|
||||
// 0x51850C
|
||||
static bool gDisplayMonitorInitialized = false;
|
||||
|
||||
@@ -86,6 +96,9 @@ static int _disp_start;
|
||||
// 0x56FB58
|
||||
static unsigned int gDisplayMonitorLastBeepTimestamp;
|
||||
|
||||
static std::ofstream gConsoleFileStream;
|
||||
static int gConsoleFilePrintCount = 0;
|
||||
|
||||
// 0x431610
|
||||
int displayMonitorInit()
|
||||
{
|
||||
@@ -105,7 +118,7 @@ int displayMonitorInit()
|
||||
}
|
||||
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
int backgroundFid = buildFid(6, 16, 0, 0, 0);
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 16, 0, 0, 0);
|
||||
Art* backgroundFrm = artLock(backgroundFid, &backgroundFrmHandle);
|
||||
if (backgroundFrm == NULL) {
|
||||
internal_free(gDisplayMonitorBackgroundFrmData);
|
||||
@@ -168,14 +181,11 @@ int displayMonitorInit()
|
||||
gDisplayMonitorEnabled = true;
|
||||
gDisplayMonitorInitialized = true;
|
||||
|
||||
for (int index = 0; index < gDisplayMonitorLinesCapacity; index++) {
|
||||
gDisplayMonitorLines[index][0] = '\0';
|
||||
}
|
||||
// NOTE: Uninline.
|
||||
display_clear();
|
||||
|
||||
_disp_start = 0;
|
||||
_disp_curr = 0;
|
||||
|
||||
displayMonitorRefresh();
|
||||
// SFALL
|
||||
consoleFileInit();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -184,15 +194,12 @@ int displayMonitorInit()
|
||||
// 0x431800
|
||||
int displayMonitorReset()
|
||||
{
|
||||
if (gDisplayMonitorInitialized) {
|
||||
for (int index = 0; index < gDisplayMonitorLinesCapacity; index++) {
|
||||
gDisplayMonitorLines[index][0] = '\0';
|
||||
}
|
||||
// NOTE: Uninline.
|
||||
display_clear();
|
||||
|
||||
// SFALL
|
||||
consoleFileReset();
|
||||
|
||||
_disp_start = 0;
|
||||
_disp_curr = 0;
|
||||
displayMonitorRefresh();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -200,6 +207,9 @@ int displayMonitorReset()
|
||||
void displayMonitorExit()
|
||||
{
|
||||
if (gDisplayMonitorInitialized) {
|
||||
// SFALL
|
||||
consoleFileExit();
|
||||
|
||||
internal_free(gDisplayMonitorBackgroundFrmData);
|
||||
gDisplayMonitorInitialized = false;
|
||||
}
|
||||
@@ -212,6 +222,9 @@ void displayMonitorAddMessage(char* str)
|
||||
return;
|
||||
}
|
||||
|
||||
// SFALL
|
||||
consoleFileAddMessage(str);
|
||||
|
||||
int oldFont = fontGetCurrent();
|
||||
fontSetCurrent(DISPLAY_MONITOR_FONT);
|
||||
|
||||
@@ -295,6 +308,24 @@ void displayMonitorAddMessage(char* str)
|
||||
displayMonitorRefresh();
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x431A2C
|
||||
static void display_clear()
|
||||
{
|
||||
int index;
|
||||
|
||||
if (gDisplayMonitorInitialized) {
|
||||
for (index = 0; index < gDisplayMonitorLinesCapacity; index++) {
|
||||
gDisplayMonitorLines[index][0] = '\0';
|
||||
}
|
||||
|
||||
_disp_start = 0;
|
||||
_disp_curr = 0;
|
||||
displayMonitorRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
// 0x431A78
|
||||
static void displayMonitorRefresh()
|
||||
{
|
||||
@@ -389,3 +420,51 @@ void displayMonitorEnable()
|
||||
gDisplayMonitorEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void consoleFileInit()
|
||||
{
|
||||
char* consoleFilePath;
|
||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_CONSOLE_OUTPUT_FILE_KEY, &consoleFilePath);
|
||||
if (consoleFilePath != NULL && *consoleFilePath == '\0') {
|
||||
consoleFilePath = NULL;
|
||||
}
|
||||
|
||||
if (consoleFilePath != NULL) {
|
||||
gConsoleFileStream.open(consoleFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
static void consoleFileReset()
|
||||
{
|
||||
if (gConsoleFileStream.is_open()) {
|
||||
gConsoleFilePrintCount = 0;
|
||||
gConsoleFileStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
static void consoleFileExit()
|
||||
{
|
||||
if (gConsoleFileStream.is_open()) {
|
||||
gConsoleFileStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
static void consoleFileAddMessage(const char* message)
|
||||
{
|
||||
if (gConsoleFileStream.is_open()) {
|
||||
gConsoleFileStream << message << '\n';
|
||||
|
||||
gConsoleFilePrintCount++;
|
||||
if (gConsoleFilePrintCount >= 20) {
|
||||
consoleFileFlush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void consoleFileFlush()
|
||||
{
|
||||
if (gConsoleFileStream.is_open()) {
|
||||
gConsoleFilePrintCount = 0;
|
||||
gConsoleFileStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "draw.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
#include "mmx.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// 0x4D2FC0
|
||||
void bufferDrawLine(unsigned char* buf, int pitch, int x1, int y1, int x2, int y2, int color)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef DRAW_H
|
||||
#define DRAW_H
|
||||
|
||||
void bufferDrawLine(unsigned char* buf, int pitch, int left, int top, int right, int bottom, int color);
|
||||
void bufferDrawLine(unsigned char* buf, int pitch, int left, int top, int right, int bottom, int color);
|
||||
void bufferDrawRect(unsigned char* buf, int a2, int a3, int a4, int a5, int a6, int a7);
|
||||
void bufferDrawRectShadowed(unsigned char* buf, int a2, int a3, int a4, int a5, int a6, int a7, int a8);
|
||||
void blitBufferToBufferStretch(unsigned char* src, int srcWidth, int srcHeight, int srcPitch, unsigned char* dest, int destWidth, int destHeight, int destPitch);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "electronic_registration.h"
|
||||
|
||||
#include "game_config.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "game_config.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
// 0x440DD0
|
||||
void runElectronicRegistration()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include "elevator.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "art.h"
|
||||
#include "core.h"
|
||||
#include "cycle.h"
|
||||
@@ -12,11 +17,9 @@
|
||||
#include "map.h"
|
||||
#include "pipboy.h"
|
||||
#include "scripts.h"
|
||||
#include "sfall_config.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
// The maximum number of elevator levels.
|
||||
#define ELEVATOR_LEVEL_MAX (4)
|
||||
|
||||
@@ -26,6 +29,10 @@
|
||||
// (instead of using NULL).
|
||||
#define ELEVATOR_BACKGROUND_NULL ((unsigned char*)(-1))
|
||||
|
||||
// Max number of elevators that can be loaded from elevators.ini. This limit is
|
||||
// emposed by Sfall.
|
||||
#define ELEVATORS_MAX 50
|
||||
|
||||
typedef enum ElevatorFrm {
|
||||
ELEVATOR_FRM_BUTTON_DOWN,
|
||||
ELEVATOR_FRM_BUTTON_UP,
|
||||
@@ -56,7 +63,7 @@ static const int gElevatorFrmIds[ELEVATOR_FRM_COUNT] = {
|
||||
};
|
||||
|
||||
// 0x43E95C
|
||||
static const ElevatorBackground gElevatorBackgrounds[ELEVATOR_COUNT] = {
|
||||
static ElevatorBackground gElevatorBackgrounds[ELEVATORS_MAX] = {
|
||||
{ 143, -1 },
|
||||
{ 143, 150 },
|
||||
{ 144, -1 },
|
||||
@@ -86,7 +93,7 @@ static const ElevatorBackground gElevatorBackgrounds[ELEVATOR_COUNT] = {
|
||||
// Number of levels for eleveators.
|
||||
//
|
||||
// 0x43EA1C
|
||||
static const int gElevatorLevels[ELEVATOR_COUNT] = {
|
||||
static int gElevatorLevels[ELEVATORS_MAX] = {
|
||||
4,
|
||||
2,
|
||||
3,
|
||||
@@ -114,7 +121,7 @@ static const int gElevatorLevels[ELEVATOR_COUNT] = {
|
||||
};
|
||||
|
||||
// 0x43EA7C
|
||||
static const ElevatorDescription gElevatorDescriptions[ELEVATOR_COUNT][ELEVATOR_LEVEL_MAX] = {
|
||||
static ElevatorDescription gElevatorDescriptions[ELEVATORS_MAX][ELEVATOR_LEVEL_MAX] = {
|
||||
{
|
||||
{ 14, 0, 18940 },
|
||||
{ 14, 1, 18936 },
|
||||
@@ -264,7 +271,7 @@ static const ElevatorDescription gElevatorDescriptions[ELEVATOR_COUNT][ELEVATOR_
|
||||
// NOTE: These values are also used as key bindings.
|
||||
//
|
||||
// 0x43EEFC
|
||||
static const char gElevatorLevelLabels[ELEVATOR_COUNT][ELEVATOR_LEVEL_MAX] = {
|
||||
static char gElevatorLevelLabels[ELEVATORS_MAX][ELEVATOR_LEVEL_MAX] = {
|
||||
{ '1', '2', '3', '4' },
|
||||
{ 'G', '1', '\0', '\0' },
|
||||
{ '1', '2', '3', '\0' },
|
||||
@@ -360,10 +367,11 @@ static unsigned char* gElevatorPanelFrmData;
|
||||
// 0x43EF5C
|
||||
int elevatorSelectLevel(int elevator, int* mapPtr, int* elevationPtr, int* tilePtr)
|
||||
{
|
||||
if (elevator < 0 || elevator >= ELEVATOR_COUNT) {
|
||||
if (elevator < 0 || elevator >= ELEVATORS_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// SFALL
|
||||
if (elevatorWindowInit(elevator) == -1) {
|
||||
return -1;
|
||||
}
|
||||
@@ -503,7 +511,7 @@ static int elevatorWindowInit(int elevator)
|
||||
|
||||
int index;
|
||||
for (index = 0; index < ELEVATOR_FRM_COUNT; index++) {
|
||||
int fid = buildFid(6, gElevatorFrmIds[index], 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, gElevatorFrmIds[index], 0, 0, 0);
|
||||
gElevatorFrmData[index] = artLockFrameDataReturningSize(fid, &(gElevatorFrmHandles[index]), &(gElevatorFrmSizes[index].width), &(gElevatorFrmSizes[index].height));
|
||||
if (gElevatorFrmData[index] == NULL) {
|
||||
break;
|
||||
@@ -530,11 +538,11 @@ static int elevatorWindowInit(int elevator)
|
||||
const ElevatorBackground* elevatorBackground = &(gElevatorBackgrounds[elevator]);
|
||||
bool backgroundsLoaded = true;
|
||||
|
||||
int backgroundFid = buildFid(6, elevatorBackground->backgroundFrmId, 0, 0, 0);
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, elevatorBackground->backgroundFrmId, 0, 0, 0);
|
||||
gElevatorBackgroundFrmData = artLockFrameDataReturningSize(backgroundFid, &gElevatorBackgroundFrmHandle, &gElevatorBackgroundFrmWidth, &gElevatorBackgroundFrmHeight);
|
||||
if (gElevatorBackgroundFrmData != NULL) {
|
||||
if (elevatorBackground->panelFrmId != -1) {
|
||||
int panelFid = buildFid(6, elevatorBackground->panelFrmId, 0, 0, 0);
|
||||
int panelFid = buildFid(OBJ_TYPE_INTERFACE, elevatorBackground->panelFrmId, 0, 0, 0);
|
||||
gElevatorPanelFrmData = artLockFrameDataReturningSize(panelFid, &gElevatorPanelFrmHandle, &gElevatorPanelFrmWidth, &gElevatorPanelFrmHeight);
|
||||
if (gElevatorPanelFrmData == NULL) {
|
||||
gElevatorPanelFrmData = ELEVATOR_BACKGROUND_NULL;
|
||||
@@ -681,3 +689,65 @@ static int elevatorGetLevelFromKeyCode(int elevator, int keyCode)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void elevatorsInit()
|
||||
{
|
||||
char* elevatorsFileName;
|
||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_ELEVATORS_FILE_KEY, &elevatorsFileName);
|
||||
if (elevatorsFileName != NULL && *elevatorsFileName == '\0') {
|
||||
elevatorsFileName = NULL;
|
||||
}
|
||||
|
||||
if (elevatorsFileName != NULL) {
|
||||
Config elevatorsConfig;
|
||||
if (configInit(&elevatorsConfig)) {
|
||||
if (configRead(&elevatorsConfig, elevatorsFileName, false)) {
|
||||
char sectionKey[4];
|
||||
char key[32];
|
||||
for (int index = 0; index < ELEVATORS_MAX; index++) {
|
||||
sprintf(sectionKey, "%d", index);
|
||||
|
||||
if (index >= ELEVATOR_COUNT) {
|
||||
int levels = 0;
|
||||
configGetInt(&elevatorsConfig, sectionKey, "ButtonCount", &levels);
|
||||
gElevatorLevels[index] = std::clamp(levels, 2, ELEVATOR_LEVEL_MAX);
|
||||
}
|
||||
|
||||
configGetInt(&elevatorsConfig, sectionKey, "MainFrm", &(gElevatorBackgrounds[index].backgroundFrmId));
|
||||
configGetInt(&elevatorsConfig, sectionKey, "ButtonsFrm", &(gElevatorBackgrounds[index].panelFrmId));
|
||||
|
||||
for (int level = 0; level < ELEVATOR_LEVEL_MAX; level++) {
|
||||
sprintf(key, "ID%d", level + 1);
|
||||
configGetInt(&elevatorsConfig, sectionKey, key, &(gElevatorDescriptions[index][level].map));
|
||||
|
||||
sprintf(key, "Elevation%d", level + 1);
|
||||
configGetInt(&elevatorsConfig, sectionKey, key, &(gElevatorDescriptions[index][level].elevation));
|
||||
|
||||
sprintf(key, "Tile%d", level + 1);
|
||||
configGetInt(&elevatorsConfig, sectionKey, key, &(gElevatorDescriptions[index][level].tile));
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Sfall implementation is slightly different. It uses one
|
||||
// loop and stores `type` value in a separate lookup table. This
|
||||
// value is then used in the certain places to remap from
|
||||
// requested elevator to the new one.
|
||||
for (int index = 0; index < ELEVATORS_MAX; index++) {
|
||||
sprintf(sectionKey, "%d", index);
|
||||
|
||||
int type;
|
||||
if (configGetInt(&elevatorsConfig, sectionKey, "Image", &type)) {
|
||||
type = std::clamp(type, 0, ELEVATORS_MAX - 1);
|
||||
if (index != type) {
|
||||
memcpy(&(gElevatorBackgrounds[index]), &(gElevatorBackgrounds[type]), sizeof(*gElevatorBackgrounds));
|
||||
memcpy(&(gElevatorLevels[index]), &(gElevatorLevels[type]), sizeof(*gElevatorLevels));
|
||||
memcpy(&(gElevatorLevelLabels[index]), &(gElevatorLevelLabels[type]), sizeof(*gElevatorLevelLabels));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configFree(&elevatorsConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,6 @@ typedef enum Elevator {
|
||||
|
||||
int elevatorSelectLevel(int elevator, int* mapPtr, int* elevationPtr, int* tilePtr);
|
||||
|
||||
void elevatorsInit();
|
||||
|
||||
#endif /* ELEVATOR_H */
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#include "endgame.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
@@ -25,13 +31,7 @@
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
#include "word_wrap.h"
|
||||
#include "world_map.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "worldmap.h"
|
||||
|
||||
// The maximum number of subtitle lines per slide.
|
||||
#define ENDGAME_ENDING_MAX_SUBTITLES (50)
|
||||
@@ -217,7 +217,7 @@ void endgamePlaySlideshow()
|
||||
if (ending->art_num == 327) {
|
||||
endgameEndingRenderPanningScene(ending->direction, ending->voiceOverBaseName);
|
||||
} else {
|
||||
int fid = buildFid(6, ending->art_num, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, ending->art_num, 0, 0, 0);
|
||||
endgameEndingRenderStaticScene(fid, ending->voiceOverBaseName);
|
||||
}
|
||||
}
|
||||
@@ -309,7 +309,7 @@ static int endgameEndingHandleContinuePlaying()
|
||||
// 0x43FBDC
|
||||
static void endgameEndingRenderPanningScene(int direction, const char* narratorFileName)
|
||||
{
|
||||
int fid = buildFid(6, 327, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, 327, 0, 0, 0);
|
||||
|
||||
CacheEntry* backgroundHandle;
|
||||
Art* background = artLock(fid, &backgroundHandle);
|
||||
@@ -441,7 +441,7 @@ static void endgameEndingRenderStaticScene(int fid, const char* narratorFileName
|
||||
blitBufferToBuffer(backgroundData, ENDGAME_ENDING_WINDOW_WIDTH, ENDGAME_ENDING_WINDOW_HEIGHT, ENDGAME_ENDING_WINDOW_WIDTH, gEndgameEndingSlideshowWindowBuffer, ENDGAME_ENDING_WINDOW_WIDTH);
|
||||
windowRefresh(gEndgameEndingSlideshowWindow);
|
||||
|
||||
endgameEndingLoadPalette((fid & 0xF000000) >> 24, fid & 0xFFF);
|
||||
endgameEndingLoadPalette(FID_TYPE(fid), fid & 0xFFF);
|
||||
|
||||
endgameEndingVoiceOverInit(narratorFileName);
|
||||
|
||||
@@ -661,7 +661,7 @@ static void endgameEndingVoiceOverInit(const char* fileBaseName)
|
||||
|
||||
unsigned int timing = 0;
|
||||
for (int index = 0; index < gEndgameEndingSubtitlesLength; index++) {
|
||||
double charactersCount = strlen(gEndgameEndingSubtitles[index]);
|
||||
double charactersCount = static_cast<double>(strlen(gEndgameEndingSubtitles[index]));
|
||||
// NOTE: There is floating point math at 0x4402E6 used to add
|
||||
// timing.
|
||||
timing += (unsigned int)trunc(charactersCount * durationPerCharacter * 1000.0);
|
||||
@@ -746,27 +746,19 @@ static int endgameEndingSubtitlesLoad(const char* filePath)
|
||||
char* pch;
|
||||
|
||||
// Find and clamp string at EOL.
|
||||
pch = string;
|
||||
while (*pch != '\0' && *pch != '\n') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch != '\0') {
|
||||
pch = strchr(string, '\n');
|
||||
if (pch != NULL) {
|
||||
*pch = '\0';
|
||||
}
|
||||
|
||||
// Find separator. The value before separator is ignored (as opposed to
|
||||
// movie subtitles, where the value before separator is a timing).
|
||||
pch = string;
|
||||
while (*pch != '\0' && *pch != ':') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch != '\0') {
|
||||
pch = strchr(string, ':');
|
||||
if (pch != NULL) {
|
||||
if (gEndgameEndingSubtitlesLength < ENDGAME_ENDING_MAX_SUBTITLES) {
|
||||
gEndgameEndingSubtitles[gEndgameEndingSubtitlesLength] = internal_strdup(pch + 1);
|
||||
gEndgameEndingSubtitlesLength++;
|
||||
gEndgameEndingSubtitlesCharactersCount += strlen(pch + 1);
|
||||
gEndgameEndingSubtitlesCharactersCount += static_cast<int>(strlen(pch + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -869,7 +861,7 @@ static int endgameEndingInit()
|
||||
const char* delim = " \t,";
|
||||
EndgameEnding entry;
|
||||
EndgameEnding* entries;
|
||||
int narrator_file_len;
|
||||
size_t narratorFileNameLength;
|
||||
|
||||
if (gEndgameEndings != NULL) {
|
||||
internal_free(gEndgameEndings);
|
||||
@@ -921,9 +913,9 @@ static int endgameEndingInit()
|
||||
|
||||
strcpy(entry.voiceOverBaseName, tok);
|
||||
|
||||
narrator_file_len = strlen(entry.voiceOverBaseName);
|
||||
if (isspace(entry.voiceOverBaseName[narrator_file_len - 1])) {
|
||||
entry.voiceOverBaseName[narrator_file_len - 1] = '\0';
|
||||
narratorFileNameLength = strlen(entry.voiceOverBaseName);
|
||||
if (isspace(entry.voiceOverBaseName[narratorFileNameLength - 1])) {
|
||||
entry.voiceOverBaseName[narratorFileNameLength - 1] = '\0';
|
||||
}
|
||||
|
||||
tok = strtok(NULL, delim);
|
||||
@@ -979,7 +971,7 @@ int endgameDeathEndingInit()
|
||||
char* tok;
|
||||
EndgameDeathEnding entry;
|
||||
EndgameDeathEnding* entries;
|
||||
int narrator_file_len;
|
||||
size_t narratorFileNameLength;
|
||||
|
||||
strcpy(gEndgameDeathEndingFileName, "narrator\\nar_5");
|
||||
|
||||
@@ -1046,13 +1038,13 @@ int endgameDeathEndingInit()
|
||||
}
|
||||
|
||||
// this code is slightly different from the original, but does the same thing
|
||||
narrator_file_len = strlen(tok);
|
||||
strncpy(entry.voiceOverBaseName, tok, narrator_file_len);
|
||||
narratorFileNameLength = strlen(tok);
|
||||
strncpy(entry.voiceOverBaseName, tok, narratorFileNameLength);
|
||||
|
||||
entry.enabled = false;
|
||||
|
||||
if (isspace(entry.voiceOverBaseName[narrator_file_len - 1])) {
|
||||
entry.voiceOverBaseName[narrator_file_len - 1] = '\0';
|
||||
if (isspace(entry.voiceOverBaseName[narratorFileNameLength - 1])) {
|
||||
entry.voiceOverBaseName[narratorFileNameLength - 1] = '\0';
|
||||
}
|
||||
|
||||
entries = (EndgameDeathEnding*)internal_realloc(gEndgameDeathEndings, sizeof(*entries) * (gEndgameDeathEndingsLength + 1));
|
||||
@@ -1166,13 +1158,13 @@ static int endgameDeathEndingValidate(int* percentage)
|
||||
}
|
||||
|
||||
if (deathEnding->worldAreaKnown != -1) {
|
||||
if (!_wmAreaIsKnown(deathEnding->worldAreaKnown)) {
|
||||
if (!wmAreaIsKnown(deathEnding->worldAreaKnown)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (deathEnding->worldAreaNotKnown != -1) {
|
||||
if (_wmAreaIsKnown(deathEnding->worldAreaNotKnown)) {
|
||||
if (wmAreaIsKnown(deathEnding->worldAreaNotKnown)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "export.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "interpreter_lib.h"
|
||||
#include "memory_manager.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct ExternalVariable {
|
||||
char name[32];
|
||||
char* programName;
|
||||
@@ -176,12 +176,11 @@ int externalVariableSetValue(Program* program, const char* name, ProgramValue& p
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if ((exportedVariable->value.opcode & 0xF7FF) == VALUE_TYPE_STRING) {
|
||||
if ((exportedVariable->value.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) {
|
||||
internal_free_safe(exportedVariable->stringValue, __FILE__, __LINE__); // "..\\int\\EXPORT.C", 169
|
||||
}
|
||||
|
||||
if ((programValue.opcode & 0xF7FF) == VALUE_TYPE_STRING) {
|
||||
if ((programValue.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) {
|
||||
if (program != NULL) {
|
||||
const char* stringValue = programGetString(program, programValue.opcode, programValue.integerValue);
|
||||
exportedVariable->value.opcode = VALUE_TYPE_DYNAMIC_STRING;
|
||||
@@ -204,7 +203,7 @@ int externalVariableGetValue(Program* program, const char* name, ProgramValue& v
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((exportedVariable->value.opcode & 0xF7FF) == VALUE_TYPE_STRING) {
|
||||
if ((exportedVariable->value.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) {
|
||||
value.opcode = exportedVariable->value.opcode;
|
||||
value.integerValue = programPushString(program, exportedVariable->stringValue);
|
||||
} else {
|
||||
@@ -225,7 +224,7 @@ int externalVariableCreate(Program* program, const char* identifier)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((exportedVariable->value.opcode & 0xF7FF) == VALUE_TYPE_STRING) {
|
||||
if ((exportedVariable->value.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) {
|
||||
internal_free_safe(exportedVariable->stringValue, __FILE__, __LINE__); // "..\\int\\EXPORT.C", 234
|
||||
}
|
||||
} else {
|
||||
@@ -261,7 +260,7 @@ void _removeProgramReferences(Program* program)
|
||||
// 0x44152C
|
||||
void _initExport()
|
||||
{
|
||||
_interpretRegisterProgramDeleteCallback(_removeProgramReferences);
|
||||
intLibRegisterProgramDeleteCallback(_removeProgramReferences);
|
||||
}
|
||||
|
||||
// 0x441538
|
||||
@@ -328,7 +327,7 @@ void _exportClearAllVariables()
|
||||
for (int index = 0; index < 1013; index++) {
|
||||
ExternalVariable* exportedVariable = &(gExternalVariables[index]);
|
||||
if (exportedVariable->name[0] != '\0') {
|
||||
if ((exportedVariable->value.opcode & 0xF7FF) == VALUE_TYPE_STRING) {
|
||||
if ((exportedVariable->value.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) {
|
||||
if (exportedVariable->stringValue != NULL) {
|
||||
internal_free_safe(exportedVariable->stringValue, __FILE__, __LINE__); // "..\\int\\EXPORT.C", 387
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "file_find.h"
|
||||
|
||||
#include <fpattern.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fpattern.h>
|
||||
|
||||
// 0x4E6380
|
||||
bool fileFindFirst(const char* path, DirectoryFileFindData* findData)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#ifndef FILE_FIND_H
|
||||
#define FILE_FIND_H
|
||||
|
||||
#include "platform_compat.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
@@ -11,6 +9,8 @@
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#include "platform_compat.h"
|
||||
|
||||
// NOTE: This structure is significantly different from what was in the
|
||||
// original code. Watcom provides opendir/readdir/closedir implementations,
|
||||
// that use Win32 FindFirstFile/FindNextFile under the hood, which in turn
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// of regular __usercall.
|
||||
|
||||
#include "file_utils.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -10,6 +9,8 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "platform_compat.h"
|
||||
|
||||
static void fileCopy(const char* existingFilePath, const char* newFilePath);
|
||||
|
||||
// 0x452740
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
#include "font_manager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "color.h"
|
||||
#include "db.h"
|
||||
#include "memory_manager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// The maximum number of interface fonts.
|
||||
#define INTERFACE_FONT_MAX (16)
|
||||
|
||||
typedef struct InterfaceFontGlyph {
|
||||
short width;
|
||||
short field_2;
|
||||
int field_4;
|
||||
short height;
|
||||
int offset;
|
||||
} InterfaceFontGlyph;
|
||||
|
||||
typedef struct InterfaceFontDescriptor {
|
||||
short field_0;
|
||||
short maxHeight;
|
||||
short letterSpacing;
|
||||
short wordSpacing;
|
||||
short field_6;
|
||||
short lineSpacing;
|
||||
short field_8;
|
||||
short field_A;
|
||||
InterfaceFontGlyph glyphs[256];
|
||||
@@ -79,7 +79,7 @@ int interfaceFontsInit()
|
||||
|
||||
for (int font = 0; font < INTERFACE_FONT_MAX; font++) {
|
||||
if (interfaceFontLoad(font) == -1) {
|
||||
gInterfaceFontDescriptors[font].field_0 = 0;
|
||||
gInterfaceFontDescriptors[font].maxHeight = 0;
|
||||
gInterfaceFontDescriptors[font].data = NULL;
|
||||
} else {
|
||||
++gInterfaceFontsLength;
|
||||
@@ -132,8 +132,8 @@ static int interfaceFontLoad(int font_index)
|
||||
interfaceFontByteSwapInt32(&sig);
|
||||
if (sig != 0x41414646) goto err;
|
||||
|
||||
if (fileRead(&(fontDescriptor->field_0), 2, 1, stream) != 1) goto err;
|
||||
interfaceFontByteSwapInt16(&(fontDescriptor->field_0));
|
||||
if (fileRead(&(fontDescriptor->maxHeight), 2, 1, stream) != 1) goto err;
|
||||
interfaceFontByteSwapInt16(&(fontDescriptor->maxHeight));
|
||||
|
||||
if (fileRead(&(fontDescriptor->letterSpacing), 2, 1, stream) != 1) goto err;
|
||||
interfaceFontByteSwapInt16(&(fontDescriptor->letterSpacing));
|
||||
@@ -141,8 +141,8 @@ static int interfaceFontLoad(int font_index)
|
||||
if (fileRead(&(fontDescriptor->wordSpacing), 2, 1, stream) != 1) goto err;
|
||||
interfaceFontByteSwapInt16(&(fontDescriptor->wordSpacing));
|
||||
|
||||
if (fileRead(&(fontDescriptor->field_6), 2, 1, stream) != 1) goto err;
|
||||
interfaceFontByteSwapInt16(&(fontDescriptor->field_6));
|
||||
if (fileRead(&(fontDescriptor->lineSpacing), 2, 1, stream) != 1) goto err;
|
||||
interfaceFontByteSwapInt16(&(fontDescriptor->lineSpacing));
|
||||
|
||||
for (int index = 0; index < 256; index++) {
|
||||
InterfaceFontGlyph* glyph = &(fontDescriptor->glyphs[index]);
|
||||
@@ -150,11 +150,11 @@ static int interfaceFontLoad(int font_index)
|
||||
if (fileRead(&(glyph->width), 2, 1, stream) != 1) goto err;
|
||||
interfaceFontByteSwapInt16(&(glyph->width));
|
||||
|
||||
if (fileRead(&(glyph->field_2), 2, 1, stream) != 1) goto err;
|
||||
interfaceFontByteSwapInt16(&(glyph->field_2));
|
||||
if (fileRead(&(glyph->height), 2, 1, stream) != 1) goto err;
|
||||
interfaceFontByteSwapInt16(&(glyph->height));
|
||||
|
||||
if (fileRead(&(glyph->field_4), 4, 1, stream) != 1) goto err;
|
||||
interfaceFontByteSwapInt32(&(glyph->field_4));
|
||||
if (fileRead(&(glyph->offset), 4, 1, stream) != 1) goto err;
|
||||
interfaceFontByteSwapInt32(&(glyph->offset));
|
||||
}
|
||||
|
||||
fileSize -= sizeof(InterfaceFontDescriptor);
|
||||
@@ -199,7 +199,7 @@ static int interfaceFontGetLineHeightImpl()
|
||||
return 0;
|
||||
}
|
||||
|
||||
return gCurrentInterfaceFontDescriptor->field_6 + gCurrentInterfaceFontDescriptor->field_0;
|
||||
return gCurrentInterfaceFontDescriptor->lineSpacing + gCurrentInterfaceFontDescriptor->maxHeight;
|
||||
}
|
||||
|
||||
// 0x442188
|
||||
@@ -288,12 +288,12 @@ static int interfaceFontGetMonospacedCharacterWidthImpl()
|
||||
|
||||
int v1;
|
||||
if (gCurrentInterfaceFontDescriptor->wordSpacing <= gCurrentInterfaceFontDescriptor->field_8) {
|
||||
v1 = gCurrentInterfaceFontDescriptor->field_6;
|
||||
v1 = gCurrentInterfaceFontDescriptor->lineSpacing;
|
||||
} else {
|
||||
v1 = gCurrentInterfaceFontDescriptor->letterSpacing;
|
||||
}
|
||||
|
||||
return v1 + gCurrentInterfaceFontDescriptor->field_0;
|
||||
return v1 + gCurrentInterfaceFontDescriptor->maxHeight;
|
||||
}
|
||||
|
||||
// 0x4422B4
|
||||
@@ -342,12 +342,12 @@ static void interfaceFontDrawImpl(unsigned char* buf, const char* string, int le
|
||||
}
|
||||
|
||||
InterfaceFontGlyph* glyph = &(gCurrentInterfaceFontDescriptor->glyphs[ch & 0xFF]);
|
||||
unsigned char* glyphDataPtr = gCurrentInterfaceFontDescriptor->data + glyph->field_4;
|
||||
unsigned char* glyphDataPtr = gCurrentInterfaceFontDescriptor->data + glyph->offset;
|
||||
|
||||
// Skip blank pixels (difference between font's line height and glyph height).
|
||||
ptr += (gCurrentInterfaceFontDescriptor->field_0 - glyph->field_2) * pitch;
|
||||
ptr += (gCurrentInterfaceFontDescriptor->maxHeight - glyph->height) * pitch;
|
||||
|
||||
for (int y = 0; y < glyph->field_2; y++) {
|
||||
for (int y = 0; y < glyph->height; y++) {
|
||||
for (int x = 0; x < glyph->width; x++) {
|
||||
unsigned char byte = *glyphDataPtr++;
|
||||
|
||||
@@ -362,7 +362,7 @@ static void interfaceFontDrawImpl(unsigned char* buf, const char* string, int le
|
||||
|
||||
if ((color & FONT_UNDERLINE) != 0) {
|
||||
int length = ptr - buf;
|
||||
unsigned char* underlinePtr = buf + pitch * (gCurrentInterfaceFontDescriptor->field_0 - 1);
|
||||
unsigned char* underlinePtr = buf + pitch * (gCurrentInterfaceFontDescriptor->maxHeight - 1);
|
||||
for (int index = 0; index < length; index++) {
|
||||
*underlinePtr++ = color & 0xFF;
|
||||
}
|
||||
|
||||
233
src/game.cc
@@ -1,5 +1,14 @@
|
||||
#include "game.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h> // access
|
||||
#endif
|
||||
|
||||
#include "actions.h"
|
||||
#include "animation.h"
|
||||
#include "art.h"
|
||||
@@ -55,16 +64,7 @@
|
||||
#include "trap.h"
|
||||
#include "version.h"
|
||||
#include "window_manager.h"
|
||||
#include "world_map.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h> // access
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "worldmap.h"
|
||||
|
||||
#define HELP_SCREEN_WIDTH (640)
|
||||
#define HELP_SCREEN_HEIGHT (480)
|
||||
@@ -90,7 +90,7 @@ static char _aDec11199816543[] = VERSION_BUILD_TIME;
|
||||
static bool gGameUiDisabled = false;
|
||||
|
||||
// 0x5186B8
|
||||
static int _game_state_cur = 0;
|
||||
static int _game_state_cur = GAME_STATE_0;
|
||||
|
||||
// 0x5186BC
|
||||
static bool gIsMapper = false;
|
||||
@@ -268,7 +268,7 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
|
||||
|
||||
debugPrint(">scr_game_init\t");
|
||||
|
||||
if (worldmapInit() != 0) {
|
||||
if (wmWorldMap_init() != 0) {
|
||||
debugPrint("Failed on wmWorldMap_init\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -343,6 +343,9 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
|
||||
|
||||
debugPrint(">endgameDeathEndingInit\n");
|
||||
|
||||
// SFALL
|
||||
premadeCharactersInit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -373,7 +376,7 @@ void gameReset()
|
||||
_scr_reset();
|
||||
gameLoadGlobalVars();
|
||||
scriptsReset();
|
||||
worldmapReset();
|
||||
wmWorldMap_reset();
|
||||
partyMembersReset();
|
||||
characterEditorInit();
|
||||
pipboyReset();
|
||||
@@ -390,6 +393,9 @@ void gameExit()
|
||||
{
|
||||
debugPrint("\nGame Exit\n");
|
||||
|
||||
// SFALL
|
||||
premadeCharactersExit();
|
||||
|
||||
tileDisable();
|
||||
messageListFree(&gMiscMessageList);
|
||||
combatExit();
|
||||
@@ -419,7 +425,7 @@ void gameExit()
|
||||
badwordsExit();
|
||||
automapExit();
|
||||
paletteExit();
|
||||
worldmapExit();
|
||||
wmWorldMap_exit();
|
||||
partyMembersExit();
|
||||
endgameDeathEndingExit();
|
||||
interfaceFontsExit();
|
||||
@@ -433,11 +439,33 @@ void gameExit()
|
||||
// 0x442D44
|
||||
int gameHandleKey(int eventCode, bool isInCombatMode)
|
||||
{
|
||||
if (_game_state_cur == 5) {
|
||||
// NOTE: Uninline.
|
||||
if (_game_state() == GAME_STATE_5) {
|
||||
_gdialogSystemEnter();
|
||||
}
|
||||
|
||||
if (eventCode == -1) {
|
||||
if ((mouseGetEvent() & MOUSE_EVENT_WHEEL) != 0) {
|
||||
int wheelX;
|
||||
int wheelY;
|
||||
mouseGetWheel(&wheelX, &wheelY);
|
||||
|
||||
int dx = 0;
|
||||
if (wheelX > 0) {
|
||||
dx = 1;
|
||||
} else if (wheelX < 0) {
|
||||
dx = -1;
|
||||
}
|
||||
|
||||
int dy = 0;
|
||||
if (wheelY > 0) {
|
||||
dy = -1;
|
||||
} else if (wheelY < 0) {
|
||||
dy = 1;
|
||||
}
|
||||
|
||||
mapScroll(dx, dy);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -452,6 +480,8 @@ int gameHandleKey(int eventCode, bool isInCombatMode)
|
||||
if (mouseX == _scr_size.left || mouseX == _scr_size.right
|
||||
|| mouseY == _scr_size.top || mouseY == _scr_size.bottom) {
|
||||
_gmouse_clicked_on_edge = true;
|
||||
} else {
|
||||
_gmouse_clicked_on_edge = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -474,6 +504,31 @@ int gameHandleKey(int eventCode, bool isInCombatMode)
|
||||
_intface_use_item();
|
||||
}
|
||||
break;
|
||||
case -2:
|
||||
if (1) {
|
||||
int mouseEvent = mouseGetEvent();
|
||||
int mouseX;
|
||||
int mouseY;
|
||||
mouseGetPosition(&mouseX, &mouseY);
|
||||
|
||||
if ((mouseEvent & MOUSE_EVENT_LEFT_BUTTON_DOWN) != 0) {
|
||||
if ((mouseEvent & MOUSE_EVENT_LEFT_BUTTON_REPEAT) == 0) {
|
||||
if (mouseX == _scr_size.left || mouseX == _scr_size.right
|
||||
|| mouseY == _scr_size.top || mouseY == _scr_size.bottom) {
|
||||
_gmouse_clicked_on_edge = true;
|
||||
} else {
|
||||
_gmouse_clicked_on_edge = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((mouseEvent & MOUSE_EVENT_LEFT_BUTTON_UP) != 0) {
|
||||
_gmouse_clicked_on_edge = false;
|
||||
}
|
||||
}
|
||||
|
||||
_gmouse_handle_event(mouseX, mouseY, mouseEvent);
|
||||
}
|
||||
break;
|
||||
case KEY_CTRL_Q:
|
||||
case KEY_CTRL_X:
|
||||
case KEY_F10:
|
||||
@@ -561,7 +616,7 @@ int gameHandleKey(int eventCode, bool isInCombatMode)
|
||||
showDialogBox(title, NULL, 0, 192, 116, _colorTable[32328], NULL, _colorTable[32328], 0);
|
||||
} else {
|
||||
soundPlayFile("ib1p1xx1");
|
||||
pipboyOpen(false);
|
||||
pipboyOpen(PIPBOY_OPEN_INTENT_UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -629,7 +684,7 @@ int gameHandleKey(int eventCode, bool isInCombatMode)
|
||||
showDialogBox(title, NULL, 0, 192, 116, _colorTable[32328], NULL, _colorTable[32328], 0);
|
||||
} else {
|
||||
soundPlayFile("ib1p1xx1");
|
||||
pipboyOpen(true);
|
||||
pipboyOpen(PIPBOY_OPEN_INTENT_REST);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -719,15 +774,15 @@ int gameHandleKey(int eventCode, bool isInCombatMode)
|
||||
break;
|
||||
case KEY_COMMA:
|
||||
case KEY_LESS:
|
||||
if (reg_anim_begin(0) == 0) {
|
||||
reg_anim_rotate_counter_clockwise(gDude);
|
||||
if (reg_anim_begin(ANIMATION_REQUEST_RESERVED) == 0) {
|
||||
animationRegisterRotateCounterClockwise(gDude);
|
||||
reg_anim_end();
|
||||
}
|
||||
break;
|
||||
case KEY_DOT:
|
||||
case KEY_GREATER:
|
||||
if (reg_anim_begin(0) == 0) {
|
||||
reg_anim_rotate_clockwise(gDude);
|
||||
if (reg_anim_begin(ANIMATION_REQUEST_RESERVED) == 0) {
|
||||
animationRegisterRotateClockwise(gDude);
|
||||
reg_anim_end();
|
||||
}
|
||||
break;
|
||||
@@ -841,8 +896,6 @@ int gameHandleKey(int eventCode, bool isInCombatMode)
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Incomplete.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -930,68 +983,56 @@ static int gameLoadGlobalVars()
|
||||
}
|
||||
|
||||
// 0x443CE8
|
||||
int globalVarsRead(const char* path, const char* section, int* out_vars_num, int** out_vars)
|
||||
int globalVarsRead(const char* path, const char* section, int* variablesListLengthPtr, int** variablesListPtr)
|
||||
{
|
||||
File* stream;
|
||||
char str[258];
|
||||
char* ch;
|
||||
|
||||
_inven_reset_dude();
|
||||
|
||||
stream = fileOpen(path, "rt");
|
||||
File* stream = fileOpen(path, "rt");
|
||||
if (stream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*out_vars_num != 0) {
|
||||
internal_free(*out_vars);
|
||||
*out_vars = NULL;
|
||||
*out_vars_num = 0;
|
||||
if (*variablesListLengthPtr != 0) {
|
||||
internal_free(*variablesListPtr);
|
||||
*variablesListPtr = NULL;
|
||||
*variablesListLengthPtr = 0;
|
||||
}
|
||||
|
||||
char string[260];
|
||||
if (section != NULL) {
|
||||
while (fileReadString(str, sizeof(str), stream)) {
|
||||
if (strncmp(str, section, 16) == 0) {
|
||||
while (fileReadString(string, 258, stream)) {
|
||||
if (strncmp(string, section, 16) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (fileReadString(str, sizeof(str), stream)) {
|
||||
if (str[0] == '\n') {
|
||||
while (fileReadString(string, 258, stream)) {
|
||||
if (string[0] == '\n') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str[0] == '/' && str[1] == '/') {
|
||||
if (string[0] == '/' && string[1] == '/') {
|
||||
continue;
|
||||
}
|
||||
|
||||
ch = str;
|
||||
|
||||
while (*ch != '\0' && *ch != ';') {
|
||||
ch++;
|
||||
char* semicolon = strchr(string, ';');
|
||||
if (semicolon != NULL) {
|
||||
*semicolon = '\0';
|
||||
}
|
||||
|
||||
if (*ch != '\0') {
|
||||
*ch = '\0';
|
||||
}
|
||||
*variablesListLengthPtr = *variablesListLengthPtr + 1;
|
||||
*variablesListPtr = (int*)internal_realloc(*variablesListPtr, sizeof(int) * *variablesListLengthPtr);
|
||||
|
||||
*out_vars_num = *out_vars_num + 1;
|
||||
*out_vars = (int*)internal_realloc(*out_vars, sizeof(int) * *out_vars_num);
|
||||
|
||||
if (*out_vars == NULL) {
|
||||
if (*variablesListPtr == NULL) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ch = str;
|
||||
while (*ch != '\0' && *ch != '=') {
|
||||
ch++;
|
||||
}
|
||||
|
||||
if (*ch != '\0') {
|
||||
sscanf(ch + 1, "%d", *out_vars + *out_vars_num - 1);
|
||||
char* equals = strchr(string, '=');
|
||||
if (equals != NULL) {
|
||||
sscanf(equals + 1, "%d", *variablesListPtr + *variablesListLengthPtr - 1);
|
||||
} else {
|
||||
*out_vars[*out_vars_num - 1] = 0;
|
||||
*variablesListPtr[*variablesListLengthPtr - 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1009,15 +1050,15 @@ int _game_state()
|
||||
// 0x443E34
|
||||
int _game_state_request(int a1)
|
||||
{
|
||||
if (a1 == 0) {
|
||||
a1 = 1;
|
||||
} else if (a1 == 2) {
|
||||
a1 = 3;
|
||||
} else if (a1 == 4) {
|
||||
a1 = 5;
|
||||
if (a1 == GAME_STATE_0) {
|
||||
a1 = GAME_STATE_1;
|
||||
} else if (a1 == GAME_STATE_2) {
|
||||
a1 = GAME_STATE_3;
|
||||
} else if (a1 == GAME_STATE_4) {
|
||||
a1 = GAME_STATE_5;
|
||||
}
|
||||
|
||||
if (_game_state_cur != 4 || a1 != 5) {
|
||||
if (_game_state_cur != GAME_STATE_4 || a1 != GAME_STATE_5) {
|
||||
_game_state_cur = a1;
|
||||
return 0;
|
||||
}
|
||||
@@ -1032,14 +1073,14 @@ void _game_state_update()
|
||||
|
||||
v0 = _game_state_cur;
|
||||
switch (_game_state_cur) {
|
||||
case 1:
|
||||
v0 = 0;
|
||||
case GAME_STATE_1:
|
||||
v0 = GAME_STATE_0;
|
||||
break;
|
||||
case 3:
|
||||
v0 = 2;
|
||||
case GAME_STATE_3:
|
||||
v0 = GAME_STATE_2;
|
||||
break;
|
||||
case 5:
|
||||
v0 = 4;
|
||||
case GAME_STATE_5:
|
||||
v0 = GAME_STATE_4;
|
||||
}
|
||||
|
||||
_game_state_cur = v0;
|
||||
@@ -1098,7 +1139,7 @@ static void showHelp()
|
||||
if (win != -1) {
|
||||
unsigned char* windowBuffer = windowGetBuffer(win);
|
||||
if (windowBuffer != NULL) {
|
||||
int backgroundFid = buildFid(6, 297, 0, 0, 0);
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 297, 0, 0, 0);
|
||||
CacheEntry* backgroundHandle;
|
||||
unsigned char* backgroundData = artLockFrameData(backgroundFid, 0, 0, &backgroundHandle);
|
||||
if (backgroundData != NULL) {
|
||||
@@ -1236,6 +1277,7 @@ static int gameDbInit()
|
||||
|
||||
_critter_db_handle = dbOpen(main_file_name, 0, patch_file_name, 1);
|
||||
if (_critter_db_handle == -1) {
|
||||
_db_select(_master_db_handle);
|
||||
showMesageBox("Could not find the critter datafile. Please make sure the FALLOUT CD is in the drive and that you are running FALLOUT from the directory you installed it to.");
|
||||
return -1;
|
||||
}
|
||||
@@ -1248,6 +1290,8 @@ static int gameDbInit()
|
||||
}
|
||||
}
|
||||
|
||||
_db_select(_master_db_handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1314,3 +1358,50 @@ static void showSplash()
|
||||
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_SPLASH_KEY, splash + 1);
|
||||
}
|
||||
|
||||
int gameShowDeathDialog(const char* message)
|
||||
{
|
||||
bool isoWasEnabled = isoDisable();
|
||||
|
||||
bool gameMouseWasVisible;
|
||||
if (isoWasEnabled) {
|
||||
gameMouseWasVisible = gameMouseObjectsIsVisible();
|
||||
} else {
|
||||
gameMouseWasVisible = false;
|
||||
}
|
||||
|
||||
if (gameMouseWasVisible) {
|
||||
gameMouseObjectsHide();
|
||||
}
|
||||
|
||||
bool cursorWasHidden = cursorIsHidden();
|
||||
if (cursorWasHidden) {
|
||||
mouseShowCursor();
|
||||
}
|
||||
|
||||
int oldCursor = gameMouseGetCursor();
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
|
||||
int oldUserWantsToQuit = _game_user_wants_to_quit;
|
||||
_game_user_wants_to_quit = 0;
|
||||
|
||||
int rc = showDialogBox(message, 0, 0, 169, 117, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE);
|
||||
|
||||
_game_user_wants_to_quit = oldUserWantsToQuit;
|
||||
|
||||
gameMouseSetCursor(oldCursor);
|
||||
|
||||
if (cursorWasHidden) {
|
||||
mouseHideCursor();
|
||||
}
|
||||
|
||||
if (gameMouseWasVisible) {
|
||||
gameMouseObjectsShow();
|
||||
}
|
||||
|
||||
if (isoWasEnabled) {
|
||||
isoEnable();
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
13
src/game.h
@@ -4,6 +4,15 @@
|
||||
#include "game_vars.h"
|
||||
#include "message.h"
|
||||
|
||||
typedef enum GameState {
|
||||
GAME_STATE_0,
|
||||
GAME_STATE_1,
|
||||
GAME_STATE_2,
|
||||
GAME_STATE_3,
|
||||
GAME_STATE_4,
|
||||
GAME_STATE_5,
|
||||
} GameState;
|
||||
|
||||
extern int* gGameGlobalVars;
|
||||
extern int gGameGlobalVarsLength;
|
||||
extern const char* asc_5186C8;
|
||||
@@ -22,10 +31,12 @@ void gameUiEnable();
|
||||
bool gameUiIsDisabled();
|
||||
int gameGetGlobalVar(int var);
|
||||
int gameSetGlobalVar(int var, int value);
|
||||
int globalVarsRead(const char* path, const char* section, int* out_vars_num, int** out_vars);
|
||||
int globalVarsRead(const char* path, const char* section, int* variablesListLengthPtr, int** variablesListPtr);
|
||||
int _game_state();
|
||||
int _game_state_request(int a1);
|
||||
void _game_state_update();
|
||||
int showQuitConfirmationDialog();
|
||||
|
||||
int gameShowDeathDialog(const char* message);
|
||||
|
||||
#endif /* GAME_H */
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "game_config.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
// A flag indicating if [gGameConfig] was initialized.
|
||||
//
|
||||
// 0x5186D0
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include "game_dialog.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "actions.h"
|
||||
#include "animation.h"
|
||||
#include "art.h"
|
||||
@@ -26,6 +30,7 @@
|
||||
#include "proto.h"
|
||||
#include "random.h"
|
||||
#include "scripts.h"
|
||||
#include "sfall_config.h"
|
||||
#include "skill.h"
|
||||
#include "stat.h"
|
||||
#include "text_font.h"
|
||||
@@ -33,10 +38,6 @@
|
||||
#include "tile.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DIALOG_REVIEW_ENTRIES_CAPACITY 80
|
||||
|
||||
#define DIALOG_OPTION_ENTRIES_CAPACITY 30
|
||||
@@ -603,6 +604,8 @@ static int gGameDialogFidgetFrmCurrentFrame;
|
||||
|
||||
static int _gdialogReset();
|
||||
static void gameDialogEndLips();
|
||||
static int gdHide();
|
||||
static int gdUnhide();
|
||||
static int gameDialogAddMessageOption(int a1, int a2, int a3);
|
||||
static int gameDialogAddTextOption(int a1, const char* a2, int a3);
|
||||
static int gameDialogReviewWindowInit(int* win);
|
||||
@@ -639,6 +642,7 @@ static void _gDialogRefreshOptionsRect(int win, Rect* drawRect);
|
||||
static void gameDialogTicker();
|
||||
static void _gdialog_scroll_subwin(int a1, int a2, unsigned char* a3, unsigned char* a4, unsigned char* a5, int a6, int a7);
|
||||
static int _text_num_lines(const char* a1, int a2);
|
||||
static int text_to_rect_wrapped(unsigned char* buffer, Rect* rect, char* string, int* a4, int height, int pitch, int color);
|
||||
static int gameDialogDrawText(unsigned char* buffer, Rect* rect, char* string, int* a4, int height, int pitch, int color, int a7);
|
||||
static int _gdialog_barter_create_win();
|
||||
static void _gdialog_barter_destroy_win();
|
||||
@@ -660,16 +664,27 @@ static void _gdCustomUpdateSetting(int option, int value);
|
||||
static void gameDialogBarterButtonUpMouseUp(int btn, int a2);
|
||||
static int _gdialog_window_create();
|
||||
static void _gdialog_window_destroy();
|
||||
static int talk_to_create_background_window();
|
||||
static int gameDialogWindowRenderBackground();
|
||||
static int _talkToRefreshDialogWindowRect(Rect* rect);
|
||||
static void gameDialogRenderHighlight(unsigned char* src, int srcWidth, int srcHeight, int srcPitch, unsigned char* dest, int x, int y, int destPitch, unsigned char* a9, unsigned char* a10);
|
||||
static void gameDialogRenderTalkingHead(Art* art, int frame);
|
||||
static void gameDialogPrepareHighlights();
|
||||
static void gameDialogHighlightsInit();
|
||||
static void gameDialogHighlightsExit();
|
||||
|
||||
static void gameDialogRedButtonsInit();
|
||||
static void gameDialogRedButtonsExit();
|
||||
|
||||
static bool gGameDialogFix;
|
||||
|
||||
// gdialog_init
|
||||
// 0x444D1C
|
||||
int gameDialogInit()
|
||||
{
|
||||
// SFALL: Prevents from using 0 to escape from dialogue at any time.
|
||||
gGameDialogFix = true;
|
||||
configGetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_GAME_DIALOG_FIX_KEY, &gGameDialogFix);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -717,7 +732,7 @@ void gameDialogEnter(Object* a1, int a2)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((a1->pid >> 24) != OBJ_TYPE_ITEM && (a1->sid >> 24) != SCRIPT_TYPE_SPATIAL) {
|
||||
if (PID_TYPE(a1->pid) != OBJ_TYPE_ITEM && SID_TYPE(a1->sid) != SCRIPT_TYPE_SPATIAL) {
|
||||
MessageListItem messageListItem;
|
||||
|
||||
int rc = _action_can_talk_to(gDude, a1);
|
||||
@@ -843,7 +858,7 @@ void _gdialogSystemEnter()
|
||||
_tile_scroll_to(gGameDialogOldCenterTile, 2);
|
||||
}
|
||||
|
||||
_game_state_request(2);
|
||||
_game_state_request(GAME_STATE_2);
|
||||
|
||||
_game_state_update();
|
||||
}
|
||||
@@ -915,13 +930,13 @@ int _gdialogInitFromScript(int headFid, int reaction)
|
||||
gGameDialogSpeakerIsPartyMember = objectIsPartyMember(gGameDialogSpeaker);
|
||||
_oldFont = fontGetCurrent();
|
||||
fontSetCurrent(101);
|
||||
dialogSetReplyWindow(135, 225, 379, 58, 0);
|
||||
dialogSetReplyWindow(135, 225, 379, 58, NULL);
|
||||
dialogSetReplyColor(0.3f, 0.3f, 0.3f);
|
||||
dialogSetOptionWindow(127, 335, 393, 117, 0);
|
||||
dialogSetOptionWindow(127, 335, 393, 117, NULL);
|
||||
dialogSetOptionColor(0.2f, 0.2f, 0.2f);
|
||||
dialogSetReplyTitle(NULL);
|
||||
_dialogRegisterWinDrawCallbacks(_demo_copy_title, _demo_copy_options);
|
||||
gameDialogPrepareHighlights();
|
||||
gameDialogHighlightsInit();
|
||||
colorCycleDisable();
|
||||
if (_gdDialogTurnMouseOff) {
|
||||
_gmouse_disable(0);
|
||||
@@ -930,12 +945,15 @@ int _gdialogInitFromScript(int headFid, int reaction)
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
textObjectsReset();
|
||||
|
||||
if ((gGameDialogSpeaker->pid >> 24) != OBJ_TYPE_ITEM) {
|
||||
if (PID_TYPE(gGameDialogSpeaker->pid) != OBJ_TYPE_ITEM) {
|
||||
_tile_scroll_to(gGameDialogSpeaker->tile, 2);
|
||||
}
|
||||
|
||||
_talk_need_to_center = 1;
|
||||
|
||||
// CE: Fix Barter button.
|
||||
gameDialogRedButtonsInit();
|
||||
|
||||
_gdCreateHeadWindow();
|
||||
tickersAdd(gameDialogTicker);
|
||||
_gdSetupFidget(headFid, reaction);
|
||||
@@ -970,7 +988,7 @@ int _gdialogExitFromScript()
|
||||
dialogReviewEntriesClear();
|
||||
tickersRemove(gameDialogTicker);
|
||||
|
||||
if (gGameDialogSpeaker->pid >> 24 != OBJ_TYPE_ITEM) {
|
||||
if (PID_TYPE(gGameDialogSpeaker->pid) != OBJ_TYPE_ITEM) {
|
||||
if (gGameDialogOldDudeTile != gDude->tile) {
|
||||
gGameDialogOldCenterTile = gDude->tile;
|
||||
}
|
||||
@@ -979,6 +997,9 @@ int _gdialogExitFromScript()
|
||||
|
||||
_gdDestroyHeadWindow();
|
||||
|
||||
// CE: Fix Barter button.
|
||||
gameDialogRedButtonsExit();
|
||||
|
||||
fontSetCurrent(_oldFont);
|
||||
|
||||
if (gGameDialogFidgetFrm != NULL) {
|
||||
@@ -995,11 +1016,8 @@ int _gdialogExitFromScript()
|
||||
_lipsFID = 0;
|
||||
}
|
||||
|
||||
_freeColorBlendTable(_colorTable[17969]);
|
||||
_freeColorBlendTable(_colorTable[22187]);
|
||||
|
||||
artUnlock(gGameDialogUpperHighlightFrmHandle);
|
||||
artUnlock(gGameDialogLowerHighlightFrmHandle);
|
||||
// NOTE: Uninline.
|
||||
gameDialogHighlightsExit();
|
||||
|
||||
_gdialog_state = 0;
|
||||
_dialogue_state = 0;
|
||||
@@ -1067,7 +1085,15 @@ void gameDialogRenderSupplementaryMessage(char* msg)
|
||||
int lineHeight = fontGetLineHeight();
|
||||
|
||||
int a4 = 0;
|
||||
gameDialogDrawText(windowBuffer, &_replyRect, msg, &a4, lineHeight, 379, _colorTable[992] | 0x2000000, 1);
|
||||
|
||||
// NOTE: Uninline.
|
||||
text_to_rect_wrapped(windowBuffer,
|
||||
&_replyRect,
|
||||
msg,
|
||||
&a4,
|
||||
lineHeight,
|
||||
379,
|
||||
_colorTable[992] | 0x2000000);
|
||||
|
||||
windowUnhide(_gd_replyWin);
|
||||
windowRefresh(gGameDialogReplyWindow);
|
||||
@@ -1208,6 +1234,24 @@ void _gdialogUpdatePartyStatus()
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
gdHide();
|
||||
|
||||
_gdialog_window_destroy();
|
||||
|
||||
gGameDialogSpeakerIsPartyMember = isPartyMember;
|
||||
|
||||
_gdialog_window_create();
|
||||
|
||||
// NOTE: Uninline.
|
||||
gdUnhide();
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4457EC
|
||||
static int gdHide()
|
||||
{
|
||||
if (_gd_replyWin != -1) {
|
||||
windowHide(_gd_replyWin);
|
||||
}
|
||||
@@ -1216,12 +1260,14 @@ void _gdialogUpdatePartyStatus()
|
||||
windowHide(_gd_optionsWin);
|
||||
}
|
||||
|
||||
_gdialog_window_destroy();
|
||||
|
||||
gGameDialogSpeakerIsPartyMember = isPartyMember;
|
||||
|
||||
_gdialog_window_create();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x445818
|
||||
static int gdUnhide()
|
||||
{
|
||||
if (_gd_replyWin != -1) {
|
||||
windowUnhide(_gd_replyWin);
|
||||
}
|
||||
@@ -1229,6 +1275,8 @@ void _gdialogUpdatePartyStatus()
|
||||
if (_gd_optionsWin != -1) {
|
||||
windowUnhide(_gd_optionsWin);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x44585C
|
||||
@@ -1298,7 +1346,7 @@ int gameDialogReviewWindowInit(int* win)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fid = buildFid(6, 102, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, 102, 0, 0, 0);
|
||||
unsigned char* backgroundFrmData = artLockFrameData(fid, 0, 0, &_reviewBackKey);
|
||||
if (backgroundFrmData == NULL) {
|
||||
windowDestroy(*win);
|
||||
@@ -1318,10 +1366,10 @@ int gameDialogReviewWindowInit(int* win)
|
||||
_reviewBackKey = INVALID_CACHE_ENTRY;
|
||||
|
||||
unsigned char* buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_COUNT];
|
||||
|
||||
|
||||
int index;
|
||||
for (index = 0; index < GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_COUNT; index++) {
|
||||
int fid = buildFid(6, gGameDialogReviewWindowButtonFrmIds[index], 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, gGameDialogReviewWindowButtonFrmIds[index], 0, 0, 0);
|
||||
buttonFrmData[index] = artLockFrameData(fid, 0, 0, &(gGameDialogReviewWindowButtonFrmHandles[index]));
|
||||
if (buttonFrmData[index] == NULL) {
|
||||
break;
|
||||
@@ -1360,11 +1408,11 @@ int gameDialogReviewWindowInit(int* win)
|
||||
gGameDialogReviewWindowButtonHeights[GAME_DIALOG_REVIEW_WINDOW_BUTTON_SCROLL_DOWN],
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
KEY_ARROW_DOWN,
|
||||
buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_ARROW_DOWN_NORMAL],
|
||||
buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_ARROW_DOWN_PRESSED],
|
||||
NULL,
|
||||
buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_ARROW_DOWN_PRESSED],
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (downBtn == -1) {
|
||||
gameDialogReviewWindowFree(win);
|
||||
@@ -1373,18 +1421,18 @@ int gameDialogReviewWindowInit(int* win)
|
||||
|
||||
buttonSetCallbacks(downBtn, _gsound_med_butt_press, _gsound_med_butt_release);
|
||||
|
||||
int doneBtn = buttonCreate(*win,
|
||||
499,
|
||||
398,
|
||||
gGameDialogReviewWindowButtonWidths[GAME_DIALOG_REVIEW_WINDOW_BUTTON_DONE],
|
||||
int doneBtn = buttonCreate(*win,
|
||||
499,
|
||||
398,
|
||||
gGameDialogReviewWindowButtonWidths[GAME_DIALOG_REVIEW_WINDOW_BUTTON_DONE],
|
||||
gGameDialogReviewWindowButtonHeights[GAME_DIALOG_REVIEW_WINDOW_BUTTON_DONE],
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
KEY_ESCAPE,
|
||||
buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_DONE_NORMAL],
|
||||
-1,
|
||||
-1,
|
||||
KEY_ESCAPE,
|
||||
buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_DONE_NORMAL],
|
||||
buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_DONE_PRESSED],
|
||||
NULL,
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (doneBtn == -1) {
|
||||
gameDialogReviewWindowFree(win);
|
||||
@@ -1399,7 +1447,7 @@ int gameDialogReviewWindowInit(int* win)
|
||||
|
||||
tickersRemove(gameDialogTicker);
|
||||
|
||||
int backgroundFid = buildFid(6, 102, 0, 0, 0);
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 102, 0, 0, 0);
|
||||
gGameDialogReviewWindowBackgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &gGameDialogReviewWindowBackgroundFrmHandle);
|
||||
if (gGameDialogReviewWindowBackgroundFrmData == NULL) {
|
||||
gameDialogReviewWindowFree(win);
|
||||
@@ -1540,7 +1588,14 @@ void gameDialogReviewWindowUpdate(int win, int origin)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
y = gameDialogDrawText(windowBuffer + 113, &entriesRect, replyText, NULL, fontGetLineHeight(), 640, _colorTable[768] | 0x2000000, 1);
|
||||
// NOTE: Uninline.
|
||||
y = text_to_rect_wrapped(windowBuffer + 113,
|
||||
&entriesRect,
|
||||
replyText,
|
||||
NULL,
|
||||
fontGetLineHeight(),
|
||||
640,
|
||||
_colorTable[768] | 0x2000000);
|
||||
|
||||
// SFALL: Cosmetic fix to the dialog review interface to prevent the
|
||||
// player name from being displayed at the bottom of the window when the
|
||||
@@ -1566,7 +1621,14 @@ void gameDialogReviewWindowUpdate(int win, int origin)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
y = gameDialogDrawText(windowBuffer + 113, &entriesRect, optionText, NULL, fontGetLineHeight(), 640, _colorTable[15855] | 0x2000000, 1);
|
||||
// NOTE: Uninline.
|
||||
y = text_to_rect_wrapped(windowBuffer + 113,
|
||||
&entriesRect,
|
||||
optionText,
|
||||
NULL,
|
||||
fontGetLineHeight(),
|
||||
640,
|
||||
_colorTable[15855] | 0x2000000);
|
||||
}
|
||||
|
||||
if (y >= 407) {
|
||||
@@ -1691,11 +1753,10 @@ int gameDialogSetReviewOptionText(const char* string)
|
||||
// 0x446288
|
||||
int _gdProcessInit()
|
||||
{
|
||||
int upBtn;
|
||||
int upBtn;
|
||||
int downBtn;
|
||||
int optionsWindowX;
|
||||
int optionsWindowY;
|
||||
int fid;
|
||||
|
||||
int replyWindowX = (screenGetWidth() - GAME_DIALOG_WINDOW_WIDTH) / 2 + GAME_DIALOG_REPLY_WINDOW_X;
|
||||
int replyWindowY = (screenGetHeight() - GAME_DIALOG_WINDOW_HEIGHT) / 2 + GAME_DIALOG_REPLY_WINDOW_Y;
|
||||
@@ -1734,30 +1795,13 @@ int _gdProcessInit()
|
||||
goto err_2;
|
||||
}
|
||||
|
||||
// di_rdbt2.frm - dialog red button down
|
||||
fid = buildFid(6, 96, 0, 0, 0);
|
||||
gGameDialogRedButtonUpFrmData = artLockFrameData(fid, 0, 0, &gGameDialogRedButtonUpFrmHandle);
|
||||
if (gGameDialogRedButtonUpFrmData == NULL) {
|
||||
goto err_3;
|
||||
}
|
||||
|
||||
// di_rdbt1.frm - dialog red button up
|
||||
fid = buildFid(6, 95, 0, 0, 0);
|
||||
gGameDialogRedButtonDownFrmData = artLockFrameData(fid, 0, 0, &gGameDialogRedButtonDownFrmHandle);
|
||||
if (gGameDialogRedButtonDownFrmData == NULL) {
|
||||
goto err_3;
|
||||
}
|
||||
// CE: Move red buttons init to `_gdialogInitFromScript`.
|
||||
|
||||
_talkOldFont = fontGetCurrent();
|
||||
fontSetCurrent(101);
|
||||
|
||||
return 0;
|
||||
|
||||
err_3:
|
||||
|
||||
artUnlock(gGameDialogRedButtonUpFrmHandle);
|
||||
gGameDialogRedButtonUpFrmHandle = NULL;
|
||||
|
||||
err_2:
|
||||
|
||||
windowDestroy(gGameDialogOptionsWindow);
|
||||
@@ -1795,13 +1839,7 @@ int _gdProcessExit()
|
||||
{
|
||||
_gdProcessCleanup();
|
||||
|
||||
artUnlock(gGameDialogRedButtonDownFrmHandle);
|
||||
gGameDialogRedButtonDownFrmHandle = NULL;
|
||||
gGameDialogRedButtonDownFrmData = NULL;
|
||||
|
||||
artUnlock(gGameDialogRedButtonUpFrmHandle);
|
||||
gGameDialogRedButtonUpFrmHandle = NULL;
|
||||
gGameDialogRedButtonUpFrmData = NULL;
|
||||
// CE: Move red buttons exit to `_gdialogExitFromScript`.
|
||||
|
||||
windowDestroy(gGameDialogReplyWindow);
|
||||
gGameDialogReplyWindow = -1;
|
||||
@@ -1869,6 +1907,8 @@ int _gdProcess()
|
||||
for (;;) {
|
||||
int keyCode = _get_input();
|
||||
|
||||
convertMouseWheelToArrowKey(&keyCode);
|
||||
|
||||
if (keyCode == KEY_CTRL_Q || keyCode == KEY_CTRL_X || keyCode == KEY_F10) {
|
||||
showQuitConfirmationDialog();
|
||||
}
|
||||
@@ -1960,6 +2000,11 @@ int _gdProcess()
|
||||
} else if (keyCode >= 1300 && keyCode <= 1330) {
|
||||
gameDialogOptionOnMouseExit(keyCode - 1300);
|
||||
} else if (keyCode >= 48 && keyCode <= 57) {
|
||||
// SFALL: Prevents from using 0 to escape from dialogue at any time.
|
||||
if (keyCode == KEY_0 && gGameDialogFix) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int v11 = keyCode - 49;
|
||||
if (v11 < gGameDialogOptionEntriesLength) {
|
||||
pageCount = 0;
|
||||
@@ -2107,8 +2152,14 @@ void gameDialogOptionOnMouseEnter(int index)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* windowBuffer = windowGetBuffer(gGameDialogOptionsWindow);
|
||||
gameDialogDrawText(windowBuffer, &_optionRect, dialogOptionEntry->text, NULL, fontGetLineHeight(), 393, color, 1);
|
||||
// NOTE: Uninline.
|
||||
text_to_rect_wrapped(windowGetBuffer(gGameDialogOptionsWindow),
|
||||
&_optionRect,
|
||||
dialogOptionEntry->text,
|
||||
NULL,
|
||||
fontGetLineHeight(),
|
||||
393,
|
||||
color);
|
||||
|
||||
_optionRect.left = 0;
|
||||
_optionRect.right = 391;
|
||||
@@ -2149,8 +2200,14 @@ void gameDialogOptionOnMouseExit(int index)
|
||||
_optionRect.left = 5;
|
||||
_optionRect.right = 388;
|
||||
|
||||
unsigned char* windowBuffer = windowGetBuffer(gGameDialogOptionsWindow);
|
||||
gameDialogDrawText(windowBuffer, &_optionRect, dialogOptionEntry->text, NULL, fontGetLineHeight(), 393, color, 1);
|
||||
// NOTE: Uninline.
|
||||
text_to_rect_wrapped(windowGetBuffer(gGameDialogOptionsWindow),
|
||||
&_optionRect,
|
||||
dialogOptionEntry->text,
|
||||
NULL,
|
||||
fontGetLineHeight(),
|
||||
393,
|
||||
color);
|
||||
|
||||
_optionRect.right = 391;
|
||||
_optionRect.top = dialogOptionEntry->field_14;
|
||||
@@ -2171,16 +2228,14 @@ void gameDialogRenderReply()
|
||||
|
||||
_demo_copy_title(gGameDialogReplyWindow);
|
||||
|
||||
// Render reply.
|
||||
unsigned char* windowBuffer = windowGetBuffer(gGameDialogReplyWindow);
|
||||
gameDialogDrawText(windowBuffer,
|
||||
// NOTE: Uninline.
|
||||
text_to_rect_wrapped(windowGetBuffer(gGameDialogReplyWindow),
|
||||
&_replyRect,
|
||||
gDialogReplyText,
|
||||
&dword_58F4E0,
|
||||
fontGetLineHeight(),
|
||||
379,
|
||||
_colorTable[992] | 0x2000000,
|
||||
1);
|
||||
_colorTable[992] | 0x2000000);
|
||||
windowRefresh(gGameDialogReplyWindow);
|
||||
}
|
||||
|
||||
@@ -2290,14 +2345,14 @@ void _gdProcessUpdate()
|
||||
y = 0;
|
||||
}
|
||||
|
||||
gameDialogDrawText(windowGetBuffer(gGameDialogOptionsWindow),
|
||||
// NOTE: Uninline.
|
||||
text_to_rect_wrapped(windowGetBuffer(gGameDialogOptionsWindow),
|
||||
&_optionRect,
|
||||
dialogOptionEntry->text,
|
||||
NULL,
|
||||
fontGetLineHeight(),
|
||||
393,
|
||||
color,
|
||||
1);
|
||||
color);
|
||||
|
||||
_optionRect.top += 2;
|
||||
|
||||
@@ -2328,14 +2383,8 @@ int _gdCreateHeadWindow()
|
||||
|
||||
int windowWidth = GAME_DIALOG_WINDOW_WIDTH;
|
||||
|
||||
int backgroundWindowX = (screenGetWidth() - GAME_DIALOG_WINDOW_WIDTH) / 2;
|
||||
int backgroundWindowY = (screenGetHeight() - GAME_DIALOG_WINDOW_HEIGHT) / 2;
|
||||
gGameDialogBackgroundWindow = windowCreate(backgroundWindowX,
|
||||
backgroundWindowY,
|
||||
windowWidth,
|
||||
GAME_DIALOG_WINDOW_HEIGHT,
|
||||
256,
|
||||
WINDOW_FLAG_0x02);
|
||||
// NOTE: Uninline.
|
||||
talk_to_create_background_window();
|
||||
gameDialogWindowRenderBackground();
|
||||
|
||||
unsigned char* buf = windowGetBuffer(gGameDialogBackgroundWindow);
|
||||
@@ -2749,12 +2798,11 @@ void gameDialogTicker()
|
||||
_dialogue_switch_mode = 0;
|
||||
_gdialog_barter_destroy_win();
|
||||
_gdialog_window_create();
|
||||
if (_gd_replyWin != -1) {
|
||||
windowUnhide(_gd_replyWin);
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
gdUnhide();
|
||||
|
||||
if (_gd_optionsWin != -1) {
|
||||
windowUnhide(_gd_optionsWin);
|
||||
// SFALL: Fix for the player's money not being displayed in the
|
||||
// dialog window after leaving the barter/combat control interface.
|
||||
gameDialogRenderCaps();
|
||||
@@ -2969,6 +3017,14 @@ int _text_num_lines(const char* a1, int a2)
|
||||
return v1;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x447F80
|
||||
static int text_to_rect_wrapped(unsigned char* buffer, Rect* rect, char* string, int* a4, int height, int pitch, int color)
|
||||
{
|
||||
return gameDialogDrawText(buffer, rect, string, a4, height, pitch, color, 1);
|
||||
}
|
||||
|
||||
// display_msg
|
||||
// 0x447FA0
|
||||
int gameDialogDrawText(unsigned char* buffer, Rect* rect, char* string, int* a4, int height, int pitch, int color, int a7)
|
||||
@@ -3010,7 +3066,7 @@ int gameDialogDrawText(unsigned char* buffer, Rect* rect, char* string, int* a4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (*end == ' ') {
|
||||
*end = '\0';
|
||||
}
|
||||
@@ -3026,7 +3082,7 @@ int gameDialogDrawText(unsigned char* buffer, Rect* rect, char* string, int* a4,
|
||||
}
|
||||
|
||||
if (a4 != NULL) {
|
||||
*a4 += strlen(start) + 1;
|
||||
*a4 += static_cast<int>(strlen(start)) + 1;
|
||||
}
|
||||
|
||||
rect->top += height;
|
||||
@@ -3057,7 +3113,7 @@ int gameDialogDrawText(unsigned char* buffer, Rect* rect, char* string, int* a4,
|
||||
}
|
||||
|
||||
if (a4 != NULL && end != NULL) {
|
||||
*a4 += strlen(start) + 1;
|
||||
*a4 += static_cast<int>(strlen(start)) + 1;
|
||||
}
|
||||
|
||||
rect->top += height;
|
||||
@@ -3127,7 +3183,7 @@ int _gdialog_barter_create_win()
|
||||
frmId = 111;
|
||||
}
|
||||
|
||||
int backgroundFid = buildFid(6, frmId, 0, 0, 0);
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, frmId, 0, 0, 0);
|
||||
CacheEntry* backgroundHandle;
|
||||
Art* backgroundFrm = artLock(backgroundFid, &backgroundHandle);
|
||||
if (backgroundFrm == NULL) {
|
||||
@@ -3236,7 +3292,7 @@ void _gdialog_barter_destroy_win()
|
||||
}
|
||||
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
int fid = buildFid(6, frmId, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, frmId, 0, 0, 0);
|
||||
unsigned char* backgroundFrmData = artLockFrameData(fid, 0, 0, &backgroundFrmHandle);
|
||||
if (backgroundFrmData != NULL) {
|
||||
unsigned char* windowBuffer = windowGetBuffer(gGameDialogWindow);
|
||||
@@ -3247,7 +3303,7 @@ void _gdialog_barter_destroy_win()
|
||||
windowDestroy(gGameDialogWindow);
|
||||
gGameDialogWindow = -1;
|
||||
|
||||
_cai_attempt_w_reload(gGameDialogSpeaker, 0);
|
||||
aiAttemptWeaponReload(gGameDialogSpeaker, 0);
|
||||
}
|
||||
|
||||
// 0x448660
|
||||
@@ -3260,16 +3316,16 @@ void _gdialog_barter_cleanup_tables()
|
||||
length = inventory->length;
|
||||
for (int index = 0; index < length; index++) {
|
||||
Object* item = inventory->items->item;
|
||||
int quantity = _item_count(_peon_table_obj, item);
|
||||
_item_move_force(_peon_table_obj, gDude, item, quantity);
|
||||
int quantity = itemGetQuantity(_peon_table_obj, item);
|
||||
itemMoveForce(_peon_table_obj, gDude, item, quantity);
|
||||
}
|
||||
|
||||
inventory = &(_barterer_table_obj->data.inventory);
|
||||
length = inventory->length;
|
||||
for (int index = 0; index < length; index++) {
|
||||
Object* item = inventory->items->item;
|
||||
int quantity = _item_count(_barterer_table_obj, item);
|
||||
_item_move_force(_barterer_table_obj, gGameDialogSpeaker, item, quantity);
|
||||
int quantity = itemGetQuantity(_barterer_table_obj, item);
|
||||
itemMoveForce(_barterer_table_obj, gGameDialogSpeaker, item, quantity);
|
||||
}
|
||||
|
||||
if (_barterer_temp_obj != NULL) {
|
||||
@@ -3277,8 +3333,8 @@ void _gdialog_barter_cleanup_tables()
|
||||
length = inventory->length;
|
||||
for (int index = 0; index < length; index++) {
|
||||
Object* item = inventory->items->item;
|
||||
int quantity = _item_count(_barterer_temp_obj, item);
|
||||
_item_move_force(_barterer_temp_obj, gGameDialogSpeaker, item, quantity);
|
||||
int quantity = itemGetQuantity(_barterer_temp_obj, item);
|
||||
itemMoveForce(_barterer_temp_obj, gGameDialogSpeaker, item, quantity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3287,7 +3343,7 @@ void _gdialog_barter_cleanup_tables()
|
||||
int partyMemberControlWindowInit()
|
||||
{
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
int backgroundFid = buildFid(6, 390, 0, 0, 0);
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 390, 0, 0, 0);
|
||||
Art* backgroundFrm = artLock(backgroundFid, &backgroundFrmHandle);
|
||||
if (backgroundFrm == NULL) {
|
||||
return -1;
|
||||
@@ -3359,7 +3415,7 @@ int partyMemberControlWindowInit()
|
||||
GameDialogButtonData* buttonData = &(gGameDialogDispositionButtonsData[index]);
|
||||
int fid;
|
||||
|
||||
fid = buildFid(6, buttonData->upFrmId, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, buttonData->upFrmId, 0, 0, 0);
|
||||
Art* upButtonFrm = artLock(fid, &(buttonData->upFrmHandle));
|
||||
if (upButtonFrm == NULL) {
|
||||
partyMemberControlWindowFree();
|
||||
@@ -3370,7 +3426,7 @@ int partyMemberControlWindowInit()
|
||||
int height = artGetHeight(upButtonFrm, 0, 0);
|
||||
unsigned char* upButtonFrmData = artGetFrameData(upButtonFrm, 0, 0);
|
||||
|
||||
fid = buildFid(6, buttonData->downFrmId, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, buttonData->downFrmId, 0, 0, 0);
|
||||
Art* downButtonFrm = artLock(fid, &(buttonData->downFrmHandle));
|
||||
if (downButtonFrm == NULL) {
|
||||
partyMemberControlWindowFree();
|
||||
@@ -3379,7 +3435,7 @@ int partyMemberControlWindowInit()
|
||||
|
||||
unsigned char* downButtonFrmData = artGetFrameData(downButtonFrm, 0, 0);
|
||||
|
||||
fid = buildFid(6, buttonData->disabledFrmId, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, buttonData->disabledFrmId, 0, 0, 0);
|
||||
Art* disabledButtonFrm = artLock(fid, &(buttonData->disabledFrmHandle));
|
||||
if (disabledButtonFrm == NULL) {
|
||||
partyMemberControlWindowFree();
|
||||
@@ -3394,14 +3450,14 @@ int partyMemberControlWindowInit()
|
||||
buttonData->x,
|
||||
buttonData->y,
|
||||
width,
|
||||
height,
|
||||
height,
|
||||
-1,
|
||||
-1,
|
||||
buttonData->keyCode,
|
||||
-1,
|
||||
upButtonFrmData,
|
||||
-1,
|
||||
buttonData->keyCode,
|
||||
-1,
|
||||
upButtonFrmData,
|
||||
downButtonFrmData,
|
||||
NULL,
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT | BUTTON_FLAG_0x04 | BUTTON_FLAG_0x01);
|
||||
if (_gdialog_buttons[v21] == -1) {
|
||||
partyMemberControlWindowFree();
|
||||
@@ -3463,7 +3519,7 @@ void partyMemberControlWindowFree()
|
||||
|
||||
// control.frm - party member control interface
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
int backgroundFid = buildFid(6, 390, 0, 0, 0);
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 390, 0, 0, 0);
|
||||
unsigned char* backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle);
|
||||
if (backgroundFrmData != NULL) {
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, 0, backgroundFrmData, windowGetBuffer(gGameDialogWindow), windowGetBuffer(gGameDialogBackgroundWindow) + (GAME_DIALOG_WINDOW_WIDTH) * (480 - _dialogue_subwin_len), _dialogue_subwin_len, 0);
|
||||
@@ -3484,7 +3540,7 @@ void partyMemberControlWindowUpdate()
|
||||
int windowWidth = windowGetWidth(gGameDialogWindow);
|
||||
|
||||
CacheEntry* backgroundHandle;
|
||||
int backgroundFid = buildFid(6, 390, 0, 0, 0);
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 390, 0, 0, 0);
|
||||
Art* background = artLock(backgroundFid, &backgroundHandle);
|
||||
if (background != NULL) {
|
||||
int width = artGetWidth(background, 0, 0);
|
||||
@@ -3523,7 +3579,7 @@ void partyMemberControlWindowUpdate()
|
||||
|
||||
// Render preview.
|
||||
CacheEntry* previewHandle;
|
||||
int previewFid = buildFid((gGameDialogSpeaker->fid & 0xF000000) >> 24, gGameDialogSpeaker->fid & 0xFFF, ANIM_STAND, (gGameDialogSpeaker->fid & 0xF000) >> 12, ROTATION_SW);
|
||||
int previewFid = buildFid(FID_TYPE(gGameDialogSpeaker->fid), gGameDialogSpeaker->fid & 0xFFF, ANIM_STAND, (gGameDialogSpeaker->fid & 0xF000) >> 12, ROTATION_SW);
|
||||
Art* preview = artLock(previewFid, &previewHandle);
|
||||
if (preview != NULL) {
|
||||
int width = artGetWidth(preview, 0, ROTATION_SW);
|
||||
@@ -3576,13 +3632,8 @@ void gameDialogCombatControlButtonOnMouseUp(int btn, int keyCode)
|
||||
_dialogue_switch_mode = 8;
|
||||
_dialogue_state = 10;
|
||||
|
||||
if (_gd_replyWin != -1) {
|
||||
windowHide(_gd_replyWin);
|
||||
}
|
||||
|
||||
if (_gd_optionsWin != -1) {
|
||||
windowHide(_gd_optionsWin);
|
||||
}
|
||||
// NOTE: Uninline.
|
||||
gdHide();
|
||||
}
|
||||
|
||||
// 0x4492D0
|
||||
@@ -3603,7 +3654,7 @@ int _gdPickAIUpdateMsg(Object* critter)
|
||||
// 0x449330
|
||||
int _gdCanBarter()
|
||||
{
|
||||
if ((gGameDialogSpeaker->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(gGameDialogSpeaker->pid) != OBJ_TYPE_CRITTER) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -3612,7 +3663,7 @@ int _gdCanBarter()
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (proto->critter.data.flags & 0x02) {
|
||||
if (proto->critter.data.flags & CRITTER_FLAG_0x2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -3658,7 +3709,7 @@ void partyMemberControlWindowHandleEvents()
|
||||
Object* weapon = _ai_search_inven_weap(gGameDialogSpeaker, 0, NULL);
|
||||
if (weapon != NULL) {
|
||||
_inven_wield(gGameDialogSpeaker, weapon, 1);
|
||||
_cai_attempt_w_reload(gGameDialogSpeaker, 0);
|
||||
aiAttemptWeaponReload(gGameDialogSpeaker, 0);
|
||||
|
||||
int num = _gdPickAIUpdateMsg(gGameDialogSpeaker);
|
||||
char* msg = getmsg(&gProtoMessageList, &messageListItem, num);
|
||||
@@ -3724,7 +3775,7 @@ int partyMemberCustomizationWindowInit()
|
||||
}
|
||||
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
int backgroundFid = buildFid(6, 391, 0, 0, 0);
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 391, 0, 0, 0);
|
||||
Art* backgroundFrm = artLock(backgroundFid, &backgroundFrmHandle);
|
||||
if (backgroundFrm == NULL) {
|
||||
return -1;
|
||||
@@ -3778,7 +3829,7 @@ int partyMemberCustomizationWindowInit()
|
||||
for (int index = 0; index < PARTY_MEMBER_CUSTOMIZATION_OPTION_COUNT; index++) {
|
||||
GameDialogButtonData* buttonData = &(_custom_button_info[index]);
|
||||
|
||||
int upButtonFid = buildFid(6, buttonData->upFrmId, 0, 0, 0);
|
||||
int upButtonFid = buildFid(OBJ_TYPE_INTERFACE, buttonData->upFrmId, 0, 0, 0);
|
||||
Art* upButtonFrm = artLock(upButtonFid, &(buttonData->upFrmHandle));
|
||||
if (upButtonFrm == NULL) {
|
||||
partyMemberCustomizationWindowFree();
|
||||
@@ -3789,7 +3840,7 @@ int partyMemberCustomizationWindowInit()
|
||||
int height = artGetHeight(upButtonFrm, 0, 0);
|
||||
unsigned char* upButtonFrmData = artGetFrameData(upButtonFrm, 0, 0);
|
||||
|
||||
int downButtonFid = buildFid(6, buttonData->downFrmId, 0, 0, 0);
|
||||
int downButtonFid = buildFid(OBJ_TYPE_INTERFACE, buttonData->downFrmId, 0, 0, 0);
|
||||
Art* downButtonFrm = artLock(downButtonFid, &(buttonData->downFrmHandle));
|
||||
if (downButtonFrm == NULL) {
|
||||
partyMemberCustomizationWindowFree();
|
||||
@@ -3867,7 +3918,7 @@ void partyMemberCustomizationWindowFree()
|
||||
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
// custom.frm - party member control interface
|
||||
int fid = buildFid(6, 391, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, 391, 0, 0, 0);
|
||||
unsigned char* backgroundFrmData = artLockFrameData(fid, 0, 0, &backgroundFrmHandle);
|
||||
if (backgroundFrmData != NULL) {
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, 0, backgroundFrmData, windowGetBuffer(gGameDialogWindow), windowGetBuffer(gGameDialogBackgroundWindow) + (GAME_DIALOG_WINDOW_WIDTH) * (480 - _dialogue_subwin_len), _dialogue_subwin_len, 0);
|
||||
@@ -3917,7 +3968,7 @@ void partyMemberCustomizationWindowUpdate()
|
||||
int windowWidth = windowGetWidth(gGameDialogWindow);
|
||||
|
||||
CacheEntry* backgroundHandle;
|
||||
int backgroundFid = buildFid(6, 391, 0, 0, 0);
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 391, 0, 0, 0);
|
||||
Art* background = artLock(backgroundFid, &backgroundHandle);
|
||||
if (background == NULL) {
|
||||
return;
|
||||
@@ -4025,7 +4076,7 @@ int _gdCustomSelect(int a1)
|
||||
int oldFont = fontGetCurrent();
|
||||
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
int backgroundFid = buildFid(6, 419, 0, 0, 0);
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 419, 0, 0, 0);
|
||||
Art* backgroundFrm = artLock(backgroundFid, &backgroundFrmHandle);
|
||||
if (backgroundFrm == NULL) {
|
||||
return -1;
|
||||
@@ -4208,7 +4259,7 @@ void _gdCustomUpdateSetting(int option, int value)
|
||||
// 0x44A52C
|
||||
void gameDialogBarterButtonUpMouseUp(int btn, int keyCode)
|
||||
{
|
||||
if ((gGameDialogSpeaker->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(gGameDialogSpeaker->pid) != OBJ_TYPE_CRITTER) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4219,7 +4270,7 @@ void gameDialogBarterButtonUpMouseUp(int btn, int keyCode)
|
||||
|
||||
Proto* proto;
|
||||
protoGetProto(gGameDialogSpeaker->pid, &proto);
|
||||
if (proto->critter.data.flags & 2) {
|
||||
if (proto->critter.data.flags & CRITTER_FLAG_0x2) {
|
||||
if (gGameDialogLipSyncStarted) {
|
||||
if (soundIsPlaying(gLipsData.sound)) {
|
||||
gameDialogEndLips();
|
||||
@@ -4229,13 +4280,8 @@ void gameDialogBarterButtonUpMouseUp(int btn, int keyCode)
|
||||
_dialogue_switch_mode = 2;
|
||||
_dialogue_state = 4;
|
||||
|
||||
if (_gd_replyWin != -1) {
|
||||
windowHide(_gd_replyWin);
|
||||
}
|
||||
|
||||
if (_gd_optionsWin != -1) {
|
||||
windowHide(_gd_optionsWin);
|
||||
}
|
||||
// NOTE: Uninline.
|
||||
gdHide();
|
||||
} else {
|
||||
MessageListItem messageListItem;
|
||||
// This person will not barter with you.
|
||||
@@ -4269,7 +4315,7 @@ int _gdialog_window_create()
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
// 389 - di_talkp.frm - dialog screen subwindow (party members)
|
||||
// 99 - di_talk.frm - dialog screen subwindow (NPC's)
|
||||
int backgroundFid = buildFid(6, gGameDialogSpeakerIsPartyMember ? 389 : 99, 0, 0, 0);
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, gGameDialogSpeakerIsPartyMember ? 389 : 99, 0, 0, 0);
|
||||
Art* backgroundFrm = artLock(backgroundFid, &backgroundFrmHandle);
|
||||
if (backgroundFrm == NULL) {
|
||||
return -1;
|
||||
@@ -4306,11 +4352,11 @@ int _gdialog_window_create()
|
||||
buttonSetCallbacks(_gdialog_buttons[0], _gsound_med_butt_press, _gsound_med_butt_release);
|
||||
|
||||
// di_rest1.frm - dialog rest button up
|
||||
int upFid = buildFid(6, 97, 0, 0, 0);
|
||||
int upFid = buildFid(OBJ_TYPE_INTERFACE, 97, 0, 0, 0);
|
||||
unsigned char* reviewButtonUpData = artLockFrameData(upFid, 0, 0, &gGameDialogReviewButtonUpFrmHandle);
|
||||
if (reviewButtonUpData != NULL) {
|
||||
// di_rest2.frm - dialog rest button down
|
||||
int downFid = buildFid(6, 98, 0, 0, 0);
|
||||
int downFid = buildFid(OBJ_TYPE_INTERFACE, 98, 0, 0, 0);
|
||||
unsigned char* reivewButtonDownData = artLockFrameData(downFid, 0, 0, &gGameDialogReviewButtonDownFrmHandle);
|
||||
if (reivewButtonDownData != NULL) {
|
||||
// REVIEW
|
||||
@@ -4386,7 +4432,7 @@ void _gdialog_window_destroy()
|
||||
}
|
||||
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
int fid = buildFid(6, frmId, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, frmId, 0, 0, 0);
|
||||
unsigned char* backgroundFrmData = artLockFrameData(fid, 0, 0, &backgroundFrmHandle);
|
||||
if (backgroundFrmData != NULL) {
|
||||
unsigned char* windowBuffer = windowGetBuffer(gGameDialogWindow);
|
||||
@@ -4398,12 +4444,33 @@ void _gdialog_window_destroy()
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x44AAD8
|
||||
static int talk_to_create_background_window()
|
||||
{
|
||||
int backgroundWindowX = (screenGetWidth() - GAME_DIALOG_WINDOW_WIDTH) / 2;
|
||||
int backgroundWindowY = (screenGetHeight() - GAME_DIALOG_WINDOW_HEIGHT) / 2;
|
||||
gGameDialogBackgroundWindow = windowCreate(backgroundWindowX,
|
||||
backgroundWindowY,
|
||||
GAME_DIALOG_WINDOW_WIDTH,
|
||||
GAME_DIALOG_WINDOW_HEIGHT,
|
||||
256,
|
||||
WINDOW_FLAG_0x02);
|
||||
|
||||
if (gGameDialogBackgroundWindow != -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x44AB18
|
||||
int gameDialogWindowRenderBackground()
|
||||
{
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
// alltlk.frm - dialog screen background
|
||||
int fid = buildFid(6, 103, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, 103, 0, 0, 0);
|
||||
unsigned char* backgroundFrmData = artLockFrameData(fid, 0, 0, &backgroundFrmHandle);
|
||||
if (backgroundFrmData == NULL) {
|
||||
return -1;
|
||||
@@ -4434,7 +4501,7 @@ int _talkToRefreshDialogWindowRect(Rect* rect)
|
||||
}
|
||||
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
int fid = buildFid(6, frmId, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, frmId, 0, 0, 0);
|
||||
unsigned char* backgroundFrmData = artLockFrameData(fid, 0, 0, &backgroundFrmHandle);
|
||||
if (backgroundFrmData == NULL) {
|
||||
return -1;
|
||||
@@ -4550,7 +4617,7 @@ void gameDialogRenderTalkingHead(Art* headFrm, int frame)
|
||||
unsigned char* src = windowGetBuffer(gIsoWindow);
|
||||
|
||||
// Usually rendering functions use `screenGetWidth`/`screenGetHeight` to
|
||||
// determine rendering position. However in this case `windowGetHeight`
|
||||
// determine rendering position. However in this case `windowGetHeight`
|
||||
// is a must because isometric window's height can either include
|
||||
// interface bar or not. Offset is updated accordingly (332 -> 232, the
|
||||
// missing 100 is interface bar height, which is already accounted for
|
||||
@@ -4595,7 +4662,7 @@ void gameDialogRenderTalkingHead(Art* headFrm, int frame)
|
||||
}
|
||||
|
||||
// 0x44B080
|
||||
void gameDialogPrepareHighlights()
|
||||
void gameDialogHighlightsInit()
|
||||
{
|
||||
for (int color = 0; color < 256; color++) {
|
||||
int r = (_Color2RGB_(color) & 0x7C00) >> 10;
|
||||
@@ -4612,14 +4679,58 @@ void gameDialogPrepareHighlights()
|
||||
_dark_BlendTable = _getColorBlendTable(_colorTable[22187]);
|
||||
|
||||
// hilight1.frm - dialogue upper hilight
|
||||
int upperHighlightFid = buildFid(6, 115, 0, 0, 0);
|
||||
int upperHighlightFid = buildFid(OBJ_TYPE_INTERFACE, 115, 0, 0, 0);
|
||||
gGameDialogUpperHighlightFrm = artLock(upperHighlightFid, &gGameDialogUpperHighlightFrmHandle);
|
||||
gGameDialogUpperHighlightFrmWidth = artGetWidth(gGameDialogUpperHighlightFrm, 0, 0);
|
||||
gGameDialogUpperHighlightFrmHeight = artGetHeight(gGameDialogUpperHighlightFrm, 0, 0);
|
||||
|
||||
// hilight2.frm - dialogue lower hilight
|
||||
int lowerHighlightFid = buildFid(6, 116, 0, 0, 0);
|
||||
int lowerHighlightFid = buildFid(OBJ_TYPE_INTERFACE, 116, 0, 0, 0);
|
||||
gGameDialogLowerHighlightFrm = artLock(lowerHighlightFid, &gGameDialogLowerHighlightFrmHandle);
|
||||
gGameDialogLowerHighlightFrmWidth = artGetWidth(gGameDialogLowerHighlightFrm, 0, 0);
|
||||
gGameDialogLowerHighlightFrmHeight = artGetHeight(gGameDialogLowerHighlightFrm, 0, 0);
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x44B1D4
|
||||
static void gameDialogHighlightsExit()
|
||||
{
|
||||
_freeColorBlendTable(_colorTable[17969]);
|
||||
_freeColorBlendTable(_colorTable[22187]);
|
||||
|
||||
artUnlock(gGameDialogUpperHighlightFrmHandle);
|
||||
artUnlock(gGameDialogLowerHighlightFrmHandle);
|
||||
}
|
||||
|
||||
static void gameDialogRedButtonsInit()
|
||||
{
|
||||
// di_rdbt2.frm - dialog red button down
|
||||
int pressedFid = buildFid(OBJ_TYPE_INTERFACE, 96, 0, 0, 0);
|
||||
gGameDialogRedButtonUpFrmData = artLockFrameData(pressedFid, 0, 0, &gGameDialogRedButtonUpFrmHandle);
|
||||
if (gGameDialogRedButtonUpFrmData == NULL) {
|
||||
gameDialogRedButtonsExit();
|
||||
}
|
||||
|
||||
// di_rdbt1.frm - dialog red button up
|
||||
int normalFid = buildFid(OBJ_TYPE_INTERFACE, 95, 0, 0, 0);
|
||||
gGameDialogRedButtonDownFrmData = artLockFrameData(normalFid, 0, 0, &gGameDialogRedButtonDownFrmHandle);
|
||||
if (gGameDialogRedButtonDownFrmData == NULL) {
|
||||
gameDialogRedButtonsExit();
|
||||
}
|
||||
}
|
||||
|
||||
static void gameDialogRedButtonsExit()
|
||||
{
|
||||
if (gGameDialogRedButtonDownFrmHandle != NULL) {
|
||||
artUnlock(gGameDialogRedButtonDownFrmHandle);
|
||||
gGameDialogRedButtonDownFrmHandle = NULL;
|
||||
gGameDialogRedButtonDownFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gGameDialogRedButtonUpFrmHandle != NULL) {
|
||||
artUnlock(gGameDialogRedButtonUpFrmHandle);
|
||||
gGameDialogRedButtonUpFrmHandle = NULL;
|
||||
gGameDialogRedButtonUpFrmData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include "game_mouse.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "actions.h"
|
||||
#include "animation.h"
|
||||
#include "art.h"
|
||||
@@ -16,16 +20,13 @@
|
||||
#include "object.h"
|
||||
#include "proto.h"
|
||||
#include "proto_instance.h"
|
||||
#include "sfall_config.h"
|
||||
#include "skill.h"
|
||||
#include "skilldex.h"
|
||||
#include "text_font.h"
|
||||
#include "tile.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef enum ScrollableDirections {
|
||||
SCROLLABLE_W = 0x01,
|
||||
SCROLLABLE_E = 0x02,
|
||||
@@ -308,12 +309,15 @@ static int gameMouseObjectsReset();
|
||||
static void gameMouseObjectsFree();
|
||||
static int gameMouseActionMenuInit();
|
||||
static void gameMouseActionMenuFree();
|
||||
static int gmouse_3d_set_flat_fid(int fid, Rect* rect);
|
||||
static int gameMouseUpdateHexCursorFid(Rect* rect);
|
||||
static int _gmouse_3d_move_to(int x, int y, int elevation, Rect* a4);
|
||||
static int gameMouseHandleScrolling(int x, int y, int cursor);
|
||||
static int objectIsDoor(Object* object);
|
||||
static bool gameMouseClickOnInterfaceBar();
|
||||
|
||||
static void customMouseModeFrmsInit();
|
||||
|
||||
// 0x44B2B0
|
||||
int gameMouseInit()
|
||||
{
|
||||
@@ -330,6 +334,9 @@ int gameMouseInit()
|
||||
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
|
||||
// SFALL
|
||||
customMouseModeFrmsInit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -420,6 +427,14 @@ void _gmouse_disable_scrolling()
|
||||
_gmouse_scrolling_enabled = 0;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x44B4E4
|
||||
bool gmouse_scrolling_is_enabled()
|
||||
{
|
||||
return _gmouse_scrolling_enabled;
|
||||
}
|
||||
|
||||
// 0x44B504
|
||||
int _gmouse_get_click_to_scroll()
|
||||
{
|
||||
@@ -477,7 +492,8 @@ void gameMouseRefresh()
|
||||
if (gGameMouseCursor >= FIRST_GAME_MOUSE_ANIMATED_CURSOR) {
|
||||
_mouse_info();
|
||||
|
||||
if (_gmouse_scrolling_enabled) {
|
||||
// NOTE: Uninline.
|
||||
if (gmouse_scrolling_is_enabled()) {
|
||||
mouseGetPosition(&mouseX, &mouseY);
|
||||
int oldMouseCursor = gGameMouseCursor;
|
||||
|
||||
@@ -519,7 +535,8 @@ void gameMouseRefresh()
|
||||
}
|
||||
|
||||
if (!_gmouse_enabled) {
|
||||
if (_gmouse_scrolling_enabled) {
|
||||
// NOTE: Uninline.
|
||||
if (gmouse_scrolling_is_enabled()) {
|
||||
mouseGetPosition(&mouseX, &mouseY);
|
||||
int oldMouseCursor = gGameMouseCursor;
|
||||
|
||||
@@ -648,7 +665,7 @@ void gameMouseRefresh()
|
||||
if (pointedObject != NULL) {
|
||||
int primaryAction = -1;
|
||||
|
||||
switch ((pointedObject->fid & 0xF000000) >> 24) {
|
||||
switch (FID_TYPE(pointedObject->fid)) {
|
||||
case OBJ_TYPE_ITEM:
|
||||
primaryAction = GAME_MOUSE_ACTION_MENU_ITEM_USE;
|
||||
if (gGameMouseItemHighlightEnabled) {
|
||||
@@ -670,7 +687,7 @@ void gameMouseRefresh()
|
||||
primaryAction = GAME_MOUSE_ACTION_MENU_ITEM_TALK;
|
||||
}
|
||||
} else {
|
||||
if (_critter_flag_check(pointedObject->pid, 32)) {
|
||||
if (_critter_flag_check(pointedObject->pid, CRITTER_FLAG_0x20)) {
|
||||
primaryAction = GAME_MOUSE_ACTION_MENU_ITEM_LOOK;
|
||||
} else {
|
||||
primaryAction = GAME_MOUSE_ACTION_MENU_ITEM_USE;
|
||||
@@ -693,8 +710,9 @@ void gameMouseRefresh()
|
||||
if (primaryAction != -1) {
|
||||
if (gameMouseRenderPrimaryAction(mouseX, mouseY, primaryAction, _scr_size.right - _scr_size.left + 1, _scr_size.bottom - _scr_size.top - 99) == 0) {
|
||||
Rect tmp;
|
||||
int fid = buildFid(6, 282, 0, 0, 0);
|
||||
if (objectSetFid(gGameMouseHexCursor, fid, &tmp) == 0) {
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, 282, 0, 0, 0);
|
||||
// NOTE: Uninline.
|
||||
if (gmouse_3d_set_flat_fid(fid, &tmp) == 0) {
|
||||
tileWindowRefreshRect(&tmp, gElevation);
|
||||
}
|
||||
}
|
||||
@@ -715,7 +733,7 @@ void gameMouseRefresh()
|
||||
}
|
||||
|
||||
if (pointedObject != NULL) {
|
||||
bool pointedObjectIsCritter = (pointedObject->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER;
|
||||
bool pointedObjectIsCritter = FID_TYPE(pointedObject->fid) == OBJ_TYPE_CRITTER;
|
||||
|
||||
int combatLooks = 0;
|
||||
configGetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_LOOKS_KEY, &combatLooks);
|
||||
@@ -756,8 +774,9 @@ void gameMouseRefresh()
|
||||
|
||||
if (gameMouseRenderAccuracy(formattedAccuracy, color) == 0) {
|
||||
Rect tmp;
|
||||
int fid = buildFid(6, 284, 0, 0, 0);
|
||||
if (objectSetFid(gGameMouseHexCursor, fid, &tmp) == 0) {
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, 284, 0, 0, 0);
|
||||
// NOTE: Uninline.
|
||||
if (gmouse_3d_set_flat_fid(fid, &tmp) == 0) {
|
||||
tileWindowRefreshRect(&tmp, gElevation);
|
||||
}
|
||||
}
|
||||
@@ -825,7 +844,7 @@ void gameMouseRefresh()
|
||||
gGameMouseLastY = mouseY;
|
||||
|
||||
if (!_gmouse_mapper_mode) {
|
||||
int fid = buildFid(6, 0, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, 0, 0, 0, 0);
|
||||
gameMouseSetBouncingCursorFid(fid);
|
||||
}
|
||||
|
||||
@@ -936,13 +955,13 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
if (gGameMouseMode == GAME_MOUSE_MODE_ARROW) {
|
||||
Object* v5 = gameMouseGetObjectUnderCursor(-1, true, gElevation);
|
||||
if (v5 != NULL) {
|
||||
switch ((v5->fid & 0xF000000) >> 24) {
|
||||
switch (FID_TYPE(v5->fid)) {
|
||||
case OBJ_TYPE_ITEM:
|
||||
actionPickUp(gDude, v5);
|
||||
break;
|
||||
case OBJ_TYPE_CRITTER:
|
||||
if (v5 == gDude) {
|
||||
if (((gDude->fid & 0xFF0000) >> 16) == ANIM_STAND) {
|
||||
if (FID_ANIM_TYPE(gDude->fid) == ANIM_STAND) {
|
||||
Rect a1;
|
||||
if (objectRotateClockwise(v5, &a1) == 0) {
|
||||
tileWindowRefreshRect(&a1, v5->elevation);
|
||||
@@ -1010,7 +1029,7 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
? HIT_MODE_RIGHT_WEAPON_PRIMARY
|
||||
: HIT_MODE_LEFT_WEAPON_PRIMARY;
|
||||
|
||||
int actionPointsRequired = _item_mp_cost(gDude, hitMode, false);
|
||||
int actionPointsRequired = itemGetActionPointCost(gDude, hitMode, false);
|
||||
if (actionPointsRequired <= gDude->data.critter.combat.ap) {
|
||||
if (_action_use_an_item_on_object(gDude, object, weapon) != -1) {
|
||||
int actionPoints = gDude->data.critter.combat.ap;
|
||||
@@ -1053,7 +1072,7 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
if (v16 != NULL) {
|
||||
int actionMenuItemsCount = 0;
|
||||
int actionMenuItems[6];
|
||||
switch ((v16->fid & 0xF000000) >> 24) {
|
||||
switch (FID_TYPE(v16->fid)) {
|
||||
case OBJ_TYPE_ITEM:
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_USE;
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_LOOK;
|
||||
@@ -1072,7 +1091,7 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_TALK;
|
||||
}
|
||||
} else {
|
||||
if (!_critter_flag_check(v16->pid, 32)) {
|
||||
if (!_critter_flag_check(v16->pid, CRITTER_FLAG_0x20)) {
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_USE;
|
||||
}
|
||||
}
|
||||
@@ -1108,8 +1127,9 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
|
||||
if (gameMouseRenderActionMenuItems(mouseX, mouseY, actionMenuItems, actionMenuItemsCount, _scr_size.right - _scr_size.left + 1, _scr_size.bottom - _scr_size.top - 99) == 0) {
|
||||
Rect v43;
|
||||
int fid = buildFid(6, 283, 0, 0, 0);
|
||||
if (objectSetFid(gGameMouseHexCursor, fid, &v43) == 0 && _gmouse_3d_move_to(mouseX, mouseY, gElevation, &v43) == 0) {
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, 283, 0, 0, 0);
|
||||
// NOTE: Uninline.
|
||||
if (gmouse_3d_set_flat_fid(fid, &v43) == 0 && _gmouse_3d_move_to(mouseX, mouseY, gElevation, &v43) == 0) {
|
||||
tileWindowRefreshRect(&v43, gElevation);
|
||||
isoDisable();
|
||||
|
||||
@@ -1171,7 +1191,7 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
actionTalk(gDude, v16);
|
||||
break;
|
||||
case GAME_MOUSE_ACTION_MENU_ITEM_USE:
|
||||
switch ((v16->fid & 0xF000000) >> 24) {
|
||||
switch (FID_TYPE(v16->fid)) {
|
||||
case OBJ_TYPE_SCENERY:
|
||||
_action_use_an_object(gDude, v16);
|
||||
break;
|
||||
@@ -1242,7 +1262,7 @@ int gameMouseSetCursor(int cursor)
|
||||
}
|
||||
|
||||
CacheEntry* mouseCursorFrmHandle;
|
||||
int fid = buildFid(6, gGameMouseCursorFrmIds[cursor], 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseCursorFrmIds[cursor], 0, 0, 0);
|
||||
Art* mouseCursorFrm = artLock(fid, &mouseCursorFrmHandle);
|
||||
if (mouseCursorFrm == NULL) {
|
||||
return -1;
|
||||
@@ -1327,13 +1347,14 @@ void gameMouseSetMode(int mode)
|
||||
return;
|
||||
}
|
||||
|
||||
int fid = buildFid(6, 0, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, 0, 0, 0, 0);
|
||||
gameMouseSetBouncingCursorFid(fid);
|
||||
|
||||
fid = buildFid(6, gGameMouseModeFrmIds[mode], 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseModeFrmIds[mode], 0, 0, 0);
|
||||
|
||||
Rect rect;
|
||||
if (objectSetFid(gGameMouseHexCursor, fid, &rect) == -1) {
|
||||
// NOTE: Uninline.
|
||||
if (gmouse_3d_set_flat_fid(fid, &rect) == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1472,7 +1493,7 @@ int gameMouseSetBouncingCursorFid(int fid)
|
||||
// 0x44CD0C
|
||||
void gameMouseResetBouncingCursorFid()
|
||||
{
|
||||
int fid = buildFid(6, 0, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, 0, 0, 0, 0);
|
||||
gameMouseSetBouncingCursorFid(fid);
|
||||
}
|
||||
|
||||
@@ -1601,7 +1622,7 @@ Object* gameMouseGetObjectUnderCursor(int objectType, bool a2, int elevation)
|
||||
v4 = ptr->object;
|
||||
if ((ptr->flags & 0x01) != 0) {
|
||||
if ((ptr->flags & 0x04) == 0) {
|
||||
if ((ptr->object->fid & 0xF000000) >> 24 != OBJ_TYPE_CRITTER || (ptr->object->data.critter.combat.results & (DAM_KNOCKED_OUT | DAM_DEAD)) == 0) {
|
||||
if (FID_TYPE(ptr->object->fid) != OBJ_TYPE_CRITTER || (ptr->object->data.critter.combat.results & (DAM_KNOCKED_OUT | DAM_DEAD)) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1620,14 +1641,14 @@ Object* gameMouseGetObjectUnderCursor(int objectType, bool a2, int elevation)
|
||||
int gameMouseRenderPrimaryAction(int x, int y, int menuItem, int width, int height)
|
||||
{
|
||||
CacheEntry* menuItemFrmHandle;
|
||||
int menuItemFid = buildFid(6, gGameMouseActionMenuItemFrmIds[menuItem], 0, 0, 0);
|
||||
int menuItemFid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseActionMenuItemFrmIds[menuItem], 0, 0, 0);
|
||||
Art* menuItemFrm = artLock(menuItemFid, &menuItemFrmHandle);
|
||||
if (menuItemFrm == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CacheEntry* arrowFrmHandle;
|
||||
int arrowFid = buildFid(6, gGameMouseModeFrmIds[GAME_MOUSE_MODE_ARROW], 0, 0, 0);
|
||||
int arrowFid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseModeFrmIds[GAME_MOUSE_MODE_ARROW], 0, 0, 0);
|
||||
Art* arrowFrm = artLock(arrowFid, &arrowFrmHandle);
|
||||
if (arrowFrm == NULL) {
|
||||
artUnlock(menuItemFrmHandle);
|
||||
@@ -1666,7 +1687,7 @@ int gameMouseRenderPrimaryAction(int x, int y, int menuItem, int width, int heig
|
||||
} else {
|
||||
artUnlock(arrowFrmHandle);
|
||||
|
||||
arrowFid = buildFid(6, 285, 0, 0, 0);
|
||||
arrowFid = buildFid(OBJ_TYPE_INTERFACE, 285, 0, 0, 0);
|
||||
arrowFrm = artLock(arrowFid, &arrowFrmHandle);
|
||||
arrowFrmData = artGetFrameData(arrowFrm, 0, 0);
|
||||
arrowFrmDest += menuItemFrmWidth;
|
||||
@@ -1725,7 +1746,7 @@ int gameMouseRenderActionMenuItems(int x, int y, const int* menuItems, int menuI
|
||||
frmId -= 1;
|
||||
}
|
||||
|
||||
int fid = buildFid(6, frmId, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, frmId, 0, 0, 0);
|
||||
|
||||
menuItemFrms[index] = artLock(fid, &(menuItemFrmHandles[index]));
|
||||
if (menuItemFrms[index] == NULL) {
|
||||
@@ -1736,7 +1757,7 @@ int gameMouseRenderActionMenuItems(int x, int y, const int* menuItems, int menuI
|
||||
}
|
||||
}
|
||||
|
||||
int fid = buildFid(6, gGameMouseModeFrmIds[GAME_MOUSE_MODE_ARROW], 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseModeFrmIds[GAME_MOUSE_MODE_ARROW], 0, 0, 0);
|
||||
CacheEntry* arrowFrmHandle;
|
||||
Art* arrowFrm = artLock(fid, &arrowFrmHandle);
|
||||
if (arrowFrm == NULL) {
|
||||
@@ -1772,7 +1793,7 @@ int gameMouseRenderActionMenuItems(int x, int y, const int* menuItems, int menuI
|
||||
}
|
||||
} else {
|
||||
// Mirrored arrow (from left to right).
|
||||
fid = buildFid(6, 285, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 285, 0, 0, 0);
|
||||
arrowFrm = artLock(fid, &arrowFrmHandle);
|
||||
arrowData = artGetFrameData(arrowFrm, 0, 0);
|
||||
gGameMouseActionMenuFrm->xOffsets[0] = -gGameMouseActionMenuFrm->xOffsets[0];
|
||||
@@ -1820,7 +1841,7 @@ int gameMouseHighlightActionMenuItemAtIndex(int menuItemIndex)
|
||||
}
|
||||
|
||||
CacheEntry* handle;
|
||||
int fid = buildFid(6, gGameMouseActionMenuItemFrmIds[gGameMouseActionMenuItems[gGameMouseActionMenuHighlightedItemIndex]], 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseActionMenuItemFrmIds[gGameMouseActionMenuItems[gGameMouseActionMenuHighlightedItemIndex]], 0, 0, 0);
|
||||
Art* art = artLock(fid, &handle);
|
||||
if (art == NULL) {
|
||||
return -1;
|
||||
@@ -1832,7 +1853,7 @@ int gameMouseHighlightActionMenuItemAtIndex(int menuItemIndex)
|
||||
blitBufferToBuffer(data, width, height, width, _gmouse_3d_menu_actions_start + gGameMouseActionMenuFrmWidth * height * gGameMouseActionMenuHighlightedItemIndex, gGameMouseActionMenuFrmWidth);
|
||||
artUnlock(handle);
|
||||
|
||||
fid = buildFid(6, gGameMouseActionMenuItemFrmIds[gGameMouseActionMenuItems[menuItemIndex]] - 1, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseActionMenuItemFrmIds[gGameMouseActionMenuItems[menuItemIndex]] - 1, 0, 0, 0);
|
||||
art = artLock(fid, &handle);
|
||||
if (art == NULL) {
|
||||
return -1;
|
||||
@@ -1851,7 +1872,7 @@ int gameMouseHighlightActionMenuItemAtIndex(int menuItemIndex)
|
||||
int gameMouseRenderAccuracy(const char* string, int color)
|
||||
{
|
||||
CacheEntry* crosshairFrmHandle;
|
||||
int fid = buildFid(6, gGameMouseModeFrmIds[GAME_MOUSE_MODE_CROSSHAIR], 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseModeFrmIds[GAME_MOUSE_MODE_CROSSHAIR], 0, 0, 0);
|
||||
Art* crosshairFrm = artLock(fid, &crosshairFrmHandle);
|
||||
if (crosshairFrm == NULL) {
|
||||
return -1;
|
||||
@@ -1910,7 +1931,7 @@ int gameMouseRenderActionPoints(const char* string, int color)
|
||||
|
||||
fontSetCurrent(oldFont);
|
||||
|
||||
int fid = buildFid(6, 1, 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, 1, 0, 0, 0);
|
||||
gameMouseSetBouncingCursorFid(fid);
|
||||
|
||||
return 0;
|
||||
@@ -1934,12 +1955,12 @@ int gameMouseObjectsInit()
|
||||
return -1;
|
||||
}
|
||||
|
||||
fid = buildFid(6, 0, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 0, 0, 0, 0);
|
||||
if (objectCreateWithFidPid(&gGameMouseBouncingCursor, fid, -1) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fid = buildFid(6, 1, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 1, 0, 0, 0);
|
||||
if (objectCreateWithFidPid(&gGameMouseHexCursor, fid, -1) != 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -2031,35 +2052,35 @@ int gameMouseActionMenuInit()
|
||||
int fid;
|
||||
|
||||
// actmenu.frm - action menu
|
||||
fid = buildFid(6, 283, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 283, 0, 0, 0);
|
||||
gGameMouseActionMenuFrm = artLock(fid, &gGameMouseActionMenuFrmHandle);
|
||||
if (gGameMouseActionMenuFrm == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// actpick.frm - action pick
|
||||
fid = buildFid(6, 282, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 282, 0, 0, 0);
|
||||
gGameMouseActionPickFrm = artLock(fid, &gGameMouseActionPickFrmHandle);
|
||||
if (gGameMouseActionPickFrm == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// acttohit.frm - action to hit
|
||||
fid = buildFid(6, 284, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 284, 0, 0, 0);
|
||||
gGameMouseActionHitFrm = artLock(fid, &gGameMouseActionHitFrmHandle);
|
||||
if (gGameMouseActionHitFrm == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// blank.frm - used be mset000.frm for top of bouncing mouse cursor
|
||||
fid = buildFid(6, 0, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 0, 0, 0, 0);
|
||||
gGameMouseBouncingCursorFrm = artLock(fid, &gGameMouseBouncingCursorFrmHandle);
|
||||
if (gGameMouseBouncingCursorFrm == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// msef000.frm - hex mouse cursor
|
||||
fid = buildFid(6, 1, 0, 0, 0);
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 1, 0, 0, 0);
|
||||
gGameMouseHexCursorFrm = artLock(fid, &gGameMouseHexCursorFrmHandle);
|
||||
if (gGameMouseHexCursorFrm == NULL) {
|
||||
goto err;
|
||||
@@ -2142,15 +2163,28 @@ void gameMouseActionMenuFree()
|
||||
gGameMouseActionPickFrmDataSize = 0;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x44DF1C
|
||||
static int gmouse_3d_set_flat_fid(int fid, Rect* rect)
|
||||
{
|
||||
if (objectSetFid(gGameMouseHexCursor, fid, rect) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x44DF40
|
||||
int gameMouseUpdateHexCursorFid(Rect* rect)
|
||||
{
|
||||
int fid = buildFid(6, gGameMouseModeFrmIds[gGameMouseMode], 0, 0, 0);
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseModeFrmIds[gGameMouseMode], 0, 0, 0);
|
||||
if (gGameMouseHexCursor->fid == fid) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return objectSetFid(gGameMouseHexCursor, fid, rect);
|
||||
// NOTE: Uninline.
|
||||
return gmouse_3d_set_flat_fid(fid, rect);
|
||||
}
|
||||
|
||||
// 0x44DF94
|
||||
@@ -2210,7 +2244,7 @@ int _gmouse_3d_move_to(int x, int y, int elevation, Rect* a4)
|
||||
int y1 = 0;
|
||||
|
||||
int fid = gGameMouseBouncingCursor->fid;
|
||||
if ((fid & 0xF000000) >> 24 == OBJ_TYPE_TILE) {
|
||||
if (FID_TYPE(fid) == OBJ_TYPE_TILE) {
|
||||
int squareTile = squareTileFromScreenXY(x, y, elevation);
|
||||
if (squareTile == -1) {
|
||||
tile = HEX_GRID_WIDTH * (2 * (squareTile / SQUARE_GRID_WIDTH) + 1) + 2 * (squareTile % SQUARE_GRID_WIDTH) + 1;
|
||||
@@ -2398,7 +2432,7 @@ int objectIsDoor(Object* object)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((object->pid >> 24) != OBJ_TYPE_SCENERY) {
|
||||
if (PID_TYPE(object->pid) != OBJ_TYPE_SCENERY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2409,3 +2443,14 @@ int objectIsDoor(Object* object)
|
||||
|
||||
return proto->scenery.type == SCENERY_TYPE_DOOR;
|
||||
}
|
||||
|
||||
static void customMouseModeFrmsInit()
|
||||
{
|
||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_FIRST_AID_FRM_KEY, &(gGameMouseModeFrmIds[GAME_MOUSE_MODE_USE_FIRST_AID]));
|
||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_DOCTOR_FRM_KEY, &(gGameMouseModeFrmIds[GAME_MOUSE_MODE_USE_DOCTOR]));
|
||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_LOCKPICK_FRM_KEY, &(gGameMouseModeFrmIds[GAME_MOUSE_MODE_USE_LOCKPICK]));
|
||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_STEAL_FRM_KEY, &(gGameMouseModeFrmIds[GAME_MOUSE_MODE_USE_STEAL]));
|
||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_TRAPS_FRM_KEY, &(gGameMouseModeFrmIds[GAME_MOUSE_MODE_USE_TRAPS]));
|
||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_SCIENCE_FRM_KEY, &(gGameMouseModeFrmIds[GAME_MOUSE_MODE_USE_SCIENCE]));
|
||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_REPAIR_FRM_KEY, &(gGameMouseModeFrmIds[GAME_MOUSE_MODE_USE_REPAIR]));
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ void _gmouse_enable();
|
||||
void _gmouse_disable(int a1);
|
||||
void _gmouse_enable_scrolling();
|
||||
void _gmouse_disable_scrolling();
|
||||
bool gmouse_scrolling_is_enabled();
|
||||
int _gmouse_is_scrolling();
|
||||
void gameMouseRefresh();
|
||||
void _gmouse_handle_event(int mouseX, int mouseY, int mouseState);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "game_movie.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
#include "cycle.h"
|
||||
@@ -13,12 +16,8 @@
|
||||
#include "palette.h"
|
||||
#include "platform_compat.h"
|
||||
#include "text_font.h"
|
||||
#include "widget.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define GAME_MOVIE_WINDOW_WIDTH 640
|
||||
#define GAME_MOVIE_WINDOW_HEIGHT 480
|
||||
|
||||
@@ -176,7 +175,7 @@ int gameMoviePlay(int movie, int flags)
|
||||
int gameMovieWindowY = (screenGetHeight() - GAME_MOVIE_WINDOW_HEIGHT) / 2;
|
||||
int win = windowCreate(gameMovieWindowX,
|
||||
gameMovieWindowY,
|
||||
GAME_MOVIE_WINDOW_WIDTH,
|
||||
GAME_MOVIE_WINDOW_WIDTH,
|
||||
GAME_MOVIE_WINDOW_HEIGHT,
|
||||
0,
|
||||
WINDOW_FLAG_0x10);
|
||||
@@ -221,11 +220,11 @@ int gameMoviePlay(int movie, int flags)
|
||||
|
||||
colorPaletteLoad(subtitlesPaletteFilePath);
|
||||
|
||||
oldTextColor = widgetGetTextColor();
|
||||
widgetSetTextColor(1.0, 1.0, 1.0);
|
||||
oldTextColor = windowGetTextColor();
|
||||
windowSetTextColor(1.0, 1.0, 1.0);
|
||||
|
||||
oldFont = fontGetCurrent();
|
||||
widgetSetFont(101);
|
||||
windowSetFont(101);
|
||||
}
|
||||
|
||||
bool cursorWasHidden = cursorIsHidden();
|
||||
@@ -258,7 +257,7 @@ int gameMoviePlay(int movie, int flags)
|
||||
_mouse_get_raw_state(&x, &y, &buttons);
|
||||
|
||||
v11 |= buttons;
|
||||
} while ((v11 & 1) == 0 && (v11 & 2) == 0 || (buttons & 1) != 0 || (buttons & 2) != 0);
|
||||
} while (((v11 & 1) == 0 && (v11 & 2) == 0) || (buttons & 1) != 0 || (buttons & 2) != 0);
|
||||
|
||||
_movieStop();
|
||||
_moviefx_stop();
|
||||
@@ -278,12 +277,12 @@ int gameMoviePlay(int movie, int flags)
|
||||
if (subtitlesEnabled) {
|
||||
colorPaletteLoad("color.pal");
|
||||
|
||||
widgetSetFont(oldFont);
|
||||
windowSetFont(oldFont);
|
||||
|
||||
float r = (float)((_Color2RGB_(oldTextColor) & 0x7C00) >> 10) * flt_50352A;
|
||||
float g = (float)((_Color2RGB_(oldTextColor) & 0x3E0) >> 5) * flt_50352A;
|
||||
float b = (float)(_Color2RGB_(oldTextColor) & 0x1F) * flt_50352A;
|
||||
widgetSetTextColor(r, g, b);
|
||||
windowSetTextColor(r, g, b);
|
||||
}
|
||||
|
||||
windowDestroy(win);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "game_sound.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "animation.h"
|
||||
#include "art.h"
|
||||
#include "audio.h"
|
||||
@@ -19,10 +22,7 @@
|
||||
#include "sound_effects_cache.h"
|
||||
#include "stat.h"
|
||||
#include "window_manager.h"
|
||||
#include "world_map.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "worldmap.h"
|
||||
|
||||
typedef enum SoundEffectActionType {
|
||||
SOUND_EFFECT_ACTION_TYPE_ACTIVE,
|
||||
@@ -1118,7 +1118,7 @@ Sound* soundEffectLoad(const char* name, Object* object)
|
||||
}
|
||||
|
||||
if (object != NULL) {
|
||||
if ((object->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER && (name[0] == 'H' || name[0] == 'N')) {
|
||||
if (FID_TYPE(object->fid) == OBJ_TYPE_CRITTER && (name[0] == 'H' || name[0] == 'N')) {
|
||||
char v9 = name[1];
|
||||
if (v9 == 'A' || v9 == 'F' || v9 == 'M') {
|
||||
if (v9 == 'A') {
|
||||
@@ -1230,7 +1230,7 @@ void soundEffectDelete(Sound* sound)
|
||||
}
|
||||
|
||||
// 0x4514F0
|
||||
int _gsnd_anim_sound(Sound* sound)
|
||||
int _gsnd_anim_sound(Sound* sound, void* a2)
|
||||
{
|
||||
if (!gGameSoundInitialized) {
|
||||
return 0;
|
||||
@@ -1287,7 +1287,7 @@ int _gsound_compute_relative_volume(Object* obj)
|
||||
v3 = 0x7FFF;
|
||||
|
||||
if (obj) {
|
||||
type = (obj->fid & 0xF000000) >> 24;
|
||||
type = FID_TYPE(obj->fid);
|
||||
if (type == 0 || type == 1 || type == 2) {
|
||||
v7 = objectGetOwner(obj);
|
||||
if (!v7) {
|
||||
@@ -1325,7 +1325,7 @@ char* sfxBuildCharName(Object* a1, int anim, int extra)
|
||||
char v8;
|
||||
char v9;
|
||||
|
||||
if (artCopyFileName((a1->fid & 0xF000000) >> 24, a1->fid & 0xFFF, v7) == -1) {
|
||||
if (artCopyFileName(FID_TYPE(a1->fid), a1->fid & 0xFFF, v7) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1400,11 +1400,12 @@ char* sfxBuildWeaponName(int effectType, Object* weapon, int hitMode, Object* ta
|
||||
}
|
||||
|
||||
int damageType = weaponGetDamageType(NULL, weapon);
|
||||
// TODO: Check damageType conditions.
|
||||
if (effectTypeCode != 'H' || target == NULL || damageType == DAMAGE_TYPE_EXPLOSION || damageType == DAMAGE_TYPE_PLASMA || damageType == DAMAGE_TYPE_EMP) {
|
||||
|
||||
// SFALL
|
||||
if (effectTypeCode != 'H' || target == NULL || damageType == explosionGetDamageType() || damageType == DAMAGE_TYPE_PLASMA || damageType == DAMAGE_TYPE_EMP) {
|
||||
materialCode = 'X';
|
||||
} else {
|
||||
const int type = (target->fid & 0xF000000) >> 24;
|
||||
const int type = FID_TYPE(target->fid);
|
||||
int material;
|
||||
switch (type) {
|
||||
case OBJ_TYPE_ITEM:
|
||||
@@ -1466,7 +1467,7 @@ char* sfxBuildSceneryName(int actionType, int action, const char* name)
|
||||
// 0x4518D
|
||||
char* sfxBuildOpenName(Object* object, int action)
|
||||
{
|
||||
if ((object->fid & 0xF000000) >> 24 == OBJ_TYPE_SCENERY) {
|
||||
if (FID_TYPE(object->fid) == OBJ_TYPE_SCENERY) {
|
||||
char scenerySoundId;
|
||||
Proto* proto;
|
||||
if (protoGetProto(object->pid, &proto) != -1) {
|
||||
@@ -1816,7 +1817,7 @@ int gameSoundFindBackgroundSoundPathWithCopy(char* dest, const char* src)
|
||||
int gameSoundFindBackgroundSoundPath(char* dest, const char* src)
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
int len;
|
||||
size_t len;
|
||||
|
||||
len = strlen(src) + strlen(".ACM");
|
||||
if (strlen(_sound_music_path1) + len > COMPAT_MAX_PATH || strlen(_sound_music_path2) + len > COMPAT_MAX_PATH) {
|
||||
@@ -1961,7 +1962,7 @@ int speechPlay()
|
||||
// 0x452208
|
||||
int _gsound_get_music_path(char** out_value, const char* key)
|
||||
{
|
||||
int v3;
|
||||
size_t v3;
|
||||
char* v4;
|
||||
char* value;
|
||||
|
||||
@@ -2104,8 +2105,8 @@ int ambientSoundEffectEventProcess(Object* a1, void* data)
|
||||
if (soundEffectEvent != NULL) {
|
||||
ambientSoundEffectIndex = soundEffectEvent->ambientSoundEffectIndex;
|
||||
} else {
|
||||
if (ambientSoundEffectGetLength() > 0) {
|
||||
ambientSoundEffectIndex = ambientSoundEffectGetRandom();
|
||||
if (wmSfxMaxCount() > 0) {
|
||||
ambientSoundEffectIndex = wmSfxRollNextIdx();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2119,8 +2120,8 @@ int ambientSoundEffectEventProcess(Object* a1, void* data)
|
||||
}
|
||||
|
||||
int delay = 10 * randomBetween(15, 20);
|
||||
if (ambientSoundEffectGetLength() > 0) {
|
||||
nextSoundEffectEvent->ambientSoundEffectIndex = ambientSoundEffectGetRandom();
|
||||
if (wmSfxMaxCount() > 0) {
|
||||
nextSoundEffectEvent->ambientSoundEffectIndex = wmSfxRollNextIdx();
|
||||
if (queueAddEvent(delay, NULL, nextSoundEffectEvent, EVENT_TYPE_GSOUND_SFX_EVENT) == -1) {
|
||||
return -1;
|
||||
}
|
||||
@@ -2132,7 +2133,7 @@ int ambientSoundEffectEventProcess(Object* a1, void* data)
|
||||
|
||||
if (ambientSoundEffectIndex != -1) {
|
||||
char* fileName;
|
||||
if (ambientSoundEffectGetName(ambientSoundEffectIndex, &fileName) == 0) {
|
||||
if (wmSfxIdxName(ambientSoundEffectIndex, &fileName) == 0) {
|
||||
int v7 = _get_bk_time();
|
||||
if (getTicksBetween(v7, _lastTime_1) >= 5000) {
|
||||
if (soundPlayFile(fileName) == -1) {
|
||||
|
||||
@@ -63,7 +63,7 @@ int _gsound_play_sfx_file_volume(const char* a1, int a2);
|
||||
Sound* soundEffectLoad(const char* name, Object* a2);
|
||||
Sound* soundEffectLoadWithVolume(const char* a1, Object* a2, int a3);
|
||||
void soundEffectDelete(Sound* a1);
|
||||
int _gsnd_anim_sound(Sound* a1);
|
||||
int _gsnd_anim_sound(Sound* sound, void* a2);
|
||||
int soundEffectPlay(Sound* a1);
|
||||
int _gsound_compute_relative_volume(Object* obj);
|
||||
char* sfxBuildCharName(Object* a1, int anim, int extra);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#include "geometry.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
// 0x51DEF4
|
||||
static RectListNode* _rectList = NULL;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "graph_lib.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "memory.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static void _InitTree();
|
||||
static void _InsertNode(int a1);
|
||||
static void _DeleteNode(int a1);
|
||||
@@ -108,7 +108,7 @@ int graphCompress(unsigned char* a1, unsigned char* a2, int a3)
|
||||
int v11 = v36 + 1;
|
||||
if (_match_length > 2) {
|
||||
v29[v36 + 1] = _match_position;
|
||||
v29[v36 + 2] = ((_match_length - 3) | (_match_position >> 4) & 0xF0);
|
||||
v29[v36 + 2] = ((_match_length - 3) | ((_match_position >> 4) & 0xF0));
|
||||
v36 = v11 + 1;
|
||||
} else {
|
||||
_match_length = 1;
|
||||
|
||||