Compare commits
144 Commits
v1.0.3
...
fix-androi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cca4a81e9 | ||
|
|
3924b6bba3 | ||
|
|
a1c1e03da0 | ||
|
|
ac0a044a32 | ||
|
|
4aae167bd8 | ||
|
|
2e5be31ed4 | ||
|
|
45278f66a5 | ||
|
|
2205077d36 | ||
|
|
67f966f7a9 | ||
|
|
463968d798 | ||
|
|
109dc6680c | ||
|
|
23c5f070fa | ||
|
|
fd9843f8dc | ||
|
|
443070226f | ||
|
|
db63d8a085 | ||
|
|
f203cfcc83 | ||
|
|
9ceb490f72 | ||
|
|
5b7a676b35 | ||
|
|
e50e26cf87 | ||
|
|
f59c072d68 | ||
|
|
79c396c1a0 | ||
|
|
9bb053b3ba | ||
|
|
3168c2ec09 | ||
|
|
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 |
1
.github/workflows/ci-build.yml
vendored
@@ -54,6 +54,7 @@ jobs:
|
||||
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
|
||||
|
||||
1
.github/workflows/release.yml
vendored
@@ -33,6 +33,7 @@ jobs:
|
||||
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
|
||||
|
||||
@@ -239,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"
|
||||
)
|
||||
@@ -276,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.
|
||||
@@ -42,7 +42,7 @@ $ sudo apt install libsdl2-2.0-0
|
||||
|
||||
- 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. There is no fancy importing interface (yet), just wait for about 30 seconds. The game will start automatically.
|
||||
- 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
|
||||
|
||||
@@ -52,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).
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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" >
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
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;
|
||||
@@ -8,10 +10,6 @@ import android.os.Bundle;
|
||||
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 ImportActivity extends Activity {
|
||||
private static final int IMPORT_REQUEST_CODE = 1;
|
||||
@@ -31,10 +29,8 @@ public class ImportActivity extends Activity {
|
||||
if (treeUri != null) {
|
||||
final DocumentFile treeDocument = DocumentFile.fromTreeUri(this, treeUri);
|
||||
if (treeDocument != null) {
|
||||
copyRecursively(treeDocument, getExternalFilesDir(null));
|
||||
|
||||
final Intent intent = new Intent(this, MainActivity.class);
|
||||
startActivity(intent);
|
||||
copyFiles(treeDocument);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,45 +41,34 @@ public class ImportActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean copyRecursively(DocumentFile src, File dest) {
|
||||
final DocumentFile[] documentFiles = src.listFiles();
|
||||
for (final DocumentFile documentFile : documentFiles) {
|
||||
if (documentFile.isFile()) {
|
||||
if (!copyFile(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();
|
||||
}
|
||||
private void copyFiles(DocumentFile treeDocument) {
|
||||
ProgressDialog dialog = createProgressDialog();
|
||||
dialog.show();
|
||||
|
||||
if (!copyRecursively(documentFile, subdirectory)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
new Thread(() -> {
|
||||
ContentResolver contentResolver = getContentResolver();
|
||||
File externalFilesDir = getExternalFilesDir(null);
|
||||
FileUtils.copyRecursively(contentResolver, treeDocument, externalFilesDir);
|
||||
|
||||
startMainActivity();
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
}).start();
|
||||
}
|
||||
|
||||
private boolean copyFile(DocumentFile src, File dest) {
|
||||
try {
|
||||
final InputStream inputStream = getContentResolver().openInputStream(src.getUri());
|
||||
final OutputStream outputStream = new FileOutputStream(dest);
|
||||
private void startMainActivity() {
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
final byte[] buffer = new byte[16384];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
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);
|
||||
|
||||
inputStream.close();
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return progressDialog;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2036,6 +2036,14 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||
switch (event.getAction()) {
|
||||
case KeyEvent.ACTION_DOWN:
|
||||
case KeyEvent.ACTION_UP:
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
SDLActivity.onNativeMouse(MotionEvent.BUTTON_SECONDARY, MotionEvent.ACTION_DOWN, 0, 0, true);
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
SDLActivity.onNativeMouse(MotionEvent.BUTTON_SECONDARY, MotionEvent.ACTION_UP, 0, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
// mark the event as handled or it will be handled by system
|
||||
// handling KEYCODE_BACK by system will call onBackPressed()
|
||||
return true;
|
||||
|
||||
@@ -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</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"
|
||||
163
src/actions.cc
@@ -1,5 +1,8 @@
|
||||
#include "actions.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "animation.h"
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
@@ -25,17 +28,23 @@
|
||||
#include "proto_types.h"
|
||||
#include "random.h"
|
||||
#include "scripts.h"
|
||||
#include "sfall_config.h"
|
||||
#include "skill.h"
|
||||
#include "stat.h"
|
||||
#include "text_object.h"
|
||||
#include "tile.h"
|
||||
#include "trait.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
#define MAX_KNOCKDOWN_DISTANCE 20
|
||||
|
||||
typedef enum ScienceRepairTargetType {
|
||||
SCIENCE_REPAIR_TARGET_TYPE_DEFAULT,
|
||||
SCIENCE_REPAIR_TARGET_TYPE_DUDE,
|
||||
SCIENCE_REPAIR_TARGET_TYPE_ANYONE,
|
||||
} ScienceRepairTargetType;
|
||||
|
||||
// 0x5106D0
|
||||
static int _action_in_explode = 0;
|
||||
|
||||
@@ -74,6 +83,7 @@ static int _action_melee(Attack* attack, int a2);
|
||||
static int _action_ranged(Attack* attack, int a2);
|
||||
static int _is_next_to(Object* a1, Object* a2);
|
||||
static int _action_climb_ladder(Object* a1, Object* a2);
|
||||
static int _action_use_skill_in_combat_error(Object* critter);
|
||||
static int _pick_fall(Object* obj, int anim);
|
||||
static int _report_explosion(Attack* attack, Object* a2);
|
||||
static int _finished_explosion(Object* a1, Object* a2);
|
||||
@@ -316,8 +326,32 @@ void _show_damage_to_object(Object* a1, int damage, int flags, Object* weapon, b
|
||||
sfx_name = sfxBuildCharName(a1, anim, CHARACTER_SOUND_EFFECT_UNUSED);
|
||||
animationRegisterPlaySoundEffect(a1, sfx_name, a10);
|
||||
|
||||
// SFALL
|
||||
if (explosionEmitsLight()) {
|
||||
// 0xFFFF0002:
|
||||
// - distance: 2
|
||||
// - intensity: 65535
|
||||
//
|
||||
// NOTE: Change intensity to 65536 (which is on par with
|
||||
// `anim_set_check_light_fix` Sfall's hack).
|
||||
animationRegisterSetLightIntensity(a1, 2, 65536, 0);
|
||||
}
|
||||
|
||||
animationRegisterAnimate(a1, anim, 0);
|
||||
|
||||
// SFALL
|
||||
if (explosionEmitsLight()) {
|
||||
// 0x00010000:
|
||||
// - distance: 0
|
||||
// - intensity: 1
|
||||
//
|
||||
// NOTE: Change intensity to 0. I guess using 1 was a
|
||||
// workaround for `anim_set_check_light_fix` hack which
|
||||
// requires two upper bytes to be non-zero to override
|
||||
// default behaviour.
|
||||
animationRegisterSetLightIntensity(a1, 0, 0, -1);
|
||||
}
|
||||
|
||||
int randomDistance = randomBetween(2, 5);
|
||||
int randomRotation = randomBetween(0, 5);
|
||||
|
||||
@@ -441,7 +475,7 @@ int _show_death(Object* obj, int anim)
|
||||
}
|
||||
|
||||
if (anim >= 30 && anim <= 31 && _critter_flag_check(obj->pid, CRITTER_FLAG_0x1000) == 0 && _critter_flag_check(obj->pid, CRITTER_FLAG_0x40) == 0) {
|
||||
_item_drop_all(obj, obj->tile);
|
||||
itemDropAll(obj, obj->tile);
|
||||
}
|
||||
|
||||
tileWindowRefreshRect(&v8, obj->elevation);
|
||||
@@ -682,7 +716,7 @@ int _action_ranged(Attack* attack, int anim)
|
||||
int actionFrame = (art != NULL) ? artGetActionFrame(art) : 0;
|
||||
artUnlock(artHandle);
|
||||
|
||||
_item_w_range(attack->attacker, attack->hitMode);
|
||||
weaponGetRange(attack->attacker, attack->hitMode);
|
||||
|
||||
int damageType = weaponGetDamageType(attack->attacker, attack->weapon);
|
||||
|
||||
@@ -692,7 +726,8 @@ int _action_ranged(Attack* attack, int anim)
|
||||
|
||||
bool isGrenade = false;
|
||||
if (anim == ANIM_THROW_ANIM) {
|
||||
if (damageType == DAMAGE_TYPE_EXPLOSION || damageType == DAMAGE_TYPE_PLASMA || damageType == DAMAGE_TYPE_EMP) {
|
||||
// SFALL
|
||||
if (damageType == explosionGetDamageType() || damageType == DAMAGE_TYPE_PLASMA || damageType == DAMAGE_TYPE_EMP) {
|
||||
isGrenade = true;
|
||||
}
|
||||
} else {
|
||||
@@ -728,7 +763,7 @@ int _action_ranged(Attack* attack, int anim)
|
||||
interfaceGetItemActions(&leftItemAction, &rightItemAction);
|
||||
|
||||
itemRemove(attack->attacker, weapon, 1);
|
||||
v50 = _item_replace(attack->attacker, weapon, weaponFlags & OBJECT_IN_ANY_HAND);
|
||||
v50 = itemReplace(attack->attacker, weapon, weaponFlags & OBJECT_IN_ANY_HAND);
|
||||
objectSetFid(projectile, projectileProto->fid, NULL);
|
||||
_cAIPrepWeaponItem(attack->attacker, weapon);
|
||||
|
||||
@@ -750,7 +785,12 @@ int _action_ranged(Attack* attack, int anim)
|
||||
|
||||
objectHide(projectile, NULL);
|
||||
|
||||
objectSetLight(projectile, 9, projectile->lightIntensity, NULL);
|
||||
// SFALL
|
||||
if (explosionEmitsLight() && projectile->lightIntensity == 0) {
|
||||
objectSetLight(projectile, projectileProto->item.lightDistance, projectileProto->item.lightIntensity, NULL);
|
||||
} else {
|
||||
objectSetLight(projectile, 9, projectile->lightIntensity, NULL);
|
||||
}
|
||||
|
||||
int projectileOrigin = _combat_bullet_start(attack->attacker, attack->defender);
|
||||
objectSetLocation(projectile, projectileOrigin, attack->attacker->elevation, NULL);
|
||||
@@ -774,7 +814,8 @@ int _action_ranged(Attack* attack, int anim)
|
||||
v24 = attack->tile;
|
||||
}
|
||||
|
||||
if (isGrenade || damageType == DAMAGE_TYPE_EXPLOSION) {
|
||||
// SFALL
|
||||
if (isGrenade || damageType == explosionGetDamageType()) {
|
||||
if ((attack->attackerFlags & DAM_DROP) == 0) {
|
||||
int explosionFrmId;
|
||||
if (isGrenade) {
|
||||
@@ -793,6 +834,12 @@ int _action_ranged(Attack* attack, int anim)
|
||||
explosionFrmId = 10;
|
||||
}
|
||||
|
||||
// SFALL
|
||||
int explosionFrmIdOverride = explosionGetFrm();
|
||||
if (explosionFrmIdOverride != -1) {
|
||||
explosionFrmId = explosionFrmIdOverride;
|
||||
}
|
||||
|
||||
if (isGrenade) {
|
||||
animationRegisterSetFid(projectile, weaponFid, -1);
|
||||
}
|
||||
@@ -803,9 +850,23 @@ int _action_ranged(Attack* attack, int anim)
|
||||
const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_HIT, weapon, attack->hitMode, attack->defender);
|
||||
animationRegisterPlaySoundEffect(projectile, sfx, 0);
|
||||
|
||||
animationRegisterAnimateAndHide(projectile, ANIM_STAND, 0);
|
||||
// SFALL
|
||||
if (explosionEmitsLight()) {
|
||||
animationRegisterAnimate(projectile, ANIM_STAND, 0);
|
||||
// 0xFFFF0008
|
||||
// - distance: 8
|
||||
// - intensity: 65535
|
||||
animationRegisterSetLightIntensity(projectile, 8, 65536, 0);
|
||||
} else {
|
||||
animationRegisterAnimateAndHide(projectile, ANIM_STAND, 0);
|
||||
}
|
||||
|
||||
for (int rotation = 0; rotation < ROTATION_COUNT; rotation++) {
|
||||
// SFALL
|
||||
int startRotation;
|
||||
int endRotation;
|
||||
explosionGetPattern(&startRotation, &endRotation);
|
||||
|
||||
for (int rotation = startRotation; rotation < endRotation; rotation++) {
|
||||
if (objectCreateWithFidPid(&(neighboors[rotation]), explosionFid, -1) != -1) {
|
||||
objectHide(neighboors[rotation], NULL);
|
||||
|
||||
@@ -864,7 +925,8 @@ int _action_ranged(Attack* attack, int anim)
|
||||
}
|
||||
}
|
||||
|
||||
if (projectile != NULL && (isGrenade || damageType == DAMAGE_TYPE_EXPLOSION)) {
|
||||
// SFALL
|
||||
if (projectile != NULL && (isGrenade || damageType == explosionGetDamageType())) {
|
||||
animationRegisterHideObjectForced(projectile);
|
||||
} else if (anim == ANIM_THROW_ANIM && projectile != NULL) {
|
||||
animationRegisterSetFid(projectile, weaponFid, -1);
|
||||
@@ -1230,23 +1292,33 @@ int _action_skill_use(int skill)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x412500
|
||||
static int _action_use_skill_in_combat_error(Object* critter)
|
||||
{
|
||||
MessageListItem messageListItem;
|
||||
|
||||
if (critter == gDude) {
|
||||
messageListItem.num = 902;
|
||||
if (messageListGetItem(&gProtoMessageList, &messageListItem) == 1) {
|
||||
displayMonitorAddMessage(messageListItem.text);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// skill_use
|
||||
// 0x41255C
|
||||
int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
{
|
||||
MessageListItem messageListItem;
|
||||
|
||||
switch (skill) {
|
||||
case SKILL_FIRST_AID:
|
||||
case SKILL_DOCTOR:
|
||||
if (isInCombat()) {
|
||||
if (a1 == gDude) {
|
||||
messageListItem.num = 902;
|
||||
if (messageListGetItem(&gProtoMessageList, &messageListItem)) {
|
||||
displayMonitorAddMessage(messageListItem.text);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(a1);
|
||||
}
|
||||
|
||||
if (PID_TYPE(a2->pid) != OBJ_TYPE_CRITTER) {
|
||||
@@ -1255,13 +1327,8 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
break;
|
||||
case SKILL_LOCKPICK:
|
||||
if (isInCombat()) {
|
||||
if (a1 == gDude) {
|
||||
messageListItem.num = 902;
|
||||
if (messageListGetItem(&gProtoMessageList, &messageListItem)) {
|
||||
displayMonitorAddMessage(messageListItem.text);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(a1);
|
||||
}
|
||||
|
||||
if (PID_TYPE(a2->pid) != OBJ_TYPE_ITEM && PID_TYPE(a2->pid) != OBJ_TYPE_SCENERY) {
|
||||
@@ -1271,13 +1338,8 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
break;
|
||||
case SKILL_STEAL:
|
||||
if (isInCombat()) {
|
||||
if (a1 == gDude) {
|
||||
messageListItem.num = 902;
|
||||
if (messageListGetItem(&gProtoMessageList, &messageListItem)) {
|
||||
displayMonitorAddMessage(messageListItem.text);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(a1);
|
||||
}
|
||||
|
||||
if (PID_TYPE(a2->pid) != OBJ_TYPE_ITEM && PID_TYPE(a2->pid) != OBJ_TYPE_CRITTER) {
|
||||
@@ -1291,13 +1353,8 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
break;
|
||||
case SKILL_TRAPS:
|
||||
if (isInCombat()) {
|
||||
if (a1 == gDude) {
|
||||
messageListItem.num = 902;
|
||||
if (messageListGetItem(&gProtoMessageList, &messageListItem)) {
|
||||
displayMonitorAddMessage(messageListItem.text);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(a1);
|
||||
}
|
||||
|
||||
if (PID_TYPE(a2->pid) == OBJ_TYPE_CRITTER) {
|
||||
@@ -1308,13 +1365,8 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
case SKILL_SCIENCE:
|
||||
case SKILL_REPAIR:
|
||||
if (isInCombat()) {
|
||||
if (a1 == gDude) {
|
||||
messageListItem.num = 902;
|
||||
if (messageListGetItem(&gProtoMessageList, &messageListItem)) {
|
||||
displayMonitorAddMessage(messageListItem.text);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(a1);
|
||||
}
|
||||
|
||||
if (PID_TYPE(a2->pid) != OBJ_TYPE_CRITTER) {
|
||||
@@ -1330,6 +1382,19 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
break;
|
||||
}
|
||||
|
||||
// SFALL: Science on critters patch.
|
||||
if (1) {
|
||||
int targetType = SCIENCE_REPAIR_TARGET_TYPE_DEFAULT;
|
||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_SCIENCE_REPAIR_TARGET_TYPE_KEY, &targetType);
|
||||
if (targetType == SCIENCE_REPAIR_TARGET_TYPE_DUDE) {
|
||||
if (a2 == gDude) {
|
||||
break;
|
||||
}
|
||||
} else if (targetType == SCIENCE_REPAIR_TARGET_TYPE_ANYONE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
case SKILL_SNEAK:
|
||||
dudeToggleState(0);
|
||||
@@ -2051,3 +2116,5 @@ int _action_can_talk_to(Object* a1, Object* a2)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "combat_defs.h"
|
||||
#include "obj_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
int _action_attack(Attack* attack);
|
||||
int _action_use_an_item_on_object(Object* a1, Object* a2, Object* a3);
|
||||
int _action_use_an_object(Object* a1, Object* a2);
|
||||
@@ -21,4 +23,6 @@ bool actionCheckPush(Object* a1, Object* a2);
|
||||
int actionPush(Object* a1, Object* a2);
|
||||
int _action_can_talk_to(Object* a1, Object* a2);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* ACTIONS_H */
|
||||
|
||||
200
src/animation.cc
@@ -1,5 +1,8 @@
|
||||
#include "animation.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "combat.h"
|
||||
@@ -28,8 +31,7 @@
|
||||
#include "tile.h"
|
||||
#include "trait.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
#define ANIMATION_SEQUENCE_LIST_CAPACITY 32
|
||||
#define ANIMATION_DESCRIPTION_LIST_CAPACITY 55
|
||||
@@ -57,13 +59,17 @@ typedef enum AnimationKind {
|
||||
ANIM_KIND_SET_FID = 17,
|
||||
ANIM_KIND_TAKE_OUT_WEAPON = 18,
|
||||
ANIM_KIND_SET_LIGHT_DISTANCE = 19,
|
||||
ANIM_KIND_20 = 20,
|
||||
ANIM_KIND_23 = 23,
|
||||
ANIM_KIND_MOVE_ON_STAIRS = 20,
|
||||
ANIM_KIND_CHECK_FALLING = 23,
|
||||
ANIM_KIND_TOGGLE_OUTLINE = 24,
|
||||
ANIM_KIND_ANIMATE_FOREVER = 25,
|
||||
ANIM_KIND_26 = 26,
|
||||
ANIM_KIND_27 = 27,
|
||||
ANIM_KIND_NOOP = 28,
|
||||
|
||||
// New animation to update both light distance and intensity. Required to
|
||||
// impement Sfall's explosion light effects without resorting to hackery.
|
||||
ANIM_KIND_SET_LIGHT_INTENSITY,
|
||||
} AnimationKind;
|
||||
|
||||
typedef enum AnimationSequenceFlags {
|
||||
@@ -197,6 +203,9 @@ typedef struct AnimationDescription {
|
||||
|
||||
// ANIM_KIND_CALLBACK3
|
||||
void* param3;
|
||||
|
||||
// ANIM_KIND_SET_LIGHT_INTENSITY
|
||||
int lightIntensity;
|
||||
};
|
||||
CacheEntry* artCacheKey;
|
||||
} AnimationDescription;
|
||||
@@ -247,6 +256,7 @@ typedef struct AnimationSad {
|
||||
} AnimationSad;
|
||||
|
||||
static int _anim_free_slot(int a1);
|
||||
static int _anim_preload(Object* object, int fid, CacheEntry** cacheEntryPtr);
|
||||
static void _anim_cleanup();
|
||||
static int _check_registry(Object* obj);
|
||||
static int animationRunSequence(int a1);
|
||||
@@ -266,6 +276,7 @@ static void _object_straight_move(int index);
|
||||
static int _anim_animate(Object* obj, int anim, int animationSequenceIndex, int flags);
|
||||
static void _object_anim_compact();
|
||||
static int actionRotate(Object* obj, int delta, int animationSequenceIndex);
|
||||
static int _anim_hide(Object* object, int animationSequenceIndex);
|
||||
static int _anim_change_fid(Object* obj, int animationSequenceIndex, int fid);
|
||||
static int _check_gravity(int tile, int elevation);
|
||||
static unsigned int animationComputeTicksPerFrame(Object* object, int fid);
|
||||
@@ -494,6 +505,22 @@ int reg_anim_end()
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x413D6C
|
||||
static int _anim_preload(Object* object, int fid, CacheEntry** cacheEntryPtr)
|
||||
{
|
||||
*cacheEntryPtr = NULL;
|
||||
|
||||
if (artLock(fid, cacheEntryPtr) != NULL) {
|
||||
artUnlock(*cacheEntryPtr);
|
||||
*cacheEntryPtr = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x413D98
|
||||
static void _anim_cleanup()
|
||||
{
|
||||
@@ -611,14 +638,12 @@ int animationRegisterMoveToObject(Object* owner, Object* destination, int action
|
||||
|
||||
int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1);
|
||||
|
||||
if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) {
|
||||
// NOTE: Uninline.
|
||||
if (_anim_preload(owner, fid, &(animationDescription->artCacheKey)) == -1) {
|
||||
_anim_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
artUnlock(animationDescription->artCacheKey);
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
|
||||
return animationRegisterRotateToTile(owner, destination->tile);
|
||||
@@ -673,15 +698,12 @@ int animationRegisterRunToObject(Object* owner, Object* destination, int actionP
|
||||
|
||||
int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1);
|
||||
|
||||
animationDescription->artCacheKey = NULL;
|
||||
if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) {
|
||||
// NOTE: Uninline.
|
||||
if (_anim_preload(owner, fid, &(animationDescription->artCacheKey)) == -1) {
|
||||
_anim_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
artUnlock(animationDescription->artCacheKey);
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
return animationRegisterRotateToTile(owner, destination->tile);
|
||||
}
|
||||
@@ -706,17 +728,15 @@ int animationRegisterMoveToTile(Object* owner, int tile, int elevation, int acti
|
||||
animationDescription->elevation = elevation;
|
||||
animationDescription->actionPoints = actionPoints;
|
||||
animationDescription->delay = delay;
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1);
|
||||
if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) {
|
||||
|
||||
// NOTE: Uninline.
|
||||
if (_anim_preload(owner, fid, &(animationDescription->artCacheKey)) == -1) {
|
||||
_anim_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
artUnlock(animationDescription->artCacheKey);
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
|
||||
return 0;
|
||||
@@ -774,15 +794,12 @@ int animationRegisterRunToTile(Object* owner, int tile, int elevation, int actio
|
||||
|
||||
int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1);
|
||||
|
||||
animationDescription->artCacheKey = NULL;
|
||||
if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) {
|
||||
// NOTE: Uninline.
|
||||
if (_anim_preload(owner, fid, &(animationDescription->artCacheKey)) == -1) {
|
||||
_anim_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
artUnlock(animationDescription->artCacheKey);
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
|
||||
return 0;
|
||||
@@ -809,17 +826,15 @@ int animationRegisterMoveToTileStraight(Object* object, int tile, int elevation,
|
||||
animationDescription->elevation = elevation;
|
||||
animationDescription->anim = anim;
|
||||
animationDescription->delay = delay;
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
int fid = buildFid(FID_TYPE(object->fid), object->fid & 0xFFF, animationDescription->anim, (object->fid & 0xF000) >> 12, object->rotation + 1);
|
||||
if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) {
|
||||
|
||||
// NOTE: Uninline.
|
||||
if (_anim_preload(object, fid, &(animationDescription->artCacheKey)) == -1) {
|
||||
_anim_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
artUnlock(animationDescription->artCacheKey);
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
|
||||
return 0;
|
||||
@@ -845,17 +860,15 @@ int animationRegisterMoveToTileStraightAndWaitForComplete(Object* owner, int til
|
||||
animationDescription->elevation = elevation;
|
||||
animationDescription->anim = anim;
|
||||
animationDescription->delay = delay;
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1);
|
||||
if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) {
|
||||
|
||||
// NOTE: Uninline.
|
||||
if (_anim_preload(owner, fid, &(animationDescription->artCacheKey)) == -1) {
|
||||
_anim_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
artUnlock(animationDescription->artCacheKey);
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
|
||||
return 0;
|
||||
@@ -875,17 +888,15 @@ int animationRegisterAnimate(Object* owner, int anim, int delay)
|
||||
animationDescription->owner = owner;
|
||||
animationDescription->anim = anim;
|
||||
animationDescription->delay = delay;
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1);
|
||||
if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) {
|
||||
|
||||
// NOTE: Uninline.
|
||||
if (_anim_preload(owner, fid, &(animationDescription->artCacheKey)) == -1) {
|
||||
_anim_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
artUnlock(animationDescription->artCacheKey);
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
|
||||
return 0;
|
||||
@@ -908,14 +919,13 @@ int animationRegisterAnimateReversed(Object* owner, int anim, int delay)
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1);
|
||||
if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) {
|
||||
|
||||
// NOTE: Uninline.
|
||||
if (_anim_preload(owner, fid, &(animationDescription->artCacheKey)) == -1) {
|
||||
_anim_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
artUnlock(animationDescription->artCacheKey);
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
|
||||
return 0;
|
||||
@@ -938,14 +948,13 @@ int animationRegisterAnimateAndHide(Object* owner, int anim, int delay)
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1);
|
||||
if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) {
|
||||
|
||||
// NOTE: Uninline.
|
||||
if (_anim_preload(owner, fid, &(animationDescription->artCacheKey)) == -1) {
|
||||
_anim_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
artUnlock(animationDescription->artCacheKey);
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
|
||||
return 0;
|
||||
@@ -1192,16 +1201,13 @@ int animationRegisterSetFid(Object* owner, int fid, int delay)
|
||||
animationDescription->owner = owner;
|
||||
animationDescription->fid = fid;
|
||||
animationDescription->delay = delay;
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) {
|
||||
// NOTE: Uninline.
|
||||
if (_anim_preload(owner, fid, &(animationDescription->artCacheKey)) == -1) {
|
||||
_anim_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
artUnlock(animationDescription->artCacheKey);
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
|
||||
return 0;
|
||||
@@ -1229,14 +1235,13 @@ int animationRegisterTakeOutWeapon(Object* owner, int weaponAnimationCode, int d
|
||||
animationDescription->weaponAnimationCode = weaponAnimationCode;
|
||||
|
||||
int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, ANIM_TAKE_OUT, weaponAnimationCode, owner->rotation + 1);
|
||||
if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) {
|
||||
|
||||
// NOTE: Uninline.
|
||||
if (_anim_preload(owner, fid, &(animationDescription->artCacheKey)) == -1) {
|
||||
_anim_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
artUnlock(animationDescription->artCacheKey);
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
|
||||
return 0;
|
||||
@@ -1332,17 +1337,15 @@ int animationRegisterAnimateForever(Object* owner, int anim, int delay)
|
||||
animationDescription->owner = owner;
|
||||
animationDescription->anim = anim;
|
||||
animationDescription->delay = delay;
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1);
|
||||
if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) {
|
||||
|
||||
// NOTE: Uninline.
|
||||
if (_anim_preload(owner, fid, &(animationDescription->artCacheKey)) == -1) {
|
||||
_anim_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
artUnlock(animationDescription->artCacheKey);
|
||||
animationDescription->artCacheKey = NULL;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
|
||||
return 0;
|
||||
@@ -1431,15 +1434,8 @@ static int animationRunSequence(int animationSequenceIndex)
|
||||
case ANIM_KIND_ANIMATE_AND_HIDE:
|
||||
rc = _anim_animate(animationDescription->owner, animationDescription->anim, animationSequenceIndex, ANIM_SAD_HIDE_ON_END);
|
||||
if (rc == -1) {
|
||||
Rect rect;
|
||||
if (objectHide(animationDescription->owner, &rect) == 0) {
|
||||
tileWindowRefreshRect(&rect, animationDescription->elevation);
|
||||
}
|
||||
|
||||
if (animationSequenceIndex != -1) {
|
||||
_anim_set_continue(animationSequenceIndex, 0);
|
||||
}
|
||||
rc = 0;
|
||||
// NOTE: Uninline.
|
||||
rc = _anim_hide(animationDescription->owner, animationSequenceIndex);
|
||||
}
|
||||
break;
|
||||
case ANIM_KIND_ANIMATE_FOREVER:
|
||||
@@ -1460,13 +1456,8 @@ static int animationRunSequence(int animationSequenceIndex)
|
||||
rc = actionRotate(animationDescription->owner, -1, animationSequenceIndex);
|
||||
break;
|
||||
case ANIM_KIND_HIDE:
|
||||
if (objectHide(animationDescription->owner, &rect) == 0) {
|
||||
tileWindowRefreshRect(&rect, animationDescription->owner->elevation);
|
||||
}
|
||||
if (animationSequenceIndex != -1) {
|
||||
_anim_set_continue(animationSequenceIndex, 0);
|
||||
}
|
||||
rc = 0;
|
||||
// NOTE: Uninline.
|
||||
rc = _anim_hide(animationDescription->owner, animationSequenceIndex);
|
||||
break;
|
||||
case ANIM_KIND_CALLBACK:
|
||||
rc = animationDescription->callback(animationDescription->param1, animationDescription->param2);
|
||||
@@ -1527,10 +1518,15 @@ static int animationRunSequence(int animationSequenceIndex)
|
||||
tileWindowRefreshRect(&rect, animationDescription->owner->elevation);
|
||||
rc = _anim_set_continue(animationSequenceIndex, 0);
|
||||
break;
|
||||
case ANIM_KIND_20:
|
||||
case ANIM_KIND_SET_LIGHT_INTENSITY:
|
||||
objectSetLight(animationDescription->owner, animationDescription->lightDistance, animationDescription->lightIntensity, &rect);
|
||||
tileWindowRefreshRect(&rect, animationDescription->owner->elevation);
|
||||
rc = _anim_set_continue(animationSequenceIndex, 0);
|
||||
break;
|
||||
case ANIM_KIND_MOVE_ON_STAIRS:
|
||||
rc = _anim_move_on_stairs(animationDescription->owner, animationDescription->tile, animationDescription->elevation, animationDescription->anim, animationSequenceIndex);
|
||||
break;
|
||||
case ANIM_KIND_23:
|
||||
case ANIM_KIND_CHECK_FALLING:
|
||||
rc = _check_for_falling(animationDescription->owner, animationDescription->anim, animationSequenceIndex);
|
||||
break;
|
||||
case ANIM_KIND_TOGGLE_OUTLINE:
|
||||
@@ -2837,9 +2833,8 @@ void _object_animate()
|
||||
artUnlock(cacheHandle);
|
||||
|
||||
if ((sad->flags & ANIM_SAD_HIDE_ON_END) != 0) {
|
||||
if (objectHide(object, &tempRect) == 0) {
|
||||
tileWindowRefreshRect(&tempRect, object->elevation);
|
||||
}
|
||||
// NOTE: Uninline.
|
||||
_anim_hide(object, -1);
|
||||
}
|
||||
|
||||
_anim_set_continue(sad->animationSequenceIndex, 1);
|
||||
@@ -2993,7 +2988,7 @@ int _check_move(int* a1)
|
||||
bool aiming;
|
||||
interfaceGetCurrentHitMode(&hitMode, &aiming);
|
||||
|
||||
int v6 = _item_mp_cost(gDude, hitMode, aiming);
|
||||
int v6 = itemGetActionPointCost(gDude, hitMode, aiming);
|
||||
*a1 = *a1 - v6;
|
||||
if (*a1 <= 0) {
|
||||
return -1;
|
||||
@@ -3250,6 +3245,24 @@ static int actionRotate(Object* obj, int delta, int animationSequenceIndex)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x41862C
|
||||
static int _anim_hide(Object* object, int animationSequenceIndex)
|
||||
{
|
||||
Rect rect;
|
||||
|
||||
if (objectHide(object, &rect) == 0) {
|
||||
tileWindowRefreshRect(&rect, object->elevation);
|
||||
}
|
||||
|
||||
if (animationSequenceIndex != -1) {
|
||||
_anim_set_continue(animationSequenceIndex, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x418660
|
||||
static int _anim_change_fid(Object* obj, int animationSequenceIndex, int fid)
|
||||
{
|
||||
@@ -3330,3 +3343,26 @@ static unsigned int animationComputeTicksPerFrame(Object* object, int fid)
|
||||
|
||||
return 1000 / fps;
|
||||
}
|
||||
|
||||
int animationRegisterSetLightIntensity(Object* owner, int lightDistance, int lightIntensity, int delay)
|
||||
{
|
||||
if (_check_registry(owner) == -1) {
|
||||
_anim_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]);
|
||||
AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]);
|
||||
animationDescription->kind = ANIM_KIND_SET_LIGHT_INTENSITY;
|
||||
animationDescription->artCacheKey = NULL;
|
||||
animationDescription->owner = owner;
|
||||
animationDescription->lightDistance = lightDistance;
|
||||
animationDescription->lightIntensity = lightIntensity;
|
||||
animationDescription->delay = delay;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "combat_defs.h"
|
||||
#include "obj_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum AnimationRequestOptions {
|
||||
ANIMATION_REQUEST_UNRESERVED = 0x01,
|
||||
ANIMATION_REQUEST_RESERVED = 0x02,
|
||||
@@ -154,4 +156,8 @@ 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);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* ANIMATION_H */
|
||||
|
||||
113
src/art.cc
@@ -1,5 +1,9 @@
|
||||
#include "art.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "animation.h"
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
@@ -10,9 +14,7 @@
|
||||
#include "proto.h"
|
||||
#include "sfall_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
typedef struct ArtListDescription {
|
||||
int flags;
|
||||
@@ -146,15 +148,31 @@ int artInit()
|
||||
gArtLanguageInitialized = true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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[OBJ_TYPE_CRITTER].fileNamesLength);
|
||||
@@ -698,12 +716,6 @@ static int artReadList(const char* path, char** artListPtr, int* artListSizePtr)
|
||||
fileClose(stream);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
||||
fileClose(stream);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x419760
|
||||
@@ -854,8 +866,8 @@ bool artExists(int fid)
|
||||
int oldDb = -1;
|
||||
|
||||
if (FID_TYPE(fid) == OBJ_TYPE_CRITTER) {
|
||||
oldDb = _db_current(1);
|
||||
_db_current(_critter_db_handle);
|
||||
oldDb = _db_current();
|
||||
_db_select(_critter_db_handle);
|
||||
}
|
||||
|
||||
char* filePath = artBuildFilePath(fid);
|
||||
@@ -867,27 +879,38 @@ bool artExists(int fid)
|
||||
}
|
||||
|
||||
if (oldDb != -1) {
|
||||
_db_current(oldDb);
|
||||
_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
|
||||
@@ -937,8 +960,8 @@ static int artCacheGetFileSizeImpl(int fid, int* sizePtr)
|
||||
int result = -1;
|
||||
|
||||
if (FID_TYPE(fid) == OBJ_TYPE_CRITTER) {
|
||||
oldDb = _db_current(1);
|
||||
_db_current(_critter_db_handle);
|
||||
oldDb = _db_current();
|
||||
_db_select(_critter_db_handle);
|
||||
}
|
||||
|
||||
char* artFilePath = artBuildFilePath(fid);
|
||||
@@ -973,7 +996,7 @@ static int artCacheGetFileSizeImpl(int fid, int* sizePtr)
|
||||
}
|
||||
|
||||
if (oldDb != -1) {
|
||||
_db_current(oldDb);
|
||||
_db_select(oldDb);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -986,8 +1009,8 @@ static int artCacheReadDataImpl(int fid, int* sizePtr, unsigned char* data)
|
||||
int result = -1;
|
||||
|
||||
if (FID_TYPE(fid) == OBJ_TYPE_CRITTER) {
|
||||
oldDb = _db_current(1);
|
||||
_db_current(_critter_db_handle);
|
||||
oldDb = _db_current();
|
||||
_db_select(_critter_db_handle);
|
||||
}
|
||||
|
||||
char* artFileName = artBuildFilePath(fid);
|
||||
@@ -1021,7 +1044,7 @@ static int artCacheReadDataImpl(int fid, int* sizePtr, unsigned char* data)
|
||||
}
|
||||
|
||||
if (oldDb != -1) {
|
||||
_db_current(oldDb);
|
||||
_db_select(oldDb);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1207,3 +1230,43 @@ int artWrite(const char* path, unsigned char* data)
|
||||
fileClose(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FrmImage::FrmImage()
|
||||
{
|
||||
_key = nullptr;
|
||||
_data = nullptr;
|
||||
_width = 0;
|
||||
_height = 0;
|
||||
}
|
||||
|
||||
FrmImage::~FrmImage()
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
|
||||
bool FrmImage::lock(unsigned int fid)
|
||||
{
|
||||
if (isLocked()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_data = artLockFrameDataReturningSize(fid, &_key, &_width, &_height);
|
||||
if (!_data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FrmImage::unlock()
|
||||
{
|
||||
if (isLocked()) {
|
||||
artUnlock(_key);
|
||||
_key = nullptr;
|
||||
_data = nullptr;
|
||||
_width = 0;
|
||||
_height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
24
src/art.h
@@ -8,6 +8,8 @@
|
||||
#include "platform_compat.h"
|
||||
#include "proto_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum Head {
|
||||
HEAD_INVALID,
|
||||
HEAD_MARCUS,
|
||||
@@ -149,4 +151,26 @@ 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);
|
||||
|
||||
class FrmImage {
|
||||
public:
|
||||
FrmImage();
|
||||
~FrmImage();
|
||||
|
||||
bool isLocked() const { return _key != nullptr; }
|
||||
bool lock(unsigned int fid);
|
||||
void unlock();
|
||||
|
||||
int getWidth() const { return _width; }
|
||||
int getHeight() const { return _height; }
|
||||
unsigned char* getData() const { return _data; }
|
||||
|
||||
private:
|
||||
CacheEntry* _key;
|
||||
unsigned char* _data;
|
||||
int _width;
|
||||
int _height;
|
||||
};
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif
|
||||
|
||||
10
src/audio.cc
@@ -1,14 +1,16 @@
|
||||
#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>
|
||||
namespace fallout {
|
||||
|
||||
static bool _defaultCompressionFunc(char* filePath);
|
||||
static int audioSoundDecoderReadHandler(int fileHandle, void* buf, unsigned int size);
|
||||
@@ -252,3 +254,5 @@ void audioExit()
|
||||
gAudioListLength = 0;
|
||||
gAudioList = NULL;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "audio_file.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
int audioOpen(const char* fname, int mode, ...);
|
||||
int audioClose(int fileHandle);
|
||||
int audioRead(int fileHandle, void* buffer, unsigned int size);
|
||||
@@ -13,4 +15,6 @@ int audioWrite(int handle, const void* buf, unsigned int size);
|
||||
int audioInit(AudioFileIsCompressedProc* isCompressedProc);
|
||||
void audioExit();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* AUDIO_H */
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define AUDIO_ENGINE_SOUND_BUFFERS 8
|
||||
|
||||
struct AudioEngineSoundBuffer {
|
||||
@@ -430,3 +432,5 @@ bool audioEngineSoundBufferGetStatus(int soundBufferIndex, unsigned int* statusP
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef AUDIO_ENGINE_H
|
||||
#define AUDIO_ENGINE_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define AUDIO_ENGINE_SOUND_BUFFER_LOCK_FROM_WRITE_POS 0x00000001
|
||||
#define AUDIO_ENGINE_SOUND_BUFFER_LOCK_ENTIRE_BUFFER 0x00000002
|
||||
|
||||
@@ -26,4 +28,6 @@ bool audioEngineSoundBufferLock(int soundBufferIndex, unsigned int writePos, uns
|
||||
bool audioEngineSoundBufferUnlock(int soundBufferIndex, void* audioPtr1, unsigned int audioBytes1, void* audioPtr2, unsigned int audioBytes2);
|
||||
bool audioEngineSoundBufferGetStatus(int soundBufferIndex, unsigned int* status);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* AUDIO_ENGINE_H */
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
#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>
|
||||
namespace fallout {
|
||||
|
||||
static bool _defaultCompressionFunc__(char* filePath);
|
||||
static int audioFileSoundDecoderReadHandler(int fileHandle, void* buffer, unsigned int size);
|
||||
@@ -103,7 +105,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;
|
||||
@@ -249,3 +251,5 @@ void audioFileExit()
|
||||
gAudioFileListLength = 0;
|
||||
gAudioFileList = NULL;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "sound_decoder.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum AudioFileFlags {
|
||||
AUDIO_FILE_IN_USE = 0x01,
|
||||
AUDIO_FILE_COMPRESSED = 0x02,
|
||||
@@ -30,4 +32,6 @@ int audioFileWrite(int handle, const void* buf, unsigned int size);
|
||||
int audioFileInit(AudioFileIsCompressedProc* isCompressedProc);
|
||||
void audioFileExit();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* AUDIO_FILE_H */
|
||||
|
||||
@@ -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,10 +25,7 @@
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
namespace fallout {
|
||||
|
||||
#define AUTOMAP_OFFSET_COUNT (AUTOMAP_MAP_COUNT * ELEVATION_COUNT)
|
||||
|
||||
@@ -66,7 +68,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,
|
||||
@@ -299,15 +301,10 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
int frmIds[AUTOMAP_FRM_COUNT];
|
||||
memcpy(frmIds, gAutomapFrmIds, sizeof(gAutomapFrmIds));
|
||||
|
||||
unsigned char* frmData[AUTOMAP_FRM_COUNT];
|
||||
CacheEntry* frmHandle[AUTOMAP_FRM_COUNT];
|
||||
FrmImage frmImages[AUTOMAP_FRM_COUNT];
|
||||
for (int index = 0; index < AUTOMAP_FRM_COUNT; index++) {
|
||||
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) {
|
||||
artUnlock(frmHandle[index]);
|
||||
}
|
||||
if (!frmImages[index].lock(fid)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -327,17 +324,53 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
int automapWindowY = (screenGetHeight() - AUTOMAP_WINDOW_HEIGHT) / 2;
|
||||
int window = windowCreate(automapWindowX, automapWindowY, AUTOMAP_WINDOW_WIDTH, AUTOMAP_WINDOW_HEIGHT, color, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
|
||||
|
||||
int scannerBtn = buttonCreate(window, 111, 454, 15, 16, -1, -1, -1, KEY_LOWERCASE_S, frmData[AUTOMAP_FRM_BUTTON_UP], frmData[AUTOMAP_FRM_BUTTON_DOWN], NULL, BUTTON_FLAG_TRANSPARENT);
|
||||
int scannerBtn = buttonCreate(window,
|
||||
111,
|
||||
454,
|
||||
15,
|
||||
16,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
KEY_LOWERCASE_S,
|
||||
frmImages[AUTOMAP_FRM_BUTTON_UP].getData(),
|
||||
frmImages[AUTOMAP_FRM_BUTTON_DOWN].getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (scannerBtn != -1) {
|
||||
buttonSetCallbacks(scannerBtn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
|
||||
int cancelBtn = buttonCreate(window, 277, 454, 15, 16, -1, -1, -1, KEY_ESCAPE, frmData[AUTOMAP_FRM_BUTTON_UP], frmData[AUTOMAP_FRM_BUTTON_DOWN], NULL, BUTTON_FLAG_TRANSPARENT);
|
||||
int cancelBtn = buttonCreate(window,
|
||||
277,
|
||||
454,
|
||||
15,
|
||||
16,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
KEY_ESCAPE,
|
||||
frmImages[AUTOMAP_FRM_BUTTON_UP].getData(),
|
||||
frmImages[AUTOMAP_FRM_BUTTON_DOWN].getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (cancelBtn != -1) {
|
||||
buttonSetCallbacks(cancelBtn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
|
||||
int switchBtn = buttonCreate(window, 457, 340, 42, 74, -1, -1, KEY_LOWERCASE_L, KEY_LOWERCASE_H, frmData[AUTOMAP_FRM_SWITCH_UP], frmData[AUTOMAP_FRM_SWITCH_DOWN], NULL, BUTTON_FLAG_TRANSPARENT | BUTTON_FLAG_0x01);
|
||||
int switchBtn = buttonCreate(window,
|
||||
457,
|
||||
340,
|
||||
42,
|
||||
74,
|
||||
-1,
|
||||
-1,
|
||||
KEY_LOWERCASE_L,
|
||||
KEY_LOWERCASE_H,
|
||||
frmImages[AUTOMAP_FRM_SWITCH_UP].getData(),
|
||||
frmImages[AUTOMAP_FRM_SWITCH_DOWN].getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT | BUTTON_FLAG_0x01);
|
||||
if (switchBtn != -1) {
|
||||
buttonSetCallbacks(switchBtn, _gsound_toggle_butt_press_, _gsound_toggle_butt_press_);
|
||||
}
|
||||
@@ -358,7 +391,7 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
gAutomapFlags |= AUTOMAP_WITH_SCANNER;
|
||||
}
|
||||
|
||||
automapRenderInMapWindow(window, elevation, frmData[AUTOMAP_FRM_BACKGROUND], gAutomapFlags);
|
||||
automapRenderInMapWindow(window, elevation, frmImages[AUTOMAP_FRM_BACKGROUND].getData(), gAutomapFlags);
|
||||
|
||||
bool isoWasEnabled = isoDisable();
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
@@ -442,7 +475,7 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
}
|
||||
|
||||
if (needsRefresh) {
|
||||
automapRenderInMapWindow(window, elevation, frmData[AUTOMAP_FRM_BACKGROUND], gAutomapFlags);
|
||||
automapRenderInMapWindow(window, elevation, frmImages[AUTOMAP_FRM_BACKGROUND].getData(), gAutomapFlags);
|
||||
needsRefresh = false;
|
||||
}
|
||||
}
|
||||
@@ -453,10 +486,6 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
|
||||
windowDestroy(window);
|
||||
fontSetCurrent(oldFont);
|
||||
|
||||
for (int index = 0; index < AUTOMAP_FRM_COUNT; index++) {
|
||||
artUnlock(frmHandle[index]);
|
||||
}
|
||||
}
|
||||
|
||||
// Renders automap in Map window.
|
||||
@@ -1153,3 +1182,12 @@ int automapGetHeader(AutomapHeader** automapHeaderPtr)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void automapSetDisplayMap(int map, bool available)
|
||||
{
|
||||
if (map >= 0 && map < AUTOMAP_MAP_COUNT) {
|
||||
_displayMapList[map] = available ? 0 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "db.h"
|
||||
#include "map_defs.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define AUTOMAP_DB ("AUTOMAP.DB")
|
||||
#define AUTOMAP_TMP ("AUTOMAP.TMP")
|
||||
|
||||
@@ -54,4 +56,8 @@ int automapRenderInPipboyWindow(int win, int map, int elevation);
|
||||
int automapSaveCurrent();
|
||||
int automapGetHeader(AutomapHeader** automapHeaderPtr);
|
||||
|
||||
void automapSetDisplayMap(int map, bool available);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* AUTOMAP_H */
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
static HANDLE gInterplayGenericAutorunMutex;
|
||||
#endif
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// 0x4139C0
|
||||
bool autorunMutexCreate()
|
||||
{
|
||||
@@ -34,3 +36,5 @@ void autorunMutexClose()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#ifndef AUTORUN_H
|
||||
#define AUTORUN_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
bool autorunMutexCreate();
|
||||
void autorunMutexClose();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* AUTORUN_H */
|
||||
|
||||
12
src/cache.cc
@@ -1,14 +1,16 @@
|
||||
#include "cache.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "memory.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "memory.h"
|
||||
#include "sound.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// The initial number of cache entries in new cache.
|
||||
#define CACHE_ENTRIES_INITIAL_CAPACITY (100)
|
||||
|
||||
@@ -613,3 +615,5 @@ static int cacheEntriesCompareByMostRecentHit(const void* a1, const void* a2)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "heap.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define INVALID_CACHE_ENTRY ((CacheEntry*)-1)
|
||||
|
||||
typedef enum CacheEntryFlags {
|
||||
@@ -66,4 +68,6 @@ bool cacheUnlock(Cache* cache, CacheEntry* cacheEntry);
|
||||
bool cacheFlush(Cache* cache);
|
||||
bool cachePrintStats(Cache* cache, char* dest);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CACHE_H */
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "db.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
extern int gCharacterEditorRemainingCharacterPoints;
|
||||
|
||||
int characterEditorShow(bool isCreationMode);
|
||||
@@ -13,4 +15,6 @@ int characterEditorSave(File* stream);
|
||||
int characterEditorLoad(File* stream);
|
||||
void characterEditorReset();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CHARACTER_EDITOR_H */
|
||||
|
||||
@@ -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,14 +24,14 @@
|
||||
#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>
|
||||
namespace fallout {
|
||||
|
||||
#define CS_WINDOW_WIDTH (640)
|
||||
#define CS_WINDOW_HEIGHT (480)
|
||||
@@ -57,12 +64,28 @@
|
||||
#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();
|
||||
static bool characterSelectorWindowRenderFace();
|
||||
static bool characterSelectorWindowRenderStats();
|
||||
static bool characterSelectorWindowRenderBio();
|
||||
static bool characterSelectorWindowFatalError(bool result);
|
||||
|
||||
static void premadeCharactersLocalizePath(char* path);
|
||||
|
||||
// 0x51C84C
|
||||
static int gCurrentPremadeCharacter = PREMADE_CHARACTER_NARG;
|
||||
@@ -75,7 +98,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;
|
||||
@@ -89,92 +112,35 @@ static unsigned char* gCharacterSelectorBackground = NULL;
|
||||
// 0x51C804
|
||||
static int gCharacterSelectorWindowPreviousButton = -1;
|
||||
|
||||
// 0x51C808
|
||||
static CacheEntry* gCharacterSelectorWindowPreviousButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C80C
|
||||
static CacheEntry* gCharacterSelectorWindowPreviousButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C810
|
||||
static int gCharacterSelectorWindowNextButton = -1;
|
||||
|
||||
// 0x51C814
|
||||
static CacheEntry* gCharacterSelectorWindowNextButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C818
|
||||
static CacheEntry* gCharacterSelectorWindowNextButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C81C
|
||||
static int gCharacterSelectorWindowTakeButton = -1;
|
||||
|
||||
// 0x51C820
|
||||
static CacheEntry* gCharacterSelectorWindowTakeButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C824
|
||||
static CacheEntry* gCharacterSelectorWindowTakeButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C828
|
||||
static int gCharacterSelectorWindowModifyButton = -1;
|
||||
|
||||
// 0x51C82C
|
||||
static CacheEntry* gCharacterSelectorWindowModifyButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C830
|
||||
static CacheEntry* gCharacterSelectorWindowModifyButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C834
|
||||
static int gCharacterSelectorWindowCreateButton = -1;
|
||||
|
||||
// 0x51C838
|
||||
static CacheEntry* gCharacterSelectorWindowCreateButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C83C
|
||||
static CacheEntry* gCharacterSelectorWindowCreateButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C840
|
||||
static int gCharacterSelectorWindowBackButton = -1;
|
||||
|
||||
// 0x51C844
|
||||
static CacheEntry* gCharacterSelectorWindowBackButtonUpFrmHandle = NULL;
|
||||
static FrmImage _takeButtonNormalFrmImage;
|
||||
static FrmImage _takeButtonPressedFrmImage;
|
||||
static FrmImage _modifyButtonNormalFrmImage;
|
||||
static FrmImage _modifyButtonPressedFrmImage;
|
||||
static FrmImage _createButtonNormalFrmImage;
|
||||
static FrmImage _createButtonPressedFrmImage;
|
||||
static FrmImage _backButtonNormalFrmImage;
|
||||
static FrmImage _backButtonPressedFrmImage;
|
||||
static FrmImage _nextButtonNormalFrmImage;
|
||||
static FrmImage _nextButtonPressedFrmImage;
|
||||
static FrmImage _previousButtonNormalFrmImage;
|
||||
static FrmImage _previousButtonPressedFrmImage;
|
||||
|
||||
// 0x51C848
|
||||
static CacheEntry* gCharacterSelectorWindowBackButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x667764
|
||||
static unsigned char* gCharacterSelectorWindowTakeButtonUpFrmData;
|
||||
|
||||
// 0x667768
|
||||
static unsigned char* gCharacterSelectorWindowModifyButtonDownFrmData;
|
||||
|
||||
// 0x66776C
|
||||
static unsigned char* gCharacterSelectorWindowBackButtonUpFrmData;
|
||||
|
||||
// 0x667770
|
||||
static unsigned char* gCharacterSelectorWindowCreateButtonUpFrmData;
|
||||
|
||||
// 0x667774
|
||||
static unsigned char* gCharacterSelectorWindowModifyButtonUpFrmData;
|
||||
|
||||
// 0x667778
|
||||
static unsigned char* gCharacterSelectorWindowBackButtonDownFrmData;
|
||||
|
||||
// 0x66777C
|
||||
static unsigned char* gCharacterSelectorWindowCreateButtonDownFrmData;
|
||||
|
||||
// 0x667780
|
||||
static unsigned char* gCharacterSelectorWindowTakeButtonDownFrmData;
|
||||
|
||||
// 0x667784
|
||||
static unsigned char* gCharacterSelectorWindowNextButtonDownFrmData;
|
||||
|
||||
// 0x667788
|
||||
static unsigned char* gCharacterSelectorWindowNextButtonUpFrmData;
|
||||
|
||||
// 0x66778C
|
||||
static unsigned char* gCharacterSelectorWindowPreviousButtonUpFrmData;
|
||||
|
||||
// 0x667790
|
||||
static unsigned char* gCharacterSelectorWindowPreviousButtonDownFrmData;
|
||||
static std::vector<PremadeCharacterDescription> gCustomPremadeCharacterDescriptions;
|
||||
|
||||
// 0x4A71D0
|
||||
int characterSelectorOpen()
|
||||
@@ -221,6 +187,8 @@ int characterSelectorOpen()
|
||||
if (characterEditorShow(1) == 0) {
|
||||
rc = 2;
|
||||
done = true;
|
||||
} else {
|
||||
characterSelectorWindowRefresh();
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -229,6 +197,8 @@ int characterSelectorOpen()
|
||||
if (!characterEditorShow(1)) {
|
||||
rc = 2;
|
||||
done = true;
|
||||
} else {
|
||||
characterSelectorWindowRefresh();
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -279,9 +249,6 @@ int characterSelectorOpen()
|
||||
// 0x4A7468
|
||||
static bool characterSelectorWindowInit()
|
||||
{
|
||||
int backgroundFid;
|
||||
unsigned char* backgroundFrmData;
|
||||
|
||||
if (gCharacterSelectorWindow != -1) {
|
||||
return false;
|
||||
}
|
||||
@@ -290,22 +257,21 @@ static bool characterSelectorWindowInit()
|
||||
int characterSelectorWindowY = (screenGetHeight() - CS_WINDOW_HEIGHT) / 2;
|
||||
gCharacterSelectorWindow = windowCreate(characterSelectorWindowX, characterSelectorWindowY, CS_WINDOW_WIDTH, CS_WINDOW_HEIGHT, _colorTable[0], 0);
|
||||
if (gCharacterSelectorWindow == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowBuffer = windowGetBuffer(gCharacterSelectorWindow);
|
||||
if (gCharacterSelectorWindowBuffer == NULL) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 174, 0, 0, 0);
|
||||
backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle);
|
||||
if (backgroundFrmData == NULL) {
|
||||
goto err;
|
||||
FrmImage backgroundFrmImage;
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 174, 0, 0, 0);
|
||||
if (!backgroundFrmImage.lock(backgroundFid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
blitBufferToBuffer(backgroundFrmData,
|
||||
blitBufferToBuffer(backgroundFrmImage.getData(),
|
||||
CS_WINDOW_WIDTH,
|
||||
CS_WINDOW_HEIGHT,
|
||||
CS_WINDOW_WIDTH,
|
||||
@@ -314,30 +280,28 @@ static bool characterSelectorWindowInit()
|
||||
|
||||
gCharacterSelectorBackground = (unsigned char*)internal_malloc(CS_WINDOW_BACKGROUND_WIDTH * CS_WINDOW_BACKGROUND_HEIGHT);
|
||||
if (gCharacterSelectorBackground == NULL)
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
|
||||
blitBufferToBuffer(backgroundFrmData + CS_WINDOW_WIDTH * CS_WINDOW_BACKGROUND_Y + CS_WINDOW_BACKGROUND_X,
|
||||
blitBufferToBuffer(backgroundFrmImage.getData() + CS_WINDOW_WIDTH * CS_WINDOW_BACKGROUND_Y + CS_WINDOW_BACKGROUND_X,
|
||||
CS_WINDOW_BACKGROUND_WIDTH,
|
||||
CS_WINDOW_BACKGROUND_HEIGHT,
|
||||
CS_WINDOW_WIDTH,
|
||||
gCharacterSelectorBackground,
|
||||
CS_WINDOW_BACKGROUND_WIDTH);
|
||||
|
||||
artUnlock(backgroundFrmHandle);
|
||||
backgroundFrmImage.unlock();
|
||||
|
||||
int fid;
|
||||
|
||||
// Setup "Previous" button.
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 122, 0, 0, 0);
|
||||
gCharacterSelectorWindowPreviousButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowPreviousButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowPreviousButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
if (!_previousButtonNormalFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 123, 0, 0, 0);
|
||||
gCharacterSelectorWindowPreviousButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowPreviousButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowPreviousButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
if (!_previousButtonPressedFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowPreviousButton = buttonCreate(gCharacterSelectorWindow,
|
||||
@@ -349,27 +313,25 @@ static bool characterSelectorWindowInit()
|
||||
-1,
|
||||
-1,
|
||||
500,
|
||||
gCharacterSelectorWindowPreviousButtonUpFrmData,
|
||||
gCharacterSelectorWindowPreviousButtonDownFrmData,
|
||||
_previousButtonNormalFrmImage.getData(),
|
||||
_previousButtonPressedFrmImage.getData(),
|
||||
NULL,
|
||||
0);
|
||||
if (gCharacterSelectorWindowPreviousButton == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowPreviousButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
||||
|
||||
// Setup "Next" button.
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 124, 0, 0, 0);
|
||||
gCharacterSelectorWindowNextButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowNextButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowNextButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
if (!_nextButtonNormalFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 125, 0, 0, 0);
|
||||
gCharacterSelectorWindowNextButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowNextButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowNextButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
if (!_nextButtonPressedFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowNextButton = buttonCreate(gCharacterSelectorWindow,
|
||||
@@ -381,27 +343,25 @@ static bool characterSelectorWindowInit()
|
||||
-1,
|
||||
-1,
|
||||
501,
|
||||
gCharacterSelectorWindowNextButtonUpFrmData,
|
||||
gCharacterSelectorWindowNextButtonDownFrmData,
|
||||
_nextButtonNormalFrmImage.getData(),
|
||||
_nextButtonPressedFrmImage.getData(),
|
||||
NULL,
|
||||
0);
|
||||
if (gCharacterSelectorWindowNextButton == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowNextButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
||||
|
||||
// Setup "Take" button.
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowTakeButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowTakeButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowTakeButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
if (!_takeButtonNormalFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowTakeButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowTakeButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowTakeButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
if (!_takeButtonPressedFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowTakeButton = buttonCreate(gCharacterSelectorWindow,
|
||||
@@ -413,26 +373,24 @@ static bool characterSelectorWindowInit()
|
||||
-1,
|
||||
-1,
|
||||
KEY_LOWERCASE_T,
|
||||
gCharacterSelectorWindowTakeButtonUpFrmData,
|
||||
gCharacterSelectorWindowTakeButtonDownFrmData,
|
||||
_takeButtonNormalFrmImage.getData(),
|
||||
_takeButtonPressedFrmImage.getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (gCharacterSelectorWindowTakeButton == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowTakeButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
|
||||
// Setup "Modify" button.
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowModifyButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowModifyButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowModifyButtonUpFrmData == NULL)
|
||||
goto err;
|
||||
if (!_modifyButtonNormalFrmImage.lock(fid))
|
||||
return characterSelectorWindowFatalError(false);
|
||||
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowModifyButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowModifyButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowModifyButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
if (!_modifyButtonPressedFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowModifyButton = buttonCreate(gCharacterSelectorWindow,
|
||||
@@ -444,27 +402,25 @@ static bool characterSelectorWindowInit()
|
||||
-1,
|
||||
-1,
|
||||
KEY_LOWERCASE_M,
|
||||
gCharacterSelectorWindowModifyButtonUpFrmData,
|
||||
gCharacterSelectorWindowModifyButtonDownFrmData,
|
||||
_modifyButtonNormalFrmImage.getData(),
|
||||
_modifyButtonPressedFrmImage.getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (gCharacterSelectorWindowModifyButton == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowModifyButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
|
||||
// Setup "Create" button.
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowCreateButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowCreateButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowCreateButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
if (!_createButtonNormalFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowCreateButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowCreateButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowCreateButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
if (!_createButtonPressedFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowCreateButton = buttonCreate(gCharacterSelectorWindow,
|
||||
@@ -476,27 +432,25 @@ static bool characterSelectorWindowInit()
|
||||
-1,
|
||||
-1,
|
||||
KEY_LOWERCASE_C,
|
||||
gCharacterSelectorWindowCreateButtonUpFrmData,
|
||||
gCharacterSelectorWindowCreateButtonDownFrmData,
|
||||
_createButtonNormalFrmImage.getData(),
|
||||
_createButtonPressedFrmImage.getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (gCharacterSelectorWindowCreateButton == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowCreateButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
|
||||
// Setup "Back" button.
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowBackButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowBackButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowBackButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
if (!_backButtonNormalFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowBackButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowBackButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowBackButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
if (!_backButtonPressedFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowBackButton = buttonCreate(gCharacterSelectorWindow,
|
||||
@@ -508,12 +462,12 @@ static bool characterSelectorWindowInit()
|
||||
-1,
|
||||
-1,
|
||||
KEY_ESCAPE,
|
||||
gCharacterSelectorWindowBackButtonUpFrmData,
|
||||
gCharacterSelectorWindowBackButtonDownFrmData,
|
||||
_backButtonNormalFrmImage.getData(),
|
||||
_backButtonPressedFrmImage.getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (gCharacterSelectorWindowBackButton == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowBackButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
@@ -523,16 +477,10 @@ static bool characterSelectorWindowInit()
|
||||
windowRefresh(gCharacterSelectorWindow);
|
||||
|
||||
if (!characterSelectorWindowRefresh()) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
err:
|
||||
|
||||
characterSelectorWindowFree();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x4A7AD4
|
||||
@@ -547,102 +495,48 @@ static void characterSelectorWindowFree()
|
||||
gCharacterSelectorWindowPreviousButton = -1;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowPreviousButtonDownFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowPreviousButtonDownFrmHandle);
|
||||
gCharacterSelectorWindowPreviousButtonDownFrmHandle = NULL;
|
||||
gCharacterSelectorWindowPreviousButtonDownFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowPreviousButtonUpFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowPreviousButtonUpFrmHandle);
|
||||
gCharacterSelectorWindowPreviousButtonUpFrmHandle = NULL;
|
||||
gCharacterSelectorWindowPreviousButtonUpFrmData = NULL;
|
||||
}
|
||||
_previousButtonNormalFrmImage.unlock();
|
||||
_previousButtonPressedFrmImage.unlock();
|
||||
|
||||
if (gCharacterSelectorWindowNextButton != -1) {
|
||||
buttonDestroy(gCharacterSelectorWindowNextButton);
|
||||
gCharacterSelectorWindowNextButton = -1;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowNextButtonDownFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowNextButtonDownFrmHandle);
|
||||
gCharacterSelectorWindowNextButtonDownFrmHandle = NULL;
|
||||
gCharacterSelectorWindowNextButtonDownFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowNextButtonUpFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowNextButtonUpFrmHandle);
|
||||
gCharacterSelectorWindowNextButtonUpFrmHandle = NULL;
|
||||
gCharacterSelectorWindowNextButtonUpFrmData = NULL;
|
||||
}
|
||||
_nextButtonNormalFrmImage.unlock();
|
||||
_nextButtonPressedFrmImage.unlock();
|
||||
|
||||
if (gCharacterSelectorWindowTakeButton != -1) {
|
||||
buttonDestroy(gCharacterSelectorWindowTakeButton);
|
||||
gCharacterSelectorWindowTakeButton = -1;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowTakeButtonDownFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowTakeButtonDownFrmHandle);
|
||||
gCharacterSelectorWindowTakeButtonDownFrmHandle = NULL;
|
||||
gCharacterSelectorWindowTakeButtonDownFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowTakeButtonUpFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowTakeButtonUpFrmHandle);
|
||||
gCharacterSelectorWindowTakeButtonUpFrmHandle = NULL;
|
||||
gCharacterSelectorWindowTakeButtonUpFrmData = NULL;
|
||||
}
|
||||
_takeButtonNormalFrmImage.unlock();
|
||||
_takeButtonPressedFrmImage.unlock();
|
||||
|
||||
if (gCharacterSelectorWindowModifyButton != -1) {
|
||||
buttonDestroy(gCharacterSelectorWindowModifyButton);
|
||||
gCharacterSelectorWindowModifyButton = -1;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowModifyButtonDownFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowModifyButtonDownFrmHandle);
|
||||
gCharacterSelectorWindowModifyButtonDownFrmHandle = NULL;
|
||||
gCharacterSelectorWindowModifyButtonDownFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowModifyButtonUpFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowModifyButtonUpFrmHandle);
|
||||
gCharacterSelectorWindowModifyButtonUpFrmHandle = NULL;
|
||||
gCharacterSelectorWindowModifyButtonUpFrmData = NULL;
|
||||
}
|
||||
_modifyButtonNormalFrmImage.unlock();
|
||||
_modifyButtonPressedFrmImage.unlock();
|
||||
|
||||
if (gCharacterSelectorWindowCreateButton != -1) {
|
||||
buttonDestroy(gCharacterSelectorWindowCreateButton);
|
||||
gCharacterSelectorWindowCreateButton = -1;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowCreateButtonDownFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowCreateButtonDownFrmHandle);
|
||||
gCharacterSelectorWindowCreateButtonDownFrmHandle = NULL;
|
||||
gCharacterSelectorWindowCreateButtonDownFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowCreateButtonUpFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowCreateButtonUpFrmHandle);
|
||||
gCharacterSelectorWindowCreateButtonUpFrmHandle = NULL;
|
||||
gCharacterSelectorWindowCreateButtonUpFrmData = NULL;
|
||||
}
|
||||
_createButtonNormalFrmImage.unlock();
|
||||
_createButtonPressedFrmImage.unlock();
|
||||
|
||||
if (gCharacterSelectorWindowBackButton != -1) {
|
||||
buttonDestroy(gCharacterSelectorWindowBackButton);
|
||||
gCharacterSelectorWindowBackButton = -1;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowBackButtonDownFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowBackButtonDownFrmHandle);
|
||||
gCharacterSelectorWindowBackButtonDownFrmHandle = NULL;
|
||||
gCharacterSelectorWindowBackButtonDownFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowBackButtonUpFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowBackButtonUpFrmHandle);
|
||||
gCharacterSelectorWindowBackButtonUpFrmHandle = NULL;
|
||||
gCharacterSelectorWindowBackButtonUpFrmData = NULL;
|
||||
}
|
||||
_backButtonNormalFrmImage.unlock();
|
||||
_backButtonPressedFrmImage.unlock();
|
||||
|
||||
if (gCharacterSelectorBackground != NULL) {
|
||||
internal_free(gCharacterSelectorBackground);
|
||||
@@ -657,7 +551,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;
|
||||
@@ -687,18 +583,17 @@ static bool characterSelectorWindowRenderFace()
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
CacheEntry* faceFrmHandle;
|
||||
int faceFid = buildFid(OBJ_TYPE_INTERFACE, gPremadeCharacterDescriptions[gCurrentPremadeCharacter].face, 0, 0, 0);
|
||||
Art* frm = artLock(faceFid, &faceFrmHandle);
|
||||
if (frm != NULL) {
|
||||
unsigned char* data = artGetFrameData(frm, 0, 0);
|
||||
FrmImage faceFrmImage;
|
||||
int faceFid = buildFid(OBJ_TYPE_INTERFACE, gCustomPremadeCharacterDescriptions[gCurrentPremadeCharacter].face, 0, 0, 0);
|
||||
if (faceFrmImage.lock(faceFid)) {
|
||||
unsigned char* data = faceFrmImage.getData();
|
||||
if (data != NULL) {
|
||||
int width = artGetWidth(frm, 0, 0);
|
||||
int height = artGetHeight(frm, 0, 0);
|
||||
int width = faceFrmImage.getWidth();
|
||||
int height = faceFrmImage.getHeight();
|
||||
blitBufferToBufferTrans(data, width, height, width, (gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * 23 + 27), CS_WINDOW_WIDTH);
|
||||
success = true;
|
||||
}
|
||||
artUnlock(faceFrmHandle);
|
||||
faceFrmImage.unlock();
|
||||
}
|
||||
|
||||
return success;
|
||||
@@ -963,7 +858,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 +879,124 @@ static bool characterSelectorWindowRenderBio()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4A8BD0
|
||||
static bool characterSelectorWindowFatalError(bool result)
|
||||
{
|
||||
characterSelectorWindowFree();
|
||||
return result;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
#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;
|
||||
namespace fallout {
|
||||
|
||||
int characterSelectorOpen();
|
||||
|
||||
void premadeCharactersInit();
|
||||
void premadeCharactersExit();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CHARACTER_SELECTOR_H */
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#include "color.h"
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define COLOR_PALETTE_STACK_CAPACITY 16
|
||||
|
||||
typedef struct ColorPaletteStackEntry {
|
||||
@@ -679,3 +681,5 @@ void _colorsClose()
|
||||
|
||||
gColorPaletteStackSize = 0;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "memory_defs.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef const char*(ColorFileNameManger)(const char*);
|
||||
typedef void(ColorTransitionCallback)();
|
||||
|
||||
@@ -40,4 +42,6 @@ bool colorPopColorPalette();
|
||||
bool _initColors();
|
||||
void _colorsClose();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* COLOR_H */
|
||||
|
||||
1547
src/combat.cc
28
src/combat.h
@@ -6,6 +6,8 @@
|
||||
#include "obj_types.h"
|
||||
#include "proto_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
extern int _combatNumTurns;
|
||||
extern unsigned int gCombatState;
|
||||
|
||||
@@ -17,8 +19,8 @@ void combatExit();
|
||||
int _find_cid(int a1, int a2, Object** a3, int a4);
|
||||
int combatLoad(File* stream);
|
||||
int combatSave(File* stream);
|
||||
bool _combat_safety_invalidate_weapon(Object* a1, Object* a2, int hitMode, Object* a4, int* a5);
|
||||
bool _combatTestIncidentalHit(Object* a1, Object* a2, Object* a3, Object* a4);
|
||||
bool _combat_safety_invalidate_weapon(Object* attacker, Object* weapon, int hitMode, Object* defender, int* safeDistancePtr);
|
||||
bool _combatTestIncidentalHit(Object* attacker, Object* defender, Object* attackerFriend, Object* weapon);
|
||||
Object* _combat_whose_turn();
|
||||
void _combat_data_init(Object* obj);
|
||||
Object* aiInfoGetFriendlyDead(Object* obj);
|
||||
@@ -56,9 +58,31 @@ 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);
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* COMBAT_H */
|
||||
|
||||
330
src/combat_ai.cc
@@ -1,5 +1,9 @@
|
||||
#include "combat_ai.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "actions.h"
|
||||
#include "animation.h"
|
||||
#include "art.h"
|
||||
@@ -30,9 +34,7 @@
|
||||
#include "text_object.h"
|
||||
#include "tile.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
#define AI_PACKET_CHEM_PRIMARY_DESIRE_COUNT (3)
|
||||
|
||||
@@ -99,13 +101,16 @@ static void _ai_run_away(Object* a1, Object* a2);
|
||||
static int _ai_move_away(Object* a1, Object* a2, int a3);
|
||||
static bool _ai_find_friend(Object* a1, int a2, int a3);
|
||||
static int _compare_nearer(const void* a1, const void* a2);
|
||||
static void _ai_sort_list_distance(Object** critterList, int length, Object* origin);
|
||||
static int _compare_strength(const void* p1, const void* p2);
|
||||
static void _ai_sort_list_strength(Object** critterList, int length);
|
||||
static int _compare_weakness(const void* p1, const void* p2);
|
||||
static void _ai_sort_list_weakness(Object** critterList, int length);
|
||||
static Object* _ai_find_nearest_team(Object* a1, Object* a2, int a3);
|
||||
static Object* _ai_find_nearest_team_in_combat(Object* a1, Object* a2, int a3);
|
||||
static int _ai_find_attackers(Object* a1, Object** a2, Object** a3, Object** a4);
|
||||
static Object* _ai_danger_source(Object* a1);
|
||||
static int _ai_have_ammo(Object* critter_obj, Object* weapon_obj, Object** out_ammo_obj);
|
||||
static bool aiHaveAmmo(Object* critter, Object* weapon, Object** ammoPtr);
|
||||
static bool _caiHasWeapPrefType(AiPacket* ai, int attackType);
|
||||
static Object* _ai_best_weapon(Object* a1, Object* a2, Object* a3, Object* a4);
|
||||
static bool _ai_can_use_weapon(Object* critter, Object* weapon, int hitMode);
|
||||
@@ -114,9 +119,10 @@ static Object* _ai_search_environ(Object* critter, int itemType);
|
||||
static Object* _ai_retrieve_object(Object* a1, Object* a2);
|
||||
static int _ai_pick_hit_mode(Object* a1, Object* a2, Object* a3);
|
||||
static int _ai_move_steps_closer(Object* a1, Object* a2, int actionPoints, int a4);
|
||||
static int _ai_move_closer(Object* a1, Object* a2, int a3);
|
||||
static int _cai_retargetTileFromFriendlyFire(Object* source, Object* target, int* tilePtr);
|
||||
static int _cai_retargetTileFromFriendlyFireSubFunc(AiRetargetData* aiRetargetData, int tile);
|
||||
static bool _cai_attackWouldIntersect(Object* a1, Object* a2, Object* a3, int tile, int* distance);
|
||||
static bool _cai_attackWouldIntersect(Object* attacker, Object* defender, Object* attackerFriend, int tile, int* distance);
|
||||
static int _ai_switch_weapons(Object* a1, int* hitMode, Object** weapon, Object* a4);
|
||||
static int _ai_called_shot(Object* a1, Object* a2, int a3);
|
||||
static int _ai_attack(Object* a1, Object* a2, int a3);
|
||||
@@ -291,7 +297,7 @@ static char _attack_str[268];
|
||||
// parse hurt_too_much
|
||||
static void _parse_hurt_str(char* str, int* valuePtr)
|
||||
{
|
||||
int v5, v10;
|
||||
size_t v5, v10;
|
||||
char tmp;
|
||||
int i;
|
||||
|
||||
@@ -988,8 +994,7 @@ static int _ai_check_drugs(Object* critter)
|
||||
}
|
||||
|
||||
int drugPid = drug->pid;
|
||||
if ((drugPid == PROTO_ID_STIMPACK || drugPid == PROTO_ID_SUPER_STIMPACK || drugPid == PROTO_ID_HEALING_POWDER)
|
||||
&& itemRemove(critter, drug, 1) == 0) {
|
||||
if (itemIsHealing(drugPid) && itemRemove(critter, drug, 1) == 0) {
|
||||
if (_item_d_take_drug(critter, drug) == -1) {
|
||||
itemAdd(critter, drug, 1);
|
||||
} else {
|
||||
@@ -1027,8 +1032,7 @@ static int _ai_check_drugs(Object* critter)
|
||||
}
|
||||
|
||||
if (index < AI_PACKET_CHEM_PRIMARY_DESIRE_COUNT) {
|
||||
if (drugPid != PROTO_ID_STIMPACK && drugPid != PROTO_ID_SUPER_STIMPACK && drugPid != 273
|
||||
&& itemRemove(critter, drug, 1) == 0) {
|
||||
if (!itemIsHealing(drugPid) && itemRemove(critter, drug, 1) == 0) {
|
||||
if (_item_d_take_drug(critter, drug) == -1) {
|
||||
itemAdd(critter, drug, 1);
|
||||
} else {
|
||||
@@ -1238,6 +1242,15 @@ static int _compare_nearer(const void* a1, const void* a2)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x428B74
|
||||
static void _ai_sort_list_distance(Object** critterList, int length, Object* origin)
|
||||
{
|
||||
_combat_obj = origin;
|
||||
qsort(critterList, length, sizeof(*critterList), _compare_nearer);
|
||||
}
|
||||
|
||||
// qsort compare function - melee then ranged.
|
||||
//
|
||||
// 0x428B8C
|
||||
@@ -1272,6 +1285,14 @@ static int _compare_strength(const void* p1, const void* p2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x428BD0
|
||||
static void _ai_sort_list_strength(Object** critterList, int length)
|
||||
{
|
||||
qsort(critterList, length, sizeof(*critterList), _compare_strength);
|
||||
}
|
||||
|
||||
// qsort compare unction - ranged then melee
|
||||
//
|
||||
// 0x428BE4
|
||||
@@ -1306,6 +1327,14 @@ static int _compare_weakness(const void* p1, const void* p2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x428C28
|
||||
static void _ai_sort_list_weakness(Object** critterList, int length)
|
||||
{
|
||||
qsort(critterList, length, sizeof(*critterList), _compare_weakness);
|
||||
}
|
||||
|
||||
// 0x428C3C
|
||||
static Object* _ai_find_nearest_team(Object* a1, Object* a2, int a3)
|
||||
{
|
||||
@@ -1320,8 +1349,8 @@ static Object* _ai_find_nearest_team(Object* a1, Object* a2, int a3)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_combat_obj = a1;
|
||||
qsort(_curr_crit_list, _curr_crit_num, sizeof(*_curr_crit_list), _compare_nearer);
|
||||
// NOTE: Uninline.
|
||||
_ai_sort_list_distance(_curr_crit_list, _curr_crit_num, a1);
|
||||
|
||||
for (i = 0; i < _curr_crit_num; i++) {
|
||||
obj = _curr_crit_list[i];
|
||||
@@ -1346,8 +1375,8 @@ static Object* _ai_find_nearest_team_in_combat(Object* a1, Object* a2, int a3)
|
||||
|
||||
int team = a2->data.critter.combat.team;
|
||||
|
||||
_combat_obj = a1;
|
||||
qsort(_curr_crit_list, _curr_crit_num, sizeof(*_curr_crit_list), _compare_nearer);
|
||||
// NOTE: Uninline.
|
||||
_ai_sort_list_distance(_curr_crit_list, _curr_crit_num, a1);
|
||||
|
||||
for (int index = 0; index < _curr_crit_num; index++) {
|
||||
Object* obj = _curr_crit_list[index];
|
||||
@@ -1383,8 +1412,8 @@ static int _ai_find_attackers(Object* a1, Object** a2, Object** a3, Object** a4)
|
||||
return 0;
|
||||
}
|
||||
|
||||
_combat_obj = a1;
|
||||
qsort(_curr_crit_list, _curr_crit_num, sizeof(*_curr_crit_list), _compare_nearer);
|
||||
// NOTE: Uninline.
|
||||
_ai_sort_list_distance(_curr_crit_list, _curr_crit_num, a1);
|
||||
|
||||
int foundTargetCount = 0;
|
||||
int team = a1->data.critter.combat.team;
|
||||
@@ -1473,7 +1502,7 @@ static Object* _ai_danger_source(Object* a1)
|
||||
}
|
||||
|
||||
if (pathfinderFindPath(a1, a1->tile, gDude->data.critter.combat.whoHitMe->tile, NULL, 0, _obj_blocking_at) == 0
|
||||
&& _combat_check_bad_shot(a1, candidate, HIT_MODE_RIGHT_WEAPON_PRIMARY, false) != 0) {
|
||||
&& _combat_check_bad_shot(a1, candidate, HIT_MODE_RIGHT_WEAPON_PRIMARY, false) != COMBAT_BAD_SHOT_OK) {
|
||||
debugPrint("\nai_danger_source: %s couldn't attack at target! Picking alternate!", critterGetName(a1));
|
||||
break;
|
||||
}
|
||||
@@ -1523,27 +1552,26 @@ static Object* _ai_danger_source(Object* a1)
|
||||
}
|
||||
}
|
||||
|
||||
int (*compareProc)(const void*, const void*);
|
||||
switch (attackWho) {
|
||||
case ATTACK_WHO_STRONGEST:
|
||||
compareProc = _compare_strength;
|
||||
// NOTE: Uninline.
|
||||
_ai_sort_list_strength(targets, 4);
|
||||
break;
|
||||
case ATTACK_WHO_WEAKEST:
|
||||
compareProc = _compare_weakness;
|
||||
// NOTE: Uninline.
|
||||
_ai_sort_list_weakness(targets, 4);
|
||||
break;
|
||||
default:
|
||||
compareProc = _compare_nearer;
|
||||
_combat_obj = a1;
|
||||
// NOTE: Uninline.
|
||||
_ai_sort_list_distance(targets, 4, a1);
|
||||
break;
|
||||
}
|
||||
|
||||
qsort(targets, 4, sizeof(*targets), compareProc);
|
||||
|
||||
for (int index = 0; index < 4; index++) {
|
||||
Object* candidate = targets[index];
|
||||
if (candidate != NULL && objectCanHearObject(a1, candidate)) {
|
||||
if (pathfinderFindPath(a1, a1->tile, candidate->tile, NULL, 0, _obj_blocking_at) != 0
|
||||
|| _combat_check_bad_shot(a1, candidate, HIT_MODE_RIGHT_WEAPON_PRIMARY, false) == 0) {
|
||||
|| _combat_check_bad_shot(a1, candidate, HIT_MODE_RIGHT_WEAPON_PRIMARY, false) == COMBAT_BAD_SHOT_OK) {
|
||||
return candidate;
|
||||
}
|
||||
debugPrint("\nai_danger_source: I couldn't get at my target! Picking alternate!");
|
||||
@@ -1621,44 +1649,41 @@ void _caiTeamCombatExit()
|
||||
}
|
||||
|
||||
// 0x4292D4
|
||||
static int _ai_have_ammo(Object* critter_obj, Object* weapon_obj, Object** out_ammo_obj)
|
||||
static bool aiHaveAmmo(Object* critter, Object* weapon, Object** ammoPtr)
|
||||
{
|
||||
int v9;
|
||||
Object* ammo_obj;
|
||||
|
||||
if (out_ammo_obj) {
|
||||
*out_ammo_obj = NULL;
|
||||
if (ammoPtr != NULL) {
|
||||
*ammoPtr = NULL;
|
||||
}
|
||||
|
||||
if (weapon_obj->pid == PROTO_ID_SOLAR_SCORCHER) {
|
||||
if (weapon->pid == PROTO_ID_SOLAR_SCORCHER) {
|
||||
return lightGetLightLevel() > 62259;
|
||||
}
|
||||
|
||||
v9 = -1;
|
||||
int inventoryItemIndex = -1;
|
||||
|
||||
while (1) {
|
||||
ammo_obj = _inven_find_type(critter_obj, 4, &v9);
|
||||
if (ammo_obj == NULL) {
|
||||
Object* ammo = _inven_find_type(critter, ITEM_TYPE_AMMO, &inventoryItemIndex);
|
||||
if (ammo == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (weaponCanBeReloadedWith(weapon_obj, ammo_obj)) {
|
||||
if (out_ammo_obj) {
|
||||
*out_ammo_obj = ammo_obj;
|
||||
if (weaponCanBeReloadedWith(weapon, ammo)) {
|
||||
if (ammoPtr != NULL) {
|
||||
*ammoPtr = ammo;
|
||||
}
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (weaponGetAnimationCode(weapon_obj)) {
|
||||
if (_item_w_range(critter_obj, 2) < 3) {
|
||||
_inven_unwield(critter_obj, 1);
|
||||
if (weaponGetAnimationCode(weapon)) {
|
||||
if (weaponGetRange(critter, HIT_MODE_RIGHT_WEAPON_PRIMARY) < 3) {
|
||||
_inven_unwield(critter, HAND_RIGHT);
|
||||
}
|
||||
} else {
|
||||
_inven_unwield(critter_obj, 1);
|
||||
_inven_unwield(critter, HAND_RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x42938C
|
||||
@@ -1716,17 +1741,18 @@ static Object* _ai_best_weapon(Object* attacker, Object* weapon1, Object* weapon
|
||||
return NULL;
|
||||
}
|
||||
|
||||
avgDamage1 = (maxDamage - minDamage) / 2;
|
||||
if (_item_w_area_damage_radius(weapon1, HIT_MODE_RIGHT_WEAPON_PRIMARY) > 0 && defender != NULL) {
|
||||
// SFALL: Fix avg damage calculation.
|
||||
avgDamage1 = (maxDamage + minDamage) / 2;
|
||||
if (weaponGetDamageRadius(weapon1, HIT_MODE_RIGHT_WEAPON_PRIMARY) > 0 && defender != NULL) {
|
||||
attack.weapon = weapon1;
|
||||
_compute_explosion_on_extras(&attack, 0, weaponIsGrenade(weapon1), 1);
|
||||
avgDamage1 *= attack.extrasLength + 1;
|
||||
}
|
||||
|
||||
// TODO: Probably an error, why it takes [weapon2], should likely use
|
||||
// [weapon1].
|
||||
if (weaponGetPerk(weapon2) != -1) {
|
||||
avgDamage1 *= 5;
|
||||
// SFALL: Fix for the incorrect item being checked.
|
||||
if (weaponGetPerk(weapon1) != -1) {
|
||||
// SFALL: Lower weapon score multiplier for having perk.
|
||||
avgDamage1 *= 2;
|
||||
}
|
||||
|
||||
if (defender != NULL) {
|
||||
@@ -1735,12 +1761,12 @@ static Object* _ai_best_weapon(Object* attacker, Object* weapon1, Object* weapon
|
||||
}
|
||||
}
|
||||
|
||||
if (weaponIsNatural(weapon1)) {
|
||||
if (itemIsHidden(weapon1)) {
|
||||
return weapon1;
|
||||
}
|
||||
} else {
|
||||
distance = objectGetDistanceBetween(attacker, defender);
|
||||
if (_item_w_range(attacker, HIT_MODE_PUNCH) >= distance) {
|
||||
if (weaponGetRange(attacker, HIT_MODE_PUNCH) >= distance) {
|
||||
attackType1 = ATTACK_TYPE_UNARMED;
|
||||
}
|
||||
}
|
||||
@@ -1760,15 +1786,17 @@ static Object* _ai_best_weapon(Object* attacker, Object* weapon1, Object* weapon
|
||||
return NULL;
|
||||
}
|
||||
|
||||
avgDamage2 = (maxDamage - minDamage) / 2;
|
||||
if (_item_w_area_damage_radius(weapon2, HIT_MODE_RIGHT_WEAPON_PRIMARY) > 0 && defender != NULL) {
|
||||
// SFALL: Fix avg damage calculation.
|
||||
avgDamage2 = (maxDamage + minDamage) / 2;
|
||||
if (weaponGetDamageRadius(weapon2, HIT_MODE_RIGHT_WEAPON_PRIMARY) > 0 && defender != NULL) {
|
||||
attack.weapon = weapon2;
|
||||
_compute_explosion_on_extras(&attack, 0, weaponIsGrenade(weapon2), 1);
|
||||
avgDamage2 *= attack.extrasLength + 1;
|
||||
}
|
||||
|
||||
if (weaponGetPerk(weapon2) != -1) {
|
||||
avgDamage2 *= 5;
|
||||
// SFALL: Lower weapon score multiplier for having perk.
|
||||
avgDamage2 *= 2;
|
||||
}
|
||||
|
||||
if (defender != NULL) {
|
||||
@@ -1777,7 +1805,7 @@ static Object* _ai_best_weapon(Object* attacker, Object* weapon1, Object* weapon
|
||||
}
|
||||
}
|
||||
|
||||
if (weaponIsNatural(weapon2)) {
|
||||
if (itemIsHidden(weapon2)) {
|
||||
return weapon2;
|
||||
}
|
||||
} else {
|
||||
@@ -1785,7 +1813,7 @@ static Object* _ai_best_weapon(Object* attacker, Object* weapon1, Object* weapon
|
||||
distance = objectGetDistanceBetween(attacker, weapon1);
|
||||
}
|
||||
|
||||
if (_item_w_range(attacker, HIT_MODE_PUNCH) >= distance) {
|
||||
if (weaponGetRange(attacker, HIT_MODE_PUNCH) >= distance) {
|
||||
attackType2 = ATTACK_TYPE_UNARMED;
|
||||
}
|
||||
}
|
||||
@@ -1881,7 +1909,7 @@ Object* _ai_search_inven_weap(Object* critter, int a2, Object* a3)
|
||||
}
|
||||
|
||||
if (a2) {
|
||||
if (weaponGetActionPointCost1(weapon) > critter->data.critter.combat.ap) {
|
||||
if (weaponGetPrimaryActionPointCost(weapon) > critter->data.critter.combat.ap) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1892,7 +1920,7 @@ Object* _ai_search_inven_weap(Object* critter, int a2, Object* a3)
|
||||
|
||||
if (weaponGetAttackTypeForHitMode(weapon, HIT_MODE_RIGHT_WEAPON_PRIMARY) == ATTACK_TYPE_RANGED) {
|
||||
if (ammoGetQuantity(weapon) == 0) {
|
||||
if (!_ai_have_ammo(critter, weapon, NULL)) {
|
||||
if (!aiHaveAmmo(critter, weapon, NULL)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -2024,8 +2052,8 @@ static Object* _ai_search_environ(Object* critter, int itemType)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_combat_obj = critter;
|
||||
qsort(objects, count, sizeof(*objects), _compare_nearer);
|
||||
// NOTE: Uninline.
|
||||
_ai_sort_list_distance(objects, count, critter);
|
||||
|
||||
int perception = critterGetStat(critter, STAT_PERCEPTION) + 5;
|
||||
Object* item2 = critterGetItem2(critter);
|
||||
@@ -2158,6 +2186,20 @@ static int _ai_pick_hit_mode(Object* a1, Object* a2, Object* a3)
|
||||
}
|
||||
}
|
||||
|
||||
// SFALL: Add a check for the weapon range and the AP cost when AI is
|
||||
// choosing weapon attack modes.
|
||||
if (useSecondaryMode) {
|
||||
if (objectGetDistanceBetween(a1, a3) > weaponGetRange(a1, HIT_MODE_RIGHT_WEAPON_SECONDARY)) {
|
||||
useSecondaryMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (useSecondaryMode) {
|
||||
if (a1->data.critter.combat.ap < weaponGetActionPointCost(a1, HIT_MODE_RIGHT_WEAPON_SECONDARY, false)) {
|
||||
useSecondaryMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (useSecondaryMode) {
|
||||
if (attackType != ATTACK_TYPE_THROW
|
||||
|| _ai_search_inven_weap(a1, 0, a3) != NULL
|
||||
@@ -2261,6 +2303,14 @@ static int _ai_move_steps_closer(Object* a1, Object* a2, int actionPoints, int a
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x42A1C0
|
||||
static int _ai_move_closer(Object* a1, Object* a2, int a3)
|
||||
{
|
||||
return _ai_move_steps_closer(a1, a2, a1->data.critter.combat.ap, a3);
|
||||
}
|
||||
|
||||
// 0x42A1D4
|
||||
static int _cai_retargetTileFromFriendlyFire(Object* source, Object* target, int* tilePtr)
|
||||
{
|
||||
@@ -2316,9 +2366,8 @@ static int _cai_retargetTileFromFriendlyFire(Object* source, Object* target, int
|
||||
}
|
||||
}
|
||||
|
||||
_combat_obj = source;
|
||||
|
||||
qsort(aiRetargetData.critterList, aiRetargetData.critterCount, sizeof(*aiRetargetData.critterList), _compare_nearer);
|
||||
// NOTE: Uninline.
|
||||
_ai_sort_list_distance(aiRetargetData.critterList, aiRetargetData.critterCount, source);
|
||||
|
||||
if (_cai_retargetTileFromFriendlyFireSubFunc(&aiRetargetData, *tilePtr) == 0) {
|
||||
int minDistance = 99999;
|
||||
@@ -2374,27 +2423,27 @@ static int _cai_retargetTileFromFriendlyFireSubFunc(AiRetargetData* aiRetargetDa
|
||||
}
|
||||
|
||||
// 0x42A518
|
||||
static bool _cai_attackWouldIntersect(Object* a1, Object* a2, Object* a3, int tile, int* distance)
|
||||
static bool _cai_attackWouldIntersect(Object* attacker, Object* defender, Object* attackerFriend, int tile, int* distance)
|
||||
{
|
||||
int hitMode = HIT_MODE_RIGHT_WEAPON_PRIMARY;
|
||||
bool aiming = false;
|
||||
if (a1 == gDude) {
|
||||
if (attacker == gDude) {
|
||||
interfaceGetCurrentHitMode(&hitMode, &aiming);
|
||||
}
|
||||
|
||||
Object* v8 = critterGetWeaponForHitMode(a1, hitMode);
|
||||
if (v8 == NULL) {
|
||||
Object* weapon = critterGetWeaponForHitMode(attacker, hitMode);
|
||||
if (weapon == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_item_w_range(a1, hitMode) < 1) {
|
||||
if (weaponGetRange(attacker, hitMode) < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object* object = NULL;
|
||||
_make_straight_path_func(a1, a1->tile, a2->tile, NULL, &object, 32, _obj_shoot_blocking_at);
|
||||
if (object != a3) {
|
||||
if (!_combatTestIncidentalHit(a1, a2, a3, v8)) {
|
||||
_make_straight_path_func(attacker, attacker->tile, defender->tile, NULL, &object, 32, _obj_shoot_blocking_at);
|
||||
if (object != attackerFriend) {
|
||||
if (!_combatTestIncidentalHit(attacker, defender, attackerFriend, weapon)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2415,7 +2464,7 @@ static int _ai_switch_weapons(Object* a1, int* hitMode, Object** weapon, Object*
|
||||
} else {
|
||||
Object* v8 = _ai_search_environ(a1, ITEM_TYPE_WEAPON);
|
||||
if (v8 == NULL) {
|
||||
if (_item_w_mp_cost(a1, *hitMode, 0) <= a1->data.critter.combat.ap) {
|
||||
if (weaponGetActionPointCost(a1, *hitMode, 0) <= a1->data.critter.combat.ap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2432,7 +2481,7 @@ static int _ai_switch_weapons(Object* a1, int* hitMode, Object** weapon, Object*
|
||||
if (*weapon != NULL) {
|
||||
_inven_wield(a1, *weapon, 1);
|
||||
_combat_turn_run();
|
||||
if (_item_w_mp_cost(a1, *hitMode, 0) <= a1->data.critter.combat.ap) {
|
||||
if (weaponGetActionPointCost(a1, *hitMode, 0) <= a1->data.critter.combat.ap) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -2451,8 +2500,8 @@ static int _ai_called_shot(Object* a1, Object* a2, int a3)
|
||||
|
||||
v5 = 3;
|
||||
|
||||
if (_item_w_mp_cost(a1, a3, 1) <= a1->data.critter.combat.ap) {
|
||||
if (_item_w_called_shot(a1, a3)) {
|
||||
if (weaponGetActionPointCost(a1, a3, 1) <= a1->data.critter.combat.ap) {
|
||||
if (critterCanAim(a1, a3)) {
|
||||
ai = aiGetPacket(a1);
|
||||
if (randomBetween(1, ai->called_freq) == 1) {
|
||||
combat_difficulty = 1;
|
||||
@@ -2524,13 +2573,17 @@ static int _ai_try_attack(Object* a1, Object* a2)
|
||||
int actionPoints = a1->data.critter.combat.ap;
|
||||
int v31 = 0;
|
||||
int v42 = 0;
|
||||
if (weapon == NULL) {
|
||||
if (critterGetBodyType(a2) != BODY_TYPE_BIPED
|
||||
|| ((a2->fid & 0xF000) >> 12 != 0)
|
||||
|| !artExists(buildFid(OBJ_TYPE_CRITTER, a1->fid & 0xFFF, ANIM_THROW_PUNCH, 0, a1->rotation + 1))
|
||||
|| _combat_safety_invalidate_weapon(a1, weapon, HIT_MODE_RIGHT_WEAPON_PRIMARY, a2, &v31)) {
|
||||
if (weapon != NULL
|
||||
|| (critterGetBodyType(a2) == BODY_TYPE_BIPED
|
||||
&& ((a2->fid & 0xF000) >> 12 == 0)
|
||||
&& artExists(buildFid(OBJ_TYPE_CRITTER, a1->fid & 0xFFF, ANIM_THROW_PUNCH, 0, a1->rotation + 1)))) {
|
||||
// SFALL: Check the safety of weapons based on the selected attack mode
|
||||
// instead of always the primary weapon hit mode.
|
||||
if (_combat_safety_invalidate_weapon(a1, weapon, hitMode, a2, &v31)) {
|
||||
_ai_switch_weapons(a1, &hitMode, &weapon, a2);
|
||||
}
|
||||
} else {
|
||||
_ai_switch_weapons(a1, &hitMode, &weapon, a2);
|
||||
}
|
||||
|
||||
unsigned char v30[800];
|
||||
@@ -2542,10 +2595,10 @@ static int _ai_try_attack(Object* a1, Object* a2)
|
||||
}
|
||||
|
||||
int reason = _combat_check_bad_shot(a1, a2, hitMode, false);
|
||||
if (reason == 1) {
|
||||
if (reason == COMBAT_BAD_SHOT_NO_AMMO) {
|
||||
// out of ammo
|
||||
if (_ai_have_ammo(a1, weapon, &ammo)) {
|
||||
int v9 = _item_w_reload(weapon, ammo);
|
||||
if (aiHaveAmmo(a1, weapon, &ammo)) {
|
||||
int v9 = weaponReload(weapon, ammo);
|
||||
if (v9 == 0 && ammo != NULL) {
|
||||
_obj_destroy(ammo);
|
||||
}
|
||||
@@ -2556,9 +2609,14 @@ static int _ai_try_attack(Object* a1, Object* a2)
|
||||
_gsound_play_sfx_file_volume(sfx, volume);
|
||||
_ai_magic_hands(a1, weapon, 5002);
|
||||
|
||||
int actionPoints = a1->data.critter.combat.ap;
|
||||
if (actionPoints >= 2) {
|
||||
a1->data.critter.combat.ap = actionPoints - 2;
|
||||
// SFALL: Fix incorrect AP cost when AI reloads a weapon.
|
||||
// CE: There is a commented out code which checks
|
||||
// available action points before performing reload. Not
|
||||
// sure why it was commented, probably needs additional
|
||||
// testing.
|
||||
int actionPointsRequired = weaponGetActionPointCost(a1, HIT_MODE_RIGHT_WEAPON_RELOAD, false);
|
||||
if (a1->data.critter.combat.ap >= actionPointsRequired) {
|
||||
a1->data.critter.combat.ap -= actionPointsRequired;
|
||||
} else {
|
||||
a1->data.critter.combat.ap = 0;
|
||||
}
|
||||
@@ -2568,7 +2626,7 @@ static int _ai_try_attack(Object* a1, Object* a2)
|
||||
if (ammo != NULL) {
|
||||
ammo = _ai_retrieve_object(a1, ammo);
|
||||
if (ammo != NULL) {
|
||||
int v15 = _item_w_reload(weapon, ammo);
|
||||
int v15 = weaponReload(weapon, ammo);
|
||||
if (v15 == 0) {
|
||||
_obj_destroy(ammo);
|
||||
}
|
||||
@@ -2579,9 +2637,14 @@ static int _ai_try_attack(Object* a1, Object* a2)
|
||||
_gsound_play_sfx_file_volume(sfx, volume);
|
||||
_ai_magic_hands(a1, weapon, 5002);
|
||||
|
||||
int actionPoints = a1->data.critter.combat.ap;
|
||||
if (actionPoints >= 2) {
|
||||
a1->data.critter.combat.ap = actionPoints - 2;
|
||||
// SFALL: Fix incorrect AP cost when AI reloads a
|
||||
// weapon.
|
||||
// CE: See note above, probably need to check
|
||||
// available action points before performing
|
||||
// reload.
|
||||
int actionPointsRequired = weaponGetActionPointCost(a1, HIT_MODE_RIGHT_WEAPON_RELOAD, false);
|
||||
if (a1->data.critter.combat.ap >= actionPointsRequired) {
|
||||
a1->data.critter.combat.ap -= actionPointsRequired;
|
||||
} else {
|
||||
a1->data.critter.combat.ap = 0;
|
||||
}
|
||||
@@ -2600,14 +2663,14 @@ static int _ai_try_attack(Object* a1, Object* a2)
|
||||
_ai_switch_weapons(a1, &hitMode, &weapon, a2);
|
||||
}
|
||||
}
|
||||
} else if (reason == 3 || reason == 6 || reason == 7) {
|
||||
} else if (reason == COMBAT_BAD_SHOT_NOT_ENOUGH_AP || reason == COMBAT_BAD_SHOT_ARM_CRIPPLED || reason == COMBAT_BAD_SHOT_BOTH_ARMS_CRIPPLED) {
|
||||
// 3 - not enough action points
|
||||
// 6 - crippled one arm for two-handed weapon
|
||||
// 7 - both hands crippled
|
||||
if (_ai_switch_weapons(a1, &hitMode, &weapon, a2) == -1) {
|
||||
return -1;
|
||||
}
|
||||
} else if (reason == 2) {
|
||||
} else if (reason == COMBAT_BAD_SHOT_OUT_OF_RANGE) {
|
||||
// target out of range
|
||||
int accuracy = _determine_to_hit_no_range(a1, a2, HIT_LOCATION_UNCALLED, hitMode, v30);
|
||||
if (accuracy < minToHit) {
|
||||
@@ -2624,19 +2687,20 @@ static int _ai_try_attack(Object* a1, Object* a2)
|
||||
v38 = 0;
|
||||
} else {
|
||||
if (_ai_switch_weapons(a1, &hitMode, &weapon, a2) == -1 || weapon == NULL) {
|
||||
if (_ai_move_steps_closer(a1, a2, a1->data.critter.combat.ap, v38) == -1) {
|
||||
// NOTE: Uninline.
|
||||
if (_ai_move_closer(a1, a2, v38) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
v38 = 0;
|
||||
}
|
||||
} else if (reason == 5) {
|
||||
} else if (reason == COMBAT_BAD_SHOT_AIM_BLOCKED) {
|
||||
// aim is blocked
|
||||
if (_ai_move_steps_closer(a1, a2, a1->data.critter.combat.ap, v38) == -1) {
|
||||
return -1;
|
||||
}
|
||||
v38 = 0;
|
||||
} else if (reason == 0) {
|
||||
} else if (reason == COMBAT_BAD_SHOT_OK) {
|
||||
int accuracy = _determine_to_hit(a1, a2, HIT_LOCATION_UNCALLED, hitMode);
|
||||
if (v31) {
|
||||
if (_ai_move_away(a1, a2, v31) == -1) {
|
||||
@@ -2689,11 +2753,11 @@ static int _ai_try_attack(Object* a1, Object* a2)
|
||||
}
|
||||
|
||||
v38 = 0;
|
||||
if (_ai_attack(a1, a2, hitMode) == -1 || _item_w_mp_cost(a1, hitMode, 0) > a1->data.critter.combat.ap) {
|
||||
if (_ai_attack(a1, a2, hitMode) == -1 || weaponGetActionPointCost(a1, hitMode, 0) > a1->data.critter.combat.ap) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (_ai_attack(a1, a2, hitMode) == -1 || _item_w_mp_cost(a1, hitMode, 0) > a1->data.critter.combat.ap) {
|
||||
if (_ai_attack(a1, a2, hitMode) == -1 || weaponGetActionPointCost(a1, hitMode, 0) > a1->data.critter.combat.ap) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -2715,33 +2779,31 @@ int _cAIPrepWeaponItem(Object* critter, Object* item)
|
||||
}
|
||||
|
||||
// 0x42AECC
|
||||
void _cai_attempt_w_reload(Object* critter_obj, int a2)
|
||||
void aiAttemptWeaponReload(Object* critter, int animate)
|
||||
{
|
||||
Object* weapon_obj;
|
||||
Object* ammo_obj;
|
||||
int v5;
|
||||
int v9;
|
||||
const char* sfx;
|
||||
int v10;
|
||||
|
||||
weapon_obj = critterGetItem2(critter_obj);
|
||||
if (weapon_obj == NULL) {
|
||||
Object* weapon = critterGetItem2(critter);
|
||||
if (weapon == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
v5 = ammoGetQuantity(weapon_obj);
|
||||
if (v5 < ammoGetCapacity(weapon_obj) && _ai_have_ammo(critter_obj, weapon_obj, &ammo_obj)) {
|
||||
v9 = _item_w_reload(weapon_obj, ammo_obj);
|
||||
if (v9 == 0) {
|
||||
_obj_destroy(ammo_obj);
|
||||
}
|
||||
int ammoQuantity = ammoGetQuantity(weapon);
|
||||
int ammoCapacity = ammoGetCapacity(weapon);
|
||||
if (ammoQuantity < ammoCapacity) {
|
||||
Object* ammo;
|
||||
if (aiHaveAmmo(critter, weapon, &ammo)) {
|
||||
int rc = weaponReload(weapon, ammo);
|
||||
if (rc == 0) {
|
||||
_obj_destroy(ammo);
|
||||
}
|
||||
|
||||
if (v9 != -1 && objectIsPartyMember(critter_obj)) {
|
||||
v10 = _gsound_compute_relative_volume(critter_obj);
|
||||
sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_READY, weapon_obj, HIT_MODE_RIGHT_WEAPON_PRIMARY, NULL);
|
||||
_gsound_play_sfx_file_volume(sfx, v10);
|
||||
if (a2) {
|
||||
_ai_magic_hands(critter_obj, weapon_obj, 5002);
|
||||
if (rc != -1 && objectIsPartyMember(critter)) {
|
||||
int volume = _gsound_compute_relative_volume(critter);
|
||||
const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_READY, weapon, HIT_MODE_RIGHT_WEAPON_PRIMARY, NULL);
|
||||
_gsound_play_sfx_file_volume(sfx, volume);
|
||||
|
||||
if (animate) {
|
||||
_ai_magic_hands(critter, weapon, 5002);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2798,14 +2860,28 @@ int _cai_perform_distance_prefs(Object* a1, Object* a2)
|
||||
break;
|
||||
case DISTANCE_CHARGE:
|
||||
if (a2 != NULL) {
|
||||
_ai_move_steps_closer(a1, a2, a1->data.critter.combat.ap, 1);
|
||||
// NOTE: Uninline.
|
||||
_ai_move_closer(a1, a2, 1);
|
||||
}
|
||||
break;
|
||||
case DISTANCE_SNIPE:
|
||||
if (a2 != NULL) {
|
||||
if (objectGetDistanceBetween(a1, a2) < 10) {
|
||||
// NOTE: some odd code omitted
|
||||
_ai_move_away(a1, a2, 10);
|
||||
// SFALL: Fix AI behavior for "Snipe" distance preference.
|
||||
int distance = objectGetDistanceBetween(a1, a2);
|
||||
if (distance < 10) {
|
||||
int attackCost = weaponGetActionPointCost(a1, HIT_MODE_RIGHT_WEAPON_PRIMARY, false);
|
||||
int movementPoints = a1->data.critter.combat.ap - attackCost;
|
||||
if (movementPoints > 0) {
|
||||
if (movementPoints + distance - 1 < 5) {
|
||||
int attackerRating = _combatai_rating(a1);
|
||||
int defenderRating = _combatai_rating(a2);
|
||||
if (attackerRating < defenderRating) {
|
||||
_ai_move_away(a1, a2, 10);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_ai_move_away(a1, a2, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -3201,7 +3277,7 @@ Object* _combat_ai_random_target(Attack* attack)
|
||||
// Looks like this function does nothing because it's result is not used. I
|
||||
// suppose it was planned to use range as a condition below, but it was
|
||||
// later moved into 0x426614, but remained here.
|
||||
_item_w_range(attack->attacker, attack->hitMode);
|
||||
weaponGetRange(attack->attacker, attack->hitMode);
|
||||
|
||||
Object* critter = NULL;
|
||||
|
||||
@@ -3214,7 +3290,7 @@ Object* _combat_ai_random_target(Attack* attack)
|
||||
if (obj != attack->attacker
|
||||
&& obj != attack->defender
|
||||
&& _can_see(attack->attacker, obj)
|
||||
&& _combat_check_bad_shot(attack->attacker, obj, attack->hitMode, false)) {
|
||||
&& _combat_check_bad_shot(attack->attacker, obj, attack->hitMode, false) == COMBAT_BAD_SHOT_OK) {
|
||||
critter = obj;
|
||||
break;
|
||||
}
|
||||
@@ -3444,3 +3520,5 @@ void _combatai_delete_critter(Object* obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "db.h"
|
||||
#include "obj_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum AiMessageType {
|
||||
AI_MESSAGE_TYPE_RUN,
|
||||
AI_MESSAGE_TYPE_MOVE,
|
||||
@@ -48,7 +50,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);
|
||||
@@ -66,4 +68,6 @@ void _combatai_notify_onlookers(Object* a1);
|
||||
void _combatai_notify_friends(Object* a1);
|
||||
void _combatai_delete_critter(Object* obj);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* COMBAT_AI_H */
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef COMBAT_AI_DEFS_H
|
||||
#define COMBAT_AI_DEFS_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum AreaAttackMode {
|
||||
AREA_ATTACK_MODE_ALWAYS,
|
||||
AREA_ATTACK_MODE_SOMETIMES,
|
||||
@@ -79,4 +81,6 @@ typedef enum HurtTooMuch {
|
||||
HURT_COUNT,
|
||||
} HurtTooMuch;
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* COMBAT_AI_DEFS_H */
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#define WEAPON_CRITICAL_FAILURE_TYPE_COUNT (7)
|
||||
#define WEAPON_CRITICAL_FAILURE_EFFECT_COUNT (5)
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum CombatState {
|
||||
COMBAT_STATE_0x01 = 0x01,
|
||||
COMBAT_STATE_0x02 = 0x02,
|
||||
@@ -121,25 +123,54 @@ 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;
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#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,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define CONFIG_FILE_MAX_LINE_LENGTH (256)
|
||||
|
||||
// The initial number of sections (or key-value) pairs in the config.
|
||||
@@ -547,3 +549,5 @@ bool configSetBool(Config* config, const char* sectionKey, const char* key, bool
|
||||
{
|
||||
return configSetInt(config, sectionKey, key, value ? 1 : 0);
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "dictionary.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// A representation of .INI file.
|
||||
//
|
||||
// It's implemented as a [Dictionary] whos keys are section names of .INI file,
|
||||
@@ -31,4 +33,6 @@ bool configSetDouble(Config* config, const char* sectionKey, const char* key, do
|
||||
bool configGetBool(Config* config, const char* sectionKey, const char* key, bool* valuePtr);
|
||||
bool configSetBool(Config* config, const char* sectionKey, const char* key, bool value);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CONFIG_H */
|
||||
|
||||
140
src/core.cc
@@ -1,5 +1,10 @@
|
||||
#include "core.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "audio_engine.h"
|
||||
#include "color.h"
|
||||
#include "config.h"
|
||||
@@ -13,15 +18,15 @@
|
||||
#include "window_manager.h"
|
||||
#include "window_manager_private.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
// NOT USED.
|
||||
void (*_idle_func)() = NULL;
|
||||
static void idleImpl();
|
||||
|
||||
// NOT USED.
|
||||
void (*_focus_func)(int) = NULL;
|
||||
// 0x51E234
|
||||
IdleFunc* _idle_func = NULL;
|
||||
|
||||
// 0x51E238
|
||||
FocusFunc* _focus_func = NULL;
|
||||
|
||||
// 0x51E23C
|
||||
int gKeyboardKeyRepeatRate = 80;
|
||||
@@ -373,6 +378,9 @@ 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)
|
||||
{
|
||||
@@ -408,6 +416,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;
|
||||
}
|
||||
|
||||
@@ -919,6 +931,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()
|
||||
{
|
||||
@@ -1269,13 +1345,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:
|
||||
handleTouchFingerEvent(&(e.tfinger));
|
||||
handleTouchEvent(&e);
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
@@ -1369,7 +1445,7 @@ void _GNW95_process_key(KeyboardData* data)
|
||||
void _GNW95_lost_focus()
|
||||
{
|
||||
if (_focus_func != NULL) {
|
||||
_focus_func(0);
|
||||
_focus_func(false);
|
||||
}
|
||||
|
||||
while (!gProgramIsActive) {
|
||||
@@ -1381,7 +1457,7 @@ void _GNW95_lost_focus()
|
||||
}
|
||||
|
||||
if (_focus_func != NULL) {
|
||||
_focus_func(1);
|
||||
_focus_func(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1679,6 +1755,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
|
||||
@@ -4804,3 +4890,33 @@ 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);
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
25
src/core.h
@@ -1,12 +1,14 @@
|
||||
#ifndef CORE_H
|
||||
#define CORE_H
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "dinput.h"
|
||||
#include "geometry.h"
|
||||
#include "window.h"
|
||||
|
||||
#include <SDL.h>
|
||||
namespace fallout {
|
||||
|
||||
#define MOUSE_DEFAULT_CURSOR_WIDTH 8
|
||||
#define MOUSE_DEFAULT_CURSOR_HEIGHT 8
|
||||
@@ -26,6 +28,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
|
||||
|
||||
@@ -413,7 +416,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;
|
||||
@@ -460,8 +465,8 @@ 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;
|
||||
@@ -595,6 +600,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();
|
||||
@@ -682,5 +695,9 @@ 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);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CORE_H */
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "credits.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
@@ -16,7 +18,7 @@
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
#define CREDITS_WINDOW_WIDTH (640)
|
||||
#define CREDITS_WINDOW_HEIGHT (480)
|
||||
@@ -274,3 +276,5 @@ static bool creditsFileParseNextLine(char* dest, int* font, int* color)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#ifndef CREDITS_H
|
||||
#define CREDITS_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
void creditsOpen(const char* path, int fid, bool useReversedStyle);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CREDITS_H */
|
||||
|
||||
@@ -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,9 @@
|
||||
#include "stat.h"
|
||||
#include "tile.h"
|
||||
#include "trait.h"
|
||||
#include "world_map.h"
|
||||
#include "worldmap.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
// Maximum length of dude's name length.
|
||||
#define DUDE_NAME_MAX_LENGTH (32)
|
||||
@@ -68,6 +70,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 +162,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 +185,9 @@ int critterInit()
|
||||
void critterReset()
|
||||
{
|
||||
dudeResetName();
|
||||
memset(gKillsByType, 0, sizeof(gKillsByType));
|
||||
|
||||
// NOTE: Uninline;
|
||||
critter_kill_count_clear();
|
||||
}
|
||||
|
||||
// 0x42D004
|
||||
@@ -568,6 +574,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 +592,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 +613,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -669,6 +686,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)
|
||||
{
|
||||
@@ -873,7 +899,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);
|
||||
@@ -1279,7 +1305,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;
|
||||
}
|
||||
|
||||
@@ -1366,3 +1392,5 @@ bool _critter_flag_check(int pid, int flag)
|
||||
protoGetProto(pid, &proto);
|
||||
return (proto->critter.data.flags & flag) != 0;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "obj_types.h"
|
||||
#include "proto_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum DudeState {
|
||||
DUDE_STATE_SNEAKING = 0,
|
||||
DUDE_STATE_LEVEL_UP_AVAILABLE = 3,
|
||||
@@ -69,4 +71,6 @@ bool critterIsEncumbered(Object* critter);
|
||||
bool critterIsFleeing(Object* a1);
|
||||
bool _critter_flag_check(int pid, int flag);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CRITTER_H */
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "game_config.h"
|
||||
#include "palette.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define COLOR_CYCLE_PERIOD_1 (200U)
|
||||
#define COLOR_CYCLE_PERIOD_2 (142U)
|
||||
#define COLOR_CYCLE_PERIOD_3 (100U)
|
||||
@@ -332,3 +334,5 @@ void colorCycleTicker()
|
||||
paletteSetEntriesInRange(palette + 229 * 3, 229, 255);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef CYCLE_H
|
||||
#define CYCLE_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
void colorCycleInit();
|
||||
void colorCycleReset();
|
||||
void colorCycleFree();
|
||||
@@ -10,4 +12,6 @@ bool colorCycleEnabled();
|
||||
void cycleSetSpeedFactor(int value);
|
||||
void colorCycleTicker();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CYCLE_H */
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "pcx.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// 0x5184AC
|
||||
DatafileLoader* gDatafileLoader = NULL;
|
||||
|
||||
@@ -89,7 +91,7 @@ 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")) {
|
||||
if (compat_stricmp(dot + 1, "pcx") == 0) {
|
||||
return pcxRead(mangledPath, widthPtr, heightPtr, gDatafilePalette);
|
||||
}
|
||||
}
|
||||
@@ -193,3 +195,5 @@ unsigned char* datafileLoad(char* path, int* sizePtr)
|
||||
*sizePtr = size;
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef DATAFILE_H
|
||||
#define DATAFILE_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef unsigned char*(DatafileLoader)(char* path, unsigned char* palette, int* widthPtr, int* heightPtr);
|
||||
typedef char*(DatafileNameMangler)(char* path);
|
||||
|
||||
@@ -21,4 +23,6 @@ void sub_42F024(unsigned char* data, int* widthPtr, int* heightPtr);
|
||||
unsigned char* datafileGetPalette();
|
||||
unsigned char* datafileLoad(char* path, int* sizePtr);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DATAFILE_H */
|
||||
|
||||
28
src/db.cc
@@ -1,12 +1,14 @@
|
||||
#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"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef struct FileList {
|
||||
XList xlist;
|
||||
struct FileList* next;
|
||||
@@ -61,20 +63,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
|
||||
@@ -653,7 +657,7 @@ int fileNameListInit(const char* pattern, char*** fileNameListPtr, int a3, int a
|
||||
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++;
|
||||
}
|
||||
}
|
||||
@@ -736,3 +740,5 @@ int _db_list_compare(const void* p1, const void* p2)
|
||||
{
|
||||
return compat_stricmp(*(const char**)p1, *(const char**)p2);
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
11
src/db.h
@@ -1,18 +1,21 @@
|
||||
#ifndef DB_H
|
||||
#define DB_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "memory_defs.h"
|
||||
#include "xfile.h"
|
||||
|
||||
#include <stddef.h>
|
||||
namespace fallout {
|
||||
|
||||
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);
|
||||
@@ -65,4 +68,6 @@ int fileGetSize(File* stream);
|
||||
void fileSetReadProgressHandler(FileReadProgressHandler* handler, int size);
|
||||
void _db_enable_hash_table_();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DB_H */
|
||||
|
||||
378
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,10 +19,7 @@
|
||||
#include "window_manager.h"
|
||||
#include "word_wrap.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
namespace fallout {
|
||||
|
||||
#define FILE_DIALOG_LINE_COUNT 12
|
||||
|
||||
@@ -193,81 +195,67 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
: DIALOG_TYPE_MEDIUM;
|
||||
}
|
||||
|
||||
CacheEntry* backgroundHandle;
|
||||
int backgroundWidth;
|
||||
int backgroundHeight;
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, gDialogBoxBackgroundFrmIds[dialogType], 0, 0, 0);
|
||||
unsigned char* background = artLockFrameDataReturningSize(fid, &backgroundHandle, &backgroundWidth, &backgroundHeight);
|
||||
if (background == NULL) {
|
||||
FrmImage backgroundFrmImage;
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, gDialogBoxBackgroundFrmIds[dialogType], 0, 0, 0);
|
||||
if (!backgroundFrmImage.lock(backgroundFid)) {
|
||||
fontSetCurrent(savedFont);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Maintain original position in original resolution, otherwise center it.
|
||||
if (screenGetWidth() != 640) x = (screenGetWidth() - backgroundWidth) / 2;
|
||||
if (screenGetHeight() != 480) y = (screenGetHeight() - backgroundHeight) / 2;
|
||||
int win = windowCreate(x, y, backgroundWidth, backgroundHeight, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
|
||||
if (screenGetWidth() != 640) x = (screenGetWidth() - backgroundFrmImage.getWidth()) / 2;
|
||||
if (screenGetHeight() != 480) y = (screenGetHeight() - backgroundFrmImage.getHeight()) / 2;
|
||||
int win = windowCreate(x,
|
||||
y,
|
||||
backgroundFrmImage.getWidth(),
|
||||
backgroundFrmImage.getHeight(),
|
||||
256,
|
||||
WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
|
||||
if (win == -1) {
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char* windowBuf = windowGetBuffer(win);
|
||||
memcpy(windowBuf, background, backgroundWidth * backgroundHeight);
|
||||
memcpy(windowBuf, backgroundFrmImage.getData(), backgroundFrmImage.getWidth() * backgroundFrmImage.getHeight());
|
||||
|
||||
CacheEntry* doneBoxHandle = NULL;
|
||||
unsigned char* doneBox = NULL;
|
||||
int doneBoxWidth;
|
||||
int doneBoxHeight;
|
||||
|
||||
CacheEntry* downButtonHandle = NULL;
|
||||
unsigned char* downButton = NULL;
|
||||
int downButtonWidth;
|
||||
int downButtonHeight;
|
||||
|
||||
CacheEntry* upButtonHandle = NULL;
|
||||
unsigned char* upButton = NULL;
|
||||
FrmImage doneBoxFrmImage;
|
||||
FrmImage buttonNormalFrmImage;
|
||||
FrmImage buttonPressedFrmImage;
|
||||
|
||||
if ((flags & DIALOG_BOX_0x20) == 0) {
|
||||
int doneBoxFid = buildFid(OBJ_TYPE_INTERFACE, 209, 0, 0, 0);
|
||||
doneBox = artLockFrameDataReturningSize(doneBoxFid, &doneBoxHandle, &doneBoxWidth, &doneBoxHeight);
|
||||
if (doneBox == NULL) {
|
||||
artUnlock(backgroundHandle);
|
||||
if (!doneBoxFrmImage.lock(doneBoxFid)) {
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int downButtonFid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
downButton = artLockFrameDataReturningSize(downButtonFid, &downButtonHandle, &downButtonWidth, &downButtonHeight);
|
||||
if (downButton == NULL) {
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
int pressedFid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
if (!buttonPressedFrmImage.lock(pressedFid)) {
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int upButtonFid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
upButton = artLockFrameData(upButtonFid, 0, 0, &upButtonHandle);
|
||||
if (upButton == NULL) {
|
||||
artUnlock(downButtonHandle);
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
int normalFid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
if (!buttonNormalFrmImage.lock(normalFid)) {
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int v27 = hasTwoButtons ? _doneX[dialogType] : (backgroundWidth - doneBoxWidth) / 2;
|
||||
blitBufferToBuffer(doneBox, doneBoxWidth, doneBoxHeight, doneBoxWidth, windowBuf + backgroundWidth * _doneY[dialogType] + v27, backgroundWidth);
|
||||
int v27 = hasTwoButtons
|
||||
? _doneX[dialogType]
|
||||
: (backgroundFrmImage.getWidth() - doneBoxFrmImage.getWidth()) / 2;
|
||||
blitBufferToBuffer(doneBoxFrmImage.getData(),
|
||||
doneBoxFrmImage.getWidth(),
|
||||
doneBoxFrmImage.getHeight(),
|
||||
doneBoxFrmImage.getWidth(),
|
||||
windowBuf + backgroundFrmImage.getWidth() * _doneY[dialogType] + v27,
|
||||
backgroundFrmImage.getWidth());
|
||||
|
||||
if (!messageListInit(&messageList)) {
|
||||
artUnlock(upButtonHandle);
|
||||
artUnlock(downButtonHandle);
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
@@ -277,10 +265,6 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
sprintf(path, "%s%s", asc_5186C8, "DBOX.MSG");
|
||||
|
||||
if (!messageListLoad(&messageList, path)) {
|
||||
artUnlock(upButtonHandle);
|
||||
artUnlock(downButtonHandle);
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
// FIXME: Window is not removed.
|
||||
return -1;
|
||||
@@ -292,10 +276,26 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
// 101 - YES
|
||||
messageListItem.num = (flags & DIALOG_BOX_YES_NO) == 0 ? 100 : 101;
|
||||
if (messageListGetItem(&messageList, &messageListItem)) {
|
||||
fontDrawText(windowBuf + backgroundWidth * (_doneY[dialogType] + 3) + v27 + 35, messageListItem.text, backgroundWidth, backgroundWidth, _colorTable[18979]);
|
||||
fontDrawText(windowBuf + backgroundFrmImage.getWidth() * (_doneY[dialogType] + 3) + v27 + 35,
|
||||
messageListItem.text,
|
||||
backgroundFrmImage.getWidth(),
|
||||
backgroundFrmImage.getWidth(),
|
||||
_colorTable[18979]);
|
||||
}
|
||||
|
||||
int btn = buttonCreate(win, v27 + 13, _doneY[dialogType] + 4, downButtonWidth, downButtonHeight, -1, -1, -1, 500, upButton, downButton, NULL, BUTTON_FLAG_TRANSPARENT);
|
||||
int btn = buttonCreate(win,
|
||||
v27 + 13,
|
||||
_doneY[dialogType] + 4,
|
||||
buttonPressedFrmImage.getWidth(),
|
||||
buttonPressedFrmImage.getHeight(),
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
500,
|
||||
buttonNormalFrmImage.getData(),
|
||||
buttonPressedFrmImage.getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (btn != -1) {
|
||||
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
@@ -311,61 +311,58 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
|
||||
fontSetCurrent(103);
|
||||
|
||||
blitBufferToBufferTrans(doneBox,
|
||||
doneBoxWidth,
|
||||
doneBoxHeight,
|
||||
doneBoxWidth,
|
||||
windowBuf + backgroundWidth * _doneY[dialogType] + _doneX[dialogType] + doneBoxWidth + 24,
|
||||
backgroundWidth);
|
||||
blitBufferToBufferTrans(doneBoxFrmImage.getData(),
|
||||
doneBoxFrmImage.getWidth(),
|
||||
doneBoxFrmImage.getHeight(),
|
||||
doneBoxFrmImage.getWidth(),
|
||||
windowBuf + backgroundFrmImage.getWidth() * _doneY[dialogType] + _doneX[dialogType] + doneBoxFrmImage.getWidth() + 24,
|
||||
backgroundFrmImage.getWidth());
|
||||
|
||||
fontDrawText(windowBuf + backgroundWidth * (_doneY[dialogType] + 3) + _doneX[dialogType] + doneBoxWidth + 59,
|
||||
a8, backgroundWidth, backgroundWidth, _colorTable[18979]);
|
||||
fontDrawText(windowBuf + backgroundFrmImage.getWidth() * (_doneY[dialogType] + 3) + _doneX[dialogType] + doneBoxFrmImage.getWidth() + 59,
|
||||
a8,
|
||||
backgroundFrmImage.getWidth(),
|
||||
backgroundFrmImage.getWidth(),
|
||||
_colorTable[18979]);
|
||||
|
||||
int btn = buttonCreate(win,
|
||||
doneBoxWidth + _doneX[dialogType] + 37,
|
||||
doneBoxFrmImage.getWidth() + _doneX[dialogType] + 37,
|
||||
_doneY[dialogType] + 4,
|
||||
downButtonWidth,
|
||||
downButtonHeight,
|
||||
-1, -1, -1, 501, upButton, downButton, 0, BUTTON_FLAG_TRANSPARENT);
|
||||
buttonPressedFrmImage.getWidth(),
|
||||
buttonPressedFrmImage.getHeight(),
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
501,
|
||||
buttonNormalFrmImage.getData(),
|
||||
buttonPressedFrmImage.getData(),
|
||||
0,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (btn != -1) {
|
||||
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
} else {
|
||||
int doneBoxFid = buildFid(OBJ_TYPE_INTERFACE, 209, 0, 0, 0);
|
||||
unsigned char* doneBox = artLockFrameDataReturningSize(doneBoxFid, &doneBoxHandle, &doneBoxWidth, &doneBoxHeight);
|
||||
if (doneBox == NULL) {
|
||||
artUnlock(backgroundHandle);
|
||||
if (!doneBoxFrmImage.lock(doneBoxFid)) {
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int downButtonFid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
unsigned char* downButton = artLockFrameDataReturningSize(downButtonFid, &downButtonHandle, &downButtonWidth, &downButtonHeight);
|
||||
if (downButton == NULL) {
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
int pressedFid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
if (!buttonPressedFrmImage.lock(pressedFid)) {
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int upButtonFid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
unsigned char* upButton = artLockFrameData(upButtonFid, 0, 0, &upButtonHandle);
|
||||
if (upButton == NULL) {
|
||||
artUnlock(downButtonHandle);
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
int normalFid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
if (!buttonNormalFrmImage.lock(normalFid)) {
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!messageListInit(&messageList)) {
|
||||
artUnlock(upButtonHandle);
|
||||
artUnlock(downButtonHandle);
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
@@ -375,38 +372,34 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
sprintf(path, "%s%s", asc_5186C8, "DBOX.MSG");
|
||||
|
||||
if (!messageListLoad(&messageList, path)) {
|
||||
artUnlock(upButtonHandle);
|
||||
artUnlock(downButtonHandle);
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
blitBufferToBufferTrans(doneBox,
|
||||
doneBoxWidth,
|
||||
doneBoxHeight,
|
||||
doneBoxWidth,
|
||||
windowBuf + backgroundWidth * _doneY[dialogType] + _doneX[dialogType],
|
||||
backgroundWidth);
|
||||
blitBufferToBufferTrans(doneBoxFrmImage.getData(),
|
||||
doneBoxFrmImage.getWidth(),
|
||||
doneBoxFrmImage.getHeight(),
|
||||
doneBoxFrmImage.getWidth(),
|
||||
windowBuf + backgroundFrmImage.getWidth() * _doneY[dialogType] + _doneX[dialogType],
|
||||
backgroundFrmImage.getWidth());
|
||||
|
||||
fontSetCurrent(103);
|
||||
|
||||
fontDrawText(windowBuf + backgroundWidth * (_doneY[dialogType] + 3) + _doneX[dialogType] + 35,
|
||||
a8, backgroundWidth, backgroundWidth, _colorTable[18979]);
|
||||
fontDrawText(windowBuf + backgroundFrmImage.getWidth() * (_doneY[dialogType] + 3) + _doneX[dialogType] + 35,
|
||||
a8, backgroundFrmImage.getWidth(), backgroundFrmImage.getWidth(), _colorTable[18979]);
|
||||
|
||||
int btn = buttonCreate(win,
|
||||
_doneX[dialogType] + 13,
|
||||
_doneY[dialogType] + 4,
|
||||
downButtonWidth,
|
||||
downButtonHeight,
|
||||
buttonPressedFrmImage.getWidth(),
|
||||
buttonPressedFrmImage.getHeight(),
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
501,
|
||||
upButton,
|
||||
downButton,
|
||||
buttonNormalFrmImage.getData(),
|
||||
buttonPressedFrmImage.getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (btn != -1) {
|
||||
@@ -428,28 +421,44 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
|
||||
if (hasTitle) {
|
||||
if ((flags & DIALOG_BOX_NO_HORIZONTAL_CENTERING) != 0) {
|
||||
fontDrawText(windowBuf + backgroundWidth * v23 + _xtable[dialogType], title, backgroundWidth, backgroundWidth, titleColor);
|
||||
fontDrawText(windowBuf + backgroundFrmImage.getWidth() * v23 + _xtable[dialogType],
|
||||
title,
|
||||
backgroundFrmImage.getWidth(),
|
||||
backgroundFrmImage.getWidth(),
|
||||
titleColor);
|
||||
} else {
|
||||
int length = fontGetStringWidth(title);
|
||||
fontDrawText(windowBuf + backgroundWidth * v23 + (backgroundWidth - length) / 2, title, backgroundWidth, backgroundWidth, titleColor);
|
||||
fontDrawText(windowBuf + backgroundFrmImage.getWidth() * v23 + (backgroundFrmImage.getWidth() - length) / 2,
|
||||
title,
|
||||
backgroundFrmImage.getWidth(),
|
||||
backgroundFrmImage.getWidth(),
|
||||
titleColor);
|
||||
}
|
||||
v23 += fontGetLineHeight();
|
||||
}
|
||||
|
||||
for (int v94 = 0; v94 < bodyLength; v94++) {
|
||||
int len = fontGetStringWidth(body[v94]);
|
||||
if (len <= backgroundWidth - 26) {
|
||||
if (len <= backgroundFrmImage.getWidth() - 26) {
|
||||
if ((flags & DIALOG_BOX_NO_HORIZONTAL_CENTERING) != 0) {
|
||||
fontDrawText(windowBuf + backgroundWidth * v23 + _xtable[dialogType], body[v94], backgroundWidth, backgroundWidth, bodyColor);
|
||||
fontDrawText(windowBuf + backgroundFrmImage.getWidth() * v23 + _xtable[dialogType],
|
||||
body[v94],
|
||||
backgroundFrmImage.getWidth(),
|
||||
backgroundFrmImage.getWidth(),
|
||||
bodyColor);
|
||||
} else {
|
||||
int length = fontGetStringWidth(body[v94]);
|
||||
fontDrawText(windowBuf + backgroundWidth * v23 + (backgroundWidth - length) / 2, body[v94], backgroundWidth, backgroundWidth, bodyColor);
|
||||
fontDrawText(windowBuf + backgroundFrmImage.getWidth() * v23 + (backgroundFrmImage.getWidth() - length) / 2,
|
||||
body[v94],
|
||||
backgroundFrmImage.getWidth(),
|
||||
backgroundFrmImage.getWidth(),
|
||||
bodyColor);
|
||||
}
|
||||
v23 += fontGetLineHeight();
|
||||
} else {
|
||||
short beginnings[WORD_WRAP_MAX_COUNT];
|
||||
short count;
|
||||
if (wordWrap(body[v94], backgroundWidth - 26, beginnings, &count) != 0) {
|
||||
if (wordWrap(body[v94], backgroundFrmImage.getWidth() - 26, beginnings, &count) != 0) {
|
||||
debugPrint("\nError: dialog_out");
|
||||
}
|
||||
|
||||
@@ -464,10 +473,18 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
string[v51] = '\0';
|
||||
|
||||
if ((flags & DIALOG_BOX_NO_HORIZONTAL_CENTERING) != 0) {
|
||||
fontDrawText(windowBuf + backgroundWidth * v23 + _xtable[dialogType], string, backgroundWidth, backgroundWidth, bodyColor);
|
||||
fontDrawText(windowBuf + backgroundFrmImage.getWidth() * v23 + _xtable[dialogType],
|
||||
string,
|
||||
backgroundFrmImage.getWidth(),
|
||||
backgroundFrmImage.getWidth(),
|
||||
bodyColor);
|
||||
} else {
|
||||
int length = fontGetStringWidth(string);
|
||||
fontDrawText(windowBuf + backgroundWidth * v23 + (backgroundWidth - length) / 2, string, backgroundWidth, backgroundWidth, bodyColor);
|
||||
fontDrawText(windowBuf + backgroundFrmImage.getWidth() * v23 + (backgroundFrmImage.getWidth() - length) / 2,
|
||||
string,
|
||||
backgroundFrmImage.getWidth(),
|
||||
backgroundFrmImage.getWidth(),
|
||||
bodyColor);
|
||||
}
|
||||
v23 += fontGetLineHeight();
|
||||
}
|
||||
@@ -503,13 +520,9 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
}
|
||||
|
||||
windowDestroy(win);
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
|
||||
if (v86) {
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(downButtonHandle);
|
||||
artUnlock(upButtonHandle);
|
||||
messageListFree(&messageList);
|
||||
}
|
||||
|
||||
@@ -536,48 +549,34 @@ int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* frmBuffers[FILE_DIALOG_FRM_COUNT];
|
||||
CacheEntry* frmHandles[FILE_DIALOG_FRM_COUNT];
|
||||
Size frmSizes[FILE_DIALOG_FRM_COUNT];
|
||||
FrmImage frmImages[FILE_DIALOG_FRM_COUNT];
|
||||
|
||||
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
|
||||
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) {
|
||||
artUnlock(frmHandles[index]);
|
||||
}
|
||||
if (!frmImages[index].lock(fid)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int backgroundWidth = frmSizes[FILE_DIALOG_FRM_BACKGROUND].width;
|
||||
int backgroundHeight = frmSizes[FILE_DIALOG_FRM_BACKGROUND].height;
|
||||
int backgroundWidth = frmImages[FILE_DIALOG_FRM_BACKGROUND].getWidth();
|
||||
int backgroundHeight = frmImages[FILE_DIALOG_FRM_BACKGROUND].getHeight();
|
||||
|
||||
// Maintain original position in original resolution, otherwise center it.
|
||||
if (screenGetWidth() != 640) x = (screenGetWidth() - backgroundWidth) / 2;
|
||||
if (screenGetHeight() != 480) y = (screenGetHeight() - backgroundHeight) / 2;
|
||||
int win = windowCreate(x, y, backgroundWidth, backgroundHeight, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
|
||||
if (win == -1) {
|
||||
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
|
||||
artUnlock(frmHandles[index]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char* windowBuffer = windowGetBuffer(win);
|
||||
memcpy(windowBuffer, frmBuffers[FILE_DIALOG_FRM_BACKGROUND], backgroundWidth * backgroundHeight);
|
||||
memcpy(windowBuffer, frmImages[FILE_DIALOG_FRM_BACKGROUND].getData(), backgroundWidth * backgroundHeight);
|
||||
|
||||
MessageList messageList;
|
||||
MessageListItem messageListItem;
|
||||
|
||||
if (!messageListInit(&messageList)) {
|
||||
windowDestroy(win);
|
||||
|
||||
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
|
||||
artUnlock(frmHandles[index]);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -586,11 +585,6 @@ int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
|
||||
if (!messageListLoad(&messageList, path)) {
|
||||
windowDestroy(win);
|
||||
|
||||
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
|
||||
artUnlock(frmHandles[index]);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -607,14 +601,14 @@ int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
int doneBtn = buttonCreate(win,
|
||||
LOAD_FILE_DIALOG_DONE_BUTTON_X,
|
||||
LOAD_FILE_DIALOG_DONE_BUTTON_Y,
|
||||
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].width,
|
||||
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].height,
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].getWidth(),
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].getHeight(),
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
500,
|
||||
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL],
|
||||
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED],
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL].getData(),
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (doneBtn != -1) {
|
||||
@@ -624,14 +618,14 @@ int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
int cancelBtn = buttonCreate(win,
|
||||
LOAD_FILE_DIALOG_CANCEL_BUTTON_X,
|
||||
LOAD_FILE_DIALOG_CANCEL_BUTTON_Y,
|
||||
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].width,
|
||||
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].height,
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].getWidth(),
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].getHeight(),
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
501,
|
||||
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL],
|
||||
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED],
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL].getData(),
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (cancelBtn != -1) {
|
||||
@@ -641,14 +635,14 @@ int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
int scrollUpBtn = buttonCreate(win,
|
||||
FILE_DIALOG_SCROLL_BUTTON_X,
|
||||
FILE_DIALOG_SCROLL_BUTTON_Y,
|
||||
frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].width,
|
||||
frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].height,
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].getWidth(),
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].getHeight(),
|
||||
-1,
|
||||
505,
|
||||
506,
|
||||
505,
|
||||
frmBuffers[FILE_DIALOG_FRM_SCROLL_UP_ARROW_NORMAL],
|
||||
frmBuffers[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED],
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_UP_ARROW_NORMAL].getData(),
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (scrollUpBtn != -1) {
|
||||
@@ -657,15 +651,15 @@ int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
|
||||
int scrollDownButton = buttonCreate(win,
|
||||
FILE_DIALOG_SCROLL_BUTTON_X,
|
||||
FILE_DIALOG_SCROLL_BUTTON_Y + frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].height,
|
||||
frmSizes[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].width,
|
||||
frmSizes[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].height,
|
||||
FILE_DIALOG_SCROLL_BUTTON_Y + frmImages[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].getHeight(),
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].getWidth(),
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].getHeight(),
|
||||
-1,
|
||||
503,
|
||||
504,
|
||||
503,
|
||||
frmBuffers[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_NORMAL],
|
||||
frmBuffers[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED],
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_NORMAL].getData(),
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (scrollUpBtn != -1) {
|
||||
@@ -707,6 +701,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);
|
||||
@@ -886,10 +882,6 @@ int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
|
||||
windowDestroy(win);
|
||||
|
||||
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
|
||||
artUnlock(frmHandles[index]);
|
||||
}
|
||||
|
||||
messageListFree(&messageList);
|
||||
fontSetCurrent(oldFont);
|
||||
|
||||
@@ -916,48 +908,34 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* frmBuffers[FILE_DIALOG_FRM_COUNT];
|
||||
CacheEntry* frmHandles[FILE_DIALOG_FRM_COUNT];
|
||||
Size frmSizes[FILE_DIALOG_FRM_COUNT];
|
||||
FrmImage frmImages[FILE_DIALOG_FRM_COUNT];
|
||||
|
||||
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
|
||||
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) {
|
||||
artUnlock(frmHandles[index]);
|
||||
}
|
||||
if (!frmImages[index].lock(fid)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int backgroundWidth = frmSizes[FILE_DIALOG_FRM_BACKGROUND].width;
|
||||
int backgroundHeight = frmSizes[FILE_DIALOG_FRM_BACKGROUND].height;
|
||||
int backgroundWidth = frmImages[FILE_DIALOG_FRM_BACKGROUND].getWidth();
|
||||
int backgroundHeight = frmImages[FILE_DIALOG_FRM_BACKGROUND].getHeight();
|
||||
|
||||
// Maintain original position in original resolution, otherwise center it.
|
||||
if (screenGetWidth() != 640) x = (screenGetWidth() - backgroundWidth) / 2;
|
||||
if (screenGetHeight() != 480) y = (screenGetHeight() - backgroundHeight) / 2;
|
||||
int win = windowCreate(x, y, backgroundWidth, backgroundHeight, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
|
||||
if (win == -1) {
|
||||
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
|
||||
artUnlock(frmHandles[index]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char* windowBuffer = windowGetBuffer(win);
|
||||
memcpy(windowBuffer, frmBuffers[FILE_DIALOG_FRM_BACKGROUND], backgroundWidth * backgroundHeight);
|
||||
memcpy(windowBuffer, frmImages[FILE_DIALOG_FRM_BACKGROUND].getData(), backgroundWidth * backgroundHeight);
|
||||
|
||||
MessageList messageList;
|
||||
MessageListItem messageListItem;
|
||||
|
||||
if (!messageListInit(&messageList)) {
|
||||
windowDestroy(win);
|
||||
|
||||
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
|
||||
artUnlock(frmHandles[index]);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -966,11 +944,6 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
|
||||
if (!messageListLoad(&messageList, path)) {
|
||||
windowDestroy(win);
|
||||
|
||||
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
|
||||
artUnlock(frmHandles[index]);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -987,14 +960,14 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
int doneBtn = buttonCreate(win,
|
||||
SAVE_FILE_DIALOG_DONE_BUTTON_X,
|
||||
SAVE_FILE_DIALOG_DONE_BUTTON_Y,
|
||||
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].width,
|
||||
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].height,
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].getWidth(),
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].getHeight(),
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
500,
|
||||
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL],
|
||||
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED],
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL].getData(),
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (doneBtn != -1) {
|
||||
@@ -1004,14 +977,14 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
int cancelBtn = buttonCreate(win,
|
||||
SAVE_FILE_DIALOG_CANCEL_BUTTON_X,
|
||||
SAVE_FILE_DIALOG_CANCEL_BUTTON_Y,
|
||||
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].width,
|
||||
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].height,
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].getWidth(),
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].getHeight(),
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
501,
|
||||
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL],
|
||||
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED],
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL].getData(),
|
||||
frmImages[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (cancelBtn != -1) {
|
||||
@@ -1021,14 +994,14 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
int scrollUpBtn = buttonCreate(win,
|
||||
FILE_DIALOG_SCROLL_BUTTON_X,
|
||||
FILE_DIALOG_SCROLL_BUTTON_Y,
|
||||
frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].width,
|
||||
frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].height,
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].getWidth(),
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].getHeight(),
|
||||
-1,
|
||||
505,
|
||||
506,
|
||||
505,
|
||||
frmBuffers[FILE_DIALOG_FRM_SCROLL_UP_ARROW_NORMAL],
|
||||
frmBuffers[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED],
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_UP_ARROW_NORMAL].getData(),
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (scrollUpBtn != -1) {
|
||||
@@ -1037,15 +1010,15 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
|
||||
int scrollDownButton = buttonCreate(win,
|
||||
FILE_DIALOG_SCROLL_BUTTON_X,
|
||||
FILE_DIALOG_SCROLL_BUTTON_Y + frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].height,
|
||||
frmSizes[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].width,
|
||||
frmSizes[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].height,
|
||||
FILE_DIALOG_SCROLL_BUTTON_Y + frmImages[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].getHeight(),
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].getWidth(),
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].getHeight(),
|
||||
-1,
|
||||
503,
|
||||
504,
|
||||
503,
|
||||
frmBuffers[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_NORMAL],
|
||||
frmBuffers[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED],
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_NORMAL].getData(),
|
||||
frmImages[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (scrollUpBtn != -1) {
|
||||
@@ -1090,7 +1063,7 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
char fileNameCopy[32];
|
||||
strncpy(fileNameCopy, dest, 32);
|
||||
|
||||
int fileNameCopyLength = strlen(fileNameCopy);
|
||||
size_t fileNameCopyLength = strlen(fileNameCopy);
|
||||
fileNameCopy[fileNameCopyLength + 1] = '\0';
|
||||
fileNameCopy[fileNameCopyLength] = ' ';
|
||||
|
||||
@@ -1115,6 +1088,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) {
|
||||
@@ -1370,11 +1345,6 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
||||
}
|
||||
|
||||
windowDestroy(win);
|
||||
|
||||
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
|
||||
artUnlock(frmHandles[index]);
|
||||
}
|
||||
|
||||
messageListFree(&messageList);
|
||||
fontSetCurrent(oldFont);
|
||||
|
||||
@@ -1399,3 +1369,5 @@ static void fileDialogRenderFileList(unsigned char* buffer, char** fileList, int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef DBOX_H
|
||||
#define DBOX_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum DialogBoxOptions {
|
||||
DIALOG_BOX_LARGE = 0x01,
|
||||
DIALOG_BOX_MEDIUM = 0x02,
|
||||
@@ -14,4 +16,6 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLength, int x, int y, int flags);
|
||||
int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLength, int x, int y, int flags);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DBOX_H */
|
||||
|
||||
103
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,19 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
#include "window_manager_private.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
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 +177,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 +244,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
|
||||
@@ -238,3 +319,5 @@ void _debug_exit(void)
|
||||
fclose(_fd);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef int(DebugPrintProc)(char* string);
|
||||
|
||||
void _GNW_debug_init();
|
||||
@@ -12,4 +14,6 @@ void _debug_register_func(DebugPrintProc* proc);
|
||||
int debugPrint(const char* format, ...);
|
||||
void _debug_exit(void);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DEBUG_H */
|
||||
|
||||
16
src/dfile.cc
@@ -1,14 +1,16 @@
|
||||
#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"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// The size of decompression buffer for reading compressed [DFile]s.
|
||||
#define DFILE_DECOMPRESSION_BUFFER_SIZE (0x400)
|
||||
|
||||
@@ -61,7 +63,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 +143,7 @@ DBase* dbaseOpen(const char* filePath)
|
||||
goto err;
|
||||
}
|
||||
|
||||
dbase->path = strdup(filePath);
|
||||
dbase->path = compat_strdup(filePath);
|
||||
dbase->dataOffset = fileSize - dbaseDataSize;
|
||||
|
||||
fclose(stream);
|
||||
@@ -852,3 +854,5 @@ static void dfileUngetCompressed(DFile* stream, int ch)
|
||||
stream->flags |= DFILE_HAS_COMPRESSED_UNGETC;
|
||||
stream->position--;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
#ifndef DFILE_H
|
||||
#define DFILE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include "platform_compat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <zlib.h>
|
||||
namespace fallout {
|
||||
|
||||
typedef struct DBase DBase;
|
||||
typedef struct DBaseEntry DBaseEntry;
|
||||
@@ -127,4 +130,6 @@ long dfileTell(DFile* stream);
|
||||
void dfileRewind(DFile* stream);
|
||||
int dfileEof(DFile* stream);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DFILE_H */
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#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>
|
||||
namespace fallout {
|
||||
|
||||
// 0x501623
|
||||
const float flt_501623 = 31.0;
|
||||
@@ -209,7 +210,7 @@ void _replyAddOption(const char* a1, const char* a2, int a3)
|
||||
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;
|
||||
}
|
||||
@@ -236,7 +237,7 @@ void _replyAddOptionProc(const char* a1, int a2, int a3)
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -388,8 +389,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 +399,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
|
||||
@@ -751,3 +752,5 @@ int _dialogGetMediaFlag()
|
||||
{
|
||||
return _mediaFlag;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "interpreter.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef void DialogFunc1(int win);
|
||||
typedef void DialogFunc2(int win);
|
||||
|
||||
@@ -131,4 +133,6 @@ void _dialogRegisterWinDrawCallbacks(DialogFunc1* a1, DialogFunc2* a2);
|
||||
int _dialogToggleMediaFlag(int a1);
|
||||
int _dialogGetMediaFlag();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DIALOG_H */
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#include "dictionary.h"
|
||||
|
||||
#include "platform_compat.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "platform_compat.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// 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.
|
||||
@@ -552,3 +554,5 @@ void dictionarySetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc,
|
||||
gDictionaryFreeProc = dictionaryFreeDefaultImpl;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#ifndef DICTIONARY_H
|
||||
#define DICTIONARY_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "memory_defs.h"
|
||||
|
||||
#include <stdio.h>
|
||||
namespace fallout {
|
||||
|
||||
typedef int(DictionaryReadProc)(FILE* stream, void* buffer, unsigned int size, int a4);
|
||||
typedef int(DictionaryWriteProc)(FILE* stream, void* buffer, unsigned int size, int a4);
|
||||
@@ -63,4 +65,6 @@ int dictionaryWriteHeader(FILE* stream, Dictionary* dictionary);
|
||||
int dictionaryWrite(FILE* stream, Dictionary* dictionary, int a3);
|
||||
void dictionarySetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DICTIONARY_H */
|
||||
|
||||
135
src/dinput.cc
@@ -1,5 +1,14 @@
|
||||
#include "dinput.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
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;
|
||||
@@ -11,6 +20,9 @@ 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();
|
||||
|
||||
@@ -59,42 +71,49 @@ bool mouseDeviceUnacquire()
|
||||
// 0x4E053C
|
||||
bool mouseDeviceGetData(MouseData* mouseState)
|
||||
{
|
||||
#if __ANDROID__
|
||||
mouseState->x = gTouchMouseDeltaX;
|
||||
mouseState->y = gTouchMouseDeltaY;
|
||||
mouseState->buttons[0] = 0;
|
||||
mouseState->buttons[1] = 0;
|
||||
gTouchMouseDeltaX = 0;
|
||||
gTouchMouseDeltaY = 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) {
|
||||
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 == 3) {
|
||||
} else if (gTouchGestureTaps == 2) {
|
||||
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;
|
||||
}
|
||||
#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;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -146,43 +165,79 @@ void keyboardDeviceFree()
|
||||
{
|
||||
}
|
||||
|
||||
void handleTouchFingerEvent(SDL_TouchFingerEvent* event)
|
||||
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->type == SDL_FINGERDOWN) {
|
||||
if (event->tfinger.type == SDL_FINGERDOWN) {
|
||||
gTouchFingers++;
|
||||
|
||||
gTouchMouseLastX = (int)(event->x * windowWidth);
|
||||
gTouchMouseLastY = (int)(event->y * windowHeight);
|
||||
gTouchMouseLastX = (int)(event->tfinger.x * windowWidth);
|
||||
gTouchMouseLastY = (int)(event->tfinger.y * windowHeight);
|
||||
gTouchMouseDeltaX = 0;
|
||||
gTouchMouseDeltaY = 0;
|
||||
|
||||
if (event->timestamp - gTouchGestureLastTouchDownTimestamp > 250) {
|
||||
if (event->tfinger.timestamp - gTouchGestureLastTouchDownTimestamp > 250) {
|
||||
gTouchGestureTaps = 0;
|
||||
gTouchGestureHandled = false;
|
||||
}
|
||||
|
||||
gTouchGestureLastTouchDownTimestamp = event->timestamp;
|
||||
} else if (event->type == SDL_FINGERMOTION) {
|
||||
gTouchGestureLastTouchDownTimestamp = event->tfinger.timestamp;
|
||||
} else if (event->tfinger.type == SDL_FINGERMOTION) {
|
||||
int prevX = gTouchMouseLastX;
|
||||
int prevY = gTouchMouseLastY;
|
||||
gTouchMouseLastX = (int)(event->x * windowWidth);
|
||||
gTouchMouseLastY = (int)(event->y * windowHeight);
|
||||
gTouchMouseLastX = (int)(event->tfinger.x * windowWidth);
|
||||
gTouchMouseLastY = (int)(event->tfinger.y * windowHeight);
|
||||
gTouchMouseDeltaX += gTouchMouseLastX - prevX;
|
||||
gTouchMouseDeltaY += gTouchMouseLastY - prevY;
|
||||
} else if (event->type == SDL_FINGERUP) {
|
||||
} else if (event->tfinger.type == SDL_FINGERUP) {
|
||||
gTouchFingers--;
|
||||
|
||||
int prevX = gTouchMouseLastX;
|
||||
int prevY = gTouchMouseLastY;
|
||||
gTouchMouseLastX = (int)(event->x * windowWidth);
|
||||
gTouchMouseLastY = (int)(event->y * windowHeight);
|
||||
gTouchMouseLastX = (int)(event->tfinger.x * windowWidth);
|
||||
gTouchMouseLastY = (int)(event->tfinger.y * windowHeight);
|
||||
gTouchMouseDeltaX += gTouchMouseLastX - prevX;
|
||||
gTouchMouseDeltaY += gTouchMouseLastY - prevY;
|
||||
|
||||
gTouchGestureTaps++;
|
||||
gTouchGestureLastTouchUpTimestamp = event->timestamp;
|
||||
gTouchGestureLastTouchUpTimestamp = event->tfinger.timestamp;
|
||||
}
|
||||
|
||||
if (gLastInputType != INPUT_TYPE_TOUCH) {
|
||||
// Reset mouse data.
|
||||
SDL_GetRelativeMouseState(NULL, NULL);
|
||||
|
||||
gLastInputType = INPUT_TYPE_TOUCH;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -3,10 +3,14 @@
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef struct MouseData {
|
||||
int x;
|
||||
int y;
|
||||
unsigned char buttons[2];
|
||||
int wheelX;
|
||||
int wheelY;
|
||||
} MouseData;
|
||||
|
||||
typedef struct KeyboardData {
|
||||
@@ -28,6 +32,9 @@ void mouseDeviceFree();
|
||||
bool keyboardDeviceInit();
|
||||
void keyboardDeviceFree();
|
||||
|
||||
void handleTouchFingerEvent(SDL_TouchFingerEvent* event);
|
||||
void handleMouseEvent(SDL_Event* event);
|
||||
void handleTouchEvent(SDL_Event* event);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#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,10 +14,11 @@
|
||||
#include "geometry.h"
|
||||
#include "interface.h"
|
||||
#include "memory.h"
|
||||
#include "sfall_config.h"
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
// The maximum number of lines display monitor can hold. Once this value
|
||||
// is reached earlier messages are thrown away.
|
||||
@@ -33,6 +38,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 +46,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 +98,9 @@ static int _disp_start;
|
||||
// 0x56FB58
|
||||
static unsigned int gDisplayMonitorLastBeepTimestamp;
|
||||
|
||||
static std::ofstream gConsoleFileStream;
|
||||
static int gConsoleFilePrintCount = 0;
|
||||
|
||||
// 0x431610
|
||||
int displayMonitorInit()
|
||||
{
|
||||
@@ -168,14 +183,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 +196,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 +209,9 @@ int displayMonitorReset()
|
||||
void displayMonitorExit()
|
||||
{
|
||||
if (gDisplayMonitorInitialized) {
|
||||
// SFALL
|
||||
consoleFileExit();
|
||||
|
||||
internal_free(gDisplayMonitorBackgroundFrmData);
|
||||
gDisplayMonitorInitialized = false;
|
||||
}
|
||||
@@ -212,6 +224,9 @@ void displayMonitorAddMessage(char* str)
|
||||
return;
|
||||
}
|
||||
|
||||
// SFALL
|
||||
consoleFileAddMessage(str);
|
||||
|
||||
int oldFont = fontGetCurrent();
|
||||
fontSetCurrent(DISPLAY_MONITOR_FONT);
|
||||
|
||||
@@ -295,6 +310,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 +422,53 @@ 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();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef DISPLAY_MONITOR_H
|
||||
#define DISPLAY_MONITOR_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
int displayMonitorInit();
|
||||
int displayMonitorReset();
|
||||
void displayMonitorExit();
|
||||
@@ -8,4 +10,6 @@ void displayMonitorAddMessage(char* string);
|
||||
void displayMonitorDisable();
|
||||
void displayMonitorEnable();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DISPLAY_MONITOR_H */
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#include "draw.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
#include "mmx.h"
|
||||
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
// 0x4D2FC0
|
||||
void bufferDrawLine(unsigned char* buf, int pitch, int x1, int y1, int x2, int y2, int color)
|
||||
@@ -326,3 +328,5 @@ void bufferOutline(unsigned char* buf, int width, int height, int pitch, int col
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef DRAW_H
|
||||
#define DRAW_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
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);
|
||||
@@ -14,4 +16,6 @@ void _lighten_buf(unsigned char* buf, int width, int height, int pitch);
|
||||
void _swap_color_buf(unsigned char* buf, int width, int height, int pitch, int color1, int color2);
|
||||
void bufferOutline(unsigned char* buf, int width, int height, int pitch, int a5);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DRAW_H */
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
#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"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// 0x440DD0
|
||||
void runElectronicRegistration()
|
||||
{
|
||||
@@ -45,3 +47,5 @@ void runElectronicRegistration()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#ifndef ELECTRONIC_REGISTRATION_H
|
||||
#define ELECTRONIC_REGISTRATION_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
void runElectronicRegistration();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* ELECTRONIC_REGISTRATION_H */
|
||||
|
||||
234
src/elevator.cc
@@ -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,19 +17,17 @@
|
||||
#include "map.h"
|
||||
#include "pipboy.h"
|
||||
#include "scripts.h"
|
||||
#include "sfall_config.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
// The maximum number of elevator levels.
|
||||
#define ELEVATOR_LEVEL_MAX (4)
|
||||
|
||||
// NOTE: There are two variables which hold background data used in the
|
||||
// elevator window - [gElevatorBackgroundFrmData] and [gElevatorPanelFrmData].
|
||||
// For unknown reason they are using -1 to denote that they are not set
|
||||
// (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,
|
||||
@@ -56,7 +59,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 +89,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 +117,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 +267,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' },
|
||||
@@ -313,57 +316,29 @@ static const char* gElevatorSoundEffects[ELEVATOR_LEVEL_MAX - 1][ELEVATOR_LEVEL_
|
||||
},
|
||||
};
|
||||
|
||||
// 0x570A2C
|
||||
static Size gElevatorFrmSizes[ELEVATOR_FRM_COUNT];
|
||||
|
||||
// 0x570A44
|
||||
static int gElevatorBackgroundFrmWidth;
|
||||
|
||||
// 0x570A48
|
||||
static int gElevatorBackgroundFrmHeight;
|
||||
|
||||
// 0x570A4C
|
||||
static int gElevatorPanelFrmWidth;
|
||||
|
||||
// 0x570A50
|
||||
static int gElevatorPanelFrmHeight;
|
||||
|
||||
// 0x570A54
|
||||
static int gElevatorWindow;
|
||||
|
||||
// 0x570A58
|
||||
static CacheEntry* gElevatorFrmHandles[ELEVATOR_FRM_COUNT];
|
||||
|
||||
// 0x570A64
|
||||
static CacheEntry* gElevatorBackgroundFrmHandle;
|
||||
|
||||
// 0x570A68
|
||||
static CacheEntry* gElevatorPanelFrmHandle;
|
||||
|
||||
// 0x570A6C
|
||||
static unsigned char* gElevatorWindowBuffer;
|
||||
|
||||
// 0x570A70
|
||||
static bool gElevatorWindowIsoWasEnabled;
|
||||
|
||||
// 0x570A74
|
||||
static unsigned char* gElevatorFrmData[ELEVATOR_FRM_COUNT];
|
||||
|
||||
// 0x570A80
|
||||
static unsigned char* gElevatorBackgroundFrmData;
|
||||
|
||||
// 0x570A84
|
||||
static unsigned char* gElevatorPanelFrmData;
|
||||
static FrmImage _elevatorFrmImages[ELEVATOR_FRM_COUNT];
|
||||
static FrmImage _elevatorBackgroundFrmImage;
|
||||
static FrmImage _elevatorPanelFrmImage;
|
||||
|
||||
// Presents elevator dialog for player to pick a desired level.
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
@@ -403,15 +378,15 @@ int elevatorSelectLevel(int elevator, int* mapPtr, int* elevationPtr, int* tileP
|
||||
|
||||
debugPrint("\n the start elev level %d\n", *elevationPtr);
|
||||
|
||||
int v18 = (gElevatorFrmSizes[ELEVATOR_FRM_GAUGE].width * gElevatorFrmSizes[ELEVATOR_FRM_GAUGE].height) / 13;
|
||||
int v18 = (_elevatorFrmImages[ELEVATOR_FRM_GAUGE].getWidth() * _elevatorFrmImages[ELEVATOR_FRM_GAUGE].getHeight()) / 13;
|
||||
float v42 = 12.0f / (float)(gElevatorLevels[elevator] - 1);
|
||||
blitBufferToBuffer(
|
||||
gElevatorFrmData[ELEVATOR_FRM_GAUGE] + v18 * (int)((float)(*elevationPtr) * v42),
|
||||
gElevatorFrmSizes[ELEVATOR_FRM_GAUGE].width,
|
||||
gElevatorFrmSizes[ELEVATOR_FRM_GAUGE].height / 13,
|
||||
gElevatorFrmSizes[ELEVATOR_FRM_GAUGE].width,
|
||||
gElevatorWindowBuffer + gElevatorBackgroundFrmWidth * 41 + 121,
|
||||
gElevatorBackgroundFrmWidth);
|
||||
_elevatorFrmImages[ELEVATOR_FRM_GAUGE].getData() + v18 * (int)((float)(*elevationPtr) * v42),
|
||||
_elevatorFrmImages[ELEVATOR_FRM_GAUGE].getWidth(),
|
||||
_elevatorFrmImages[ELEVATOR_FRM_GAUGE].getHeight() / 13,
|
||||
_elevatorFrmImages[ELEVATOR_FRM_GAUGE].getWidth(),
|
||||
gElevatorWindowBuffer + _elevatorBackgroundFrmImage.getWidth() * 41 + 121,
|
||||
_elevatorBackgroundFrmImage.getWidth());
|
||||
windowRefresh(gElevatorWindow);
|
||||
|
||||
bool done = false;
|
||||
@@ -460,12 +435,12 @@ int elevatorSelectLevel(int elevator, int* mapPtr, int* elevationPtr, int* tileP
|
||||
unsigned int tick = _get_time();
|
||||
v44 += v43;
|
||||
blitBufferToBuffer(
|
||||
gElevatorFrmData[ELEVATOR_FRM_GAUGE] + v18 * (int)v44,
|
||||
gElevatorFrmSizes[ELEVATOR_FRM_GAUGE].width,
|
||||
gElevatorFrmSizes[ELEVATOR_FRM_GAUGE].height / 13,
|
||||
gElevatorFrmSizes[ELEVATOR_FRM_GAUGE].width,
|
||||
gElevatorWindowBuffer + gElevatorBackgroundFrmWidth * 41 + 121,
|
||||
gElevatorBackgroundFrmWidth);
|
||||
_elevatorFrmImages[ELEVATOR_FRM_GAUGE].getData() + v18 * (int)v44,
|
||||
_elevatorFrmImages[ELEVATOR_FRM_GAUGE].getWidth(),
|
||||
_elevatorFrmImages[ELEVATOR_FRM_GAUGE].getHeight() / 13,
|
||||
_elevatorFrmImages[ELEVATOR_FRM_GAUGE].getWidth(),
|
||||
gElevatorWindowBuffer + _elevatorBackgroundFrmImage.getWidth() * 41 + 121,
|
||||
_elevatorBackgroundFrmImage.getWidth());
|
||||
|
||||
windowRefresh(gElevatorWindow);
|
||||
|
||||
@@ -504,15 +479,14 @@ static int elevatorWindowInit(int elevator)
|
||||
int index;
|
||||
for (index = 0; index < ELEVATOR_FRM_COUNT; index++) {
|
||||
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) {
|
||||
if (!_elevatorFrmImages[index].lock(fid)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index != ELEVATOR_FRM_COUNT) {
|
||||
for (int reversedIndex = index - 1; reversedIndex >= 0; reversedIndex--) {
|
||||
artUnlock(gElevatorFrmHandles[reversedIndex]);
|
||||
_elevatorFrmImages[reversedIndex].unlock();
|
||||
}
|
||||
|
||||
if (gElevatorWindowIsoWasEnabled) {
|
||||
@@ -524,39 +498,27 @@ static int elevatorWindowInit(int elevator)
|
||||
return -1;
|
||||
}
|
||||
|
||||
gElevatorPanelFrmData = ELEVATOR_BACKGROUND_NULL;
|
||||
gElevatorBackgroundFrmData = ELEVATOR_BACKGROUND_NULL;
|
||||
|
||||
const ElevatorBackground* elevatorBackground = &(gElevatorBackgrounds[elevator]);
|
||||
bool backgroundsLoaded = true;
|
||||
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, elevatorBackground->backgroundFrmId, 0, 0, 0);
|
||||
gElevatorBackgroundFrmData = artLockFrameDataReturningSize(backgroundFid, &gElevatorBackgroundFrmHandle, &gElevatorBackgroundFrmWidth, &gElevatorBackgroundFrmHeight);
|
||||
if (gElevatorBackgroundFrmData != NULL) {
|
||||
if (_elevatorBackgroundFrmImage.lock(backgroundFid)) {
|
||||
if (elevatorBackground->panelFrmId != -1) {
|
||||
int panelFid = buildFid(OBJ_TYPE_INTERFACE, elevatorBackground->panelFrmId, 0, 0, 0);
|
||||
gElevatorPanelFrmData = artLockFrameDataReturningSize(panelFid, &gElevatorPanelFrmHandle, &gElevatorPanelFrmWidth, &gElevatorPanelFrmHeight);
|
||||
if (gElevatorPanelFrmData == NULL) {
|
||||
gElevatorPanelFrmData = ELEVATOR_BACKGROUND_NULL;
|
||||
if (!_elevatorPanelFrmImage.lock(panelFid)) {
|
||||
backgroundsLoaded = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gElevatorBackgroundFrmData = ELEVATOR_BACKGROUND_NULL;
|
||||
backgroundsLoaded = false;
|
||||
}
|
||||
|
||||
if (!backgroundsLoaded) {
|
||||
if (gElevatorBackgroundFrmData != ELEVATOR_BACKGROUND_NULL) {
|
||||
artUnlock(gElevatorBackgroundFrmHandle);
|
||||
}
|
||||
|
||||
if (gElevatorPanelFrmData != ELEVATOR_BACKGROUND_NULL) {
|
||||
artUnlock(gElevatorPanelFrmHandle);
|
||||
}
|
||||
_elevatorBackgroundFrmImage.unlock();
|
||||
_elevatorPanelFrmImage.unlock();
|
||||
|
||||
for (int index = 0; index < ELEVATOR_FRM_COUNT; index++) {
|
||||
artUnlock(gElevatorFrmHandles[index]);
|
||||
_elevatorFrmImages[index].unlock();
|
||||
}
|
||||
|
||||
if (gElevatorWindowIsoWasEnabled) {
|
||||
@@ -568,26 +530,21 @@ static int elevatorWindowInit(int elevator)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int elevatorWindowX = (screenGetWidth() - gElevatorBackgroundFrmWidth) / 2;
|
||||
int elevatorWindowY = (screenGetHeight() - INTERFACE_BAR_HEIGHT - 1 - gElevatorBackgroundFrmHeight) / 2;
|
||||
int elevatorWindowX = (screenGetWidth() - _elevatorBackgroundFrmImage.getWidth()) / 2;
|
||||
int elevatorWindowY = (screenGetHeight() - INTERFACE_BAR_HEIGHT - 1 - _elevatorBackgroundFrmImage.getHeight()) / 2;
|
||||
gElevatorWindow = windowCreate(
|
||||
elevatorWindowX,
|
||||
elevatorWindowY,
|
||||
gElevatorBackgroundFrmWidth,
|
||||
gElevatorBackgroundFrmHeight,
|
||||
_elevatorBackgroundFrmImage.getWidth(),
|
||||
_elevatorBackgroundFrmImage.getHeight(),
|
||||
256,
|
||||
WINDOW_FLAG_0x10 | WINDOW_FLAG_0x02);
|
||||
if (gElevatorWindow == -1) {
|
||||
if (gElevatorBackgroundFrmData != ELEVATOR_BACKGROUND_NULL) {
|
||||
artUnlock(gElevatorBackgroundFrmHandle);
|
||||
}
|
||||
|
||||
if (gElevatorPanelFrmData != ELEVATOR_BACKGROUND_NULL) {
|
||||
artUnlock(gElevatorPanelFrmHandle);
|
||||
}
|
||||
_elevatorBackgroundFrmImage.unlock();
|
||||
_elevatorPanelFrmImage.unlock();
|
||||
|
||||
for (int index = 0; index < ELEVATOR_FRM_COUNT; index++) {
|
||||
artUnlock(gElevatorFrmHandles[index]);
|
||||
_elevatorFrmImages[index].unlock();
|
||||
}
|
||||
|
||||
if (gElevatorWindowIsoWasEnabled) {
|
||||
@@ -600,15 +557,15 @@ static int elevatorWindowInit(int elevator)
|
||||
}
|
||||
|
||||
gElevatorWindowBuffer = windowGetBuffer(gElevatorWindow);
|
||||
memcpy(gElevatorWindowBuffer, (unsigned char*)gElevatorBackgroundFrmData, gElevatorBackgroundFrmWidth * gElevatorBackgroundFrmHeight);
|
||||
memcpy(gElevatorWindowBuffer, _elevatorBackgroundFrmImage.getData(), _elevatorBackgroundFrmImage.getWidth() * _elevatorBackgroundFrmImage.getHeight());
|
||||
|
||||
if (gElevatorPanelFrmData != ELEVATOR_BACKGROUND_NULL) {
|
||||
blitBufferToBuffer((unsigned char*)gElevatorPanelFrmData,
|
||||
gElevatorPanelFrmWidth,
|
||||
gElevatorPanelFrmHeight,
|
||||
gElevatorPanelFrmWidth,
|
||||
gElevatorWindowBuffer + gElevatorBackgroundFrmWidth * (gElevatorBackgroundFrmHeight - gElevatorPanelFrmHeight),
|
||||
gElevatorBackgroundFrmWidth);
|
||||
if (_elevatorPanelFrmImage.isLocked()) {
|
||||
blitBufferToBuffer(_elevatorPanelFrmImage.getData(),
|
||||
_elevatorPanelFrmImage.getWidth(),
|
||||
_elevatorPanelFrmImage.getHeight(),
|
||||
_elevatorPanelFrmImage.getWidth(),
|
||||
gElevatorWindowBuffer + _elevatorBackgroundFrmImage.getWidth() * (_elevatorBackgroundFrmImage.getHeight() - _elevatorPanelFrmImage.getHeight()),
|
||||
_elevatorBackgroundFrmImage.getWidth());
|
||||
}
|
||||
|
||||
int y = 40;
|
||||
@@ -616,14 +573,14 @@ static int elevatorWindowInit(int elevator)
|
||||
int btn = buttonCreate(gElevatorWindow,
|
||||
13,
|
||||
y,
|
||||
gElevatorFrmSizes[ELEVATOR_FRM_BUTTON_DOWN].width,
|
||||
gElevatorFrmSizes[ELEVATOR_FRM_BUTTON_DOWN].height,
|
||||
_elevatorFrmImages[ELEVATOR_FRM_BUTTON_DOWN].getWidth(),
|
||||
_elevatorFrmImages[ELEVATOR_FRM_BUTTON_DOWN].getHeight(),
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
500 + level,
|
||||
gElevatorFrmData[ELEVATOR_FRM_BUTTON_UP],
|
||||
gElevatorFrmData[ELEVATOR_FRM_BUTTON_DOWN],
|
||||
_elevatorFrmImages[ELEVATOR_FRM_BUTTON_UP].getData(),
|
||||
_elevatorFrmImages[ELEVATOR_FRM_BUTTON_DOWN].getData(),
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (btn != -1) {
|
||||
@@ -640,16 +597,11 @@ static void elevatorWindowFree()
|
||||
{
|
||||
windowDestroy(gElevatorWindow);
|
||||
|
||||
if (gElevatorBackgroundFrmData != ELEVATOR_BACKGROUND_NULL) {
|
||||
artUnlock(gElevatorBackgroundFrmHandle);
|
||||
}
|
||||
|
||||
if (gElevatorPanelFrmData != ELEVATOR_BACKGROUND_NULL) {
|
||||
artUnlock(gElevatorPanelFrmHandle);
|
||||
}
|
||||
_elevatorBackgroundFrmImage.unlock();
|
||||
_elevatorPanelFrmImage.unlock();
|
||||
|
||||
for (int index = 0; index < ELEVATOR_FRM_COUNT; index++) {
|
||||
artUnlock(gElevatorFrmHandles[index]);
|
||||
_elevatorFrmImages[index].unlock();
|
||||
}
|
||||
|
||||
scriptsEnable();
|
||||
@@ -681,3 +633,67 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef ELEVATOR_H
|
||||
#define ELEVATOR_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum Elevator {
|
||||
ELEVATOR_BROTHERHOOD_OF_STEEL_MAIN,
|
||||
ELEVATOR_BROTHERHOOD_OF_STEEL_SURFACE,
|
||||
@@ -20,4 +22,8 @@ typedef enum Elevator {
|
||||
|
||||
int elevatorSelectLevel(int elevator, int* mapPtr, int* elevationPtr, int* tilePtr);
|
||||
|
||||
void elevatorsInit();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#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,9 @@
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
#include "word_wrap.h"
|
||||
#include "world_map.h"
|
||||
#include "worldmap.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
// The maximum number of subtitle lines per slide.
|
||||
#define ENDGAME_ENDING_MAX_SUBTITLES (50)
|
||||
@@ -661,7 +663,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);
|
||||
@@ -758,7 +760,7 @@ static int endgameEndingSubtitlesLoad(const char* filePath)
|
||||
if (gEndgameEndingSubtitlesLength < ENDGAME_ENDING_MAX_SUBTITLES) {
|
||||
gEndgameEndingSubtitles[gEndgameEndingSubtitlesLength] = internal_strdup(pch + 1);
|
||||
gEndgameEndingSubtitlesLength++;
|
||||
gEndgameEndingSubtitlesCharactersCount += strlen(pch + 1);
|
||||
gEndgameEndingSubtitlesCharactersCount += static_cast<int>(strlen(pch + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -861,7 +863,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);
|
||||
@@ -913,9 +915,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);
|
||||
@@ -971,7 +973,7 @@ int endgameDeathEndingInit()
|
||||
char* tok;
|
||||
EndgameDeathEnding entry;
|
||||
EndgameDeathEnding* entries;
|
||||
int narrator_file_len;
|
||||
size_t narratorFileNameLength;
|
||||
|
||||
strcpy(gEndgameDeathEndingFileName, "narrator\\nar_5");
|
||||
|
||||
@@ -1038,13 +1040,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));
|
||||
@@ -1158,13 +1160,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;
|
||||
}
|
||||
}
|
||||
@@ -1197,3 +1199,5 @@ char* endgameDeathEndingGetFileName()
|
||||
|
||||
return gEndgameDeathEndingFileName;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef ENDGAME_H
|
||||
#define ENDGAME_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum EndgameDeathEndingReason {
|
||||
// Dude died.
|
||||
ENDGAME_DEATH_ENDING_REASON_DEATH = 0,
|
||||
@@ -18,4 +20,6 @@ int endgameDeathEndingExit();
|
||||
void endgameSetupDeathEnding(int reason);
|
||||
char* endgameDeathEndingGetFileName();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* ENDGAME_H */
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#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>
|
||||
namespace fallout {
|
||||
|
||||
typedef struct ExternalVariable {
|
||||
char name[32];
|
||||
@@ -343,3 +345,5 @@ void _exportClearAllVariables()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "interpreter.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
int externalVariableSetValue(Program* program, const char* identifier, ProgramValue& value);
|
||||
int externalVariableGetValue(Program* program, const char* name, ProgramValue& value);
|
||||
int externalVariableCreate(Program* program, const char* identifier);
|
||||
@@ -12,4 +14,6 @@ Program* externalProcedureGetProgram(const char* identifier, int* addressPtr, in
|
||||
int externalProcedureCreate(Program* program, const char* identifier, int address, int argumentCount);
|
||||
void _exportClearAllVariables();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* EXPORT_H */
|
||||
|
||||