Initial commit
This commit is contained in:
commit
55661742a2
|
@ -0,0 +1,2 @@
|
|||
BasedOnStyle: WebKit
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
|
@ -0,0 +1,9 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_white_space = true
|
|
@ -0,0 +1,12 @@
|
|||
# Force LF
|
||||
*.c text eol=lf
|
||||
*.h text eol=lf
|
||||
*.md text eol=lf
|
||||
*.json text eol=lf
|
||||
*.yml text eol=lf
|
||||
.clang-format text eol=lf
|
||||
.editorconfig text eol=lf
|
||||
.gitattributes text eol=lf
|
||||
.gitignore text eol=lf
|
||||
CMakeLists.txt text eol=lf
|
||||
LICENSE text eol=lf
|
|
@ -0,0 +1,42 @@
|
|||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/Build.yml'
|
||||
- 'src/**.c'
|
||||
- 'src/**.h'
|
||||
- '**/CMakeLists.txt'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/Build.yml'
|
||||
- 'src/**.c'
|
||||
- 'src/**.h'
|
||||
- '**/CMakeLists.txt'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
|
||||
Build:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
|
||||
- name: Clone
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Prepare
|
||||
run: cmake -B Build -A Win32
|
||||
|
||||
- name: Release build
|
||||
run: cmake --build Build --config Release
|
||||
|
||||
- name: Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: fallout2-ce
|
||||
path: |
|
||||
Build/*/fallout2-ce.exe
|
||||
retention-days: 7
|
|
@ -0,0 +1,392 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Dd]ebug-Remote/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Nuget personal access tokens and Credentials
|
||||
nuget.config
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
# VS Code files for those working on multiple tools
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Windows Installer files from build outputs
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CMake
|
||||
/out
|
|
@ -0,0 +1,239 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(fallout2-ce LANGUAGES C)
|
||||
|
||||
add_executable(fallout2-ce WIN32
|
||||
"src/actions.c"
|
||||
"src/actions.h"
|
||||
"src/animation.c"
|
||||
"src/animation.h"
|
||||
"src/args.c"
|
||||
"src/args.h"
|
||||
"src/art.c"
|
||||
"src/art.h"
|
||||
"src/audio_file.c"
|
||||
"src/audio_file.h"
|
||||
"src/audio.c"
|
||||
"src/audio.h"
|
||||
"src/automap.c"
|
||||
"src/automap.h"
|
||||
"src/autorun.c"
|
||||
"src/autorun.h"
|
||||
"src/cache.c"
|
||||
"src/cache.h"
|
||||
"src/character_editor.c"
|
||||
"src/character_editor.h"
|
||||
"src/character_selector.c"
|
||||
"src/character_selector.h"
|
||||
"src/color.c"
|
||||
"src/color.h"
|
||||
"src/combat_ai_defs.h"
|
||||
"src/combat_ai.c"
|
||||
"src/combat_ai.h"
|
||||
"src/combat_defs.h"
|
||||
"src/combat.c"
|
||||
"src/combat.h"
|
||||
"src/config.c"
|
||||
"src/config.h"
|
||||
"src/core.c"
|
||||
"src/core.h"
|
||||
"src/credits.c"
|
||||
"src/credits.h"
|
||||
"src/critter.c"
|
||||
"src/critter.h"
|
||||
"src/cycle.c"
|
||||
"src/cycle.h"
|
||||
"src/datafile.c"
|
||||
"src/datafile.h"
|
||||
"src/db.c"
|
||||
"src/db.h"
|
||||
"src/dbox.c"
|
||||
"src/dbox.h"
|
||||
"src/debug.c"
|
||||
"src/debug.h"
|
||||
"src/dfile.c"
|
||||
"src/dfile.h"
|
||||
"src/dialog.c"
|
||||
"src/dialog.h"
|
||||
"src/dictionary.c"
|
||||
"src/dictionary.h"
|
||||
"src/dinput.c"
|
||||
"src/dinput.h"
|
||||
"src/display_monitor.c"
|
||||
"src/display_monitor.h"
|
||||
"src/draw.c"
|
||||
"src/draw.h"
|
||||
"src/electronic_registration.c"
|
||||
"src/electronic_registration.h"
|
||||
"src/elevator.c"
|
||||
"src/elevator.h"
|
||||
"src/endgame.c"
|
||||
"src/endgame.h"
|
||||
"src/export.c"
|
||||
"src/export.h"
|
||||
"src/file_find.c"
|
||||
"src/file_find.h"
|
||||
"src/file_utils.c"
|
||||
"src/file_utils.h"
|
||||
"src/font_manager.c"
|
||||
"src/font_manager.h"
|
||||
"src/game_config.c"
|
||||
"src/game_config.h"
|
||||
"src/game_dialog.c"
|
||||
"src/game_dialog.h"
|
||||
"src/game_memory.c"
|
||||
"src/game_memory.h"
|
||||
"src/game_mouse.c"
|
||||
"src/game_mouse.h"
|
||||
"src/game_movie.c"
|
||||
"src/game_movie.h"
|
||||
"src/game_palette.c"
|
||||
"src/game_palette.h"
|
||||
"src/game_sound.c"
|
||||
"src/game_sound.h"
|
||||
"src/game_vars.h"
|
||||
"src/game.c"
|
||||
"src/game.h"
|
||||
"src/geometry.c"
|
||||
"src/geometry.h"
|
||||
"src/graph_lib.c"
|
||||
"src/graph_lib.h"
|
||||
"src/grayscale.c"
|
||||
"src/grayscale.h"
|
||||
"src/heap.c"
|
||||
"src/heap.h"
|
||||
"src/interface.c"
|
||||
"src/interface.h"
|
||||
"src/interpreter_extra.c"
|
||||
"src/interpreter_extra.h"
|
||||
"src/interpreter_lib.c"
|
||||
"src/interpreter_lib.h"
|
||||
"src/interpreter.c"
|
||||
"src/interpreter.h"
|
||||
"src/inventory.c"
|
||||
"src/inventory.h"
|
||||
"src/item.c"
|
||||
"src/item.h"
|
||||
"src/light.c"
|
||||
"src/light.h"
|
||||
"src/lips.c"
|
||||
"src/lips.h"
|
||||
"src/loadsave.c"
|
||||
"src/loadsave.h"
|
||||
"src/main.c"
|
||||
"src/main.h"
|
||||
"src/map_defs.h"
|
||||
"src/map.c"
|
||||
"src/map.h"
|
||||
"src/memory_defs.h"
|
||||
"src/memory_manager.c"
|
||||
"src/memory_manager.h"
|
||||
"src/memory.c"
|
||||
"src/memory.h"
|
||||
"src/message.c"
|
||||
"src/message.h"
|
||||
"src/mmx.c"
|
||||
"src/mmx.h"
|
||||
"src/mouse_manager.c"
|
||||
"src/mouse_manager.h"
|
||||
"src/movie_effect.c"
|
||||
"src/movie_effect.h"
|
||||
"src/movie_lib.c"
|
||||
"src/movie_lib.h"
|
||||
"src/movie.c"
|
||||
"src/movie.h"
|
||||
"src/nevs.c"
|
||||
"src/nevs.h"
|
||||
"src/obj_types.h"
|
||||
"src/object.c"
|
||||
"src/object.h"
|
||||
"src/options.c"
|
||||
"src/options.h"
|
||||
"src/palette.c"
|
||||
"src/palette.h"
|
||||
"src/party_member.c"
|
||||
"src/party_member.h"
|
||||
"src/perk_defs.h"
|
||||
"src/perk.c"
|
||||
"src/perk.h"
|
||||
"src/pipboy.c"
|
||||
"src/pipboy.h"
|
||||
"src/proto_instance.c"
|
||||
"src/proto_instance.h"
|
||||
"src/proto_types.h"
|
||||
"src/proto.c"
|
||||
"src/proto.h"
|
||||
"src/queue.c"
|
||||
"src/queue.h"
|
||||
"src/random.c"
|
||||
"src/random.h"
|
||||
"src/reaction.c"
|
||||
"src/reaction.h"
|
||||
"src/region.c"
|
||||
"src/region.h"
|
||||
"src/scripts.c"
|
||||
"src/scripts.h"
|
||||
"src/select_file_list.c"
|
||||
"src/select_file_list.h"
|
||||
"src/selfrun.c"
|
||||
"src/selfrun.h"
|
||||
"src/skill_defs.h"
|
||||
"src/skill.c"
|
||||
"src/skill.h"
|
||||
"src/skilldex.c"
|
||||
"src/skilldex.h"
|
||||
"src/sound_decoder.c"
|
||||
"src/sound_decoder.h"
|
||||
"src/sound_effects_cache.c"
|
||||
"src/sound_effects_cache.h"
|
||||
"src/sound_effects_list.c"
|
||||
"src/sound_effects_list.h"
|
||||
"src/sound.c"
|
||||
"src/sound.h"
|
||||
"src/stat_defs.h"
|
||||
"src/stat.c"
|
||||
"src/stat.h"
|
||||
"src/string_parsers.c"
|
||||
"src/string_parsers.h"
|
||||
"src/text_font.c"
|
||||
"src/text_font.h"
|
||||
"src/text_object.c"
|
||||
"src/text_object.h"
|
||||
"src/tile.c"
|
||||
"src/tile.h"
|
||||
"src/trait_defs.h"
|
||||
"src/trait.c"
|
||||
"src/trait.h"
|
||||
"src/trap.c"
|
||||
"src/trap.h"
|
||||
"src/version.c"
|
||||
"src/version.h"
|
||||
"src/widget.c"
|
||||
"src/widget.h"
|
||||
"src/win32.c"
|
||||
"src/win32.h"
|
||||
"src/window_manager_private.c"
|
||||
"src/window_manager_private.h"
|
||||
"src/window_manager.c"
|
||||
"src/window_manager.h"
|
||||
"src/window.c"
|
||||
"src/window.h"
|
||||
"src/word_wrap.c"
|
||||
"src/word_wrap.h"
|
||||
"src/world_map.c"
|
||||
"src/world_map.h"
|
||||
"src/xfile.c"
|
||||
"src/xfile.h"
|
||||
)
|
||||
|
||||
target_compile_definitions(fallout2-ce PUBLIC
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
_CRT_NONSTDC_NO_WARNINGS
|
||||
)
|
||||
|
||||
target_link_libraries(fallout2-ce
|
||||
winmm
|
||||
)
|
||||
|
||||
add_subdirectory("third_party/fpattern")
|
||||
add_subdirectory("third_party/zlib")
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x86-Debug",
|
||||
"generator": "Visual Studio 16 2019",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "x86-Release",
|
||||
"generator": "Visual Studio 16 2019",
|
||||
"configurationType": "Release",
|
||||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
# Fallout 2 Community Edition
|
||||
|
||||
## Installation
|
||||
|
||||
You must own the game to play. Purchase your copy on [GoG](https://www.gog.com/game/fallout_2) or [Steam](https://store.steampowered.com/app/38410). Download latest build or build from source. The `fallout2-ce.exe` serves as a drop-in replacement for `fallout2.exe`. Copy it to your Fallout 2 directory and run.
|
||||
|
||||
## Contributing
|
||||
|
||||
For now there are three major areas.
|
||||
|
||||
### Intergrating Sfall
|
||||
|
||||
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.
|
||||
|
||||
### SDL
|
||||
|
||||
Migrate DirectX stuff to SDL. This is the shortest path to native Linux version.
|
||||
|
||||
### Prepare to 64-bit
|
||||
|
||||
Modern macOS requires apps to be 64-bit, so even if we have SDL, the scripting part of the game will not work, because of builtin SSL interpreter. It stores pointers (both functions and variables) as 32-bit integers, so 64-bit pointers will not fit into stack. Since the stack is shared for both instructions and data, it needs some attention.
|
||||
|
||||
|
||||
## Legal & 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.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,52 @@
|
|||
#ifndef ACTIONS_H
|
||||
#define ACTIONS_H
|
||||
|
||||
#include "combat_defs.h"
|
||||
#include "obj_types.h"
|
||||
#include "proto_types.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern int _action_in_explode;
|
||||
extern const int gNormalDeathAnimations[DAMAGE_TYPE_COUNT];
|
||||
extern const int gMaximumBloodDeathAnimations[DAMAGE_TYPE_COUNT];
|
||||
|
||||
int actionKnockdown(Object* obj, int* anim, int maxDistance, int rotation, int delay);
|
||||
int _action_blood(Object* obj, int anim, int delay);
|
||||
int _pick_death(Object* attacker, Object* defender, Object* weapon, int damage, int anim, bool isFallingBack);
|
||||
int _check_death(Object* obj, int anim, int minViolenceLevel, bool isFallingBack);
|
||||
int _internal_destroy(Object* a1, Object* a2);
|
||||
void _show_damage_to_object(Object* a1, int damage, int flags, Object* weapon, bool isFallingBack, int knockbackDistance, int knockbackRotation, int a8, Object* a9, int a10);
|
||||
int _show_death(Object* obj, int anim);
|
||||
int _show_damage_extras(Attack* attack);
|
||||
void _show_damage(Attack* attack, int a2, int a3);
|
||||
int _action_attack(Attack* attack);
|
||||
int _action_melee(Attack* attack, int a2);
|
||||
int _action_ranged(Attack* attack, int a2);
|
||||
int _is_next_to(Object* a1, Object* a2);
|
||||
int _action_climb_ladder(Object* a1, Object* a2);
|
||||
int _action_use_an_item_on_object(Object* a1, Object* a2, Object* a3);
|
||||
int _action_use_an_object(Object* a1, Object* a2);
|
||||
int actionPickUp(Object* critter, Object* item);
|
||||
int _action_loot_container(Object* critter, Object* container);
|
||||
int _action_skill_use(int a1);
|
||||
int actionUseSkill(Object* a1, Object* a2, int skill);
|
||||
bool _is_hit_from_front(Object* a1, Object* a2);
|
||||
bool _can_see(Object* a1, Object* a2);
|
||||
int _pick_fall(Object* obj, int anim);
|
||||
bool _action_explode_running();
|
||||
int actionExplode(int tile, int elevation, int minDamage, int maxDamage, Object* a5, bool a6);
|
||||
int _report_explosion(Attack* attack, Object* a2);
|
||||
int _finished_explosion(Object* a1, Object* a2);
|
||||
int _compute_explosion_damage(int min, int max, Object* a3, int* a4);
|
||||
int actionTalk(Object* a1, Object* a2);
|
||||
int _can_talk_to(Object* a1, Object* a2);
|
||||
int _talk_to(Object* a1, Object* a2);
|
||||
void _action_dmg(int tile, int elevation, int minDamage, int maxDamage, int damageType, bool animated, bool bypassArmor);
|
||||
int _report_dmg(Attack* attack, Object* a2);
|
||||
int _compute_dmg_damage(int min, int max, Object* obj, int* a4, int damage_type);
|
||||
bool actionCheckPush(Object* a1, Object* a2);
|
||||
int actionPush(Object* a1, Object* a2);
|
||||
int _action_can_talk_to(Object* a1, Object* a2);
|
||||
|
||||
#endif /* ACTIONS_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,287 @@
|
|||
#ifndef ANIMATION_H
|
||||
#define ANIMATION_H
|
||||
|
||||
#include "art.h"
|
||||
#include "combat_defs.h"
|
||||
#include "obj_types.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define ANIMATION_SEQUENCE_LIST_CAPACITY (32)
|
||||
#define ANIMATION_DESCRIPTION_LIST_CAPACITY (55)
|
||||
|
||||
typedef enum AnimKind {
|
||||
ANIM_KIND_OBJ_MOVE_TO_OBJ = 0,
|
||||
ANIM_KIND_OBJ_MOVE_TO_TILE = 1,
|
||||
ANIM_KIND_2 = 2,
|
||||
ANIM_KIND_KNOCKDOWN = 3,
|
||||
ANIM_KIND_ANIMATE = 4,
|
||||
ANIM_KIND_ANIMATE_REVERSE = 5,
|
||||
ANIM_KIND_6 = 6,
|
||||
ANIM_KIND_SET_ROTATION_TO_TILE = 7,
|
||||
ANIM_KIND_ROTATE_CLOCKWISE = 8,
|
||||
ANIM_KIND_ROTATE_COUNTER_CLOCKWISE = 9,
|
||||
ANIM_KIND_HIDE = 10,
|
||||
ANIM_KIND_EXEC = 11,
|
||||
ANIM_KIND_EXEC_2 = 12,
|
||||
ANIM_KIND_14 = 14,
|
||||
ANIM_KIND_15 = 15,
|
||||
ANIM_KIND_16 = 16,
|
||||
ANIM_KIND_17 = 17,
|
||||
ANIM_KIND_18 = 18,
|
||||
ANIM_KIND_19 = 19,
|
||||
ANIM_KIND_20 = 20,
|
||||
ANIM_KIND_23 = 23,
|
||||
ANIM_KIND_24 = 24,
|
||||
ANIM_KIND_ANIMATE_FOREVER = 25,
|
||||
ANIM_KIND_26 = 26,
|
||||
ANIM_KIND_27 = 27,
|
||||
ANIM_KIND_28 = 28,
|
||||
} AnimKind;
|
||||
|
||||
// Basic animations: 0-19
|
||||
// Knockdown and death: 20-35
|
||||
// Change positions: 36-37
|
||||
// Weapon: 38-47
|
||||
// Single-frame death animations (the last frame of knockdown and death animations): 48-63
|
||||
typedef enum AnimationType {
|
||||
ANIM_STAND = 0,
|
||||
ANIM_WALK = 1,
|
||||
ANIM_JUMP_BEGIN = 2,
|
||||
ANIM_JUMP_END = 3,
|
||||
ANIM_CLIMB_LADDER = 4,
|
||||
ANIM_FALLING = 5,
|
||||
ANIM_UP_STAIRS_RIGHT = 6,
|
||||
ANIM_UP_STAIRS_LEFT = 7,
|
||||
ANIM_DOWN_STAIRS_RIGHT = 8,
|
||||
ANIM_DOWN_STAIRS_LEFT = 9,
|
||||
ANIM_MAGIC_HANDS_GROUND = 10,
|
||||
ANIM_MAGIC_HANDS_MIDDLE = 11,
|
||||
ANIM_MAGIC_HANDS_UP = 12,
|
||||
ANIM_DODGE_ANIM = 13,
|
||||
ANIM_HIT_FROM_FRONT = 14,
|
||||
ANIM_HIT_FROM_BACK = 15,
|
||||
ANIM_THROW_PUNCH = 16,
|
||||
ANIM_KICK_LEG = 17,
|
||||
ANIM_THROW_ANIM = 18,
|
||||
ANIM_RUNNING = 19,
|
||||
ANIM_FALL_BACK = 20,
|
||||
ANIM_FALL_FRONT = 21,
|
||||
ANIM_BAD_LANDING = 22,
|
||||
ANIM_BIG_HOLE = 23,
|
||||
ANIM_CHARRED_BODY = 24,
|
||||
ANIM_CHUNKS_OF_FLESH = 25,
|
||||
ANIM_DANCING_AUTOFIRE = 26,
|
||||
ANIM_ELECTRIFY = 27,
|
||||
ANIM_SLICED_IN_HALF = 28,
|
||||
ANIM_BURNED_TO_NOTHING = 29,
|
||||
ANIM_ELECTRIFIED_TO_NOTHING = 30,
|
||||
ANIM_EXPLODED_TO_NOTHING = 31,
|
||||
ANIM_MELTED_TO_NOTHING = 32,
|
||||
ANIM_FIRE_DANCE = 33,
|
||||
ANIM_FALL_BACK_BLOOD = 34,
|
||||
ANIM_FALL_FRONT_BLOOD = 35,
|
||||
ANIM_PRONE_TO_STANDING = 36,
|
||||
ANIM_BACK_TO_STANDING = 37,
|
||||
ANIM_TAKE_OUT = 38,
|
||||
ANIM_PUT_AWAY = 39,
|
||||
ANIM_PARRY_ANIM = 40,
|
||||
ANIM_THRUST_ANIM = 41,
|
||||
ANIM_SWING_ANIM = 42,
|
||||
ANIM_POINT = 43,
|
||||
ANIM_UNPOINT = 44,
|
||||
ANIM_FIRE_SINGLE = 45,
|
||||
ANIM_FIRE_BURST = 46,
|
||||
ANIM_FIRE_CONTINUOUS = 47,
|
||||
ANIM_FALL_BACK_SF = 48,
|
||||
ANIM_FALL_FRONT_SF = 49,
|
||||
ANIM_BAD_LANDING_SF = 50,
|
||||
ANIM_BIG_HOLE_SF = 51,
|
||||
ANIM_CHARRED_BODY_SF = 52,
|
||||
ANIM_CHUNKS_OF_FLESH_SF = 53,
|
||||
ANIM_DANCING_AUTOFIRE_SF = 54,
|
||||
ANIM_ELECTRIFY_SF = 55,
|
||||
ANIM_SLICED_IN_HALF_SF = 56,
|
||||
ANIM_BURNED_TO_NOTHING_SF = 57,
|
||||
ANIM_ELECTRIFIED_TO_NOTHING_SF = 58,
|
||||
ANIM_EXPLODED_TO_NOTHING_SF = 59,
|
||||
ANIM_MELTED_TO_NOTHING_SF = 60,
|
||||
ANIM_FIRE_DANCE_SF = 61,
|
||||
ANIM_FALL_BACK_BLOOD_SF = 62,
|
||||
ANIM_FALL_FRONT_BLOOD_SF = 63,
|
||||
ANIM_CALLED_SHOT_PIC = 64,
|
||||
ANIM_COUNT = 65,
|
||||
FIRST_KNOCKDOWN_AND_DEATH_ANIM = ANIM_FALL_BACK,
|
||||
LAST_KNOCKDOWN_AND_DEATH_ANIM = ANIM_FALL_FRONT_BLOOD,
|
||||
FIRST_SF_DEATH_ANIM = ANIM_FALL_BACK_SF,
|
||||
LAST_SF_DEATH_ANIM = ANIM_FALL_FRONT_BLOOD_SF,
|
||||
} AnimationType;
|
||||
|
||||
typedef int AnimationProc(Object*, Object*);
|
||||
typedef int AnimationSoundProc(Sound*);
|
||||
typedef int AnimationProc2(Object*, Object*, void*);
|
||||
|
||||
typedef struct AnimationDescription {
|
||||
int type;
|
||||
Object* owner;
|
||||
union {
|
||||
Object* destinationObj;
|
||||
Sound* sound;
|
||||
};
|
||||
union {
|
||||
int tile;
|
||||
int fid; // for type == 17
|
||||
int weaponAnimationCode; // for type == 18
|
||||
int lightDistance; // for type == 19
|
||||
};
|
||||
int elevation;
|
||||
int anim; // anim
|
||||
int delay; // delay
|
||||
union {
|
||||
AnimationProc* proc;
|
||||
AnimationSoundProc* soundProc;
|
||||
};
|
||||
AnimationProc2* field_20; // func
|
||||
int field_24;
|
||||
union {
|
||||
int field_28; // actionPoints
|
||||
Object* field_28_obj; // obj in type == 12
|
||||
void* field_28_void;
|
||||
};
|
||||
CacheEntry* field_2C;
|
||||
} AnimationDescription;
|
||||
|
||||
typedef struct AnimationSequence {
|
||||
int field_0;
|
||||
// Index of current animation in [animations] array or -1 if animations in
|
||||
// this sequence is not playing.
|
||||
int animationIndex;
|
||||
// Number of scheduled animations in [animations] array.
|
||||
int length;
|
||||
int flags;
|
||||
AnimationDescription animations[ANIMATION_DESCRIPTION_LIST_CAPACITY];
|
||||
} AnimationSequence;
|
||||
|
||||
typedef struct PathNode {
|
||||
int tile;
|
||||
int from;
|
||||
// actual type is likely char
|
||||
int rotation;
|
||||
int field_C;
|
||||
int field_10;
|
||||
} PathNode;
|
||||
|
||||
typedef struct STRUCT_530014_28 {
|
||||
int tile;
|
||||
int elevation;
|
||||
int x;
|
||||
int y;
|
||||
} STRUCT_530014_28;
|
||||
|
||||
typedef struct STRUCT_530014 {
|
||||
int flags; // flags
|
||||
Object* obj;
|
||||
int fid; // fid
|
||||
int field_C;
|
||||
int field_10;
|
||||
int field_14; // animation speed?
|
||||
int animationSequenceIndex;
|
||||
int field_1C; // length of field_28
|
||||
int field_20; // current index in field_28
|
||||
int field_24;
|
||||
union {
|
||||
unsigned char rotations[3200];
|
||||
STRUCT_530014_28 field_28[200];
|
||||
};
|
||||
} STRUCT_530014;
|
||||
|
||||
static_assert(sizeof(STRUCT_530014) == 3240, "wrong size");
|
||||
|
||||
typedef Object* PathBuilderCallback(Object* object, int tile, int elevation);
|
||||
|
||||
extern int _curr_sad;
|
||||
extern int gAnimationSequenceCurrentIndex;
|
||||
extern int _anim_in_init;
|
||||
extern bool _anim_in_anim_stop;
|
||||
extern bool _anim_in_bk;
|
||||
extern int _lastDestination;
|
||||
extern unsigned int _last_time_;
|
||||
extern unsigned int _next_time;
|
||||
|
||||
extern STRUCT_530014 _sad[24];
|
||||
extern PathNode gClosedPathNodeList[2000];
|
||||
extern AnimationSequence gAnimationSequences[32];
|
||||
extern unsigned char gPathfinderProcessedTiles[5000];
|
||||
extern PathNode gOpenPathNodeList[2000];
|
||||
extern int gAnimationDescriptionCurrentIndex;
|
||||
extern Object* dword_56C7E0[100];
|
||||
|
||||
void animationInit();
|
||||
void animationReset();
|
||||
void animationExit();
|
||||
int reg_anim_begin(int a1);
|
||||
int _anim_free_slot(int a1);
|
||||
int _register_priority(int a1);
|
||||
int reg_anim_clear(Object* a1);
|
||||
int reg_anim_end();
|
||||
void _anim_cleanup();
|
||||
int _check_registry(Object* obj);
|
||||
int animationIsBusy(Object* a1);
|
||||
int reg_anim_obj_move_to_obj(Object* a1, Object* a2, int actionPoints, int delay);
|
||||
int reg_anim_obj_run_to_obj(Object* owner, Object* destination, int actionPoints, int delay);
|
||||
int reg_anim_obj_move_to_tile(Object* obj, int tile_num, int elev, int actionPoints, int delay);
|
||||
int reg_anim_obj_run_to_tile(Object* obj, int tile_num, int elev, int actionPoints, int delay);
|
||||
int reg_anim_2(Object* obj, int tile_num, int elev, int a4, int a5);
|
||||
int reg_anim_knockdown(Object* obj, int tile, int elev, int anim, int delay);
|
||||
int reg_anim_animate(Object* obj, int anim, int delay);
|
||||
int reg_anim_animate_reverse(Object* obj, int anim, int delay);
|
||||
int reg_anim_6(Object* obj, int anim, int delay);
|
||||
int reg_anim_set_rotation_to_tile(Object* owner, int tile);
|
||||
int reg_anim_rotate_clockwise(Object* obj);
|
||||
int reg_anim_rotate_counter_clockwise(Object* obj);
|
||||
int reg_anim_hide(Object* obj);
|
||||
int reg_anim_11_0(Object* a1, Object* a2, AnimationProc* proc, int delay);
|
||||
int reg_anim_12(Object* a1, Object* a2, void* a3, AnimationProc2* proc, int delay);
|
||||
int reg_anim_11_1(Object* a1, Object* a2, AnimationProc* proc, int delay);
|
||||
int reg_anim_15(Object* obj, int a2, int a3);
|
||||
int reg_anim_17(Object* obj, int fid, int a3);
|
||||
int reg_anim_18(Object* obj, int a2, int a3);
|
||||
int reg_anim_update_light(Object* obj, int fid, int a3);
|
||||
int reg_anim_play_sfx(Object* obj, const char* a2, int a3);
|
||||
int reg_anim_animate_forever(Object* obj, int a2, int a3);
|
||||
int reg_anim_26(int a1, int a2);
|
||||
int animationRunSequence(int a1);
|
||||
int _anim_set_continue(int a1, int a2);
|
||||
int _anim_set_end(int a1);
|
||||
bool canUseDoor(Object* critter, Object* door);
|
||||
int _make_path(Object* object, int from, int to, unsigned char* a4, int a5);
|
||||
int pathfinderFindPath(Object* object, int from, int to, unsigned char* rotations, int a5, PathBuilderCallback* callback);
|
||||
int _idist(int a1, int a2, int a3, int a4);
|
||||
int _tile_idistance(int tile1, int tile2);
|
||||
int _make_straight_path(Object* a1, int from, int to, STRUCT_530014_28* pathNodes, Object** a5, int a6);
|
||||
int _make_straight_path_func(Object* a1, int from, int to, STRUCT_530014_28* a4, Object** a5, int a6, Object* (*a7)(Object*, int, int));
|
||||
int animateMoveObjectToObject(Object* a1, Object* a2, int a3, int a4, int a5);
|
||||
int animateMoveObjectToTile(Object* obj, int tile_num, int elev, int a4, int a5, int a6);
|
||||
int _anim_move(Object* obj, int tile, int elev, int a3, int a4, int a5, int animationSequenceIndex);
|
||||
int _anim_move_straight_to_tile(Object* obj, int a2, int a3, int fid, int a5, int a6);
|
||||
int _anim_move_on_stairs(Object* obj, int a2, int a3, int fid, int a5);
|
||||
int _check_for_falling(Object* obj, int a2, int a3);
|
||||
void _object_move(int index);
|
||||
void _object_straight_move(int a1);
|
||||
int _anim_animate(Object* obj, int a2, int a3, int a4);
|
||||
void _object_animate();
|
||||
void _object_anim_compact();
|
||||
int _check_move(int* a1);
|
||||
int _dude_move(int a1);
|
||||
int _dude_run(int a1);
|
||||
void _dude_fidget();
|
||||
void _dude_stand(Object* obj, int rotation, int fid);
|
||||
void _dude_standup(Object* a1);
|
||||
int actionRotate(Object* obj, int a2, int a3);
|
||||
int _anim_change_fid(Object* obj, int a2, int fid);
|
||||
void _anim_stop();
|
||||
int _check_gravity(int tile, int elevation);
|
||||
unsigned int _compute_tpf(Object* object, int fid);
|
||||
|
||||
#endif /* ANIMATION_H */
|
|
@ -0,0 +1,114 @@
|
|||
#include "args.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
// 0x4E3B90
|
||||
void argsInit(CommandLineArguments* commandLineArguments)
|
||||
{
|
||||
if (commandLineArguments != NULL) {
|
||||
commandLineArguments->argc = 0;
|
||||
commandLineArguments->argv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4E3BA4
|
||||
bool argsParse(CommandLineArguments* commandLineArguments, char* commandLine)
|
||||
{
|
||||
const char* delim = " \t";
|
||||
|
||||
int argc = 0;
|
||||
|
||||
// Get the number of arguments in command line.
|
||||
if (*commandLine != '\0') {
|
||||
char* copy = strdup(commandLine);
|
||||
if (copy == NULL) {
|
||||
argsFree(commandLineArguments);
|
||||
return false;
|
||||
}
|
||||
|
||||
char* tok = strtok(copy, delim);
|
||||
while (tok != NULL) {
|
||||
argc++;
|
||||
tok = strtok(NULL, delim);
|
||||
}
|
||||
|
||||
free(copy);
|
||||
}
|
||||
|
||||
// Make a room for argv[0] - program name.
|
||||
argc++;
|
||||
|
||||
commandLineArguments->argc = argc;
|
||||
commandLineArguments->argv = malloc(sizeof(*commandLineArguments->argv) * argc);
|
||||
if (commandLineArguments->argv == NULL) {
|
||||
argsFree(commandLineArguments);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int arg = 0; arg < argc; arg++) {
|
||||
commandLineArguments->argv[arg] = NULL;
|
||||
}
|
||||
|
||||
// Copy program name into argv[0].
|
||||
char moduleFileName[MAX_PATH];
|
||||
int moduleFileNameLength = GetModuleFileNameA(NULL, moduleFileName, MAX_PATH);
|
||||
if (moduleFileNameLength == 0) {
|
||||
argsFree(commandLineArguments);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (moduleFileNameLength >= MAX_PATH) {
|
||||
moduleFileNameLength = MAX_PATH - 1;
|
||||
}
|
||||
|
||||
moduleFileName[moduleFileNameLength] = '\0';
|
||||
|
||||
commandLineArguments->argv[0] = strdup(moduleFileName);
|
||||
if (commandLineArguments->argv[0] == NULL) {
|
||||
argsFree(commandLineArguments);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy arguments from command line into argv.
|
||||
if (*commandLine != '\0') {
|
||||
char* copy = strdup(commandLine);
|
||||
if (copy == NULL) {
|
||||
argsFree(commandLineArguments);
|
||||
return false;
|
||||
}
|
||||
|
||||
int arg = 1;
|
||||
|
||||
char* tok = strtok(copy, delim);
|
||||
while (tok != NULL) {
|
||||
commandLineArguments->argv[arg] = strdup(tok);
|
||||
tok = strtok(NULL, delim);
|
||||
arg++;
|
||||
}
|
||||
|
||||
free(copy);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4E3D3C
|
||||
void argsFree(CommandLineArguments* commandLineArguments)
|
||||
{
|
||||
if (commandLineArguments->argv != NULL) {
|
||||
// NOTE: Compiled code is slightly different - it decrements argc.
|
||||
for (int index = 0; index < commandLineArguments->argc; index++) {
|
||||
if (commandLineArguments->argv[index] != NULL) {
|
||||
free(commandLineArguments->argv[index]);
|
||||
}
|
||||
}
|
||||
free(commandLineArguments->argv);
|
||||
}
|
||||
|
||||
commandLineArguments->argc = 0;
|
||||
commandLineArguments->argv = NULL;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef ARGS_H
|
||||
#define ARGS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct CommandLineArguments {
|
||||
int argc;
|
||||
char** argv;
|
||||
} CommandLineArguments;
|
||||
|
||||
void argsInit(CommandLineArguments* commandLineArguments);
|
||||
bool argsParse(CommandLineArguments* commandLineArguments, char* commandLine);
|
||||
void argsFree(CommandLineArguments* commandLineArguments);
|
||||
|
||||
#endif /* ARGS_H */
|
|
@ -0,0 +1,187 @@
|
|||
#ifndef ART_H
|
||||
#define ART_H
|
||||
|
||||
#include "cache.h"
|
||||
#include "db.h"
|
||||
#include "heap.h"
|
||||
#include "obj_types.h"
|
||||
#include "proto_types.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
typedef enum Head {
|
||||
HEAD_INVALID,
|
||||
HEAD_MARCUS,
|
||||
HEAD_MYRON,
|
||||
HEAD_ELDER,
|
||||
HEAD_LYNETTE,
|
||||
HEAD_HAROLD,
|
||||
HEAD_TANDI,
|
||||
HEAD_COM_OFFICER,
|
||||
HEAD_SULIK,
|
||||
HEAD_PRESIDENT,
|
||||
HEAD_HAKUNIN,
|
||||
HEAD_BOSS,
|
||||
HEAD_DYING_HAKUNIN,
|
||||
HEAD_COUNT,
|
||||
} Head;
|
||||
|
||||
typedef enum HeadAnimation {
|
||||
HEAD_ANIMATION_VERY_GOOD_REACTION = 0,
|
||||
FIDGET_GOOD = 1,
|
||||
HEAD_ANIMATION_GOOD_TO_NEUTRAL = 2,
|
||||
HEAD_ANIMATION_NEUTRAL_TO_GOOD = 3,
|
||||
FIDGET_NEUTRAL = 4,
|
||||
HEAD_ANIMATION_NEUTRAL_TO_BAD = 5,
|
||||
HEAD_ANIMATION_BAD_TO_NEUTRAL = 6,
|
||||
FIDGET_BAD = 7,
|
||||
HEAD_ANIMATION_VERY_BAD_REACTION = 8,
|
||||
HEAD_ANIMATION_GOOD_PHONEMES = 9,
|
||||
HEAD_ANIMATION_NEUTRAL_PHONEMES = 10,
|
||||
HEAD_ANIMATION_BAD_PHONEMES = 11,
|
||||
} HeadAnimation;
|
||||
|
||||
typedef enum Background {
|
||||
BACKGROUND_0,
|
||||
BACKGROUND_1,
|
||||
BACKGROUND_2,
|
||||
BACKGROUND_HUB,
|
||||
BACKGROUND_NECROPOLIS,
|
||||
BACKGROUND_BROTHERHOOD,
|
||||
BACKGROUND_MILITARY_BASE,
|
||||
BACKGROUND_JUNK_TOWN,
|
||||
BACKGROUND_CATHEDRAL,
|
||||
BACKGROUND_SHADY_SANDS,
|
||||
BACKGROUND_VAULT,
|
||||
BACKGROUND_MASTER,
|
||||
BACKGROUND_FOLLOWER,
|
||||
BACKGROUND_RAIDERS,
|
||||
BACKGROUND_CAVE,
|
||||
BACKGROUND_ENCLAVE,
|
||||
BACKGROUND_WASTELAND,
|
||||
BACKGROUND_BOSS,
|
||||
BACKGROUND_PRESIDENT,
|
||||
BACKGROUND_TENT,
|
||||
BACKGROUND_ADOBE,
|
||||
BACKGROUND_COUNT,
|
||||
} Background;
|
||||
|
||||
#pragma pack(2)
|
||||
typedef struct Art {
|
||||
int field_0;
|
||||
short framesPerSecond;
|
||||
short actionFrame;
|
||||
short frameCount;
|
||||
short xOffsets[6];
|
||||
short yOffsets[6];
|
||||
int dataOffsets[6];
|
||||
int field_3A;
|
||||
unsigned char data[];
|
||||
} Art;
|
||||
#pragma pack()
|
||||
|
||||
static_assert(sizeof(Art) == 62, "wrong size");
|
||||
|
||||
typedef struct ArtFrame {
|
||||
short width;
|
||||
short height;
|
||||
int size;
|
||||
short x;
|
||||
short y;
|
||||
unsigned char data[];
|
||||
} ArtFrame;
|
||||
|
||||
typedef struct ArtListDescription {
|
||||
int flags;
|
||||
char name[16];
|
||||
char* fileNames; // dynamic array of null terminated strings 13 bytes long each
|
||||
void* field_18;
|
||||
int fileNamesLength; // number of entries in list
|
||||
} ArtListDescription;
|
||||
|
||||
typedef struct HeadDescription {
|
||||
int goodFidgetCount;
|
||||
int neutralFidgetCount;
|
||||
int badFidgetCount;
|
||||
} HeadDescription;
|
||||
|
||||
typedef enum WeaponAnimation {
|
||||
WEAPON_ANIMATION_NONE,
|
||||
WEAPON_ANIMATION_KNIFE, // d
|
||||
WEAPON_ANIMATION_CLUB, // e
|
||||
WEAPON_ANIMATION_HAMMER, // f
|
||||
WEAPON_ANIMATION_SPEAR, // g
|
||||
WEAPON_ANIMATION_PISTOL, // h
|
||||
WEAPON_ANIMATION_SMG, // i
|
||||
WEAPON_ANIMATION_SHOTGUN, // j
|
||||
WEAPON_ANIMATION_LASER_RIFLE, // k
|
||||
WEAPON_ANIMATION_MINIGUN, // l
|
||||
WEAPON_ANIMATION_LAUNCHER, // m
|
||||
WEAPON_ANIMATION_COUNT,
|
||||
} WeaponAnimation;
|
||||
|
||||
typedef enum DudeNativeLook {
|
||||
// Hero looks as one the tribals (before finishing Temple of Trails).
|
||||
DUDE_NATIVE_LOOK_TRIBAL,
|
||||
|
||||
// Hero have finished Temple of Trails and received Vault Jumpsuit.
|
||||
DUDE_NATIVE_LOOK_JUMPSUIT,
|
||||
DUDE_NATIVE_LOOK_COUNT,
|
||||
} DudeNativeLook;
|
||||
|
||||
extern ArtListDescription gArtListDescriptions[OBJ_TYPE_COUNT];
|
||||
extern bool gArtLanguageInitialized;
|
||||
extern const char* _head1;
|
||||
extern const char* _head2;
|
||||
extern int _art_vault_guy_num;
|
||||
extern int _art_vault_person_nums[DUDE_NATIVE_LOOK_COUNT][GENDER_COUNT];
|
||||
extern int _art_mapper_blank_tile;
|
||||
|
||||
extern char gArtLanguage[32];
|
||||
extern Cache gArtCache;
|
||||
extern char _art_name[MAX_PATH];
|
||||
extern HeadDescription* gHeadDescriptions;
|
||||
extern int* _anon_alias;
|
||||
extern int* gArtCritterFidShoudRunData;
|
||||
|
||||
int artInit();
|
||||
void artReset();
|
||||
void artExit();
|
||||
char* artGetObjectTypeName(int objectType);
|
||||
int artIsObjectTypeHidden(int objectType);
|
||||
int artGetFidgetCount(int headFid);
|
||||
void artRender(int fid, unsigned char* dest, int width, int height, int pitch);
|
||||
Art* artLock(int fid, CacheEntry** cache_entry);
|
||||
unsigned char* artLockFrameData(int fid, int frame, int direction, CacheEntry** out_cache_entry);
|
||||
unsigned char* artLockFrameDataReturningSize(int fid, CacheEntry** out_cache_entry, int* widthPtr, int* heightPtr);
|
||||
int artUnlock(CacheEntry* cache_entry);
|
||||
int artCacheFlush();
|
||||
int artCopyFileName(int a1, int a2, char* a3);
|
||||
int _art_get_code(int a1, int a2, char* a3, char* a4);
|
||||
char* artBuildFilePath(int a1);
|
||||
int artReadList(const char* path, char** out_arr, int* out_count);
|
||||
int artGetFramesPerSecond(Art* art);
|
||||
int artGetActionFrame(Art* art);
|
||||
int artGetFrameCount(Art* art);
|
||||
int artGetWidth(Art* art, int frame, int direction);
|
||||
int artGetHeight(Art* art, int frame, int direction);
|
||||
int artGetSize(Art* art, int frame, int direction, int* out_width, int* out_height);
|
||||
int artGetFrameOffsets(Art* art, int frame, int direction, int* a4, int* a5);
|
||||
int artGetRotationOffsets(Art* art, int rotation, int* out_offset_x, int* out_offset_y);
|
||||
unsigned char* artGetFrameData(Art* art, int frame, int direction);
|
||||
ArtFrame* artGetFrame(Art* art, int frame, int direction);
|
||||
bool artExists(int fid);
|
||||
bool _art_fid_valid(int fid);
|
||||
int _art_alias_num(int a1);
|
||||
int artCritterFidShouldRun(int a1);
|
||||
int _art_alias_fid(int a1);
|
||||
int artCacheGetFileSizeImpl(int a1, int* out_size);
|
||||
int artCacheReadDataImpl(int a1, int* a2, unsigned char* data);
|
||||
void artCacheFreeImpl(void* ptr);
|
||||
int buildFid(int a1, int a2, int a3, int a4, int a5);
|
||||
int artReadFrameData(unsigned char* data, File* stream, int count);
|
||||
int artReadHeader(Art* art, File* stream);
|
||||
int artRead(const char* path, unsigned char* data);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,250 @@
|
|||
#include "audio.h"
|
||||
|
||||
#include "db.h"
|
||||
#include "debug.h"
|
||||
#include "memory_manager.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// 0x5108BC
|
||||
AudioFileIsCompressedProc* _queryCompressedFunc = _defaultCompressionFunc;
|
||||
|
||||
// 0x56CB00
|
||||
int gAudioListLength;
|
||||
|
||||
// 0x56CB04
|
||||
AudioFile* gAudioList;
|
||||
|
||||
// 0x41A2B0
|
||||
bool _defaultCompressionFunc(char* filePath)
|
||||
{
|
||||
char* pch = strrchr(filePath, '.');
|
||||
if (pch != NULL) {
|
||||
strcpy(pch + 1, "war");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x41A2D0
|
||||
int audioSoundDecoderReadHandler(int fileHandle, void* buffer, unsigned int size)
|
||||
{
|
||||
return fileRead(buffer, 1, size, (File*)fileHandle);
|
||||
}
|
||||
|
||||
// AudioOpen
|
||||
// 0x41A2EC
|
||||
int audioOpen(const char* fname, int flags, ...)
|
||||
{
|
||||
char path[80];
|
||||
sprintf(path, fname);
|
||||
|
||||
int compression;
|
||||
if (_queryCompressedFunc(path)) {
|
||||
compression = 2;
|
||||
} else {
|
||||
compression = 0;
|
||||
}
|
||||
|
||||
char mode[4];
|
||||
memset(mode, 0, 4);
|
||||
|
||||
// NOTE: Original implementation is slightly different, it uses separate
|
||||
// variable to track index where to set 't' and 'b'.
|
||||
char* pm = mode;
|
||||
if (flags & 1) {
|
||||
*pm++ = 'w';
|
||||
} else if (flags & 2) {
|
||||
*pm++ = 'w';
|
||||
*pm++ = '+';
|
||||
} else {
|
||||
*pm++ = 'r';
|
||||
}
|
||||
|
||||
if (flags & 0x100) {
|
||||
*pm++ = 't';
|
||||
} else if (flags & 0x200) {
|
||||
*pm++ = 'b';
|
||||
}
|
||||
|
||||
File* stream = fileOpen(path, mode);
|
||||
if (stream == NULL) {
|
||||
debugPrint("AudioOpen: Couldn't open %s for read\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int index;
|
||||
for (index = 0; index < gAudioListLength; index++) {
|
||||
if ((gAudioList[index].flags & AUDIO_FILE_IN_USE) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == gAudioListLength) {
|
||||
if (gAudioList != NULL) {
|
||||
gAudioList = internal_realloc_safe(gAudioList, sizeof(*gAudioList) * (gAudioListLength + 1), __FILE__, __LINE__); // "..\int\audio.c", 216
|
||||
} else {
|
||||
gAudioList = internal_malloc_safe(sizeof(*gAudioList), __FILE__, __LINE__); // "..\int\audio.c", 218
|
||||
}
|
||||
gAudioListLength++;
|
||||
}
|
||||
|
||||
AudioFile* audioFile = &(gAudioList[index]);
|
||||
audioFile->flags = AUDIO_FILE_IN_USE;
|
||||
audioFile->fileHandle = (int)stream;
|
||||
|
||||
if (compression == 2) {
|
||||
audioFile->flags |= AUDIO_FILE_COMPRESSED;
|
||||
audioFile->soundDecoder = soundDecoderInit(audioSoundDecoderReadHandler, audioFile->fileHandle, &(audioFile->field_14), &(audioFile->field_10), &(audioFile->fileSize));
|
||||
audioFile->fileSize *= 2;
|
||||
} else {
|
||||
audioFile->fileSize = fileGetSize(stream);
|
||||
}
|
||||
|
||||
audioFile->position = 0;
|
||||
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
// 0x41A50C
|
||||
int audioClose(int fileHandle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioList[fileHandle - 1]);
|
||||
fileClose((File*)audioFile->fileHandle);
|
||||
|
||||
if ((audioFile->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
soundDecoderFree(audioFile->soundDecoder);
|
||||
}
|
||||
|
||||
memset(audioFile, 0, sizeof(AudioFile));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x41A574
|
||||
int audioRead(int fileHandle, void* buffer, unsigned int size)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioList[fileHandle - 1]);
|
||||
|
||||
int bytesRead;
|
||||
if ((audioFile->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
bytesRead = soundDecoderDecode(audioFile->soundDecoder, buffer, size);
|
||||
} else {
|
||||
bytesRead = fileRead(buffer, 1, size, (File*)audioFile->fileHandle);
|
||||
}
|
||||
|
||||
audioFile->position += bytesRead;
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
// 0x41A5E0
|
||||
int audioSeek(int fileHandle, long offset, int origin)
|
||||
{
|
||||
int pos;
|
||||
unsigned char* buf;
|
||||
int v10;
|
||||
|
||||
AudioFile* audioFile = &(gAudioList[fileHandle - 1]);
|
||||
|
||||
switch (origin) {
|
||||
case SEEK_SET:
|
||||
pos = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
pos = offset + audioFile->position;
|
||||
break;
|
||||
case SEEK_END:
|
||||
pos = offset + audioFile->fileSize;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Should be unreachable");
|
||||
}
|
||||
|
||||
if ((audioFile->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
if (pos < audioFile->position) {
|
||||
soundDecoderFree(audioFile->soundDecoder);
|
||||
fileSeek((File*)audioFile->fileHandle, 0, SEEK_SET);
|
||||
audioFile->soundDecoder = soundDecoderInit(audioSoundDecoderReadHandler, audioFile->fileHandle, &(audioFile->field_14), &(audioFile->field_10), &(audioFile->fileSize));
|
||||
audioFile->position = 0;
|
||||
audioFile->fileSize *= 2;
|
||||
|
||||
if (pos != 0) {
|
||||
buf = internal_malloc_safe(4096, __FILE__, __LINE__); // "..\int\audio.c", 361
|
||||
while (pos > 4096) {
|
||||
pos -= 4096;
|
||||
audioRead(fileHandle, buf, 4096);
|
||||
}
|
||||
|
||||
if (pos != 0) {
|
||||
audioRead(fileHandle, buf, pos);
|
||||
}
|
||||
|
||||
internal_free_safe(buf, __FILE__, __LINE__); // // "..\int\audio.c", 367
|
||||
}
|
||||
} else {
|
||||
buf = internal_malloc_safe(1024, __FILE__, __LINE__); // "..\int\audio.c", 321
|
||||
v10 = audioFile->position - pos;
|
||||
while (v10 > 1024) {
|
||||
v10 -= 1024;
|
||||
audioRead(fileHandle, buf, 1024);
|
||||
}
|
||||
|
||||
if (v10 != 0) {
|
||||
audioRead(fileHandle, buf, v10);
|
||||
}
|
||||
|
||||
// TODO: Probably leaks memory.
|
||||
}
|
||||
|
||||
return audioFile->position;
|
||||
} else {
|
||||
return fileSeek((File*)audioFile->fileHandle, offset, origin);
|
||||
}
|
||||
}
|
||||
|
||||
// 0x41A78C
|
||||
long audioGetSize(int fileHandle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioList[fileHandle - 1]);
|
||||
return audioFile->fileSize;
|
||||
}
|
||||
|
||||
// 0x41A7A8
|
||||
long audioTell(int fileHandle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioList[fileHandle - 1]);
|
||||
return audioFile->position;
|
||||
}
|
||||
|
||||
// AudioWrite
|
||||
// 0x41A7C4
|
||||
int audioWrite(int handle, const void* buf, unsigned int size)
|
||||
{
|
||||
debugPrint("AudioWrite shouldn't be ever called\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x41A7D4
|
||||
int audioInit(AudioFileIsCompressedProc* isCompressedProc)
|
||||
{
|
||||
_queryCompressedFunc = isCompressedProc;
|
||||
gAudioList = NULL;
|
||||
gAudioListLength = 0;
|
||||
|
||||
return soundSetDefaultFileIO(audioOpen, audioClose, audioRead, audioWrite, audioSeek, audioTell, audioGetSize);
|
||||
}
|
||||
|
||||
// 0x41A818
|
||||
void audioExit()
|
||||
{
|
||||
if (gAudioList != NULL) {
|
||||
internal_free_safe(gAudioList, __FILE__, __LINE__); // "..\int\audio.c", 406
|
||||
}
|
||||
|
||||
gAudioListLength = 0;
|
||||
gAudioList = NULL;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef AUDIO_H
|
||||
#define AUDIO_H
|
||||
|
||||
#include "audio_file.h"
|
||||
|
||||
extern AudioFileIsCompressedProc* _queryCompressedFunc;
|
||||
|
||||
extern int gAudioListLength;
|
||||
extern AudioFile* gAudioList;
|
||||
|
||||
bool _defaultCompressionFunc(char* filePath);
|
||||
int audioSoundDecoderReadHandler(int fileHandle, void* buf, unsigned int size);
|
||||
int audioOpen(const char* fname, int mode, ...);
|
||||
int audioClose(int fileHandle);
|
||||
int audioRead(int fileHandle, void* buffer, unsigned int size);
|
||||
int audioSeek(int fileHandle, long offset, int origin);
|
||||
long audioGetSize(int fileHandle);
|
||||
long audioTell(int fileHandle);
|
||||
int audioWrite(int handle, const void* buf, unsigned int size);
|
||||
int audioInit(AudioFileIsCompressedProc* isCompressedProc);
|
||||
void audioExit();
|
||||
|
||||
#endif /* AUDIO_H */
|
|
@ -0,0 +1,252 @@
|
|||
#include "audio_file.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "memory_manager.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
static_assert(sizeof(AudioFile) == 28, "wrong size");
|
||||
|
||||
// 0x5108C0
|
||||
AudioFileIsCompressedProc* _queryCompressedFunc_2 = _defaultCompressionFunc__;
|
||||
|
||||
// 0x56CB10
|
||||
AudioFile* gAudioFileList;
|
||||
|
||||
// 0x56CB14
|
||||
int gAudioFileListLength;
|
||||
|
||||
// 0x41A850
|
||||
bool _defaultCompressionFunc__(char* filePath)
|
||||
{
|
||||
char* pch = strrchr(filePath, '.');
|
||||
if (pch != NULL) {
|
||||
strcpy(pch + 1, "war");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x41A870
|
||||
int audioFileSoundDecoderReadHandler(int fileHandle, void* buffer, unsigned int size)
|
||||
{
|
||||
return fread(buffer, 1, size, (FILE*)fileHandle);
|
||||
}
|
||||
|
||||
// 0x41A88C
|
||||
int audioFileOpen(const char* fname, int flags, ...)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
strcpy(path, fname);
|
||||
|
||||
int compression;
|
||||
if (_queryCompressedFunc_2(path)) {
|
||||
compression = 2;
|
||||
} else {
|
||||
compression = 0;
|
||||
}
|
||||
|
||||
char mode[4];
|
||||
memset(mode, '\0', 4);
|
||||
|
||||
// NOTE: Original implementation is slightly different, it uses separate
|
||||
// variable to track index where to set 't' and 'b'.
|
||||
char* pm = mode;
|
||||
if (flags & 0x01) {
|
||||
*pm++ = 'w';
|
||||
} else if (flags & 0x02) {
|
||||
*pm++ = 'w';
|
||||
*pm++ = '+';
|
||||
} else {
|
||||
*pm++ = 'r';
|
||||
}
|
||||
|
||||
if (flags & 0x0100) {
|
||||
*pm++ = 't';
|
||||
} else if (flags & 0x0200) {
|
||||
*pm++ = 'b';
|
||||
}
|
||||
|
||||
FILE* stream = fopen(path, mode);
|
||||
if (stream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int index;
|
||||
for (index = 0; index < gAudioFileListLength; index++) {
|
||||
if ((gAudioFileList[index].flags & AUDIO_FILE_IN_USE) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == gAudioFileListLength) {
|
||||
if (gAudioFileList != NULL) {
|
||||
gAudioFileList = internal_realloc_safe(gAudioFileList, sizeof(*gAudioFileList) * (gAudioFileListLength + 1), __FILE__, __LINE__); // "..\int\audiof.c", 207
|
||||
} else {
|
||||
gAudioFileList = internal_malloc_safe(sizeof(*gAudioFileList), __FILE__, __LINE__); // "..\int\audiof.c", 209
|
||||
}
|
||||
gAudioFileListLength++;
|
||||
}
|
||||
|
||||
AudioFile* audioFile = &(gAudioFileList[index]);
|
||||
audioFile->flags = AUDIO_FILE_IN_USE;
|
||||
audioFile->fileHandle = (int)stream;
|
||||
|
||||
if (compression == 2) {
|
||||
audioFile->flags |= AUDIO_FILE_COMPRESSED;
|
||||
audioFile->soundDecoder = soundDecoderInit(audioFileSoundDecoderReadHandler, audioFile->fileHandle, &(audioFile->field_14), &(audioFile->field_10), &(audioFile->fileSize));
|
||||
audioFile->fileSize *= 2;
|
||||
} else {
|
||||
audioFile->fileSize = filelength(fileno(stream));
|
||||
}
|
||||
|
||||
audioFile->position = 0;
|
||||
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
// 0x41AAA0
|
||||
int audioFileClose(int fileHandle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioFileList[fileHandle - 1]);
|
||||
fclose((FILE*)audioFile->fileHandle);
|
||||
|
||||
if ((audioFile->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
soundDecoderFree(audioFile->soundDecoder);
|
||||
}
|
||||
|
||||
// Reset audio file (which also resets it's use flag).
|
||||
memset(audioFile, 0, sizeof(*audioFile));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x41AB08
|
||||
int audioFileRead(int fileHandle, void* buffer, unsigned int size)
|
||||
{
|
||||
|
||||
AudioFile* ptr = &(gAudioFileList[fileHandle - 1]);
|
||||
|
||||
int bytesRead;
|
||||
if ((ptr->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
bytesRead = soundDecoderDecode(ptr->soundDecoder, buffer, size);
|
||||
} else {
|
||||
bytesRead = fread(buffer, 1, size, (FILE*)ptr->fileHandle);
|
||||
}
|
||||
|
||||
ptr->position += bytesRead;
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
// 0x41AB74
|
||||
int audioFileSeek(int fileHandle, long offset, int origin)
|
||||
{
|
||||
void* buf;
|
||||
int remaining;
|
||||
int a4;
|
||||
|
||||
AudioFile* audioFile = &(gAudioFileList[fileHandle - 1]);
|
||||
|
||||
switch (origin) {
|
||||
case SEEK_SET:
|
||||
a4 = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
a4 = audioFile->fileSize + offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
a4 = audioFile->position + offset;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Should be unreachable");
|
||||
}
|
||||
|
||||
if ((audioFile->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
if (a4 <= audioFile->position) {
|
||||
soundDecoderFree(audioFile->soundDecoder);
|
||||
|
||||
fseek((FILE*)audioFile->fileHandle, 0, 0);
|
||||
|
||||
audioFile->soundDecoder = soundDecoderInit(audioFileSoundDecoderReadHandler, audioFile->fileHandle, &(audioFile->field_14), &(audioFile->field_10), &(audioFile->fileSize));
|
||||
audioFile->fileSize *= 2;
|
||||
audioFile->position = 0;
|
||||
|
||||
if (a4) {
|
||||
buf = internal_malloc_safe(4096, __FILE__, __LINE__); // "..\int\audiof.c", 364
|
||||
while (a4 > 4096) {
|
||||
audioFileRead(fileHandle, buf, 4096);
|
||||
a4 -= 4096;
|
||||
}
|
||||
if (a4 != 0) {
|
||||
audioFileRead(fileHandle, buf, a4);
|
||||
}
|
||||
internal_free_safe(buf, __FILE__, __LINE__); // "..\int\audiof.c", 370
|
||||
}
|
||||
} else {
|
||||
buf = internal_malloc_safe(0x400, __FILE__, __LINE__); // "..\int\audiof.c", 316
|
||||
remaining = audioFile->position - a4;
|
||||
while (remaining > 1024) {
|
||||
audioFileRead(fileHandle, buf, 1024);
|
||||
remaining -= 1024;
|
||||
}
|
||||
if (remaining != 0) {
|
||||
audioFileRead(fileHandle, buf, remaining);
|
||||
}
|
||||
// TODO: Obiously leaks memory.
|
||||
}
|
||||
return audioFile->position;
|
||||
}
|
||||
|
||||
return fseek((FILE*)audioFile->fileHandle, offset, origin);
|
||||
}
|
||||
|
||||
// 0x41AD20
|
||||
long audioFileGetSize(int fileHandle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioFileList[fileHandle - 1]);
|
||||
return audioFile->fileSize;
|
||||
}
|
||||
|
||||
// 0x41AD3C
|
||||
long audioFileTell(int fileHandle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioFileList[fileHandle - 1]);
|
||||
return audioFile->position;
|
||||
}
|
||||
|
||||
// AudiofWrite
|
||||
// 0x41AD58
|
||||
int audioFileWrite(int fileHandle, const void* buffer, unsigned int size)
|
||||
{
|
||||
debugPrint("AudiofWrite shouldn't be ever called\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x41AD68
|
||||
int audioFileInit(AudioFileIsCompressedProc* isCompressedProc)
|
||||
{
|
||||
_queryCompressedFunc_2 = isCompressedProc;
|
||||
gAudioFileList = NULL;
|
||||
gAudioFileListLength = 0;
|
||||
|
||||
return soundSetDefaultFileIO(audioFileOpen, audioFileClose, audioFileRead, audioFileWrite, audioFileSeek, audioFileTell, audioFileGetSize);
|
||||
}
|
||||
|
||||
// 0x41ADAC
|
||||
void audioFileExit()
|
||||
{
|
||||
if (gAudioFileList != NULL) {
|
||||
internal_free_safe(gAudioFileList, __FILE__, __LINE__); // "..\int\audiof.c", 405
|
||||
}
|
||||
|
||||
gAudioFileListLength = 0;
|
||||
gAudioFileList = NULL;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef AUDIO_FILE_H
|
||||
#define AUDIO_FILE_H
|
||||
|
||||
#include "sound_decoder.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum AudioFileFlags {
|
||||
AUDIO_FILE_IN_USE = 0x01,
|
||||
AUDIO_FILE_COMPRESSED = 0x02,
|
||||
} AudioFileFlags;
|
||||
|
||||
typedef struct AudioFile {
|
||||
int flags;
|
||||
int fileHandle;
|
||||
SoundDecoder* soundDecoder;
|
||||
int fileSize;
|
||||
int field_10;
|
||||
int field_14;
|
||||
int position;
|
||||
} AudioFile;
|
||||
|
||||
typedef bool(AudioFileIsCompressedProc)(char* filePath);
|
||||
|
||||
extern AudioFileIsCompressedProc* _queryCompressedFunc_2;
|
||||
|
||||
extern AudioFile* gAudioFileList;
|
||||
extern int gAudioFileListLength;
|
||||
|
||||
bool _defaultCompressionFunc__(char* filePath);
|
||||
int audioFileSoundDecoderReadHandler(int fileHandle, void* buffer, unsigned int size);
|
||||
int audioFileOpen(const char* fname, int flags, ...);
|
||||
int audioFileClose(int a1);
|
||||
int audioFileRead(int a1, void* buf, unsigned int size);
|
||||
int audioFileSeek(int handle, long offset, int origin);
|
||||
long audioFileGetSize(int a1);
|
||||
long audioFileTell(int a1);
|
||||
int audioFileWrite(int handle, const void* buf, unsigned int size);
|
||||
int audioFileInit(AudioFileIsCompressedProc* isCompressedProc);
|
||||
void audioFileExit();
|
||||
|
||||
#endif /* AUDIO_FILE_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,102 @@
|
|||
#ifndef AUTOMAP_H
|
||||
#define AUTOMAP_H
|
||||
|
||||
#include "db.h"
|
||||
#include "map_defs.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define AUTOMAP_DB ("AUTOMAP.DB")
|
||||
#define AUTOMAP_TMP ("AUTOMAP.TMP")
|
||||
|
||||
// The number of map entries that is stored in automap.db.
|
||||
//
|
||||
// NOTE: I don't know why this value is not equal to the number of maps.
|
||||
#define AUTOMAP_MAP_COUNT (160)
|
||||
|
||||
#define AUTOMAP_OFFSET_COUNT (AUTOMAP_MAP_COUNT * ELEVATION_COUNT)
|
||||
|
||||
#define AUTOMAP_WINDOW_X (75)
|
||||
#define AUTOMAP_WINDOW_Y (0)
|
||||
#define AUTOMAP_WINDOW_WIDTH (519)
|
||||
#define AUTOMAP_WINDOW_HEIGHT (480)
|
||||
|
||||
#define AUTOMAP_PIPBOY_VIEW_X (238)
|
||||
#define AUTOMAP_PIPBOY_VIEW_Y (105)
|
||||
|
||||
// View options for rendering automap for map window. These are stored in
|
||||
// [gAutomapFlags] and is saved in save game file.
|
||||
typedef enum AutomapFlags {
|
||||
// NOTE: This is a special flag to denote the map is activated in the game (as
|
||||
// opposed to the mapper). It's always on. Turning it off produces nice color
|
||||
// coded map with all objects and their types visible, however there is no way
|
||||
// you can do it within the game UI.
|
||||
AUTOMAP_IN_GAME = 0x01,
|
||||
|
||||
// High details is on.
|
||||
AUTOMAP_WTH_HIGH_DETAILS = 0x02,
|
||||
|
||||
// Scanner is active.
|
||||
AUTOMAP_WITH_SCANNER = 0x04,
|
||||
} AutomapFlags;
|
||||
|
||||
typedef enum AutomapFrm {
|
||||
AUTOMAP_FRM_BACKGROUND,
|
||||
AUTOMAP_FRM_BUTTON_UP,
|
||||
AUTOMAP_FRM_BUTTON_DOWN,
|
||||
AUTOMAP_FRM_SWITCH_UP,
|
||||
AUTOMAP_FRM_SWITCH_DOWN,
|
||||
AUTOMAP_FRM_COUNT,
|
||||
} AutomapFrm;
|
||||
|
||||
typedef struct AutomapHeader {
|
||||
unsigned char version;
|
||||
|
||||
// The size of entire automap database (including header itself).
|
||||
int dataSize;
|
||||
|
||||
// Offsets from the beginning of the automap database file into
|
||||
// entries data.
|
||||
//
|
||||
// These offsets are specified for every map/elevation combination. A value
|
||||
// of 0 specifies that there is no data for appropriate map/elevation
|
||||
// combination.
|
||||
int offsets[AUTOMAP_MAP_COUNT][ELEVATION_COUNT];
|
||||
} AutomapHeader;
|
||||
|
||||
typedef struct AutomapEntry {
|
||||
int dataSize;
|
||||
unsigned char isCompressed;
|
||||
unsigned char* compressedData;
|
||||
unsigned char* data;
|
||||
} AutomapEntry;
|
||||
|
||||
extern const int _defam[AUTOMAP_MAP_COUNT][ELEVATION_COUNT];
|
||||
extern const int _displayMapList[AUTOMAP_MAP_COUNT];
|
||||
extern const int gAutomapFrmIds[AUTOMAP_FRM_COUNT];
|
||||
|
||||
extern int gAutomapFlags;
|
||||
|
||||
extern AutomapHeader gAutomapHeader;
|
||||
extern AutomapEntry gAutomapEntry;
|
||||
|
||||
int automapInit();
|
||||
int automapReset();
|
||||
void automapExit();
|
||||
int automapLoad(File* stream);
|
||||
int automapSave(File* stream);
|
||||
int _automapDisplayMap(int map);
|
||||
void automapShow(bool isInGame, bool isUsingScanner);
|
||||
void automapRenderInMapWindow(int window, int elevation, unsigned char* backgroundData, int flags);
|
||||
int automapRenderInPipboyWindow(int win, int map, int elevation);
|
||||
int automapSaveCurrent();
|
||||
int automapSaveEntry(File* stream);
|
||||
int automapLoadEntry(int map, int elevation);
|
||||
int automapSaveHeader(File* stream);
|
||||
int automapLoadHeader(File* stream);
|
||||
void _decode_map_data(int elevation);
|
||||
int automapCreate();
|
||||
int _copy_file_data(File* stream1, File* stream2, int length);
|
||||
int automapGetHeader(AutomapHeader** automapHeaderPtr);
|
||||
|
||||
#endif /* AUTOMAP_H */
|
|
@ -0,0 +1,24 @@
|
|||
#include "autorun.h"
|
||||
|
||||
// 0x530010
|
||||
HANDLE gInterplayGenericAutorunMutex;
|
||||
|
||||
// 0x4139C0
|
||||
bool autorunMutexCreate()
|
||||
{
|
||||
gInterplayGenericAutorunMutex = CreateMutexA(NULL, FALSE, "InterplayGenericAutorunMutex");
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||
CloseHandle(gInterplayGenericAutorunMutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x413A00
|
||||
void autorunMutexClose()
|
||||
{
|
||||
if (gInterplayGenericAutorunMutex != NULL) {
|
||||
CloseHandle(gInterplayGenericAutorunMutex);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef AUTORUN_H
|
||||
#define AUTORUN_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
extern HANDLE gInterplayGenericAutorunMutex;
|
||||
|
||||
bool autorunMutexCreate();
|
||||
void autorunMutexClose();
|
||||
|
||||
#endif /* AUTORUN_H */
|
|
@ -0,0 +1,598 @@
|
|||
#include "cache.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "memory.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static_assert(sizeof(CacheEntry) == 32, "wrong size");
|
||||
static_assert(sizeof(Cache) == 84, "wrong size");
|
||||
|
||||
// 0x510938
|
||||
int _lock_sound_ticker = 0;
|
||||
|
||||
// cache_init
|
||||
// 0x41FCC0
|
||||
bool cacheInit(Cache* cache, CacheSizeProc* sizeProc, CacheReadProc* readProc, CacheFreeProc* freeProc, int maxSize)
|
||||
{
|
||||
if (!heapInit(&(cache->heap), maxSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cache->size = 0;
|
||||
cache->maxSize = maxSize;
|
||||
cache->entriesLength = 0;
|
||||
cache->entriesCapacity = CACHE_ENTRIES_INITIAL_CAPACITY;
|
||||
cache->hits = 0;
|
||||
cache->entries = internal_malloc(sizeof(*cache->entries) * cache->entriesCapacity);
|
||||
cache->sizeProc = sizeProc;
|
||||
cache->readProc = readProc;
|
||||
cache->freeProc = freeProc;
|
||||
|
||||
if (cache->entries == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(cache->entries, 0, sizeof(*cache->entries) * cache->entriesCapacity);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// cache_exit
|
||||
// 0x41FD50
|
||||
bool cacheFree(Cache* cache)
|
||||
{
|
||||
if (cache == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cacheClean(cache);
|
||||
cacheFlush(cache);
|
||||
heapFree(&(cache->heap));
|
||||
|
||||
cache->size = 0;
|
||||
cache->maxSize = 0;
|
||||
cache->entriesLength = 0;
|
||||
cache->entriesCapacity = 0;
|
||||
cache->hits = 0;
|
||||
|
||||
if (cache->entries != NULL) {
|
||||
internal_free(cache->entries);
|
||||
cache->entries = NULL;
|
||||
}
|
||||
|
||||
cache->sizeProc = NULL;
|
||||
cache->readProc = NULL;
|
||||
cache->freeProc = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x41FDE8
|
||||
bool cacheLock(Cache* cache, int key, void** data, CacheEntry** cacheEntryPtr)
|
||||
{
|
||||
if (cache == NULL || data == NULL || cacheEntryPtr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*cacheEntryPtr = NULL;
|
||||
|
||||
int index;
|
||||
int rc = cacheFindIndexForKey(cache, key, &index);
|
||||
if (rc == 2) {
|
||||
// Use existing cache entry.
|
||||
CacheEntry* cacheEntry = cache->entries[index];
|
||||
cacheEntry->hits++;
|
||||
} else if (rc == 3) {
|
||||
// New cache entry is required.
|
||||
if (cache->entriesLength >= INT_MAX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!cacheFetchEntryForKey(cache, key, &index)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_lock_sound_ticker %= 4;
|
||||
if (_lock_sound_ticker == 0) {
|
||||
soundContinueAll();
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
CacheEntry* cacheEntry = cache->entries[index];
|
||||
if (cacheEntry->referenceCount == 0) {
|
||||
if (!heapLock(&(cache->heap), cacheEntry->heapHandleIndex, &(cacheEntry->data))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
cacheEntry->referenceCount++;
|
||||
|
||||
cache->hits++;
|
||||
cacheEntry->mru = cache->hits;
|
||||
|
||||
if (cache->hits == UINT_MAX) {
|
||||
cacheResetStatistics(cache);
|
||||
}
|
||||
|
||||
*data = cacheEntry->data;
|
||||
*cacheEntryPtr = cacheEntry;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4200B8
|
||||
bool cacheUnlock(Cache* cache, CacheEntry* cacheEntry)
|
||||
{
|
||||
if (cache == NULL || cacheEntry == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cacheEntry->referenceCount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cacheEntry->referenceCount--;
|
||||
|
||||
if (cacheEntry->referenceCount == 0) {
|
||||
heapUnlock(&(cache->heap), cacheEntry->heapHandleIndex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// cache_flush
|
||||
// 0x42012C
|
||||
bool cacheFlush(Cache* cache)
|
||||
{
|
||||
if (cache == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Loop thru cache entries and mark those with no references for eviction.
|
||||
for (int index = 0; index < cache->entriesLength; index++) {
|
||||
CacheEntry* cacheEntry = cache->entries[index];
|
||||
if (cacheEntry->referenceCount == 0) {
|
||||
cacheEntry->flags |= CACHE_ENTRY_MARKED_FOR_EVICTION;
|
||||
}
|
||||
}
|
||||
|
||||
// Sweep cache entries marked earlier.
|
||||
cacheSweep(cache);
|
||||
|
||||
// Shrink cache entries array if it's too big.
|
||||
int optimalCapacity = cache->entriesLength + CACHE_ENTRIES_GROW_CAPACITY;
|
||||
if (optimalCapacity < cache->entriesCapacity) {
|
||||
cacheSetCapacity(cache, optimalCapacity);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x42019C
|
||||
bool cachePrintStats(Cache* cache, char* dest)
|
||||
{
|
||||
if (cache == NULL || dest == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sprintf(dest, "Cache stats are disabled.%s", "\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fetches entry for the specified key into the cache.
|
||||
//
|
||||
// 0x4203AC
|
||||
bool cacheFetchEntryForKey(Cache* cache, int key, int* indexPtr)
|
||||
{
|
||||
CacheEntry* cacheEntry = internal_malloc(sizeof(*cacheEntry));
|
||||
if (cacheEntry == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!cacheEntryInit(cacheEntry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
int size;
|
||||
if (cache->sizeProc(key, &size) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!cacheEnsureSize(cache, size)) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool allocated = false;
|
||||
int cacheEntrySize = size;
|
||||
for (int attempt = 0; attempt < 10; attempt++) {
|
||||
if (heapBlockAllocate(&(cache->heap), &(cacheEntry->heapHandleIndex), size, 1)) {
|
||||
allocated = true;
|
||||
break;
|
||||
}
|
||||
|
||||
cacheEntrySize = (int)((double)cacheEntrySize + (double)size * 0.25);
|
||||
if (cacheEntrySize > cache->maxSize) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!cacheEnsureSize(cache, cacheEntrySize)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!allocated) {
|
||||
cacheFlush(cache);
|
||||
|
||||
allocated = true;
|
||||
if (!heapBlockAllocate(&(cache->heap), &(cacheEntry->heapHandleIndex), size, 1)) {
|
||||
if (!heapBlockAllocate(&(cache->heap), &(cacheEntry->heapHandleIndex), size, 0)) {
|
||||
allocated = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!allocated) {
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
if (!heapLock(&(cache->heap), cacheEntry->heapHandleIndex, &(cacheEntry->data))) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (cache->readProc(key, &size, cacheEntry->data) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
heapUnlock(&(cache->heap), cacheEntry->heapHandleIndex);
|
||||
|
||||
cacheEntry->size = size;
|
||||
cacheEntry->key = key;
|
||||
|
||||
bool isNewKey = true;
|
||||
if (*indexPtr < cache->entriesLength) {
|
||||
if (key < cache->entries[*indexPtr]->key) {
|
||||
if (*indexPtr == 0 || key > cache->entries[*indexPtr - 1]->key) {
|
||||
isNewKey = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isNewKey) {
|
||||
if (cacheFindIndexForKey(cache, key, indexPtr) != 3) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cacheInsertEntryAtIndex(cache, cacheEntry, *indexPtr)) {
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
} while (0);
|
||||
|
||||
heapUnlock(&(cache->heap), cacheEntry->heapHandleIndex);
|
||||
} while (0);
|
||||
|
||||
// NOTE: Uninline.
|
||||
cacheEntryFree(cache, cacheEntry);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x4205E8
|
||||
bool cacheInsertEntryAtIndex(Cache* cache, CacheEntry* cacheEntry, int index)
|
||||
{
|
||||
// Ensure cache have enough space for new entry.
|
||||
if (cache->entriesLength == cache->entriesCapacity - 1) {
|
||||
if (!cacheSetCapacity(cache, cache->entriesCapacity + CACHE_ENTRIES_GROW_CAPACITY)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Move entries below insertion point.
|
||||
memmove(&(cache->entries[index + 1]), &(cache->entries[index]), sizeof(*cache->entries) * (cache->entriesLength - index));
|
||||
|
||||
cache->entries[index] = cacheEntry;
|
||||
cache->entriesLength++;
|
||||
cache->size += cacheEntry->size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Finds index for given key.
|
||||
//
|
||||
// Returns 2 if entry already exists in cache, or 3 if entry does not exist. In
|
||||
// this case indexPtr represents insertion point.
|
||||
//
|
||||
// 0x420654
|
||||
int cacheFindIndexForKey(Cache* cache, int key, int* indexPtr)
|
||||
{
|
||||
int length = cache->entriesLength;
|
||||
if (length == 0) {
|
||||
*indexPtr = 0;
|
||||
return 3;
|
||||
}
|
||||
|
||||
int r = length - 1;
|
||||
int l = 0;
|
||||
int mid;
|
||||
int cmp;
|
||||
|
||||
do {
|
||||
mid = (l + r) / 2;
|
||||
|
||||
cmp = key - cache->entries[mid]->key;
|
||||
if (cmp == 0) {
|
||||
*indexPtr = mid;
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (cmp > 0) {
|
||||
l = l + 1;
|
||||
} else {
|
||||
r = r - 1;
|
||||
}
|
||||
} while (r >= l);
|
||||
|
||||
if (cmp < 0) {
|
||||
*indexPtr = mid;
|
||||
} else {
|
||||
*indexPtr = mid + 1;
|
||||
}
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
// 0x420708
|
||||
bool cacheEntryInit(CacheEntry* cacheEntry)
|
||||
{
|
||||
cacheEntry->key = 0;
|
||||
cacheEntry->size = 0;
|
||||
cacheEntry->data = NULL;
|
||||
cacheEntry->referenceCount = 0;
|
||||
cacheEntry->hits = 0;
|
||||
cacheEntry->flags = 0;
|
||||
cacheEntry->mru = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x420740
|
||||
bool cacheEntryFree(Cache* cache, CacheEntry* cacheEntry)
|
||||
{
|
||||
if (cacheEntry->data != NULL) {
|
||||
heapBlockDeallocate(&(cache->heap), &(cacheEntry->heapHandleIndex));
|
||||
}
|
||||
|
||||
internal_free(cacheEntry);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x420764
|
||||
bool cacheClean(Cache* cache)
|
||||
{
|
||||
Heap* heap = &(cache->heap);
|
||||
for (int index = 0; index < cache->entriesLength; index++) {
|
||||
CacheEntry* cacheEntry = cache->entries[index];
|
||||
|
||||
// NOTE: Original code is slightly different. For unknown reason it uses
|
||||
// inner loop to decrement `referenceCount` one by one. Probably using
|
||||
// some inlined function.
|
||||
if (cacheEntry->referenceCount != 0) {
|
||||
heapUnlock(heap, cacheEntry->heapHandleIndex);
|
||||
cacheEntry->referenceCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4207D4
|
||||
bool cacheResetStatistics(Cache* cache)
|
||||
{
|
||||
if (cache == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CacheEntry** entries = internal_malloc(sizeof(*entries) * cache->entriesLength);
|
||||
if (entries == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(entries, cache->entries, sizeof(*entries) * cache->entriesLength);
|
||||
|
||||
qsort(entries, cache->entriesLength, sizeof(*entries), cacheEntriesCompareByMostRecentHit);
|
||||
|
||||
for (int index = 0; index < cache->entriesLength; index++) {
|
||||
CacheEntry* cacheEntry = entries[index];
|
||||
cacheEntry->mru = index;
|
||||
}
|
||||
|
||||
cache->hits = cache->entriesLength;
|
||||
|
||||
// FIXME: Obviously leak `entries`.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Prepare cache for storing new entry with the specified size.
|
||||
//
|
||||
// 0x42084C
|
||||
bool cacheEnsureSize(Cache* cache, int size)
|
||||
{
|
||||
if (size > cache->maxSize) {
|
||||
// The entry of given size is too big for caching, no matter what.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cache->maxSize - cache->size >= size) {
|
||||
// There is space available for entry of given size, there is no need to
|
||||
// evict anything.
|
||||
return true;
|
||||
}
|
||||
|
||||
CacheEntry** entries = internal_malloc(sizeof(*entries) * cache->entriesLength);
|
||||
if (entries != NULL) {
|
||||
memcpy(entries, cache->entries, sizeof(*entries) * cache->entriesLength);
|
||||
qsort(entries, cache->entriesLength, sizeof(*entries), cacheEntriesCompareByUsage);
|
||||
|
||||
// The sweeping threshold is 20% of cache size plus size for the new
|
||||
// entry. Once the threshold is reached the marking process stops.
|
||||
int threshold = size + (int)((double)cache->size * 0.2);
|
||||
|
||||
int accum = 0;
|
||||
int index;
|
||||
for (index = 0; index < cache->entriesLength; index++) {
|
||||
CacheEntry* entry = entries[index];
|
||||
if (entry->referenceCount == 0) {
|
||||
if (entry->size >= threshold) {
|
||||
entry->flags |= CACHE_ENTRY_MARKED_FOR_EVICTION;
|
||||
|
||||
// We've just found one huge entry, there is no point to
|
||||
// mark individual smaller entries in the code path below,
|
||||
// reset the accumulator to skip it entirely.
|
||||
accum = 0;
|
||||
break;
|
||||
} else {
|
||||
accum += entry->size;
|
||||
|
||||
if (accum >= threshold) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (accum != 0) {
|
||||
// The loop below assumes index to be positioned on the entry, where
|
||||
// accumulator stopped. If we've reached the end, reposition
|
||||
// it to the last entry.
|
||||
if (index == cache->entriesLength) {
|
||||
index -= 1;
|
||||
}
|
||||
|
||||
// Loop backwards from the point we've stopped and mark all
|
||||
// unreferenced entries for sweeping.
|
||||
for (; index >= 0; index--) {
|
||||
CacheEntry* entry = entries[index];
|
||||
if (entry->referenceCount == 0) {
|
||||
entry->flags |= CACHE_ENTRY_MARKED_FOR_EVICTION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal_free(entries);
|
||||
}
|
||||
|
||||
cacheSweep(cache);
|
||||
|
||||
if (cache->maxSize - cache->size >= size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x42099C
|
||||
bool cacheSweep(Cache* cache)
|
||||
{
|
||||
for (int index = 0; index < cache->entriesLength; index++) {
|
||||
CacheEntry* cacheEntry = cache->entries[index];
|
||||
if ((cacheEntry->flags & CACHE_ENTRY_MARKED_FOR_EVICTION) != 0) {
|
||||
if (cacheEntry->referenceCount != 0) {
|
||||
// Entry was marked for eviction but still has references,
|
||||
// unmark it.
|
||||
cacheEntry->flags &= ~CACHE_ENTRY_MARKED_FOR_EVICTION;
|
||||
} else {
|
||||
int cacheEntrySize = cacheEntry->size;
|
||||
|
||||
// NOTE: Uninline.
|
||||
cacheEntryFree(cache, cacheEntry);
|
||||
|
||||
// Move entries up.
|
||||
memmove(&(cache->entries[index]), &(cache->entries[index + 1]), sizeof(*cache->entries) * ((cache->entriesLength - index) - 1));
|
||||
|
||||
cache->entriesLength--;
|
||||
cache->size -= cacheEntrySize;
|
||||
|
||||
// The entry was removed, compensate index.
|
||||
index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x420A40
|
||||
bool cacheSetCapacity(Cache* cache, int newCapacity)
|
||||
{
|
||||
if (newCapacity < cache->entriesLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CacheEntry** entries = internal_realloc(cache->entries, sizeof(*cache->entries) * newCapacity);
|
||||
if (entries == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cache->entries = entries;
|
||||
cache->entriesCapacity = newCapacity;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x420A74
|
||||
int cacheEntriesCompareByUsage(const void* a1, const void* a2)
|
||||
{
|
||||
CacheEntry* v1 = *(CacheEntry**)a1;
|
||||
CacheEntry* v2 = *(CacheEntry**)a2;
|
||||
|
||||
if (v1->referenceCount != 0 && v2->referenceCount == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (v2->referenceCount != 0 && v1->referenceCount == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (v1->hits < v2->hits) {
|
||||
return -1;
|
||||
} else if (v1->hits > v2->hits) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (v1->mru < v2->mru) {
|
||||
return -1;
|
||||
} else if (v1->mru > v2->mru) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x420AE8
|
||||
int cacheEntriesCompareByMostRecentHit(const void* a1, const void* a2)
|
||||
{
|
||||
CacheEntry* v1 = *(CacheEntry**)a1;
|
||||
CacheEntry* v2 = *(CacheEntry**)a2;
|
||||
|
||||
if (v1->mru < v2->mru) {
|
||||
return 1;
|
||||
} else if (v1->mru > v2->mru) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
#ifndef CACHE_H
|
||||
#define CACHE_H
|
||||
|
||||
#include "heap.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define INVALID_CACHE_ENTRY ((CacheEntry*)-1)
|
||||
|
||||
// The initial number of cache entries in new cache.
|
||||
#define CACHE_ENTRIES_INITIAL_CAPACITY (100)
|
||||
|
||||
// The number of cache entries added when cache capacity is reached.
|
||||
#define CACHE_ENTRIES_GROW_CAPACITY (50)
|
||||
|
||||
typedef enum CacheEntryFlags {
|
||||
// Specifies that cache entry has no references as should be evicted during
|
||||
// the next sweep operation.
|
||||
CACHE_ENTRY_MARKED_FOR_EVICTION = 0x01,
|
||||
} CacheEntryFlags;
|
||||
|
||||
typedef int CacheSizeProc(int key, int* sizePtr);
|
||||
typedef int CacheReadProc(int key, int* sizePtr, unsigned char* buffer);
|
||||
typedef void CacheFreeProc(void* ptr);
|
||||
|
||||
typedef struct CacheEntry {
|
||||
int key;
|
||||
int size;
|
||||
unsigned char* data;
|
||||
unsigned int referenceCount;
|
||||
|
||||
// Total number of hits that this cache entry received during it's
|
||||
// lifetime.
|
||||
unsigned int hits;
|
||||
|
||||
CacheEntryFlags flags;
|
||||
|
||||
// The most recent hit in terms of cache hit counter. Used to track most
|
||||
// recently used entries in eviction strategy.
|
||||
unsigned int mru;
|
||||
|
||||
int heapHandleIndex;
|
||||
} CacheEntry;
|
||||
|
||||
typedef struct Cache {
|
||||
// Current size of entries in cache.
|
||||
int size;
|
||||
|
||||
// Maximum size of entries in cache.
|
||||
int maxSize;
|
||||
|
||||
// The length of `entries` array.
|
||||
int entriesLength;
|
||||
|
||||
// The capacity of `entries` array.
|
||||
int entriesCapacity;
|
||||
|
||||
// Total number of hits during cache lifetime.
|
||||
unsigned int hits;
|
||||
|
||||
// List of cache entries.
|
||||
CacheEntry** entries;
|
||||
|
||||
CacheSizeProc* sizeProc;
|
||||
CacheReadProc* readProc;
|
||||
CacheFreeProc* freeProc;
|
||||
Heap heap;
|
||||
} Cache;
|
||||
|
||||
bool cacheInit(Cache* cache, CacheSizeProc* sizeProc, CacheReadProc* readProc, CacheFreeProc* freeProc, int maxSize);
|
||||
bool cacheFree(Cache* cache);
|
||||
bool cacheLock(Cache* cache, int key, void** data, CacheEntry** cacheEntryPtr);
|
||||
bool cacheUnlock(Cache* cache, CacheEntry* cacheEntry);
|
||||
bool cacheFlush(Cache* cache);
|
||||
bool cachePrintStats(Cache* cache, char* dest);
|
||||
bool cacheFetchEntryForKey(Cache* cache, int key, int* indexPtr);
|
||||
bool cacheInsertEntryAtIndex(Cache* cache, CacheEntry* cacheEntry, int index);
|
||||
int cacheFindIndexForKey(Cache* cache, int key, int* indexPtr);
|
||||
bool cacheEntryInit(CacheEntry* cacheEntry);
|
||||
bool cacheEntryFree(Cache* cache, CacheEntry* cacheEntry);
|
||||
bool cacheClean(Cache* cache);
|
||||
bool cacheResetStatistics(Cache* cache);
|
||||
bool cacheEnsureSize(Cache* cache, int size);
|
||||
bool cacheSweep(Cache* cache);
|
||||
bool cacheSetCapacity(Cache* cache, int newCapacity);
|
||||
int cacheEntriesCompareByUsage(const void* a1, const void* a2);
|
||||
int cacheEntriesCompareByMostRecentHit(const void* a1, const void* a2);
|
||||
|
||||
#endif /* CACHE_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,313 @@
|
|||
#ifndef CHARACTER_EDITOR_H
|
||||
#define CHARACTER_EDITOR_H
|
||||
|
||||
#include "art.h"
|
||||
#include "db.h"
|
||||
#include "geometry.h"
|
||||
#include "message.h"
|
||||
#include "perk_defs.h"
|
||||
#include "proto_types.h"
|
||||
#include "skill_defs.h"
|
||||
#include "stat_defs.h"
|
||||
#include "trait_defs.h"
|
||||
|
||||
#define DIALOG_PICKER_NUM_OPTIONS max(PERK_COUNT, TRAIT_COUNT)
|
||||
#define TOWN_REPUTATION_COUNT 19
|
||||
#define ADDICTION_REPUTATION_COUNT 8
|
||||
|
||||
typedef enum EditorFolder {
|
||||
EDITOR_FOLDER_PERKS,
|
||||
EDITOR_FOLDER_KARMA,
|
||||
EDITOR_FOLDER_KILLS,
|
||||
} EditorFolder;
|
||||
|
||||
enum {
|
||||
EDITOR_DERIVED_STAT_ARMOR_CLASS,
|
||||
EDITOR_DERIVED_STAT_ACTION_POINTS,
|
||||
EDITOR_DERIVED_STAT_CARRY_WEIGHT,
|
||||
EDITOR_DERIVED_STAT_MELEE_DAMAGE,
|
||||
EDITOR_DERIVED_STAT_DAMAGE_RESISTANCE,
|
||||
EDITOR_DERIVED_STAT_POISON_RESISTANCE,
|
||||
EDITOR_DERIVED_STAT_RADIATION_RESISTANCE,
|
||||
EDITOR_DERIVED_STAT_SEQUENCE,
|
||||
EDITOR_DERIVED_STAT_HEALING_RATE,
|
||||
EDITOR_DERIVED_STAT_CRITICAL_CHANCE,
|
||||
EDITOR_DERIVED_STAT_COUNT,
|
||||
};
|
||||
|
||||
enum {
|
||||
EDITOR_FIRST_PRIMARY_STAT,
|
||||
EDITOR_HIT_POINTS = 43,
|
||||
EDITOR_POISONED,
|
||||
EDITOR_RADIATED,
|
||||
EDITOR_EYE_DAMAGE,
|
||||
EDITOR_CRIPPLED_RIGHT_ARM,
|
||||
EDITOR_CRIPPLED_LEFT_ARM,
|
||||
EDITOR_CRIPPLED_RIGHT_LEG,
|
||||
EDITOR_CRIPPLED_LEFT_LEG,
|
||||
EDITOR_FIRST_DERIVED_STAT,
|
||||
EDITOR_FIRST_SKILL = EDITOR_FIRST_DERIVED_STAT + EDITOR_DERIVED_STAT_COUNT,
|
||||
EDITOR_TAG_SKILL = EDITOR_FIRST_SKILL + SKILL_COUNT,
|
||||
EDITOR_SKILLS,
|
||||
EDITOR_OPTIONAL_TRAITS,
|
||||
EDITOR_FIRST_TRAIT,
|
||||
EDITOR_BUTTONS_COUNT = EDITOR_FIRST_TRAIT + TRAIT_COUNT,
|
||||
};
|
||||
|
||||
enum {
|
||||
EDITOR_GRAPHIC_BIG_NUMBERS,
|
||||
EDITOR_GRAPHIC_AGE_MASK,
|
||||
EDITOR_GRAPHIC_AGE_OFF,
|
||||
EDITOR_GRAPHIC_DOWN_ARROW_OFF,
|
||||
EDITOR_GRAPHIC_DOWN_ARROW_ON,
|
||||
EDITOR_GRAPHIC_NAME_MASK,
|
||||
EDITOR_GRAPHIC_NAME_ON,
|
||||
EDITOR_GRAPHIC_NAME_OFF,
|
||||
EDITOR_GRAPHIC_FOLDER_MASK, // mask for all three folders
|
||||
EDITOR_GRAPHIC_SEX_MASK,
|
||||
EDITOR_GRAPHIC_SEX_OFF,
|
||||
EDITOR_GRAPHIC_SEX_ON,
|
||||
EDITOR_GRAPHIC_SLIDER, // image containing small plus/minus buttons appeared near selected skill
|
||||
EDITOR_GRAPHIC_SLIDER_MINUS_OFF,
|
||||
EDITOR_GRAPHIC_SLIDER_MINUS_ON,
|
||||
EDITOR_GRAPHIC_SLIDER_PLUS_OFF,
|
||||
EDITOR_GRAPHIC_SLIDER_PLUS_ON,
|
||||
EDITOR_GRAPHIC_SLIDER_TRANS_MINUS_OFF,
|
||||
EDITOR_GRAPHIC_SLIDER_TRANS_MINUS_ON,
|
||||
EDITOR_GRAPHIC_SLIDER_TRANS_PLUS_OFF,
|
||||
EDITOR_GRAPHIC_SLIDER_TRANS_PLUS_ON,
|
||||
EDITOR_GRAPHIC_UP_ARROW_OFF,
|
||||
EDITOR_GRAPHIC_UP_ARROW_ON,
|
||||
EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP,
|
||||
EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN,
|
||||
EDITOR_GRAPHIC_AGE_ON,
|
||||
EDITOR_GRAPHIC_AGE_BOX, // image containing right and left buttons with age stepper in the middle
|
||||
EDITOR_GRAPHIC_ATTRIBOX, // ??? black image with two little arrows (up and down) in the right-top corner
|
||||
EDITOR_GRAPHIC_ATTRIBWN, // ??? not sure where and when it's used
|
||||
EDITOR_GRAPHIC_CHARWIN, // ??? looks like metal plate
|
||||
EDITOR_GRAPHIC_DONE_BOX, // metal plate holding DONE button
|
||||
EDITOR_GRAPHIC_FEMALE_OFF,
|
||||
EDITOR_GRAPHIC_FEMALE_ON,
|
||||
EDITOR_GRAPHIC_MALE_OFF,
|
||||
EDITOR_GRAPHIC_MALE_ON,
|
||||
EDITOR_GRAPHIC_NAME_BOX, // placeholder for name
|
||||
EDITOR_GRAPHIC_LEFT_ARROW_UP,
|
||||
EDITOR_GRAPHIC_LEFT_ARROW_DOWN,
|
||||
EDITOR_GRAPHIC_RIGHT_ARROW_UP,
|
||||
EDITOR_GRAPHIC_RIGHT_ARROW_DOWN,
|
||||
EDITOR_GRAPHIC_BARARRWS, // ??? two arrows up/down with some strange knob at the top, probably for scrollbar
|
||||
EDITOR_GRAPHIC_OPTIONS_BASE, // options metal plate
|
||||
EDITOR_GRAPHIC_OPTIONS_BUTTON_OFF,
|
||||
EDITOR_GRAPHIC_OPTIONS_BUTTON_ON,
|
||||
EDITOR_GRAPHIC_KARMA_FOLDER_SELECTED, // all three folders with middle folder selected (karma)
|
||||
EDITOR_GRAPHIC_KILLS_FOLDER_SELECTED, // all theee folders with right folder selected (kills)
|
||||
EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED, // all three folders with left folder selected (perks)
|
||||
EDITOR_GRAPHIC_KARMAFDR_PLACEOLDER, // ??? placeholder for traits folder image <- this is comment from intrface.lst
|
||||
EDITOR_GRAPHIC_TAG_SKILL_BUTTON_OFF,
|
||||
EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON,
|
||||
EDITOR_GRAPHIC_COUNT,
|
||||
};
|
||||
|
||||
typedef struct KarmaEntry {
|
||||
int gvar;
|
||||
int art_num;
|
||||
int name;
|
||||
int description;
|
||||
} KarmaEntry;
|
||||
|
||||
typedef struct GenericReputationEntry {
|
||||
int threshold;
|
||||
int name;
|
||||
} GenericReputationEntry;
|
||||
|
||||
typedef struct TownReputationEntry {
|
||||
int gvar;
|
||||
int city;
|
||||
} TownReputationEntry;
|
||||
|
||||
typedef struct STRUCT_56FCB0 {
|
||||
int field_0;
|
||||
char* field_4;
|
||||
} STRUCT_56FCB0;
|
||||
|
||||
// TODO: Field order is probably wrong.
|
||||
typedef struct KillInfo {
|
||||
const char* name;
|
||||
int killTypeId;
|
||||
int kills;
|
||||
} KillInfo;
|
||||
|
||||
extern int _grph_id[50];
|
||||
extern const unsigned char _copyflag[EDITOR_GRAPHIC_COUNT];
|
||||
extern const int word_431D3A[EDITOR_DERIVED_STAT_COUNT];
|
||||
extern const int _StatYpos[7];
|
||||
extern const int word_431D6C[EDITOR_DERIVED_STAT_COUNT];
|
||||
extern char byte_431D93[64];
|
||||
extern const int dword_431DD4[7];
|
||||
|
||||
extern const double dbl_50170B;
|
||||
extern const double dbl_501713;
|
||||
extern const double dbl_5018F0;
|
||||
extern const double dbl_5019BE;
|
||||
|
||||
extern bool _bk_enable_0;
|
||||
extern int _skill_cursor;
|
||||
extern int _slider_y;
|
||||
extern int characterEditorRemainingCharacterPoints;
|
||||
extern KarmaEntry* gKarmaEntries;
|
||||
extern int gKarmaEntriesLength;
|
||||
extern GenericReputationEntry* gGenericReputationEntries;
|
||||
extern int gGenericReputationEntriesLength;
|
||||
extern const TownReputationEntry gTownReputationEntries[TOWN_REPUTATION_COUNT];
|
||||
extern const int gAddictionReputationVars[ADDICTION_REPUTATION_COUNT];
|
||||
extern const int gAddictionReputationFrmIds[ADDICTION_REPUTATION_COUNT];
|
||||
extern int _folder_up_button;
|
||||
extern int _folder_down_button;
|
||||
|
||||
extern char _folder_card_string[256];
|
||||
extern int _skillsav[SKILL_COUNT];
|
||||
extern MessageList editorMessageList;
|
||||
extern STRUCT_56FCB0 _name_sort_list[DIALOG_PICKER_NUM_OPTIONS];
|
||||
extern int _trait_bids[TRAIT_COUNT];
|
||||
extern MessageListItem editorMessageListItem;
|
||||
extern char _old_str1[48];
|
||||
extern char _old_str2[48];
|
||||
extern int _tag_bids[SKILL_COUNT];
|
||||
extern char _name_save[32];
|
||||
extern Size _GInfo[EDITOR_GRAPHIC_COUNT];
|
||||
extern CacheEntry* _grph_key[EDITOR_GRAPHIC_COUNT];
|
||||
extern unsigned char* _grphcpy[EDITOR_GRAPHIC_COUNT];
|
||||
extern unsigned char* _grphbmp[EDITOR_GRAPHIC_COUNT];
|
||||
extern int _folder_max_lines;
|
||||
extern int _folder_line;
|
||||
extern int _folder_card_fid;
|
||||
extern int _folder_top_line;
|
||||
extern char* _folder_card_title;
|
||||
extern char* _folder_card_title2;
|
||||
extern int _folder_yoffset;
|
||||
extern int _folder_karma_top_line;
|
||||
extern int _folder_highlight_line;
|
||||
extern char* _folder_card_desc;
|
||||
extern int _folder_ypos;
|
||||
extern int _folder_kills_top_line;
|
||||
extern int _folder_perk_top_line;
|
||||
extern unsigned char* gEditorPerkBackgroundBuffer;
|
||||
extern int gEditorPerkWindow;
|
||||
extern int _SliderPlusID;
|
||||
extern int _SliderNegID;
|
||||
extern int _stat_bids_minus[7];
|
||||
extern unsigned char* characterEditorWindowBuf;
|
||||
extern int characterEditorWindowHandle;
|
||||
extern int _stat_bids_plus[7];
|
||||
extern unsigned char* gEditorPerkWindowBuffer;
|
||||
extern CritterProtoData _dude_data;
|
||||
extern unsigned char* characterEditorWindowBackgroundBuf;
|
||||
extern int _cline;
|
||||
extern int _oldsline;
|
||||
extern int _upsent_points_back;
|
||||
extern int _last_level;
|
||||
extern int characterEditorWindowOldFont;
|
||||
extern int _kills_count;
|
||||
extern CacheEntry* _bck_key;
|
||||
extern int _hp_back;
|
||||
extern int _mouse_ypos;
|
||||
extern int _mouse_xpos;
|
||||
extern int characterEditorSelectedItem;
|
||||
extern int characterEditorWindowSelectedFolder;
|
||||
extern int _frstc_draw1;
|
||||
extern int _crow;
|
||||
extern int _frstc_draw2;
|
||||
extern int _perk_back[PERK_COUNT];
|
||||
extern unsigned int _repFtime;
|
||||
extern unsigned int _frame_time;
|
||||
extern int _old_tags;
|
||||
extern int _last_level_back;
|
||||
extern bool gCharacterEditorIsCreationMode;
|
||||
extern int _tag_skill_back[NUM_TAGGED_SKILLS];
|
||||
extern int _card_old_fid2;
|
||||
extern int _card_old_fid1;
|
||||
extern int _trait_back[3];
|
||||
extern int _trait_count;
|
||||
extern int _optrt_count;
|
||||
extern int _temp_trait[3];
|
||||
extern int _tagskill_count;
|
||||
extern int _temp_tag_skill[NUM_TAGGED_SKILLS];
|
||||
extern char _free_perk_back;
|
||||
extern unsigned char _free_perk;
|
||||
extern unsigned char _first_skill_list;
|
||||
|
||||
int _editor_design(bool isCreationMode);
|
||||
int characterEditorWindowInit();
|
||||
void characterEditorWindowFree();
|
||||
void _CharEditInit();
|
||||
int _get_input_str(int win, int cancelKeyCode, char* text, int maxLength, int x, int y, int textColor, int backgroundColor, int flags);
|
||||
bool _isdoschar(int ch);
|
||||
char* _strmfe(char* dest, const char* name, const char* ext);
|
||||
void editorRenderFolders();
|
||||
void editorRenderPerks();
|
||||
int _kills_list_comp(const KillInfo* a, const KillInfo* b);
|
||||
int editorRenderKills();
|
||||
void characterEditorRenderBigNumber(int x, int y, int flags, int value, int previousValue, int windowHandle);
|
||||
void editorRenderPcStats();
|
||||
void editorRenderPrimaryStat(int stat, bool animate, int previousValue);
|
||||
void editorRenderGender();
|
||||
void editorRenderAge();
|
||||
void editorRenderName();
|
||||
void editorRenderSecondaryStats();
|
||||
void editorRenderSkills(int a1);
|
||||
void editorRenderDetails();
|
||||
int characterEditorEditName();
|
||||
void _PrintName(unsigned char* buf, int a2);
|
||||
int characterEditorRunEditAgeDialog();
|
||||
void characterEditorEditGender();
|
||||
void characterEditorHandleIncDecPrimaryStat(int eventCode);
|
||||
int _OptionWindow();
|
||||
bool characterFileExists(const char* fname);
|
||||
int characterPrintToFile(const char* fileName);
|
||||
char* _AddSpaces(char* string, int length);
|
||||
char* _AddDots(char* string, int length);
|
||||
void _ResetScreen();
|
||||
void _RegInfoAreas();
|
||||
void _SavePlayer();
|
||||
void _RestorePlayer();
|
||||
char* _itostndn(int value, char* dest);
|
||||
int _DrawCard(int graphicId, const char* name, const char* attributes, char* description);
|
||||
void _FldrButton();
|
||||
void _InfoButton(int eventCode);
|
||||
void editorAdjustSkill(int a1);
|
||||
void characterEditorToggleTaggedSkill(int skill);
|
||||
void characterEditorWindowRenderTraits();
|
||||
void characterEditorToggleOptionalTrait(int trait);
|
||||
void editorRenderKarma();
|
||||
int _editor_save(File* stream);
|
||||
int _editor_load(File* stream);
|
||||
void _editor_reset();
|
||||
int _UpdateLevel();
|
||||
void _RedrwDPrks();
|
||||
int editorSelectPerk();
|
||||
int _InputPDLoop(int count, void (*refreshProc)());
|
||||
int _ListDPerks();
|
||||
void _RedrwDMPrk();
|
||||
bool editorHandleMutate();
|
||||
void _RedrwDMTagSkl();
|
||||
bool editorHandleTag();
|
||||
void _ListNewTagSkills();
|
||||
int _ListMyTraits(int a1);
|
||||
int _name_sort_comp(const void* a1, const void* a2);
|
||||
int _DrawCard2(int frmId, const char* name, const char* rank, char* description);
|
||||
void _pop_perks();
|
||||
int _is_supper_bonus();
|
||||
int _folder_init();
|
||||
void _folder_scroll(int direction);
|
||||
void _folder_clear();
|
||||
int _folder_print_seperator(const char* string);
|
||||
bool _folder_print_line(const char* string);
|
||||
bool editorDrawKillsEntry(const char* name, int kills);
|
||||
int karmaInit();
|
||||
void karmaFree();
|
||||
int karmaEntryCompare(const void* a1, const void* a2);
|
||||
int genericReputationInit();
|
||||
void genericReputationFree();
|
||||
int genericReputationCompare(const void* a1, const void* a2);
|
||||
|
||||
#endif /* CHARACTER_EDITOR_H */
|
|
@ -0,0 +1,940 @@
|
|||
#include "character_selector.h"
|
||||
|
||||
#include "character_editor.h"
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
#include "critter.h"
|
||||
#include "db.h"
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "game_sound.h"
|
||||
#include "memory.h"
|
||||
#include "message.h"
|
||||
#include "object.h"
|
||||
#include "options.h"
|
||||
#include "palette.h"
|
||||
#include "proto.h"
|
||||
#include "skill.h"
|
||||
#include "stat.h"
|
||||
#include "text_font.h"
|
||||
#include "trait.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// 0x51C84C
|
||||
int gCurrentPremadeCharacter = PREMADE_CHARACTER_NARG;
|
||||
|
||||
// 0x51C850
|
||||
PremadeCharacterDescription gPremadeCharacterDescriptions[PREMADE_CHARACTER_COUNT] = {
|
||||
{ "premade\\combat", 201, "VID 208-197-88-125" },
|
||||
{ "premade\\stealth", 202, "VID 208-206-49-229" },
|
||||
{ "premade\\diplomat", 203, "VID 208-206-49-227" },
|
||||
};
|
||||
|
||||
// 0x51C8D4
|
||||
const int gPremadeCharacterCount = PREMADE_CHARACTER_COUNT;
|
||||
|
||||
// 0x51C7F8
|
||||
int gCharacterSelectorWindow = -1;
|
||||
|
||||
// 0x51C7FC
|
||||
unsigned char* gCharacterSelectorWindowBuffer = NULL;
|
||||
|
||||
// 0x51C800
|
||||
unsigned char* gCharacterSelectorBackground = NULL;
|
||||
|
||||
// 0x51C804
|
||||
int gCharacterSelectorWindowPreviousButton = -1;
|
||||
|
||||
// 0x51C808
|
||||
CacheEntry* gCharacterSelectorWindowPreviousButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C80C
|
||||
CacheEntry* gCharacterSelectorWindowPreviousButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C810
|
||||
int gCharacterSelectorWindowNextButton = -1;
|
||||
|
||||
// 0x51C814
|
||||
CacheEntry* gCharacterSelectorWindowNextButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C818
|
||||
CacheEntry* gCharacterSelectorWindowNextButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C81C
|
||||
int gCharacterSelectorWindowTakeButton = -1;
|
||||
|
||||
// 0x51C820
|
||||
CacheEntry* gCharacterSelectorWindowTakeButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C824
|
||||
CacheEntry* gCharacterSelectorWindowTakeButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C828
|
||||
int gCharacterSelectorWindowModifyButton = -1;
|
||||
|
||||
// 0x51C82C
|
||||
CacheEntry* gCharacterSelectorWindowModifyButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C830
|
||||
CacheEntry* gCharacterSelectorWindowModifyButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C834
|
||||
int gCharacterSelectorWindowCreateButton = -1;
|
||||
|
||||
// 0x51C838
|
||||
CacheEntry* gCharacterSelectorWindowCreateButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C83C
|
||||
CacheEntry* gCharacterSelectorWindowCreateButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C840
|
||||
int gCharacterSelectorWindowBackButton = -1;
|
||||
|
||||
// 0x51C844
|
||||
CacheEntry* gCharacterSelectorWindowBackButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C848
|
||||
CacheEntry* gCharacterSelectorWindowBackButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x667764
|
||||
unsigned char* gCharacterSelectorWindowTakeButtonUpFrmData;
|
||||
|
||||
// 0x667768
|
||||
unsigned char* gCharacterSelectorWindowModifyButtonDownFrmData;
|
||||
|
||||
// 0x66776C
|
||||
unsigned char* gCharacterSelectorWindowBackButtonUpFrmData;
|
||||
|
||||
// 0x667770
|
||||
unsigned char* gCharacterSelectorWindowCreateButtonUpFrmData;
|
||||
|
||||
// 0x667774
|
||||
unsigned char* gCharacterSelectorWindowModifyButtonUpFrmData;
|
||||
|
||||
// 0x667778
|
||||
unsigned char* gCharacterSelectorWindowBackButtonDownFrmData;
|
||||
|
||||
// 0x66777C
|
||||
unsigned char* gCharacterSelectorWindowCreateButtonDownFrmData;
|
||||
|
||||
// 0x667780
|
||||
unsigned char* gCharacterSelectorWindowTakeButtonDownFrmData;
|
||||
|
||||
// 0x667784
|
||||
unsigned char* gCharacterSelectorWindowNextButtonDownFrmData;
|
||||
|
||||
// 0x667788
|
||||
unsigned char* gCharacterSelectorWindowNextButtonUpFrmData;
|
||||
|
||||
// 0x66778C
|
||||
unsigned char* gCharacterSelectorWindowPreviousButtonUpFrmData;
|
||||
|
||||
// 0x667790
|
||||
unsigned char* gCharacterSelectorWindowPreviousButtonDownFrmData;
|
||||
|
||||
// 0x4A71D0
|
||||
int characterSelectorOpen()
|
||||
{
|
||||
if (!characterSelectorWindowInit()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool cursorWasHidden = cursorIsHidden();
|
||||
if (cursorWasHidden) {
|
||||
mouseShowCursor();
|
||||
}
|
||||
|
||||
colorPaletteLoad("color.pal");
|
||||
paletteFadeTo(_cmap);
|
||||
|
||||
int rc = 0;
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
int keyCode = _get_input();
|
||||
|
||||
switch (keyCode) {
|
||||
case KEY_MINUS:
|
||||
case KEY_UNDERSCORE:
|
||||
brightnessDecrease();
|
||||
break;
|
||||
case KEY_EQUAL:
|
||||
case KEY_PLUS:
|
||||
brightnessIncrease();
|
||||
break;
|
||||
case KEY_UPPERCASE_B:
|
||||
case KEY_LOWERCASE_B:
|
||||
case KEY_ESCAPE:
|
||||
rc = 3;
|
||||
done = true;
|
||||
break;
|
||||
case KEY_UPPERCASE_C:
|
||||
case KEY_LOWERCASE_C:
|
||||
_ResetPlayer();
|
||||
if (_editor_design(1) == 0) {
|
||||
rc = 2;
|
||||
done = true;
|
||||
}
|
||||
|
||||
break;
|
||||
case KEY_UPPERCASE_M:
|
||||
case KEY_LOWERCASE_M:
|
||||
if (!_editor_design(1)) {
|
||||
rc = 2;
|
||||
done = true;
|
||||
}
|
||||
|
||||
break;
|
||||
case KEY_UPPERCASE_T:
|
||||
case KEY_LOWERCASE_T:
|
||||
rc = 2;
|
||||
done = true;
|
||||
|
||||
break;
|
||||
case KEY_F10:
|
||||
showQuitConfirmationDialog();
|
||||
break;
|
||||
case KEY_ARROW_LEFT:
|
||||
soundPlayFile("ib2p1xx1");
|
||||
// FALLTHROUGH
|
||||
case 500:
|
||||
gCurrentPremadeCharacter -= 1;
|
||||
if (gCurrentPremadeCharacter < 0) {
|
||||
gCurrentPremadeCharacter = gPremadeCharacterCount - 1;
|
||||
}
|
||||
|
||||
characterSelectorWindowRefresh();
|
||||
break;
|
||||
case KEY_ARROW_RIGHT:
|
||||
soundPlayFile("ib2p1xx1");
|
||||
// FALLTHROUGH
|
||||
case 501:
|
||||
gCurrentPremadeCharacter += 1;
|
||||
if (gCurrentPremadeCharacter >= gPremadeCharacterCount) {
|
||||
gCurrentPremadeCharacter = 0;
|
||||
}
|
||||
|
||||
characterSelectorWindowRefresh();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
paletteFadeTo(gPaletteBlack);
|
||||
characterSelectorWindowFree();
|
||||
|
||||
if (cursorWasHidden) {
|
||||
mouseHideCursor();
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// 0x4A7468
|
||||
bool characterSelectorWindowInit()
|
||||
{
|
||||
if (gCharacterSelectorWindow != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gCharacterSelectorWindow = windowCreate(0, 0, CS_WINDOW_WIDTH, CS_WINDOW_HEIGHT, _colorTable[0], 0);
|
||||
if (gCharacterSelectorWindow == -1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowBuffer = windowGetBuffer(gCharacterSelectorWindow);
|
||||
if (gCharacterSelectorWindowBuffer == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
int backgroundFid = buildFid(6, 174, 0, 0, 0);
|
||||
unsigned char* backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle);
|
||||
if (backgroundFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
blitBufferToBuffer(backgroundFrmData,
|
||||
CS_WINDOW_WIDTH,
|
||||
CS_WINDOW_HEIGHT,
|
||||
CS_WINDOW_WIDTH,
|
||||
gCharacterSelectorWindowBuffer,
|
||||
CS_WINDOW_WIDTH);
|
||||
|
||||
gCharacterSelectorBackground = internal_malloc(CS_WINDOW_BACKGROUND_WIDTH * CS_WINDOW_BACKGROUND_HEIGHT);
|
||||
if (gCharacterSelectorBackground == NULL)
|
||||
goto err;
|
||||
|
||||
blitBufferToBuffer(backgroundFrmData + 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);
|
||||
|
||||
int fid;
|
||||
|
||||
// Setup "Previous" button.
|
||||
fid = buildFid(6, 122, 0, 0, 0);
|
||||
gCharacterSelectorWindowPreviousButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowPreviousButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowPreviousButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
fid = buildFid(6, 123, 0, 0, 0);
|
||||
gCharacterSelectorWindowPreviousButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowPreviousButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowPreviousButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowPreviousButton = buttonCreate(gCharacterSelectorWindow,
|
||||
CS_WINDOW_PREVIOUS_BUTTON_X,
|
||||
CS_WINDOW_PREVIOUS_BUTTON_Y,
|
||||
20,
|
||||
18,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
500,
|
||||
gCharacterSelectorWindowPreviousButtonUpFrmData,
|
||||
gCharacterSelectorWindowPreviousButtonDownFrmData,
|
||||
NULL,
|
||||
0);
|
||||
if (gCharacterSelectorWindowPreviousButton == -1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowPreviousButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
||||
|
||||
// Setup "Next" button.
|
||||
fid = buildFid(6, 124, 0, 0, 0);
|
||||
gCharacterSelectorWindowNextButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowNextButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowNextButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
fid = buildFid(6, 125, 0, 0, 0);
|
||||
gCharacterSelectorWindowNextButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowNextButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowNextButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowNextButton = buttonCreate(gCharacterSelectorWindow,
|
||||
CS_WINDOW_NEXT_BUTTON_X,
|
||||
CS_WINDOW_NEXT_BUTTON_Y,
|
||||
20,
|
||||
18,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
501,
|
||||
gCharacterSelectorWindowNextButtonUpFrmData,
|
||||
gCharacterSelectorWindowNextButtonDownFrmData,
|
||||
NULL,
|
||||
0);
|
||||
if (gCharacterSelectorWindowNextButton == -1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowNextButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
||||
|
||||
// Setup "Take" button.
|
||||
fid = buildFid(6, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowTakeButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowTakeButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowTakeButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
fid = buildFid(6, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowTakeButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowTakeButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowTakeButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowTakeButton = buttonCreate(gCharacterSelectorWindow,
|
||||
CS_WINDOW_TAKE_BUTTON_X,
|
||||
CS_WINDOW_TAKE_BUTTON_Y,
|
||||
15,
|
||||
16,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
KEY_LOWERCASE_T,
|
||||
gCharacterSelectorWindowTakeButtonUpFrmData,
|
||||
gCharacterSelectorWindowTakeButtonDownFrmData,
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (gCharacterSelectorWindowTakeButton == -1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowTakeButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
|
||||
// Setup "Modify" button.
|
||||
fid = buildFid(6, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowModifyButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowModifyButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowModifyButtonUpFrmData == NULL)
|
||||
goto err;
|
||||
|
||||
fid = buildFid(6, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowModifyButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowModifyButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowModifyButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowModifyButton = buttonCreate(gCharacterSelectorWindow,
|
||||
CS_WINDOW_MODIFY_BUTTON_X,
|
||||
CS_WINDOW_MODIFY_BUTTON_Y,
|
||||
15,
|
||||
16,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
KEY_LOWERCASE_M,
|
||||
gCharacterSelectorWindowModifyButtonUpFrmData,
|
||||
gCharacterSelectorWindowModifyButtonDownFrmData,
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (gCharacterSelectorWindowModifyButton == -1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowModifyButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
|
||||
// Setup "Create" button.
|
||||
fid = buildFid(6, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowCreateButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowCreateButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowCreateButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
fid = buildFid(6, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowCreateButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowCreateButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowCreateButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowCreateButton = buttonCreate(gCharacterSelectorWindow,
|
||||
CS_WINDOW_CREATE_BUTTON_X,
|
||||
CS_WINDOW_CREATE_BUTTON_Y,
|
||||
15,
|
||||
16,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
KEY_LOWERCASE_C,
|
||||
gCharacterSelectorWindowCreateButtonUpFrmData,
|
||||
gCharacterSelectorWindowCreateButtonDownFrmData,
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (gCharacterSelectorWindowCreateButton == -1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowCreateButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
|
||||
// Setup "Back" button.
|
||||
fid = buildFid(6, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowBackButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowBackButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowBackButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
fid = buildFid(6, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowBackButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowBackButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowBackButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowBackButton = buttonCreate(gCharacterSelectorWindow,
|
||||
CS_WINDOW_BACK_BUTTON_X,
|
||||
CS_WINDOW_BACK_BUTTON_Y,
|
||||
15,
|
||||
16,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
KEY_ESCAPE,
|
||||
gCharacterSelectorWindowBackButtonUpFrmData,
|
||||
gCharacterSelectorWindowBackButtonDownFrmData,
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (gCharacterSelectorWindowBackButton == -1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowBackButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
|
||||
gCurrentPremadeCharacter = PREMADE_CHARACTER_NARG;
|
||||
|
||||
windowRefresh(gCharacterSelectorWindow);
|
||||
|
||||
if (!characterSelectorWindowRefresh()) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
err:
|
||||
|
||||
characterSelectorWindowFree();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x4A7AD4
|
||||
void characterSelectorWindowFree()
|
||||
{
|
||||
if (gCharacterSelectorWindow == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowPreviousButton != -1) {
|
||||
buttonDestroy(gCharacterSelectorWindowPreviousButton);
|
||||
gCharacterSelectorWindowPreviousButton = -1;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowPreviousButtonDownFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowPreviousButtonDownFrmHandle);
|
||||
gCharacterSelectorWindowPreviousButtonDownFrmHandle = NULL;
|
||||
gCharacterSelectorWindowPreviousButtonDownFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowPreviousButtonUpFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowPreviousButtonUpFrmHandle);
|
||||
gCharacterSelectorWindowPreviousButtonUpFrmHandle = NULL;
|
||||
gCharacterSelectorWindowPreviousButtonUpFrmData = NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorBackground != NULL) {
|
||||
internal_free(gCharacterSelectorBackground);
|
||||
gCharacterSelectorBackground = NULL;
|
||||
}
|
||||
|
||||
windowDestroy(gCharacterSelectorWindow);
|
||||
gCharacterSelectorWindow = -1;
|
||||
}
|
||||
|
||||
// 0x4A7D58
|
||||
bool characterSelectorWindowRefresh()
|
||||
{
|
||||
char path[FILENAME_MAX];
|
||||
sprintf(path, "%s.gcd", gPremadeCharacterDescriptions[gCurrentPremadeCharacter].fileName);
|
||||
if (_proto_dude_init(path) == -1) {
|
||||
debugPrint("\n ** Error in dude init! **\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
blitBufferToBuffer(gCharacterSelectorBackground,
|
||||
CS_WINDOW_BACKGROUND_WIDTH,
|
||||
CS_WINDOW_BACKGROUND_HEIGHT,
|
||||
CS_WINDOW_BACKGROUND_WIDTH,
|
||||
gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * CS_WINDOW_BACKGROUND_Y + CS_WINDOW_BACKGROUND_X,
|
||||
CS_WINDOW_WIDTH);
|
||||
|
||||
bool success = false;
|
||||
if (characterSelectorWindowRenderFace()) {
|
||||
if (characterSelectorWindowRenderStats()) {
|
||||
success = characterSelectorWindowRenderBio();
|
||||
}
|
||||
}
|
||||
|
||||
windowRefresh(gCharacterSelectorWindow);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// 0x4A7E08
|
||||
bool characterSelectorWindowRenderFace()
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
CacheEntry* faceFrmHandle;
|
||||
int faceFid = buildFid(6, gPremadeCharacterDescriptions[gCurrentPremadeCharacter].face, 0, 0, 0);
|
||||
Art* frm = artLock(faceFid, &faceFrmHandle);
|
||||
if (frm != NULL) {
|
||||
unsigned char* data = artGetFrameData(frm, 0, 0);
|
||||
if (data != NULL) {
|
||||
int width = artGetWidth(frm, 0, 0);
|
||||
int height = artGetHeight(frm, 0, 0);
|
||||
blitBufferToBufferTrans(data, width, height, width, (gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * 23 + 27), CS_WINDOW_WIDTH);
|
||||
success = true;
|
||||
}
|
||||
artUnlock(faceFrmHandle);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// 0x4A7EA8
|
||||
bool characterSelectorWindowRenderStats()
|
||||
{
|
||||
char* str;
|
||||
char text[260];
|
||||
int length;
|
||||
int value;
|
||||
MessageListItem messageListItem;
|
||||
|
||||
int oldFont = fontGetCurrent();
|
||||
fontSetCurrent(101);
|
||||
|
||||
fontGetCharacterWidth(0x20);
|
||||
|
||||
int vh = fontGetLineHeight();
|
||||
int y = 40;
|
||||
|
||||
// NAME
|
||||
str = objectGetName(gDude);
|
||||
strcpy(text, str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_NAME_MID_X - (length / 2), text, 160, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
// STRENGTH
|
||||
y += vh + vh + vh;
|
||||
|
||||
value = critterGetStat(gDude, STAT_STRENGTH);
|
||||
str = statGetName(STAT_STRENGTH);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
// PERCEPTION
|
||||
y += vh;
|
||||
|
||||
value = critterGetStat(gDude, STAT_PERCEPTION);
|
||||
str = statGetName(STAT_PERCEPTION);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
// ENDURANCE
|
||||
y += vh;
|
||||
|
||||
value = critterGetStat(gDude, STAT_ENDURANCE);
|
||||
str = statGetName(STAT_PERCEPTION);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
// CHARISMA
|
||||
y += vh;
|
||||
|
||||
value = critterGetStat(gDude, STAT_CHARISMA);
|
||||
str = statGetName(STAT_CHARISMA);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
// INTELLIGENCE
|
||||
y += vh;
|
||||
|
||||
value = critterGetStat(gDude, STAT_INTELLIGENCE);
|
||||
str = statGetName(STAT_INTELLIGENCE);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
// AGILITY
|
||||
y += vh;
|
||||
|
||||
value = critterGetStat(gDude, STAT_AGILITY);
|
||||
str = statGetName(STAT_AGILITY);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
// LUCK
|
||||
y += vh;
|
||||
|
||||
value = critterGetStat(gDude, STAT_LUCK);
|
||||
str = statGetName(STAT_LUCK);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
y += vh; // blank line
|
||||
|
||||
// HIT POINTS
|
||||
y += vh;
|
||||
|
||||
messageListItem.num = 16;
|
||||
text[0] = '\0';
|
||||
if (messageListGetItem(&gMiscMessageList, &messageListItem)) {
|
||||
strcpy(text, messageListItem.text);
|
||||
}
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
value = critterGetStat(gDude, STAT_MAXIMUM_HIT_POINTS);
|
||||
sprintf(text, " %d/%d", critterGetHitPoints(gDude), value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
// ARMOR CLASS
|
||||
y += vh;
|
||||
|
||||
str = statGetName(STAT_ARMOR_CLASS);
|
||||
strcpy(text, str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
value = critterGetStat(gDude, STAT_ARMOR_CLASS);
|
||||
sprintf(text, " %d", value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
// ACTION POINTS
|
||||
y += vh;
|
||||
|
||||
messageListItem.num = 15;
|
||||
text[0] = '\0';
|
||||
if (messageListGetItem(&gMiscMessageList, &messageListItem)) {
|
||||
strcpy(text, messageListItem.text);
|
||||
}
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
value = critterGetStat(gDude, STAT_MAXIMUM_ACTION_POINTS);
|
||||
sprintf(text, " %d", value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
// MELEE DAMAGE
|
||||
y += vh;
|
||||
|
||||
str = statGetName(STAT_ARMOR_CLASS);
|
||||
strcpy(text, str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
value = critterGetStat(gDude, STAT_ARMOR_CLASS);
|
||||
sprintf(text, " %d", value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
y += vh; // blank line
|
||||
|
||||
// SKILLS
|
||||
int skills[DEFAULT_TAGGED_SKILLS];
|
||||
skillsGetTagged(skills, DEFAULT_TAGGED_SKILLS);
|
||||
|
||||
for (int index = 0; index < DEFAULT_TAGGED_SKILLS; index++) {
|
||||
y += vh;
|
||||
|
||||
str = skillGetName(skills[index]);
|
||||
strcpy(text, str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
value = skillGetValue(gDude, skills[index]);
|
||||
sprintf(text, " %d%%", value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
}
|
||||
|
||||
// TRAITS
|
||||
int traits[TRAITS_MAX_SELECTED_COUNT];
|
||||
traitsGetSelected(&(traits[0]), &(traits[1]));
|
||||
|
||||
for (int index = 0; index < TRAITS_MAX_SELECTED_COUNT; index++) {
|
||||
y += vh;
|
||||
|
||||
str = traitGetName(traits[index]);
|
||||
strcpy(text, str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
}
|
||||
|
||||
fontSetCurrent(oldFont);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4A8AE4
|
||||
bool characterSelectorWindowRenderBio()
|
||||
{
|
||||
int oldFont = fontGetCurrent();
|
||||
fontSetCurrent(101);
|
||||
|
||||
char path[FILENAME_MAX];
|
||||
sprintf(path, "%s.bio", gPremadeCharacterDescriptions[gCurrentPremadeCharacter].fileName);
|
||||
|
||||
File* stream = fileOpen(path, "rt");
|
||||
if (stream != NULL) {
|
||||
int y = 40;
|
||||
int lineHeight = fontGetLineHeight();
|
||||
|
||||
char string[256];
|
||||
while (fileReadString(string, 256, stream) && y < 260) {
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_BIO_X, string, CS_WINDOW_WIDTH - CS_WINDOW_BIO_X, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
y += lineHeight;
|
||||
}
|
||||
|
||||
fileClose(stream);
|
||||
}
|
||||
|
||||
fontSetCurrent(oldFont);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
#ifndef CHARACTER_SELECTOR_H
|
||||
#define CHARACTER_SELECTOR_H
|
||||
|
||||
#include "art.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define CS_WINDOW_WIDTH (640)
|
||||
#define CS_WINDOW_HEIGHT (480)
|
||||
|
||||
#define CS_WINDOW_BACKGROUND_X (40)
|
||||
#define CS_WINDOW_BACKGROUND_Y (30)
|
||||
#define CS_WINDOW_BACKGROUND_WIDTH (560)
|
||||
#define CS_WINDOW_BACKGROUND_HEIGHT (300)
|
||||
|
||||
#define CS_WINDOW_PREVIOUS_BUTTON_X (292)
|
||||
#define CS_WINDOW_PREVIOUS_BUTTON_Y (320)
|
||||
|
||||
#define CS_WINDOW_NEXT_BUTTON_X (318)
|
||||
#define CS_WINDOW_NEXT_BUTTON_Y (320)
|
||||
|
||||
#define CS_WINDOW_TAKE_BUTTON_X (81)
|
||||
#define CS_WINDOW_TAKE_BUTTON_Y (323)
|
||||
|
||||
#define CS_WINDOW_MODIFY_BUTTON_X (435)
|
||||
#define CS_WINDOW_MODIFY_BUTTON_Y (320)
|
||||
|
||||
#define CS_WINDOW_CREATE_BUTTON_X (80)
|
||||
#define CS_WINDOW_CREATE_BUTTON_Y (425)
|
||||
|
||||
#define CS_WINDOW_BACK_BUTTON_X (461)
|
||||
#define CS_WINDOW_BACK_BUTTON_Y (425)
|
||||
|
||||
#define CS_WINDOW_NAME_MID_X (318)
|
||||
#define CS_WINDOW_PRIMARY_STAT_MID_X (362)
|
||||
#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;
|
||||
|
||||
extern int gCurrentPremadeCharacter;
|
||||
extern PremadeCharacterDescription gPremadeCharacterDescriptions[PREMADE_CHARACTER_COUNT];
|
||||
extern const int gPremadeCharacterCount;
|
||||
|
||||
extern int gCharacterSelectorWindow;
|
||||
extern unsigned char* gCharacterSelectorWindowBuffer;
|
||||
extern unsigned char* gCharacterSelectorBackground;
|
||||
extern int gCharacterSelectorWindowPreviousButton;
|
||||
extern CacheEntry* gCharacterSelectorWindowPreviousButtonDownFrmHandle;
|
||||
extern CacheEntry* gCharacterSelectorWindowPreviousButtonUpFrmHandle;
|
||||
extern int gCharacterSelectorWindowNextButton;
|
||||
extern CacheEntry* gCharacterSelectorWindowNextButtonUpFrmHandle;
|
||||
extern CacheEntry* gCharacterSelectorWindowNextButtonDownFrmHandle;
|
||||
extern int gCharacterSelectorWindowTakeButton;
|
||||
extern CacheEntry* gCharacterSelectorWindowTakeButtonUpFrmHandle;
|
||||
extern CacheEntry* gCharacterSelectorWindowTakeButtonDownFrmHandle;
|
||||
extern int gCharacterSelectorWindowModifyButton;
|
||||
extern CacheEntry* gCharacterSelectorWindowModifyButtonUpFrmHandle;
|
||||
extern CacheEntry* gCharacterSelectorWindowModifyButtonDownFrmHandle;
|
||||
extern int gCharacterSelectorWindowCreateButton;
|
||||
extern CacheEntry* gCharacterSelectorWindowCreateButtonUpFrmHandle;
|
||||
extern CacheEntry* gCharacterSelectorWindowCreateButtonDownFrmHandle;
|
||||
extern int gCharacterSelectorWindowBackButton;
|
||||
extern CacheEntry* gCharacterSelectorWindowBackButtonUpFrmHandle;
|
||||
extern CacheEntry* gCharacterSelectorWindowBackButtonDownFrmHandle;
|
||||
|
||||
extern unsigned char* gCharacterSelectorWindowTakeButtonUpFrmData;
|
||||
extern unsigned char* gCharacterSelectorWindowModifyButtonDownFrmData;
|
||||
extern unsigned char* gCharacterSelectorWindowBackButtonUpFrmData;
|
||||
extern unsigned char* gCharacterSelectorWindowCreateButtonUpFrmData;
|
||||
extern unsigned char* gCharacterSelectorWindowModifyButtonUpFrmData;
|
||||
extern unsigned char* gCharacterSelectorWindowBackButtonDownFrmData;
|
||||
extern unsigned char* gCharacterSelectorWindowCreateButtonDownFrmData;
|
||||
extern unsigned char* gCharacterSelectorWindowTakeButtonDownFrmData;
|
||||
extern unsigned char* gCharacterSelectorWindowNextButtonDownFrmData;
|
||||
extern unsigned char* gCharacterSelectorWindowNextButtonUpFrmData;
|
||||
extern unsigned char* gCharacterSelectorWindowPreviousButtonUpFrmData;
|
||||
extern unsigned char* gCharacterSelectorWindowPreviousButtonDownFrmData;
|
||||
|
||||
int characterSelectorOpen();
|
||||
bool characterSelectorWindowInit();
|
||||
void characterSelectorWindowFree();
|
||||
bool characterSelectorWindowRefresh();
|
||||
bool characterSelectorWindowRenderFace();
|
||||
bool characterSelectorWindowRenderStats();
|
||||
bool characterSelectorWindowRenderBio();
|
||||
|
||||
#endif /* CHARACTER_SELECTOR_H */
|
|
@ -0,0 +1,589 @@
|
|||
#include "color.h"
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
// 0x50F930
|
||||
char _aColor_cNoError[] = "color.c: No errors\n";
|
||||
|
||||
// 0x50F95C
|
||||
char _aColor_cColorTa[] = "color.c: color table not found\n";
|
||||
|
||||
// 0x51DF10
|
||||
char* _errorStr = _aColor_cNoError;
|
||||
|
||||
// 0x51DF14
|
||||
bool _colorsInited = false;
|
||||
|
||||
// 0x51DF18
|
||||
double gBrightness = 1.0;
|
||||
|
||||
// 0x51DF20
|
||||
ColorTransitionCallback* gColorPaletteTransitionCallback = NULL;
|
||||
|
||||
// 0x51DF24
|
||||
MallocProc* gColorPaletteMallocProc = colorPaletteMallocDefaultImpl;
|
||||
|
||||
// 0x51DF28
|
||||
ReallocProc* gColorPaletteReallocProc = colorPaletteReallocDefaultImpl;
|
||||
|
||||
// 0x51DF2C
|
||||
FreeProc* gColorPaletteFreeProc = colorPaletteFreeDefaultImpl;
|
||||
|
||||
// 0x51DF30
|
||||
ColorFileNameManger* gColorFileNameMangler = NULL;
|
||||
|
||||
// 0x51DF34
|
||||
unsigned char _cmap[768] = {
|
||||
0x3F, 0x3F, 0x3F
|
||||
};
|
||||
|
||||
// 0x673090
|
||||
unsigned char _systemCmap[256 * 3];
|
||||
|
||||
// 0x673390
|
||||
unsigned char _currentGammaTable[64];
|
||||
|
||||
// 0x6733D0
|
||||
unsigned char* _blendTable[256];
|
||||
|
||||
// 0x6737D0
|
||||
unsigned char _mappedColor[256];
|
||||
|
||||
// 0x6738D0
|
||||
unsigned char _colorMixAddTable[65536];
|
||||
|
||||
// 0x6838D0
|
||||
unsigned char _intensityColorTable[65536];
|
||||
|
||||
// 0x6938D0
|
||||
unsigned char _colorMixMulTable[65536];
|
||||
|
||||
// 0x6A38D0
|
||||
unsigned char _colorTable[32768];
|
||||
|
||||
// 0x6AB928
|
||||
ColorPaletteFileReadProc* gColorPaletteFileReadProc;
|
||||
|
||||
// 0x6AB92C
|
||||
ColorPaletteCloseProc* gColorPaletteFileCloseProc;
|
||||
|
||||
// 0x6AB930
|
||||
ColorPaletteFileOpenProc* gColorPaletteFileOpenProc;
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4C7200
|
||||
int colorPaletteFileOpen(const char* filePath, int flags)
|
||||
{
|
||||
if (gColorPaletteFileOpenProc != NULL) {
|
||||
return gColorPaletteFileOpenProc(filePath, flags);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4C7218
|
||||
int colorPaletteFileRead(int fd, void* buffer, size_t size)
|
||||
{
|
||||
if (gColorPaletteFileReadProc != NULL) {
|
||||
return gColorPaletteFileReadProc(fd, buffer, size);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4C7230
|
||||
int colorPaletteFileClose(int fd)
|
||||
{
|
||||
if (gColorPaletteFileCloseProc != NULL) {
|
||||
return gColorPaletteFileCloseProc(fd);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x4C7248
|
||||
void colorPaletteSetFileIO(ColorPaletteFileOpenProc* openProc, ColorPaletteFileReadProc* readProc, ColorPaletteCloseProc* closeProc)
|
||||
{
|
||||
gColorPaletteFileOpenProc = openProc;
|
||||
gColorPaletteFileReadProc = readProc;
|
||||
gColorPaletteFileCloseProc = closeProc;
|
||||
}
|
||||
|
||||
// 0x4C725C
|
||||
void* colorPaletteMallocDefaultImpl(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
// 0x4C7264
|
||||
void* colorPaletteReallocDefaultImpl(void* ptr, size_t size)
|
||||
{
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
// 0x4C726C
|
||||
void colorPaletteFreeDefaultImpl(void* ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
// 0x4C72B4
|
||||
int _calculateColor(int a1, int a2)
|
||||
{
|
||||
int v1 = (a1 >> 9) + ((a2 & 0xFF) << 8);
|
||||
return _intensityColorTable[v1];
|
||||
}
|
||||
|
||||
// 0x4C72E0
|
||||
int _Color2RGB_(int a1)
|
||||
{
|
||||
int v1, v2, v3;
|
||||
|
||||
v1 = _cmap[3 * a1] >> 1;
|
||||
v2 = _cmap[3 * a1 + 1] >> 1;
|
||||
v3 = _cmap[3 * a1 + 2] >> 1;
|
||||
|
||||
return (((v1 << 5) | v2) << 5) | v3;
|
||||
}
|
||||
|
||||
// Performs animated palette transition.
|
||||
//
|
||||
// 0x4C7320
|
||||
void colorPaletteFadeBetween(unsigned char* oldPalette, unsigned char* newPalette, int steps)
|
||||
{
|
||||
for (int step = 0; step < steps; step++) {
|
||||
unsigned char palette[768];
|
||||
|
||||
for (int index = 0; index < 768; index++) {
|
||||
palette[index] = oldPalette[index] - (oldPalette[index] - newPalette[index]) * step / steps;
|
||||
}
|
||||
|
||||
if (gColorPaletteTransitionCallback != NULL) {
|
||||
if (step % 128 == 0) {
|
||||
gColorPaletteTransitionCallback();
|
||||
}
|
||||
}
|
||||
|
||||
_setSystemPalette(palette);
|
||||
}
|
||||
|
||||
_setSystemPalette(newPalette);
|
||||
}
|
||||
|
||||
// 0x4C73D4
|
||||
void colorPaletteSetTransitionCallback(ColorTransitionCallback* callback)
|
||||
{
|
||||
gColorPaletteTransitionCallback = callback;
|
||||
}
|
||||
|
||||
// 0x4C73E4
|
||||
void _setSystemPalette(unsigned char* palette)
|
||||
{
|
||||
unsigned char newPalette[768];
|
||||
|
||||
for (int index = 0; index < 768; index++) {
|
||||
newPalette[index] = _currentGammaTable[palette[index]];
|
||||
_systemCmap[index] = palette[index];
|
||||
}
|
||||
|
||||
directDrawSetPalette(newPalette);
|
||||
}
|
||||
|
||||
// 0x4C7420
|
||||
unsigned char* _getSystemPalette()
|
||||
{
|
||||
return _systemCmap;
|
||||
}
|
||||
|
||||
// 0x4C7428
|
||||
void _setSystemPaletteEntries(unsigned char* palette, int start, int end)
|
||||
{
|
||||
unsigned char newPalette[768];
|
||||
|
||||
int length = end - start + 1;
|
||||
for (int index = 0; index < length; index++) {
|
||||
newPalette[index * 3] = _currentGammaTable[palette[index * 3]];
|
||||
newPalette[index * 3 + 1] = _currentGammaTable[palette[index * 3 + 1]];
|
||||
newPalette[index * 3 + 2] = _currentGammaTable[palette[index * 3 + 2]];
|
||||
|
||||
_systemCmap[start * 3 + index * 3] = palette[index * 3];
|
||||
_systemCmap[start * 3 + index * 3 + 1] = palette[index * 3 + 1];
|
||||
_systemCmap[start * 3 + index * 3 + 2] = palette[index * 3 + 2];
|
||||
}
|
||||
|
||||
directDrawSetPaletteInRange(newPalette, start, end - start + 1);
|
||||
}
|
||||
|
||||
// 0x4C7550
|
||||
void _setIntensityTableColor(int a1)
|
||||
{
|
||||
int v1, v2, v3, v4, v5, v6, v7, v8, v9, v10;
|
||||
|
||||
v5 = 0;
|
||||
v10 = a1 << 8;
|
||||
|
||||
for (int index = 0; index < 128; index++) {
|
||||
v1 = (_Color2RGB_(a1) & 0x7C00) >> 10;
|
||||
v2 = (_Color2RGB_(a1) & 0x3E0) >> 5;
|
||||
v3 = (_Color2RGB_(a1) & 0x1F);
|
||||
|
||||
v4 = (((v1 * v5) >> 16) << 10) | (((v2 * v5) >> 16) << 5) | ((v3 * v5) >> 16);
|
||||
_intensityColorTable[index + v10] = _colorTable[v4];
|
||||
|
||||
v6 = v1 + (((0x1F - v1) * v5) >> 16);
|
||||
v7 = v2 + (((0x1F - v2) * v5) >> 16);
|
||||
v8 = v3 + (((0x1F - v3) * v5) >> 16);
|
||||
|
||||
v9 = (v6 << 10) | (v7 << 5) | v8;
|
||||
_intensityColorTable[0x7F + index + 1 + v10] = _colorTable[v9];
|
||||
|
||||
v5 += 0x200;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C7658
|
||||
void _setIntensityTables()
|
||||
{
|
||||
for (int index = 0; index < 256; index++) {
|
||||
if (_mappedColor[index] != 0) {
|
||||
_setIntensityTableColor(index);
|
||||
} else {
|
||||
memset(_intensityColorTable + index * 256, 0, 256);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C769C
|
||||
void _setMixTableColor(int a1)
|
||||
{
|
||||
int i;
|
||||
int v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19;
|
||||
int v20, v21, v22, v23, v24, v25, v26, v27, v28, v29;
|
||||
|
||||
v1 = a1 << 8;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (_mappedColor[a1] && _mappedColor[i]) {
|
||||
v2 = (_Color2RGB_(a1) & 0x7C00) >> 10;
|
||||
v3 = (_Color2RGB_(a1) & 0x3E0) >> 5;
|
||||
v4 = (_Color2RGB_(a1) & 0x1F);
|
||||
|
||||
v5 = (_Color2RGB_(i) & 0x7C00) >> 10;
|
||||
v6 = (_Color2RGB_(i) & 0x3E0) >> 5;
|
||||
v7 = (_Color2RGB_(i) & 0x1F);
|
||||
|
||||
v8 = v2 + v5;
|
||||
v9 = v3 + v6;
|
||||
v10 = v4 + v7;
|
||||
|
||||
v11 = v8;
|
||||
|
||||
if (v9 > v11) {
|
||||
v11 = v9;
|
||||
}
|
||||
|
||||
if (v10 > v11) {
|
||||
v11 = v10;
|
||||
}
|
||||
|
||||
if (v11 <= 0x1F) {
|
||||
int paletteIndex = (v8 << 10) | (v9 << 5) | v10;
|
||||
v12 = _colorTable[paletteIndex];
|
||||
} else {
|
||||
v13 = v11 - 0x1F;
|
||||
|
||||
v14 = v8 - v13;
|
||||
v15 = v9 - v13;
|
||||
v16 = v10 - v13;
|
||||
|
||||
if (v14 < 0) {
|
||||
v14 = 0;
|
||||
}
|
||||
|
||||
if (v15 < 0) {
|
||||
v15 = 0;
|
||||
}
|
||||
|
||||
if (v16 < 0) {
|
||||
v16 = 0;
|
||||
}
|
||||
|
||||
v17 = (v14 << 10) | (v15 << 5) | v16;
|
||||
v18 = _colorTable[v17];
|
||||
|
||||
v19 = (int)((((double)v11 + (-31.0)) * 0.0078125 + 1.0) * 65536.0);
|
||||
v12 = _calculateColor(v19, v18);
|
||||
}
|
||||
|
||||
_colorMixAddTable[v1 + i] = v12;
|
||||
|
||||
v20 = (_Color2RGB_(a1) & 0x7C00) >> 10;
|
||||
v21 = (_Color2RGB_(a1) & 0x3E0) >> 5;
|
||||
v22 = (_Color2RGB_(a1) & 0x1F);
|
||||
|
||||
v23 = (_Color2RGB_(i) & 0x7C00) >> 10;
|
||||
v24 = (_Color2RGB_(i) & 0x3E0) >> 5;
|
||||
v25 = (_Color2RGB_(i) & 0x1F);
|
||||
|
||||
v26 = (v20 * v23) >> 5;
|
||||
v27 = (v21 * v24) >> 5;
|
||||
v28 = (v22 * v25) >> 5;
|
||||
|
||||
v29 = (v26 << 10) | (v27 << 5) | v28;
|
||||
_colorMixMulTable[v1 + i] = _colorTable[v29];
|
||||
} else {
|
||||
if (_mappedColor[i]) {
|
||||
_colorMixAddTable[v1 + i] = i;
|
||||
_colorMixMulTable[v1 + i] = i;
|
||||
} else {
|
||||
_colorMixAddTable[v1 + i] = a1;
|
||||
_colorMixMulTable[v1 + i] = a1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C78E4
|
||||
bool colorPaletteLoad(char* path)
|
||||
{
|
||||
if (gColorFileNameMangler != NULL) {
|
||||
path = gColorFileNameMangler(path);
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
int fd = colorPaletteFileOpen(path, 0x200);
|
||||
if (fd == -1) {
|
||||
_errorStr = _aColor_cColorTa;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int index = 0; index < 256; index++) {
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, &r, sizeof(r));
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, &g, sizeof(g));
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, &b, sizeof(b));
|
||||
|
||||
if (r <= 0x3F && g <= 0x3F && b <= 0x3F) {
|
||||
_mappedColor[index] = 1;
|
||||
} else {
|
||||
r = 0;
|
||||
g = 0;
|
||||
b = 0;
|
||||
_mappedColor[index] = 0;
|
||||
}
|
||||
|
||||
_cmap[index * 3] = r;
|
||||
_cmap[index * 3 + 1] = g;
|
||||
_cmap[index * 3 + 2] = b;
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, _colorTable, 0x8000);
|
||||
|
||||
unsigned int type;
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, &type, sizeof(type));
|
||||
|
||||
// NOTE: The value is "NEWC". Original code uses cmp opcode, not stricmp,
|
||||
// or comparing characters one-by-one.
|
||||
if (type == 0x4E455743) {
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, _intensityColorTable, 0x10000);
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, _colorMixAddTable, 0x10000);
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, _colorMixMulTable, 0x10000);
|
||||
} else {
|
||||
_setIntensityTables();
|
||||
|
||||
for (int index = 0; index < 256; index++) {
|
||||
_setMixTableColor(index);
|
||||
}
|
||||
}
|
||||
|
||||
_rebuildColorBlendTables();
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileClose(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4C7AB4
|
||||
char* _colorError()
|
||||
{
|
||||
return _errorStr;
|
||||
}
|
||||
|
||||
// 0x4C7B44
|
||||
void _buildBlendTable(unsigned char* ptr, unsigned char ch)
|
||||
{
|
||||
int r, g, b;
|
||||
int i, j;
|
||||
int v12, v14, v16;
|
||||
unsigned char* beg;
|
||||
|
||||
beg = ptr;
|
||||
|
||||
r = (_Color2RGB_(ch) & 0x7C00) >> 10;
|
||||
g = (_Color2RGB_(ch) & 0x3E0) >> 5;
|
||||
b = (_Color2RGB_(ch) & 0x1F);
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
ptr[i] = i;
|
||||
}
|
||||
|
||||
ptr += 256;
|
||||
|
||||
int b_1 = b;
|
||||
int v31 = 6;
|
||||
int g_1 = g;
|
||||
int r_1 = r;
|
||||
|
||||
int b_2 = b_1;
|
||||
int g_2 = g_1;
|
||||
int r_2 = r_1;
|
||||
|
||||
for (j = 0; j < 7; j++) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
v12 = (_Color2RGB_(i) & 0x7C00) >> 10;
|
||||
v14 = (_Color2RGB_(i) & 0x3E0) >> 5;
|
||||
v16 = (_Color2RGB_(i) & 0x1F);
|
||||
int index = 0;
|
||||
index |= (r_2 + v12 * v31) / 7 << 10;
|
||||
index |= (g_2 + v14 * v31) / 7 << 5;
|
||||
index |= (b_2 + v16 * v31) / 7;
|
||||
ptr[i] = _colorTable[index];
|
||||
}
|
||||
v31--;
|
||||
ptr += 256;
|
||||
r_2 += r_1;
|
||||
g_2 += g_1;
|
||||
b_2 += b_1;
|
||||
}
|
||||
|
||||
int v18 = 0;
|
||||
for (j = 0; j < 6; j++) {
|
||||
int v20 = v18 / 7 + 0xFFFF;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
ptr[i] = _calculateColor(v20, ch);
|
||||
}
|
||||
|
||||
v18 += 0x10000;
|
||||
ptr += 256;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C7D90
|
||||
void _rebuildColorBlendTables()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (_blendTable[i]) {
|
||||
_buildBlendTable(_blendTable[i], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C7DC0
|
||||
unsigned char* _getColorBlendTable(int ch)
|
||||
{
|
||||
unsigned char* ptr;
|
||||
|
||||
if (_blendTable[ch] == NULL) {
|
||||
ptr = (unsigned char*)gColorPaletteMallocProc(4100);
|
||||
*(int*)ptr = 1;
|
||||
_blendTable[ch] = ptr + 4;
|
||||
_buildBlendTable(_blendTable[ch], ch);
|
||||
}
|
||||
|
||||
ptr = _blendTable[ch];
|
||||
*(int*)((unsigned char*)ptr - 4) = *(int*)((unsigned char*)ptr - 4) + 1;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// 0x4C7E20
|
||||
void _freeColorBlendTable(int a1)
|
||||
{
|
||||
unsigned char* v2 = _blendTable[a1];
|
||||
if (v2 != NULL) {
|
||||
int* count = (int*)(v2 - sizeof(int));
|
||||
*count -= 1;
|
||||
if (*count == 0) {
|
||||
gColorPaletteFreeProc(count);
|
||||
_blendTable[a1] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C7E58
|
||||
void colorPaletteSetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc)
|
||||
{
|
||||
gColorPaletteMallocProc = mallocProc;
|
||||
gColorPaletteReallocProc = reallocProc;
|
||||
gColorPaletteFreeProc = freeProc;
|
||||
}
|
||||
|
||||
// 0x4C7E6C
|
||||
void colorSetBrightness(double value)
|
||||
{
|
||||
gBrightness = value;
|
||||
|
||||
for (int i = 0; i < 64; i++) {
|
||||
double value = pow(i, gBrightness);
|
||||
_currentGammaTable[i] = (unsigned char)min(max(value, 0.0), 63.0);
|
||||
}
|
||||
|
||||
_setSystemPalette(_systemCmap);
|
||||
}
|
||||
|
||||
// 0x4C89CC
|
||||
bool _initColors()
|
||||
{
|
||||
if (_colorsInited) {
|
||||
return true;
|
||||
}
|
||||
|
||||
_colorsInited = true;
|
||||
|
||||
colorSetBrightness(1.0);
|
||||
|
||||
if (!colorPaletteLoad("color.pal")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_setSystemPalette(_cmap);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4C8A18
|
||||
void _colorsClose()
|
||||
{
|
||||
for (int index = 0; index < 256; index++) {
|
||||
_freeColorBlendTable(index);
|
||||
}
|
||||
|
||||
// TODO: Incomplete.
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
#ifndef COLOR_H
|
||||
#define COLOR_H
|
||||
|
||||
#include "memory_defs.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef char*(ColorFileNameManger)(char*);
|
||||
typedef void(ColorTransitionCallback)();
|
||||
|
||||
typedef int(ColorPaletteFileOpenProc)(const char* path, int mode);
|
||||
typedef int(ColorPaletteFileReadProc)(int fd, void* buffer, size_t size);
|
||||
typedef int(ColorPaletteCloseProc)(int fd);
|
||||
|
||||
extern char _aColor_cNoError[];
|
||||
extern char _aColor_cColorTa[];
|
||||
|
||||
extern char* _errorStr;
|
||||
extern bool _colorsInited;
|
||||
extern double gBrightness;
|
||||
extern ColorTransitionCallback* gColorPaletteTransitionCallback;
|
||||
extern MallocProc* gColorPaletteMallocProc;
|
||||
extern ReallocProc* gColorPaletteReallocProc;
|
||||
extern FreeProc* gColorPaletteFreeProc;
|
||||
extern ColorFileNameManger* gColorFileNameMangler;
|
||||
extern unsigned char _cmap[768];
|
||||
|
||||
extern unsigned char _systemCmap[256 * 3];
|
||||
extern unsigned char _currentGammaTable[64];
|
||||
extern unsigned char* _blendTable[256];
|
||||
extern unsigned char _mappedColor[256];
|
||||
extern unsigned char _colorMixAddTable[65536];
|
||||
extern unsigned char _intensityColorTable[65536];
|
||||
extern unsigned char _colorMixMulTable[65536];
|
||||
extern unsigned char _colorTable[32768];
|
||||
extern ColorPaletteFileReadProc* gColorPaletteFileReadProc;
|
||||
extern ColorPaletteCloseProc* gColorPaletteFileCloseProc;
|
||||
extern ColorPaletteFileOpenProc* gColorPaletteFileOpenProc;
|
||||
|
||||
int colorPaletteFileOpen(const char* filePath, int flags);
|
||||
int colorPaletteFileRead(int fd, void* buffer, size_t size);
|
||||
int colorPaletteFileClose(int fd);
|
||||
void colorPaletteSetFileIO(ColorPaletteFileOpenProc* openProc, ColorPaletteFileReadProc* readProc, ColorPaletteCloseProc* closeProc);
|
||||
void* colorPaletteMallocDefaultImpl(size_t size);
|
||||
void* colorPaletteReallocDefaultImpl(void* ptr, size_t size);
|
||||
void colorPaletteFreeDefaultImpl(void* ptr);
|
||||
int _calculateColor(int a1, int a2);
|
||||
int _Color2RGB_(int a1);
|
||||
void colorPaletteFadeBetween(unsigned char* oldPalette, unsigned char* newPalette, int steps);
|
||||
void colorPaletteSetTransitionCallback(ColorTransitionCallback* callback);
|
||||
void _setSystemPalette(unsigned char* palette);
|
||||
unsigned char* _getSystemPalette();
|
||||
void _setSystemPaletteEntries(unsigned char* a1, int a2, int a3);
|
||||
void _setIntensityTableColor(int a1);
|
||||
void _setIntensityTables();
|
||||
void _setMixTableColor(int a1);
|
||||
bool colorPaletteLoad(char* path);
|
||||
char* _colorError();
|
||||
void _buildBlendTable(unsigned char* ptr, unsigned char ch);
|
||||
void _rebuildColorBlendTables();
|
||||
unsigned char* _getColorBlendTable(int ch);
|
||||
void _freeColorBlendTable(int a1);
|
||||
void colorPaletteSetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc);
|
||||
void colorSetBrightness(double value);
|
||||
bool _initColors();
|
||||
void _colorsClose();
|
||||
|
||||
#endif /* COLOR_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,138 @@
|
|||
#ifndef COMBAT_H
|
||||
#define COMBAT_H
|
||||
|
||||
#include "animation.h"
|
||||
#include "db.h"
|
||||
#include "combat_defs.h"
|
||||
#include "message.h"
|
||||
#include "obj_types.h"
|
||||
#include "party_member.h"
|
||||
#include "proto_types.h"
|
||||
|
||||
#define CALLED_SHOW_WINDOW_X (68)
|
||||
#define CALLED_SHOW_WINDOW_Y (20)
|
||||
#define CALLED_SHOW_WINDOW_WIDTH (504)
|
||||
#define CALLED_SHOW_WINDOW_HEIGHT (309)
|
||||
|
||||
extern char _a_1[];
|
||||
|
||||
extern int _combat_turn_running;
|
||||
extern int _combatNumTurns;
|
||||
extern unsigned int gCombatState;
|
||||
extern STRUCT_510948* _aiInfoList;
|
||||
extern STRUCT_664980* _gcsd;
|
||||
extern bool _combat_call_display;
|
||||
extern const int _hit_location_penalty[HIT_LOCATION_COUNT];
|
||||
extern CriticalHitDescription gCriticalHitTables[KILL_TYPE_COUNT][HIT_LOCATION_COUNT][CRTICIAL_EFFECT_COUNT];
|
||||
extern CriticalHitDescription gPlayerCriticalHitTable[HIT_LOCATION_COUNT][CRTICIAL_EFFECT_COUNT];
|
||||
extern int _combat_end_due_to_load;
|
||||
extern bool _combat_cleanup_enabled;
|
||||
extern const int _cf_table[WEAPON_CRITICAL_FAILURE_TYPE_COUNT][WEAPON_CRITICAL_FAILURE_EFFECT_COUNT];
|
||||
extern const int _call_ty[4];
|
||||
extern const int _hit_loc_left[4];
|
||||
extern const int _hit_loc_right[4];
|
||||
|
||||
extern Attack _main_ctd;
|
||||
extern MessageList gCombatMessageList;
|
||||
extern Object* gCalledShotCritter;
|
||||
extern int gCalledShotWindow;
|
||||
extern int _combat_elev;
|
||||
extern int _list_total;
|
||||
extern Object* _combat_ending_guy;
|
||||
extern int _list_noncom;
|
||||
extern Object* _combat_turn_obj;
|
||||
extern int _combat_highlight;
|
||||
extern Object** _combat_list;
|
||||
extern int _list_com;
|
||||
extern int _combat_exps;
|
||||
extern int _combat_free_move;
|
||||
extern Attack _shoot_ctd;
|
||||
extern Attack _explosion_ctd;
|
||||
|
||||
int combatInit();
|
||||
void combatReset();
|
||||
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 _combat_safety_invalidate_weapon_func(Object* critter, Object* weapon, int hitMode, Object* a4, int* a5, Object* a6);
|
||||
bool _combatTestIncidentalHit(Object* a1, Object* a2, Object* a3, Object* a4);
|
||||
Object* _combat_whose_turn();
|
||||
void _combat_data_init(Object* obj);
|
||||
int _combatCopyAIInfo(int a1, int a2);
|
||||
Object* _combatAIInfoGetFriendlyDead(Object* obj);
|
||||
int _combatAIInfoSetFriendlyDead(Object* a1, Object* a2);
|
||||
Object* _combatAIInfoGetLastTarget(Object* obj);
|
||||
int _combatAIInfoSetLastTarget(Object* a1, Object* a2);
|
||||
Object* _combatAIInfoGetLastItem(Object* obj);
|
||||
int _combatAIInfoSetLastItem(Object* obj, Object* a2);
|
||||
void _combat_begin(Object* a1);
|
||||
void _combat_begin_extra(Object* a1);
|
||||
void _combat_update_critter_outline_for_los(Object* critter, bool a2);
|
||||
void _combat_over();
|
||||
void _combat_over_from_load();
|
||||
void _combat_give_exps(int exp_points);
|
||||
void _combat_add_noncoms();
|
||||
int _compare_faster(const void* a1, const void* a2);
|
||||
void _combat_sequence_init(Object* a1, Object* a2);
|
||||
void _combat_sequence();
|
||||
void combatAttemptEnd();
|
||||
void _combat_turn_run();
|
||||
int _combat_input();
|
||||
void _combat_set_move_all();
|
||||
int _combat_turn(Object* a1, bool a2);
|
||||
bool _combat_should_end();
|
||||
void _combat(STRUCT_664980* attack);
|
||||
void attackInit(Attack* attack, Object* a2, Object* a3, int a4, int a5);
|
||||
int _combat_attack(Object* a1, Object* a2, int a3, int a4);
|
||||
int _combat_bullet_start(const Object* a1, const Object* a2);
|
||||
bool _check_ranged_miss(Attack* attack);
|
||||
int _shoot_along_path(Attack* attack, int a2, int a3, int anim);
|
||||
int _compute_spray(Attack* attack, int accuracy, int* a3, int* a4, int anim);
|
||||
int attackComputeEnhancedKnockout(Attack* attack);
|
||||
int attackCompute(Attack* attack);
|
||||
void _compute_explosion_on_extras(Attack* attack, int a2, int a3, int a4);
|
||||
int attackComputeCriticalHit(Attack* a1);
|
||||
int _attackFindInvalidFlags(Object* a1, Object* a2);
|
||||
int attackComputeCriticalFailure(Attack* attack);
|
||||
int _determine_to_hit(Object* a1, Object* a2, int hitLocation, int hitMode);
|
||||
int _determine_to_hit_no_range(Object* a1, Object* a2, int a3, int a4, unsigned char* a5);
|
||||
int _determine_to_hit_from_tile(Object* a1, int a2, Object* a3, int a4, int a5);
|
||||
int attackDetermineToHit(Object* attacker, int tile, Object* defender, int hitLocation, int hitMode, int a6);
|
||||
void attackComputeDamage(Attack* attack, int ammoQuantity, int a3);
|
||||
void attackComputeDeathFlags(Attack* attack);
|
||||
void _apply_damage(Attack* attack, bool animated);
|
||||
void _check_for_death(Object* a1, int a2, int* a3);
|
||||
void _set_new_results(Object* a1, int a2);
|
||||
void _damage_object(Object* a1, int damage, bool animated, int a4, Object* a5);
|
||||
void _combat_display(Attack* attack);
|
||||
void combatCopyDamageAmountDescription(char* dest, Object* critter_obj, int damage);
|
||||
void combatAddDamageFlagsDescription(char* a1, int flags, Object* a3);
|
||||
void _combat_anim_begin();
|
||||
void _combat_anim_finished();
|
||||
void _combat_standup(Object* a1);
|
||||
void _print_tohit(unsigned char* dest, int dest_pitch, int a3);
|
||||
char* hitLocationGetName(Object* critter, int hitLocation);
|
||||
void _draw_loc_off(int a1, int a2);
|
||||
void _draw_loc_on_(int a1, int a2);
|
||||
void _draw_loc_(int eventCode, int color);
|
||||
int calledShotSelectHitLocation(Object* critter, int* hitLocation, int hitMode);
|
||||
int _combat_check_bad_shot(Object* attacker, Object* defender, int hitMode, bool aiming);
|
||||
bool _combat_to_hit(Object* target, int* accuracy);
|
||||
void _combat_attack_this(Object* a1);
|
||||
void _combat_outline_on();
|
||||
void _combat_outline_off();
|
||||
void _combat_highlight_change();
|
||||
bool _combat_is_shot_blocked(Object* a1, int from, int to, Object* a4, int* a5);
|
||||
int _combat_player_knocked_out_by();
|
||||
int _combat_explode_scenery(Object* a1, Object* a2);
|
||||
void _combat_delete_critter(Object* obj);
|
||||
void _combatKillCritterOutsideCombat(Object* critter_obj, char* msg);
|
||||
|
||||
static inline bool isInCombat()
|
||||
{
|
||||
return (gCombatState & COMBAT_STATE_0x01) != 0;
|
||||
}
|
||||
|
||||
#endif /* COMBAT_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,182 @@
|
|||
#ifndef COMBAT_AI_H
|
||||
#define COMBAT_AI_H
|
||||
|
||||
#include "combat_ai_defs.h"
|
||||
#include "combat_defs.h"
|
||||
#include "db.h"
|
||||
#include "message.h"
|
||||
#include "obj_types.h"
|
||||
#include "party_member.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define AI_PACKET_CHEM_PRIMARY_DESIRE_COUNT (3)
|
||||
|
||||
typedef enum AiMessageType {
|
||||
AI_MESSAGE_TYPE_RUN,
|
||||
AI_MESSAGE_TYPE_MOVE,
|
||||
AI_MESSAGE_TYPE_ATTACK,
|
||||
AI_MESSAGE_TYPE_MISS,
|
||||
AI_MESSAGE_TYPE_HIT,
|
||||
} AiMessageType;
|
||||
|
||||
typedef struct AiMessageRange {
|
||||
int start;
|
||||
int end;
|
||||
} AiMessageRange;
|
||||
|
||||
typedef struct AiPacket {
|
||||
char* name;
|
||||
int packet_num;
|
||||
int max_dist;
|
||||
int min_to_hit;
|
||||
int min_hp;
|
||||
int aggression;
|
||||
int hurt_too_much;
|
||||
int secondary_freq;
|
||||
int called_freq;
|
||||
int font;
|
||||
int color;
|
||||
int outline_color;
|
||||
int chance;
|
||||
AiMessageRange run;
|
||||
AiMessageRange move;
|
||||
AiMessageRange attack;
|
||||
AiMessageRange miss;
|
||||
AiMessageRange hit[HIT_LOCATION_SPECIFIC_COUNT];
|
||||
int area_attack_mode;
|
||||
int run_away_mode;
|
||||
int best_weapon;
|
||||
int distance;
|
||||
int attack_who;
|
||||
int chem_use;
|
||||
int chem_primary_desire[AI_PACKET_CHEM_PRIMARY_DESIRE_COUNT];
|
||||
int disposition;
|
||||
char* body_type;
|
||||
char* general_type;
|
||||
} AiPacket;
|
||||
|
||||
typedef struct STRUCT_832 {
|
||||
Object* field_0;
|
||||
Object* field_4;
|
||||
Object* field_8[100];
|
||||
int field_198[100];
|
||||
int field_328;
|
||||
int field_32C;
|
||||
int field_330;
|
||||
int field_334;
|
||||
int* field_338;
|
||||
int field_33C;
|
||||
int field_340;
|
||||
} STRUCT_832;
|
||||
|
||||
extern Object* _combat_obj;
|
||||
extern int gAiPacketsLength;
|
||||
extern AiPacket* gAiPackets;
|
||||
extern bool gAiInitialized;
|
||||
extern const char* gAreaAttackModeKeys[AREA_ATTACK_MODE_COUNT];
|
||||
extern const char* gAttackWhoKeys[ATTACK_WHO_COUNT];
|
||||
extern const char* gBestWeaponKeys[BEST_WEAPON_COUNT];
|
||||
extern const char* gChemUseKeys[CHEM_USE_COUNT];
|
||||
extern const char* gDistanceModeKeys[DISTANCE_COUNT];
|
||||
extern const char* gRunAwayModeKeys[RUN_AWAY_MODE_COUNT];
|
||||
extern const char* gDispositionKeys[DISPOSITION_COUNT];
|
||||
extern const char* gHurtTooMuchKeys[HURT_COUNT];
|
||||
extern const int _rmatchHurtVals[5];
|
||||
extern const int _hp_run_away_value[6];
|
||||
extern Object* _attackerTeamObj;
|
||||
extern Object* _targetTeamObj;
|
||||
extern const int _weapPrefOrderings[BEST_WEAPON_COUNT + 1][5];
|
||||
extern const int _aiPartyMemberDistances[DISTANCE_COUNT];
|
||||
extern int gLanguageFilter;
|
||||
|
||||
extern MessageList gCombatAiMessageList;
|
||||
extern char _target_str[260];
|
||||
extern int _curr_crit_num;
|
||||
extern Object** _curr_crit_list;
|
||||
extern char _attack_str[268];
|
||||
|
||||
void _parse_hurt_str(char* str, int* out_value);
|
||||
int _cai_match_str_to_list(const char* str, const char** list, int count, int* out_value);
|
||||
void aiPacketInit(AiPacket* ai);
|
||||
int aiInit();
|
||||
void aiReset();
|
||||
int aiExit();
|
||||
int aiLoad(File* stream);
|
||||
int aiSave(File* stream);
|
||||
int aiPacketRead(File* stream, AiPacket* ai);
|
||||
int aiPacketWrite(File* stream, AiPacket* ai);
|
||||
AiPacket* aiGetPacket(Object* obj);
|
||||
AiPacket* aiGetPacketByNum(int aiPacketNum);
|
||||
int aiGetAreaAttackMode(Object* obj);
|
||||
int aiGetRunAwayMode(Object* obj);
|
||||
int aiGetBestWeapon(Object* obj);
|
||||
int aiGetDistance(Object* obj);
|
||||
int aiGetAttackWho(Object* obj);
|
||||
int aiGetChemUse(Object* obj);
|
||||
int aiSetAreaAttackMode(Object* critter, int areaAttackMode);
|
||||
int aiSetRunAwayMode(Object* obj, int run_away_mode);
|
||||
int aiSetBestWeapon(Object* critter, int bestWeapon);
|
||||
int aiSetDistance(Object* critter, int distance);
|
||||
int aiSetAttackWho(Object* critter, int attackWho);
|
||||
int aiSetChemUse(Object* critter, int chemUse);
|
||||
int aiGetDisposition(Object* obj);
|
||||
int aiSetDisposition(Object* obj, int a2);
|
||||
int _ai_magic_hands(Object* a1, Object* a2, int num);
|
||||
int _ai_check_drugs(Object* critter);
|
||||
void _ai_run_away(Object* a1, Object* a2);
|
||||
int _ai_move_away(Object* a1, Object* a2, int a3);
|
||||
bool _ai_find_friend(Object* a1, int a2, int a3);
|
||||
int _compare_nearer(const void* a1, const void* a2);
|
||||
int _compare_strength(const void* p1, const void* p2);
|
||||
int _compare_weakness(const void* p1, const void* p2);
|
||||
Object* _ai_find_nearest_team(Object* a1, Object* a2, int a3);
|
||||
Object* _ai_find_nearest_team_in_combat(Object* a1, Object* a2, int a3);
|
||||
int _ai_find_attackers(Object* a1, Object** a2, Object** a3, Object** a4);
|
||||
Object* _ai_danger_source(Object* a1);
|
||||
int _caiSetupTeamCombat(Object* a1, Object* a2);
|
||||
int _caiTeamCombatInit(Object** a1, int a2);
|
||||
void _caiTeamCombatExit();
|
||||
int _ai_have_ammo(Object* critter_obj, Object* weapon_obj, Object** out_ammo_obj);
|
||||
bool _caiHasWeapPrefType(AiPacket* ai, int attackType);
|
||||
Object* _ai_best_weapon(Object* a1, Object* a2, Object* a3, Object* a4);
|
||||
bool _ai_can_use_weapon(Object* critter, Object* weapon, int hitMode);
|
||||
Object* _ai_search_inven_weap(Object* critter, int a2, Object* a3);
|
||||
Object* _ai_search_inven_armor(Object* critter);
|
||||
bool aiCanUseItem(Object* obj, Object* a2);
|
||||
Object* _ai_search_environ(Object* critter, int itemType);
|
||||
Object* _ai_retrieve_object(Object* a1, Object* a2);
|
||||
int _ai_pick_hit_mode(Object* a1, Object* a2, Object* a3);
|
||||
int _ai_move_steps_closer(Object* a1, Object* a2, int actionPoints, int a4);
|
||||
int _cai_retargetTileFromFriendlyFire(Object* a1, Object* a2, int* a3);
|
||||
int _cai_retargetTileFromFriendlyFireSubFunc(STRUCT_832* a1, int a2);
|
||||
bool _cai_attackWouldIntersect(Object* a1, Object* a2, Object* a3, int tile, int* distance);
|
||||
int _ai_switch_weapons(Object* a1, int* hitMode, Object** weapon, Object* a4);
|
||||
int _ai_called_shot(Object* a1, Object* a2, int a3);
|
||||
int _ai_attack(Object* a1, Object* a2, int a3);
|
||||
int _ai_try_attack(Object* a1, Object* a2);
|
||||
int _cAIPrepWeaponItem(Object* critter, Object* item);
|
||||
void _cai_attempt_w_reload(Object* critter_obj, int a2);
|
||||
void _combat_ai_begin(int a1, void* a2);
|
||||
void _combat_ai_over();
|
||||
int _cai_perform_distance_prefs(Object* a1, Object* a2);
|
||||
int _cai_get_min_hp(AiPacket* ai);
|
||||
void _combat_ai(Object* a1, Object* a2);
|
||||
bool _combatai_want_to_join(Object* a1);
|
||||
bool _combatai_want_to_stop(Object* a1);
|
||||
int critterSetTeam(Object* obj, int team);
|
||||
int critterSetAiPacket(Object* object, int aiPacket);
|
||||
int _combatai_msg(Object* a1, Attack* attack, int a3, int a4);
|
||||
int _ai_print_msg(Object* critter, int type);
|
||||
Object* _combat_ai_random_target(Attack* attack);
|
||||
int _combatai_rating(Object* obj);
|
||||
int _combatai_check_retaliation(Object* a1, Object* a2);
|
||||
bool objectCanHearObject(Object* a1, Object* a2);
|
||||
int aiMessageListInit();
|
||||
int aiMessageListFree();
|
||||
void aiMessageListReloadIfNeeded();
|
||||
void _combatai_notify_onlookers(Object* a1);
|
||||
void _combatai_notify_friends(Object* a1);
|
||||
void _combatai_delete_critter(Object* obj);
|
||||
|
||||
#endif /* COMBAT_AI_H */
|
|
@ -0,0 +1,82 @@
|
|||
#ifndef COMBAT_AI_DEFS_H
|
||||
#define COMBAT_AI_DEFS_H
|
||||
|
||||
typedef enum AreaAttackMode {
|
||||
AREA_ATTACK_MODE_ALWAYS,
|
||||
AREA_ATTACK_MODE_SOMETIMES,
|
||||
AREA_ATTACK_MODE_BE_SURE,
|
||||
AREA_ATTACK_MODE_BE_CAREFUL,
|
||||
AREA_ATTACK_MODE_BE_ABSOLUTELY_SURE,
|
||||
AREA_ATTACK_MODE_COUNT,
|
||||
} AreaAttackMode;
|
||||
|
||||
typedef enum RunAwayMode {
|
||||
RUN_AWAY_MODE_NONE,
|
||||
RUN_AWAY_MODE_COWARD,
|
||||
RUN_AWAY_MODE_FINGER_HURTS,
|
||||
RUN_AWAY_MODE_BLEEDING,
|
||||
RUN_AWAY_MODE_NOT_FEELING_GOOD,
|
||||
RUN_AWAY_MODE_TOURNIQUET,
|
||||
RUN_AWAY_MODE_NEVER,
|
||||
RUN_AWAY_MODE_COUNT,
|
||||
} RunAwayMode;
|
||||
|
||||
typedef enum BestWeapon {
|
||||
BEST_WEAPON_NO_PREF,
|
||||
BEST_WEAPON_MELEE,
|
||||
BEST_WEAPON_MELEE_OVER_RANGED,
|
||||
BEST_WEAPON_RANGED_OVER_MELEE,
|
||||
BEST_WEAPON_RANGED,
|
||||
BEST_WEAPON_UNARMED,
|
||||
BEST_WEAPON_UNARMED_OVER_THROW,
|
||||
BEST_WEAPON_RANDOM,
|
||||
BEST_WEAPON_COUNT,
|
||||
} BestWeapon;
|
||||
|
||||
typedef enum DistanceMode {
|
||||
DISTANCE_STAY_CLOSE,
|
||||
DISTANCE_CHARGE,
|
||||
DISTANCE_SNIPE,
|
||||
DISTANCE_ON_YOUR_OWN,
|
||||
DISTANCE_STAY,
|
||||
DISTANCE_COUNT,
|
||||
} DistanceMode;
|
||||
|
||||
typedef enum AttackWho {
|
||||
ATTACK_WHO_WHOMEVER_ATTACKING_ME,
|
||||
ATTACK_WHO_STRONGEST,
|
||||
ATTACK_WHO_WEAKEST,
|
||||
ATTACK_WHO_WHOMEVER,
|
||||
ATTACK_WHO_CLOSEST,
|
||||
ATTACK_WHO_COUNT,
|
||||
} AttackWho;
|
||||
|
||||
typedef enum ChemUse {
|
||||
CHEM_USE_CLEAN,
|
||||
CHEM_USE_STIMS_WHEN_HURT_LITTLE,
|
||||
CHEM_USE_STIMS_WHEN_HURT_LOTS,
|
||||
CHEM_USE_SOMETIMES,
|
||||
CHEM_USE_ANYTIME,
|
||||
CHEM_USE_ALWAYS,
|
||||
CHEM_USE_COUNT,
|
||||
} ChemUse;
|
||||
|
||||
typedef enum Disposition {
|
||||
DISPOSITION_NONE,
|
||||
DISPOSITION_CUSTOM,
|
||||
DISPOSITION_COWARD,
|
||||
DISPOSITION_DEFENSIVE,
|
||||
DISPOSITION_AGGRESSIVE,
|
||||
DISPOSITION_BERKSERK,
|
||||
DISPOSITION_COUNT,
|
||||
} Disposition;
|
||||
|
||||
typedef enum HurtTooMuch {
|
||||
HURT_BLIND,
|
||||
HURT_CRIPPLED,
|
||||
HURT_CRIPPLED_LEGS,
|
||||
HURT_CRIPPLED_ARMS,
|
||||
HURT_COUNT,
|
||||
} HurtTooMuch;
|
||||
|
||||
#endif /* COMBAT_AI_DEFS_H */
|
|
@ -0,0 +1,156 @@
|
|||
#ifndef COMBAT_DEFS_H
|
||||
#define COMBAT_DEFS_H
|
||||
|
||||
#include "obj_types.h"
|
||||
|
||||
#define EXPLOSION_TARGET_COUNT (6)
|
||||
|
||||
#define CRTICIAL_EFFECT_COUNT (6)
|
||||
|
||||
#define WEAPON_CRITICAL_FAILURE_TYPE_COUNT (7)
|
||||
#define WEAPON_CRITICAL_FAILURE_EFFECT_COUNT (5)
|
||||
|
||||
typedef enum CombatState {
|
||||
COMBAT_STATE_0x01 = 0x01,
|
||||
COMBAT_STATE_0x02 = 0x02,
|
||||
COMBAT_STATE_0x08 = 0x08,
|
||||
} CombatState;
|
||||
|
||||
typedef enum HitMode {
|
||||
HIT_MODE_LEFT_WEAPON_PRIMARY = 0,
|
||||
HIT_MODE_LEFT_WEAPON_SECONDARY = 1,
|
||||
HIT_MODE_RIGHT_WEAPON_PRIMARY = 2,
|
||||
HIT_MODE_RIGHT_WEAPON_SECONDARY = 3,
|
||||
HIT_MODE_PUNCH = 4,
|
||||
HIT_MODE_KICK = 5,
|
||||
HIT_MODE_LEFT_WEAPON_RELOAD = 6,
|
||||
HIT_MODE_RIGHT_WEAPON_RELOAD = 7,
|
||||
|
||||
// Punch Level 2
|
||||
HIT_MODE_STRONG_PUNCH = 8,
|
||||
|
||||
// Punch Level 3
|
||||
HIT_MODE_HAMMER_PUNCH = 9,
|
||||
|
||||
// Punch Level 4 aka 'Lightning Punch'
|
||||
HIT_MODE_HAYMAKER = 10,
|
||||
|
||||
// Punch Level 5 aka 'Chop Punch'
|
||||
HIT_MODE_JAB = 11,
|
||||
|
||||
// Punch Level 6 aka 'Dragon Punch'
|
||||
HIT_MODE_PALM_STRIKE = 12,
|
||||
|
||||
// Punch Level 7 aka 'Force Punch'
|
||||
HIT_MODE_PIERCING_STRIKE = 13,
|
||||
|
||||
// Kick Level 2
|
||||
HIT_MODE_STRONG_KICK = 14,
|
||||
|
||||
// Kick Level 3
|
||||
HIT_MODE_SNAP_KICK = 15,
|
||||
|
||||
// Kick Level 4 aka 'Roundhouse Kick'
|
||||
HIT_MODE_POWER_KICK = 16,
|
||||
|
||||
// Kick Level 5
|
||||
HIT_MODE_HIP_KICK = 17,
|
||||
|
||||
// Kick Level 6 aka 'Jump Kick'
|
||||
HIT_MODE_HOOK_KICK = 18,
|
||||
|
||||
// Kick Level 7 aka 'Death Blossom Kick'
|
||||
HIT_MODE_PIERCING_KICK = 19,
|
||||
HIT_MODE_COUNT,
|
||||
FIRST_ADVANCED_PUNCH_HIT_MODE = HIT_MODE_STRONG_PUNCH,
|
||||
LAST_ADVANCED_PUNCH_HIT_MODE = HIT_MODE_PIERCING_STRIKE,
|
||||
FIRST_ADVANCED_KICK_HIT_MODE = HIT_MODE_STRONG_KICK,
|
||||
LAST_ADVANCED_KICK_HIT_MODE = HIT_MODE_PIERCING_KICK,
|
||||
FIRST_ADVANCED_UNARMED_HIT_MODE = FIRST_ADVANCED_PUNCH_HIT_MODE,
|
||||
LAST_ADVANCED_UNARMED_HIT_MODE = LAST_ADVANCED_KICK_HIT_MODE,
|
||||
} HitMode;
|
||||
|
||||
typedef enum HitLocation {
|
||||
HIT_LOCATION_HEAD,
|
||||
HIT_LOCATION_LEFT_ARM,
|
||||
HIT_LOCATION_RIGHT_ARM,
|
||||
HIT_LOCATION_TORSO,
|
||||
HIT_LOCATION_RIGHT_LEG,
|
||||
HIT_LOCATION_LEFT_LEG,
|
||||
HIT_LOCATION_EYES,
|
||||
HIT_LOCATION_GROIN,
|
||||
HIT_LOCATION_UNCALLED,
|
||||
HIT_LOCATION_COUNT,
|
||||
HIT_LOCATION_SPECIFIC_COUNT = HIT_LOCATION_COUNT - 1,
|
||||
} HitLocation;
|
||||
|
||||
typedef struct STRUCT_510948 {
|
||||
Object* field_0;
|
||||
Object* field_4;
|
||||
Object* field_8;
|
||||
int field_C;
|
||||
} STRUCT_510948;
|
||||
|
||||
typedef struct STRUCT_664980 {
|
||||
Object* attacker;
|
||||
Object* defender;
|
||||
int actionPointsBonus;
|
||||
int accuracyBonus;
|
||||
int damageBonus;
|
||||
int minDamage;
|
||||
int maxDamage;
|
||||
int field_1C; // probably bool, indicating field_20 and field_24 used
|
||||
int field_20; // flags on attacker
|
||||
int field_24; // flags on defender
|
||||
} STRUCT_664980;
|
||||
|
||||
static_assert(sizeof(STRUCT_664980) == 40, "wrong size");
|
||||
|
||||
typedef struct Attack {
|
||||
Object* attacker;
|
||||
int hitMode;
|
||||
Object* weapon;
|
||||
int attackHitLocation;
|
||||
int attackerDamage;
|
||||
int attackerFlags;
|
||||
int ammoQuantity;
|
||||
int criticalMessageId;
|
||||
Object* defender;
|
||||
int tile;
|
||||
int defenderHitLocation;
|
||||
int defenderDamage;
|
||||
int defenderFlags;
|
||||
int defenderKnockback;
|
||||
Object* oops;
|
||||
int extrasLength;
|
||||
Object* extras[EXPLOSION_TARGET_COUNT];
|
||||
int extrasHitLocation[EXPLOSION_TARGET_COUNT];
|
||||
int extrasDamage[EXPLOSION_TARGET_COUNT];
|
||||
int extrasFlags[EXPLOSION_TARGET_COUNT];
|
||||
int extrasKnockback[EXPLOSION_TARGET_COUNT];
|
||||
} Attack;
|
||||
|
||||
static_assert(sizeof(Attack) == 184, "wrong size");
|
||||
|
||||
// Provides metadata about critical hit effect.
|
||||
typedef struct CriticalHitDescription {
|
||||
int damageMultiplier;
|
||||
|
||||
// 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;
|
||||
|
||||
// Bonus/penalty to massive critical stat.
|
||||
int massiveCriticalStatModifier;
|
||||
|
||||
// Additional damage flags if this critical hit become massive critical.
|
||||
int massiveCriticalFlags;
|
||||
|
||||
int messageId;
|
||||
int massiveCriticalMessageId;
|
||||
} CriticalHitDescription;
|
||||
|
||||
#endif /* COMBAT_DEFS_H */
|
|
@ -0,0 +1,549 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "db.h"
|
||||
#include "memory.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Last section key read from .INI file.
|
||||
//
|
||||
// 0x518224
|
||||
char gConfigLastSectionKey[CONFIG_FILE_MAX_LINE_LENGTH] = "unknown";
|
||||
|
||||
// 0x42BD90
|
||||
bool configInit(Config* config)
|
||||
{
|
||||
if (config == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dictionaryInit(config, CONFIG_INITIAL_CAPACITY, sizeof(ConfigSection), NULL) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x42BDBC
|
||||
void configFree(Config* config)
|
||||
{
|
||||
if (config == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int sectionIndex = 0; sectionIndex < config->entriesLength; sectionIndex++) {
|
||||
DictionaryEntry* sectionEntry = &(config->entries[sectionIndex]);
|
||||
|
||||
ConfigSection* section = sectionEntry->value;
|
||||
for (int keyValueIndex = 0; keyValueIndex < section->entriesLength; keyValueIndex++) {
|
||||
DictionaryEntry* keyValueEntry = &(section->entries[keyValueIndex]);
|
||||
|
||||
char** value = keyValueEntry->value;
|
||||
internal_free(*value);
|
||||
*value = NULL;
|
||||
}
|
||||
|
||||
dictionaryFree(section);
|
||||
}
|
||||
|
||||
dictionaryFree(config);
|
||||
}
|
||||
|
||||
// Parses command line argments and adds them into the config.
|
||||
//
|
||||
// The expected format of [argv] elements are "[section]key=value", otherwise
|
||||
// the element is silently ignored.
|
||||
//
|
||||
// NOTE: This function trims whitespace in key-value pair, but not in section.
|
||||
// I don't know if this is intentional or it's bug.
|
||||
//
|
||||
// 0x42BE38
|
||||
bool configParseCommandLineArguments(Config* config, int argc, char** argv)
|
||||
{
|
||||
if (config == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int arg = 0; arg < argc; arg++) {
|
||||
char* pch = argv[arg];
|
||||
|
||||
// Find opening bracket.
|
||||
while (*pch != '\0' && *pch != '[') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
char* sectionKey = pch + 1;
|
||||
|
||||
// Find closing bracket.
|
||||
while (*pch != '\0' && *pch != ']') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
*pch = '\0';
|
||||
|
||||
char key[260];
|
||||
char value[260];
|
||||
if (configParseKeyValue(pch + 1, key, value)) {
|
||||
if (!configSetString(config, sectionKey, key, value)) {
|
||||
*pch = ']';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*pch = ']';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x42BF48
|
||||
bool configGetString(Config* config, const char* sectionKey, const char* key, char** valuePtr)
|
||||
{
|
||||
if (config == NULL || sectionKey == NULL || key == NULL || valuePtr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int sectionIndex = dictionaryGetIndexByKey(config, sectionKey);
|
||||
if (sectionIndex == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DictionaryEntry* sectionEntry = &(config->entries[sectionIndex]);
|
||||
ConfigSection* section = sectionEntry->value;
|
||||
|
||||
int index = dictionaryGetIndexByKey(section, key);
|
||||
if (index == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DictionaryEntry* keyValueEntry = &(section->entries[index]);
|
||||
*valuePtr = *(char**)keyValueEntry->value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x42BF90
|
||||
bool configSetString(Config* config, const char* sectionKey, const char* key, const char* value)
|
||||
{
|
||||
if (config == NULL || sectionKey == NULL || key == NULL || value == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int sectionIndex = dictionaryGetIndexByKey(config, sectionKey);
|
||||
if (sectionIndex == -1) {
|
||||
// FIXME: Looks like a bug, this function never returns -1, which will
|
||||
// eventually lead to crash.
|
||||
if (configEnsureSectionExists(config, sectionKey) == -1) {
|
||||
return false;
|
||||
}
|
||||
sectionIndex = dictionaryGetIndexByKey(config, sectionKey);
|
||||
}
|
||||
|
||||
DictionaryEntry* sectionEntry = &(config->entries[sectionIndex]);
|
||||
ConfigSection* section = sectionEntry->value;
|
||||
|
||||
int index = dictionaryGetIndexByKey(section, key);
|
||||
if (index != -1) {
|
||||
DictionaryEntry* keyValueEntry = &(section->entries[index]);
|
||||
|
||||
char** existingValue = keyValueEntry->value;
|
||||
internal_free(*existingValue);
|
||||
*existingValue = NULL;
|
||||
|
||||
dictionaryRemoveValue(section, key);
|
||||
}
|
||||
|
||||
char* valueCopy = internal_strdup(value);
|
||||
if (valueCopy == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dictionaryAddValue(section, key, &valueCopy) == -1) {
|
||||
internal_free(valueCopy);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x42C05C
|
||||
bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr)
|
||||
{
|
||||
if (valuePtr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char* stringValue;
|
||||
if (!configGetString(config, sectionKey, key, &stringValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*valuePtr = atoi(stringValue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x42C090
|
||||
bool configGetIntList(Config* config, const char* sectionKey, const char* key, int* arr, int count)
|
||||
{
|
||||
if (arr == NULL || count < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char* string;
|
||||
if (!configGetString(config, sectionKey, key, &string)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char temp[CONFIG_FILE_MAX_LINE_LENGTH];
|
||||
strncpy(temp, string, CONFIG_FILE_MAX_LINE_LENGTH - 1);
|
||||
|
||||
char* beginning = temp;
|
||||
char* pch = beginning;
|
||||
while (*pch != '\0') {
|
||||
if (*pch == ',') {
|
||||
*pch = '\0';
|
||||
|
||||
*arr++ = atoi(beginning);
|
||||
|
||||
*pch = ',';
|
||||
|
||||
pch++;
|
||||
beginning = pch;
|
||||
|
||||
count--;
|
||||
|
||||
if (count < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (count <= 1) {
|
||||
*arr = atoi(beginning);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x42C160
|
||||
bool configSetInt(Config* config, const char* sectionKey, const char* key, int value)
|
||||
{
|
||||
char stringValue[20];
|
||||
itoa(value, stringValue, 10);
|
||||
|
||||
return configSetString(config, sectionKey, key, stringValue);
|
||||
}
|
||||
|
||||
// Reads .INI file into config.
|
||||
//
|
||||
// 0x42C280
|
||||
bool configRead(Config* config, const char* filePath, bool isDb)
|
||||
{
|
||||
if (config == NULL || filePath == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char string[CONFIG_FILE_MAX_LINE_LENGTH];
|
||||
|
||||
if (isDb) {
|
||||
File* stream = fileOpen(filePath, "rb");
|
||||
if (stream != NULL) {
|
||||
while (fileReadString(string, sizeof(string), stream) != NULL) {
|
||||
configParseLine(config, string);
|
||||
}
|
||||
fileClose(stream);
|
||||
}
|
||||
} else {
|
||||
FILE* stream = fopen(filePath, "rt");
|
||||
if (stream != NULL) {
|
||||
while (fgets(string, sizeof(string), stream) != NULL) {
|
||||
configParseLine(config, string);
|
||||
}
|
||||
|
||||
fclose(stream);
|
||||
}
|
||||
|
||||
// FIXME: This function returns `true` even if the file was not actually
|
||||
// read. I'm pretty sure it's bug.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Writes config into .INI file.
|
||||
//
|
||||
// 0x42C324
|
||||
bool configWrite(Config* config, const char* filePath, bool isDb)
|
||||
{
|
||||
if (config == NULL || filePath == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isDb) {
|
||||
File* stream = fileOpen(filePath, "wt");
|
||||
if (stream == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int sectionIndex = 0; sectionIndex < config->entriesLength; sectionIndex++) {
|
||||
DictionaryEntry* sectionEntry = &(config->entries[sectionIndex]);
|
||||
filePrintFormatted(stream, "[%s]\n", sectionEntry->key);
|
||||
|
||||
ConfigSection* section = sectionEntry->value;
|
||||
for (int index = 0; index < section->entriesLength; index++) {
|
||||
DictionaryEntry* keyValueEntry = &(section->entries[index]);
|
||||
filePrintFormatted(stream, "%s=%s\n", keyValueEntry->key, *(char**)keyValueEntry->value);
|
||||
}
|
||||
|
||||
filePrintFormatted(stream, "\n");
|
||||
}
|
||||
|
||||
fileClose(stream);
|
||||
} else {
|
||||
FILE* stream = fopen(filePath, "wt");
|
||||
if (stream == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int sectionIndex = 0; sectionIndex < config->entriesLength; sectionIndex++) {
|
||||
DictionaryEntry* sectionEntry = &(config->entries[sectionIndex]);
|
||||
fprintf(stream, "[%s]\n", sectionEntry->key);
|
||||
|
||||
ConfigSection* section = sectionEntry->value;
|
||||
for (int index = 0; index < section->entriesLength; index++) {
|
||||
DictionaryEntry* keyValueEntry = &(section->entries[index]);
|
||||
fprintf(stream, "%s=%s\n", keyValueEntry->key, *(char**)keyValueEntry->value);
|
||||
}
|
||||
|
||||
fprintf(stream, "\n");
|
||||
}
|
||||
|
||||
fclose(stream);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parses a line from .INI file into config.
|
||||
//
|
||||
// A line either contains a "[section]" section key or "key=value" pair. In the
|
||||
// first case section key is not added to config immediately, instead it is
|
||||
// stored in [gConfigLastSectionKey] for later usage. This prevents empty
|
||||
// sections in the config.
|
||||
//
|
||||
// In case of key-value pair it pretty straight forward - it adds key-value
|
||||
// pair into previously read section key stored in [gConfigLastSectionKey].
|
||||
//
|
||||
// Returns `true` when a section was parsed or key-value pair was parsed and
|
||||
// added to the config, or `false` otherwise.
|
||||
//
|
||||
// 0x42C4BC
|
||||
bool configParseLine(Config* config, char* string)
|
||||
{
|
||||
char* pch;
|
||||
|
||||
// Find comment marker and truncate the string.
|
||||
pch = string;
|
||||
while (*pch != '\0' && *pch != ';') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch != '\0') {
|
||||
*pch = '\0';
|
||||
}
|
||||
|
||||
// Find opening bracket.
|
||||
pch = string;
|
||||
while (*pch != '\0' && *pch != '[') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == '[') {
|
||||
char* sectionKey = pch + 1;
|
||||
|
||||
// Find closing bracket.
|
||||
while (*pch != '\0' && *pch != ']') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == ']') {
|
||||
*pch = '\0';
|
||||
strcpy(gConfigLastSectionKey, sectionKey);
|
||||
return configTrimString(gConfigLastSectionKey);
|
||||
}
|
||||
}
|
||||
|
||||
char key[260];
|
||||
char value[260];
|
||||
if (!configParseKeyValue(string, key, value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return configSetString(config, gConfigLastSectionKey, key, value);
|
||||
}
|
||||
|
||||
// Splits "key=value" pair from [string] and copy appropriate parts into [key]
|
||||
// and [value] respectively.
|
||||
//
|
||||
// Both key and value are trimmed.
|
||||
//
|
||||
// 0x42C594
|
||||
bool configParseKeyValue(char* string, char* key, char* value)
|
||||
{
|
||||
if (string == NULL || key == NULL || value == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find equals character.
|
||||
char* pch = string;
|
||||
while (*pch != '\0' && *pch != '=') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
*pch = '\0';
|
||||
|
||||
strcpy(key, string);
|
||||
strcpy(value, pch + 1);
|
||||
|
||||
*pch = '=';
|
||||
|
||||
configTrimString(key);
|
||||
configTrimString(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ensures the config has a section with specified key.
|
||||
//
|
||||
// Return `true` if section exists or it was successfully added, or `false`
|
||||
// otherwise.
|
||||
//
|
||||
// 0x42C638
|
||||
bool configEnsureSectionExists(Config* config, const char* sectionKey)
|
||||
{
|
||||
if (config == NULL || sectionKey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dictionaryGetIndexByKey(config, sectionKey) != -1) {
|
||||
// Section already exists, no need to do anything.
|
||||
return true;
|
||||
}
|
||||
|
||||
ConfigSection section;
|
||||
if (dictionaryInit(§ion, CONFIG_INITIAL_CAPACITY, sizeof(char**), NULL) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dictionaryAddValue(config, sectionKey, §ion) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Removes leading and trailing whitespace from the specified string.
|
||||
//
|
||||
// 0x42C698
|
||||
bool configTrimString(char* string)
|
||||
{
|
||||
if (string == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int length = strlen(string);
|
||||
if (length == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Starting from the end of the string, loop while it's a whitespace and
|
||||
// decrement string length.
|
||||
char* pch = string + length - 1;
|
||||
while (length != 0 && isspace(*pch)) {
|
||||
length--;
|
||||
pch--;
|
||||
}
|
||||
|
||||
// pch now points to the last non-whitespace character.
|
||||
pch[1] = '\0';
|
||||
|
||||
// Starting from the beginning of the string loop while it's a whitespace
|
||||
// and decrement string length.
|
||||
pch = string;
|
||||
while (isspace(*pch)) {
|
||||
pch++;
|
||||
length--;
|
||||
}
|
||||
|
||||
// pch now points for to the first non-whitespace character.
|
||||
memmove(string, pch, length + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x42C718
|
||||
bool configGetDouble(Config* config, const char* sectionKey, const char* key, double* valuePtr)
|
||||
{
|
||||
if (valuePtr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char* stringValue;
|
||||
if (!configGetString(config, sectionKey, key, &stringValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*valuePtr = strtod(stringValue, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x42C74C
|
||||
bool configSetDouble(Config* config, const char* sectionKey, const char* key, double value)
|
||||
{
|
||||
char stringValue[32];
|
||||
sprintf(stringValue, "%.6f", value);
|
||||
|
||||
return configSetString(config, sectionKey, key, stringValue);
|
||||
}
|
||||
|
||||
// NOTE: Boolean-typed variant of [configGetInt].
|
||||
bool configGetBool(Config* config, const char* sectionKey, const char* key, bool* valuePtr)
|
||||
{
|
||||
if (valuePtr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int integerValue;
|
||||
if (!configGetInt(config, sectionKey, key, &integerValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*valuePtr = integerValue != 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE: Boolean-typed variant of [configGetInt].
|
||||
bool configSetBool(Config* config, const char* sectionKey, const char* key, bool value)
|
||||
{
|
||||
return configSetInt(config, sectionKey, key, value ? 1 : 0);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include "dictionary.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define CONFIG_FILE_MAX_LINE_LENGTH (256)
|
||||
|
||||
// The initial number of sections (or key-value) pairs in the config.
|
||||
#define CONFIG_INITIAL_CAPACITY (10)
|
||||
|
||||
// A representation of .INI file.
|
||||
//
|
||||
// It's implemented as a [Dictionary] whos keys are section names of .INI file,
|
||||
// and it's values are [ConfigSection] structs.
|
||||
typedef Dictionary Config;
|
||||
|
||||
// Representation of .INI section.
|
||||
//
|
||||
// It's implemented as a [Dictionary] whos keys are names of .INI file
|
||||
// key-pair values, and it's values are pointers to strings (char**).
|
||||
typedef Dictionary ConfigSection;
|
||||
|
||||
extern char gConfigLastSectionKey[CONFIG_FILE_MAX_LINE_LENGTH];
|
||||
|
||||
bool configInit(Config* config);
|
||||
void configFree(Config* config);
|
||||
bool configParseCommandLineArguments(Config* config, int argc, char** argv);
|
||||
bool configGetString(Config* config, const char* sectionKey, const char* key, char** valuePtr);
|
||||
bool configSetString(Config* config, const char* sectionKey, const char* key, const char* value);
|
||||
bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr);
|
||||
bool configGetIntList(Config* config, const char* section, const char* key, int* arr, int count);
|
||||
bool configSetInt(Config* config, const char* sectionKey, const char* key, int value);
|
||||
bool configRead(Config* config, const char* filePath, bool isDb);
|
||||
bool configWrite(Config* config, const char* filePath, bool isDb);
|
||||
bool configParseLine(Config* config, char* string);
|
||||
bool configParseKeyValue(char* string, char* key, char* value);
|
||||
bool configEnsureSectionExists(Config* config, const char* sectionKey);
|
||||
bool configTrimString(char* string);
|
||||
bool configGetDouble(Config* config, const char* sectionKey, const char* key, double* valuePtr);
|
||||
bool configSetDouble(Config* config, const char* sectionKey, const char* key, double value);
|
||||
|
||||
bool configGetBool(Config* config, const char* sectionKey, const char* key, bool* valuePtr);
|
||||
bool configSetBool(Config* config, const char* sectionKey, const char* key, bool value);
|
||||
|
||||
#endif /* CONFIG_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,637 @@
|
|||
#ifndef CORE_H
|
||||
#define CORE_H
|
||||
|
||||
#include "db.h"
|
||||
#include "dinput.h"
|
||||
#include "geometry.h"
|
||||
#include "window.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MOUSE_DEFAULT_CURSOR_WIDTH 8
|
||||
#define MOUSE_DEFAULT_CURSOR_HEIGHT 8
|
||||
#define MOUSE_DEFAULT_CURSOR_SIZE (MOUSE_DEFAULT_CURSOR_WIDTH * MOUSE_DEFAULT_CURSOR_HEIGHT)
|
||||
|
||||
#define MOUSE_STATE_LEFT_BUTTON_DOWN 0x01
|
||||
#define MOUSE_STATE_RIGHT_BUTTON_DOWN 0x02
|
||||
|
||||
#define MOUSE_EVENT_LEFT_BUTTON_DOWN 0x01
|
||||
#define MOUSE_EVENT_RIGHT_BUTTON_DOWN 0x02
|
||||
#define MOUSE_EVENT_LEFT_BUTTON_REPEAT 0x04
|
||||
#define MOUSE_EVENT_RIGHT_BUTTON_REPEAT 0x08
|
||||
#define MOUSE_EVENT_LEFT_BUTTON_UP 0x10
|
||||
#define MOUSE_EVENT_RIGHT_BUTTON_UP 0x20
|
||||
#define MOUSE_EVENT_ANY_BUTTON_DOWN (MOUSE_EVENT_LEFT_BUTTON_DOWN | MOUSE_EVENT_RIGHT_BUTTON_DOWN)
|
||||
#define MOUSE_EVENT_ANY_BUTTON_REPEAT (MOUSE_EVENT_LEFT_BUTTON_REPEAT | MOUSE_EVENT_RIGHT_BUTTON_REPEAT)
|
||||
#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 BUTTON_REPEAT_TIME 250
|
||||
|
||||
#define KEY_STATE_UP 0
|
||||
#define KEY_STATE_DOWN 1
|
||||
#define KEY_STATE_REPEAT 2
|
||||
|
||||
#define MODIFIER_KEY_STATE_NUM_LOCK 0x01
|
||||
#define MODIFIER_KEY_STATE_CAPS_LOCK 0x02
|
||||
#define MODIFIER_KEY_STATE_SCROLL_LOCK 0x04
|
||||
|
||||
#define KEYBOARD_EVENT_MODIFIER_CAPS_LOCK 0x0001
|
||||
#define KEYBOARD_EVENT_MODIFIER_NUM_LOCK 0x0002
|
||||
#define KEYBOARD_EVENT_MODIFIER_SCROLL_LOCK 0x0004
|
||||
#define KEYBOARD_EVENT_MODIFIER_LEFT_SHIFT 0x0008
|
||||
#define KEYBOARD_EVENT_MODIFIER_RIGHT_SHIFT 0x0010
|
||||
#define KEYBOARD_EVENT_MODIFIER_LEFT_ALT 0x0020
|
||||
#define KEYBOARD_EVENT_MODIFIER_RIGHT_ALT 0x0040
|
||||
#define KEYBOARD_EVENT_MODIFIER_LEFT_CONTROL 0x0080
|
||||
#define KEYBOARD_EVENT_MODIFIER_RIGHT_CONTROL 0x0100
|
||||
#define KEYBOARD_EVENT_MODIFIER_ANY_SHIFT (KEYBOARD_EVENT_MODIFIER_LEFT_SHIFT | KEYBOARD_EVENT_MODIFIER_RIGHT_SHIFT)
|
||||
#define KEYBOARD_EVENT_MODIFIER_ANY_ALT (KEYBOARD_EVENT_MODIFIER_LEFT_ALT | KEYBOARD_EVENT_MODIFIER_RIGHT_ALT)
|
||||
#define KEYBOARD_EVENT_MODIFIER_ANY_CONTROL (KEYBOARD_EVENT_MODIFIER_LEFT_CONTROL | KEYBOARD_EVENT_MODIFIER_RIGHT_CONTROL)
|
||||
|
||||
#define KEY_QUEUE_SIZE 64
|
||||
|
||||
typedef enum Key {
|
||||
KEY_ESCAPE = '\x1b',
|
||||
KEY_TAB = '\x09',
|
||||
KEY_BACKSPACE = '\x08',
|
||||
KEY_RETURN = '\r',
|
||||
|
||||
KEY_SPACE = ' ',
|
||||
KEY_EXCLAMATION = '!',
|
||||
KEY_QUOTE = '"',
|
||||
KEY_NUMBER_SIGN = '#',
|
||||
KEY_DOLLAR = '$',
|
||||
KEY_PERCENT = '%',
|
||||
KEY_AMPERSAND = '&',
|
||||
KEY_SINGLE_QUOTE = '\'',
|
||||
KEY_PAREN_LEFT = '(',
|
||||
KEY_PAREN_RIGHT = ')',
|
||||
KEY_ASTERISK = '*',
|
||||
KEY_PLUS = '+',
|
||||
KEY_COMMA = ',',
|
||||
KEY_MINUS = '-',
|
||||
KEY_DOT = '.',
|
||||
KEY_SLASH = '/',
|
||||
KEY_0 = '0',
|
||||
KEY_1 = '1',
|
||||
KEY_2 = '2',
|
||||
KEY_3 = '3',
|
||||
KEY_4 = '4',
|
||||
KEY_5 = '5',
|
||||
KEY_6 = '6',
|
||||
KEY_7 = '7',
|
||||
KEY_8 = '8',
|
||||
KEY_9 = '9',
|
||||
KEY_COLON = ':',
|
||||
KEY_SEMICOLON = ';',
|
||||
KEY_LESS = '<',
|
||||
KEY_EQUAL = '=',
|
||||
KEY_GREATER = '>',
|
||||
KEY_QUESTION = '?',
|
||||
KEY_AT = '@',
|
||||
KEY_UPPERCASE_A = 'A',
|
||||
KEY_UPPERCASE_B = 'B',
|
||||
KEY_UPPERCASE_C = 'C',
|
||||
KEY_UPPERCASE_D = 'D',
|
||||
KEY_UPPERCASE_E = 'E',
|
||||
KEY_UPPERCASE_F = 'F',
|
||||
KEY_UPPERCASE_G = 'G',
|
||||
KEY_UPPERCASE_H = 'H',
|
||||
KEY_UPPERCASE_I = 'I',
|
||||
KEY_UPPERCASE_J = 'J',
|
||||
KEY_UPPERCASE_K = 'K',
|
||||
KEY_UPPERCASE_L = 'L',
|
||||
KEY_UPPERCASE_M = 'M',
|
||||
KEY_UPPERCASE_N = 'N',
|
||||
KEY_UPPERCASE_O = 'O',
|
||||
KEY_UPPERCASE_P = 'P',
|
||||
KEY_UPPERCASE_Q = 'Q',
|
||||
KEY_UPPERCASE_R = 'R',
|
||||
KEY_UPPERCASE_S = 'S',
|
||||
KEY_UPPERCASE_T = 'T',
|
||||
KEY_UPPERCASE_U = 'U',
|
||||
KEY_UPPERCASE_V = 'V',
|
||||
KEY_UPPERCASE_W = 'W',
|
||||
KEY_UPPERCASE_X = 'X',
|
||||
KEY_UPPERCASE_Y = 'Y',
|
||||
KEY_UPPERCASE_Z = 'Z',
|
||||
|
||||
KEY_BRACKET_LEFT = '[',
|
||||
KEY_BACKSLASH = '\\',
|
||||
KEY_BRACKET_RIGHT = ']',
|
||||
KEY_CARET = '^',
|
||||
KEY_UNDERSCORE = '_',
|
||||
|
||||
KEY_GRAVE = '`',
|
||||
KEY_LOWERCASE_A = 'a',
|
||||
KEY_LOWERCASE_B = 'b',
|
||||
KEY_LOWERCASE_C = 'c',
|
||||
KEY_LOWERCASE_D = 'd',
|
||||
KEY_LOWERCASE_E = 'e',
|
||||
KEY_LOWERCASE_F = 'f',
|
||||
KEY_LOWERCASE_G = 'g',
|
||||
KEY_LOWERCASE_H = 'h',
|
||||
KEY_LOWERCASE_I = 'i',
|
||||
KEY_LOWERCASE_J = 'j',
|
||||
KEY_LOWERCASE_K = 'k',
|
||||
KEY_LOWERCASE_L = 'l',
|
||||
KEY_LOWERCASE_M = 'm',
|
||||
KEY_LOWERCASE_N = 'n',
|
||||
KEY_LOWERCASE_O = 'o',
|
||||
KEY_LOWERCASE_P = 'p',
|
||||
KEY_LOWERCASE_Q = 'q',
|
||||
KEY_LOWERCASE_R = 'r',
|
||||
KEY_LOWERCASE_S = 's',
|
||||
KEY_LOWERCASE_T = 't',
|
||||
KEY_LOWERCASE_U = 'u',
|
||||
KEY_LOWERCASE_V = 'v',
|
||||
KEY_LOWERCASE_W = 'w',
|
||||
KEY_LOWERCASE_X = 'x',
|
||||
KEY_LOWERCASE_Y = 'y',
|
||||
KEY_LOWERCASE_Z = 'z',
|
||||
KEY_BRACE_LEFT = '{',
|
||||
KEY_BAR = '|',
|
||||
KEY_BRACE_RIGHT = '}',
|
||||
KEY_TILDE = '~',
|
||||
KEY_DEL = 127,
|
||||
|
||||
KEY_136 = 136,
|
||||
KEY_146 = 146,
|
||||
KEY_149 = 149,
|
||||
KEY_150 = 150,
|
||||
KEY_151 = 151,
|
||||
KEY_152 = 152,
|
||||
KEY_161 = 161,
|
||||
KEY_163 = 163,
|
||||
KEY_164 = 164,
|
||||
KEY_166 = 166,
|
||||
KEY_168 = 168,
|
||||
KEY_167 = 167,
|
||||
KEY_170 = 170,
|
||||
KEY_172 = 172,
|
||||
KEY_176 = 176,
|
||||
KEY_178 = 178,
|
||||
KEY_179 = 179,
|
||||
KEY_180 = 180,
|
||||
KEY_181 = 181,
|
||||
KEY_186 = 186,
|
||||
KEY_191 = 191,
|
||||
KEY_196 = 196,
|
||||
KEY_199 = 199,
|
||||
KEY_209 = 209,
|
||||
KEY_214 = 214,
|
||||
KEY_215 = 215,
|
||||
KEY_220 = 220,
|
||||
KEY_223 = 223,
|
||||
KEY_224 = 224,
|
||||
KEY_228 = 228,
|
||||
KEY_231 = 231,
|
||||
KEY_232 = 232,
|
||||
KEY_233 = 233,
|
||||
KEY_241 = 241,
|
||||
KEY_246 = 246,
|
||||
KEY_247 = 247,
|
||||
KEY_249 = 249,
|
||||
KEY_252 = 252,
|
||||
|
||||
KEY_ALT_Q = 272,
|
||||
KEY_ALT_W = 273,
|
||||
KEY_ALT_E = 274,
|
||||
KEY_ALT_R = 275,
|
||||
KEY_ALT_T = 276,
|
||||
KEY_ALT_Y = 277,
|
||||
KEY_ALT_U = 278,
|
||||
KEY_ALT_I = 279,
|
||||
KEY_ALT_O = 280,
|
||||
KEY_ALT_P = 281,
|
||||
KEY_ALT_A = 286,
|
||||
KEY_ALT_S = 287,
|
||||
KEY_ALT_D = 288,
|
||||
KEY_ALT_F = 289,
|
||||
KEY_ALT_G = 290,
|
||||
KEY_ALT_H = 291,
|
||||
KEY_ALT_J = 292,
|
||||
KEY_ALT_K = 293,
|
||||
KEY_ALT_L = 294,
|
||||
KEY_ALT_Z = 300,
|
||||
KEY_ALT_X = 301,
|
||||
KEY_ALT_C = 302,
|
||||
KEY_ALT_V = 303,
|
||||
KEY_ALT_B = 304,
|
||||
KEY_ALT_N = 305,
|
||||
KEY_ALT_M = 306,
|
||||
|
||||
KEY_CTRL_Q = 17,
|
||||
KEY_CTRL_W = 23,
|
||||
KEY_CTRL_E = 5,
|
||||
KEY_CTRL_R = 18,
|
||||
KEY_CTRL_T = 20,
|
||||
KEY_CTRL_Y = 25,
|
||||
KEY_CTRL_U = 21,
|
||||
KEY_CTRL_I = 9,
|
||||
KEY_CTRL_O = 15,
|
||||
KEY_CTRL_P = 16,
|
||||
KEY_CTRL_A = 1,
|
||||
KEY_CTRL_S = 19,
|
||||
KEY_CTRL_D = 4,
|
||||
KEY_CTRL_F = 6,
|
||||
KEY_CTRL_G = 7,
|
||||
KEY_CTRL_H = 8,
|
||||
KEY_CTRL_J = 10,
|
||||
KEY_CTRL_K = 11,
|
||||
KEY_CTRL_L = 12,
|
||||
KEY_CTRL_Z = 26,
|
||||
KEY_CTRL_X = 24,
|
||||
KEY_CTRL_C = 3,
|
||||
KEY_CTRL_V = 22,
|
||||
KEY_CTRL_B = 2,
|
||||
KEY_CTRL_N = 14,
|
||||
KEY_CTRL_M = 13,
|
||||
|
||||
KEY_F1 = 315,
|
||||
KEY_F2 = 316,
|
||||
KEY_F3 = 317,
|
||||
KEY_F4 = 318,
|
||||
KEY_F5 = 319,
|
||||
KEY_F6 = 320,
|
||||
KEY_F7 = 321,
|
||||
KEY_F8 = 322,
|
||||
KEY_F9 = 323,
|
||||
KEY_F10 = 324,
|
||||
KEY_F11 = 389,
|
||||
KEY_F12 = 390,
|
||||
|
||||
KEY_SHIFT_F1 = 340,
|
||||
KEY_SHIFT_F2 = 341,
|
||||
KEY_SHIFT_F3 = 342,
|
||||
KEY_SHIFT_F4 = 343,
|
||||
KEY_SHIFT_F5 = 344,
|
||||
KEY_SHIFT_F6 = 345,
|
||||
KEY_SHIFT_F7 = 346,
|
||||
KEY_SHIFT_F8 = 347,
|
||||
KEY_SHIFT_F9 = 348,
|
||||
KEY_SHIFT_F10 = 349,
|
||||
KEY_SHIFT_F11 = 391,
|
||||
KEY_SHIFT_F12 = 392,
|
||||
|
||||
KEY_CTRL_F1 = 350,
|
||||
KEY_CTRL_F2 = 351,
|
||||
KEY_CTRL_F3 = 352,
|
||||
KEY_CTRL_F4 = 353,
|
||||
KEY_CTRL_F5 = 354,
|
||||
KEY_CTRL_F6 = 355,
|
||||
KEY_CTRL_F7 = 356,
|
||||
KEY_CTRL_F8 = 357,
|
||||
KEY_CTRL_F9 = 358,
|
||||
KEY_CTRL_F10 = 359,
|
||||
KEY_CTRL_F11 = 393,
|
||||
KEY_CTRL_F12 = 394,
|
||||
|
||||
KEY_ALT_F1 = 360,
|
||||
KEY_ALT_F2 = 361,
|
||||
KEY_ALT_F3 = 362,
|
||||
KEY_ALT_F4 = 363,
|
||||
KEY_ALT_F5 = 364,
|
||||
KEY_ALT_F6 = 365,
|
||||
KEY_ALT_F7 = 366,
|
||||
KEY_ALT_F8 = 367,
|
||||
KEY_ALT_F9 = 368,
|
||||
KEY_ALT_F10 = 369,
|
||||
KEY_ALT_F11 = 395,
|
||||
KEY_ALT_F12 = 396,
|
||||
|
||||
KEY_HOME = 327,
|
||||
KEY_CTRL_HOME = 375,
|
||||
KEY_ALT_HOME = 407,
|
||||
|
||||
KEY_PAGE_UP = 329,
|
||||
KEY_CTRL_PAGE_UP = 388,
|
||||
KEY_ALT_PAGE_UP = 409,
|
||||
|
||||
KEY_INSERT = 338,
|
||||
KEY_CTRL_INSERT = 402,
|
||||
KEY_ALT_INSERT = 418,
|
||||
|
||||
KEY_DELETE = 339,
|
||||
KEY_CTRL_DELETE = 403,
|
||||
KEY_ALT_DELETE = 419,
|
||||
|
||||
KEY_END = 335,
|
||||
KEY_CTRL_END = 373,
|
||||
KEY_ALT_END = 415,
|
||||
|
||||
KEY_PAGE_DOWN = 337,
|
||||
KEY_ALT_PAGE_DOWN = 417,
|
||||
KEY_CTRL_PAGE_DOWN = 374,
|
||||
|
||||
KEY_ARROW_UP = 328,
|
||||
KEY_CTRL_ARROW_UP = 397,
|
||||
KEY_ALT_ARROW_UP = 408,
|
||||
|
||||
KEY_ARROW_DOWN = 336,
|
||||
KEY_CTRL_ARROW_DOWN = 401,
|
||||
KEY_ALT_ARROW_DOWN = 416,
|
||||
|
||||
KEY_ARROW_LEFT = 331,
|
||||
KEY_CTRL_ARROW_LEFT = 371,
|
||||
KEY_ALT_ARROW_LEFT = 411,
|
||||
|
||||
KEY_ARROW_RIGHT = 333,
|
||||
KEY_CTRL_ARROW_RIGHT = 372,
|
||||
KEY_ALT_ARROW_RIGHT = 413,
|
||||
|
||||
KEY_CTRL_BACKSLASH = 192,
|
||||
|
||||
KEY_NUMBERPAD_5 = 332,
|
||||
KEY_CTRL_NUMBERPAD_5 = 399,
|
||||
KEY_ALT_NUMBERPAD_5 = 9999,
|
||||
|
||||
KEY_FIRST_INPUT_CHARACTER = KEY_SPACE,
|
||||
KEY_LAST_INPUT_CHARACTER = KEY_LOWERCASE_Z,
|
||||
} Key;
|
||||
|
||||
typedef enum KeyboardLayout {
|
||||
KEYBOARD_LAYOUT_QWERTY,
|
||||
KEYBOARD_LAYOUT_FRENCH,
|
||||
KEYBOARD_LAYOUT_GERMAN,
|
||||
KEYBOARD_LAYOUT_ITALIAN,
|
||||
KEYBOARD_LAYOUT_SPANISH,
|
||||
} KeyboardLayout;
|
||||
|
||||
typedef struct STRUCT_6ABF50 {
|
||||
// Time when appropriate key was pressed down or -1 if it's up.
|
||||
int tick;
|
||||
int repeatCount;
|
||||
} STRUCT_6ABF50;
|
||||
|
||||
typedef struct InputEvent {
|
||||
// This is either logical key or input event id, which can be either
|
||||
// character code pressed or some other numbers used throughout the
|
||||
// game interface.
|
||||
int logicalKey;
|
||||
int mouseX;
|
||||
int mouseY;
|
||||
} InputEvent;
|
||||
|
||||
typedef void TickerProc();
|
||||
|
||||
typedef struct TickerListNode {
|
||||
int flags;
|
||||
TickerProc* proc;
|
||||
struct TickerListNode* next;
|
||||
} TickerListNode;
|
||||
|
||||
typedef struct STRUCT_51E2F0 {
|
||||
int type;
|
||||
int field_4;
|
||||
int field_8;
|
||||
union {
|
||||
struct {
|
||||
int type_1_field_C; // mouse x
|
||||
int type_1_field_10; // mouse y
|
||||
int type_1_field_14; // keyboard layout
|
||||
};
|
||||
struct {
|
||||
short type_2_field_C;
|
||||
};
|
||||
struct {
|
||||
int dx;
|
||||
int dy;
|
||||
int buttons;
|
||||
};
|
||||
};
|
||||
} STRUCT_51E2F0;
|
||||
|
||||
static_assert(sizeof(STRUCT_51E2F0) == 24, "wrong size");
|
||||
|
||||
typedef struct LogicalKeyEntry {
|
||||
short field_0;
|
||||
short unmodified;
|
||||
short shift;
|
||||
short lmenu;
|
||||
short rmenu;
|
||||
short ctrl;
|
||||
} LogicalKeyEntry;
|
||||
|
||||
typedef struct KeyboardEvent {
|
||||
unsigned char scanCode;
|
||||
unsigned short modifiers;
|
||||
} KeyboardEvent;
|
||||
|
||||
typedef int(PauseHandler)();
|
||||
typedef int(ScreenshotHandler)(int width, int height, unsigned char* buffer, unsigned char* palette);
|
||||
|
||||
extern void (*_idle_func)();
|
||||
extern void (*_focus_func)(int);
|
||||
extern int gKeyboardKeyRepeatRate;
|
||||
extern int gKeyboardKeyRepeatDelay;
|
||||
extern bool _keyboard_hooked;
|
||||
extern unsigned char gMouseDefaultCursor[MOUSE_DEFAULT_CURSOR_SIZE];
|
||||
extern int _mouse_idling;
|
||||
extern unsigned char* gMouseCursorData;
|
||||
extern unsigned char* _mouse_shape;
|
||||
extern unsigned char* _mouse_fptr;
|
||||
extern double gMouseSensitivity;
|
||||
extern unsigned int _ticker_;
|
||||
extern int gMouseButtonsState;
|
||||
|
||||
extern LPDIRECTDRAW gDirectDraw;
|
||||
extern LPDIRECTDRAWSURFACE gDirectDrawSurface1;
|
||||
extern LPDIRECTDRAWSURFACE gDirectDrawSurface2;
|
||||
extern LPDIRECTDRAWPALETTE gDirectDrawPalette;
|
||||
extern void (*_update_palette_func)();
|
||||
extern bool gMmxEnabled;
|
||||
extern bool gMmxProbed;
|
||||
|
||||
extern unsigned char _kb_installed;
|
||||
extern bool gKeyboardDisabled;
|
||||
extern bool gKeyboardNumpadDisabled;
|
||||
extern bool gKeyboardNumlockDisabled;
|
||||
extern int gKeyboardEventQueueWriteIndex;
|
||||
extern int gKeyboardEventQueueReadIndex;
|
||||
extern short word_51E2E8;
|
||||
extern int gModifierKeysState;
|
||||
extern int (*_kb_scan_to_ascii)();
|
||||
extern STRUCT_51E2F0* _vcr_buffer;
|
||||
extern int _vcr_buffer_index;
|
||||
extern int _vcr_state;
|
||||
extern int _vcr_time;
|
||||
extern int _vcr_counter;
|
||||
extern int _vcr_terminate_flags;
|
||||
extern int _vcr_terminated_condition;
|
||||
extern int _vcr_start_time;
|
||||
extern int _vcr_registered_atexit;
|
||||
extern File* _vcr_file;
|
||||
extern int _vcr_buffer_end;
|
||||
|
||||
extern unsigned char gNormalizedQwertyKeys[256];
|
||||
extern InputEvent gInputEventQueue[40];
|
||||
extern STRUCT_6ABF50 _GNW95_key_time_stamps[256];
|
||||
extern int _input_mx;
|
||||
extern int _input_my;
|
||||
extern HHOOK _GNW95_keyboardHandle;
|
||||
extern bool gPaused;
|
||||
extern int gScreenshotKeyCode;
|
||||
extern int _using_msec_timer;
|
||||
extern int gPauseKeyCode;
|
||||
extern ScreenshotHandler* gScreenshotHandler;
|
||||
extern int gInputEventQueueReadIndex;
|
||||
extern unsigned char* gScreenshotBuffer;
|
||||
extern PauseHandler* gPauseHandler;
|
||||
extern int gInputEventQueueWriteIndex;
|
||||
extern bool gRunLoopDisabled;
|
||||
extern TickerListNode* gTickerListHead;
|
||||
extern unsigned int gTickerLastTimestamp;
|
||||
extern bool gCursorIsHidden;
|
||||
extern int _raw_x;
|
||||
extern int gMouseCursorHeight;
|
||||
extern int _raw_y;
|
||||
extern int _raw_buttons;
|
||||
extern int gMouseCursorY;
|
||||
extern int gMouseCursorX;
|
||||
extern int _mouse_disabled;
|
||||
extern int gMouseEvent;
|
||||
extern unsigned int _mouse_speed;
|
||||
extern int _mouse_curr_frame;
|
||||
extern bool gMouseInitialized;
|
||||
extern int gMouseCursorPitch;
|
||||
extern int gMouseCursorWidth;
|
||||
extern int _mouse_num_frames;
|
||||
extern int _mouse_hoty;
|
||||
extern int _mouse_hotx;
|
||||
extern unsigned int _mouse_idle_start_time;
|
||||
extern WindowDrawingProc2* _mouse_blit_trans;
|
||||
extern WINDOWDRAWINGPROC _mouse_blit;
|
||||
extern unsigned char _mouse_trans;
|
||||
extern int gMouseRightButtonDownTimestamp;
|
||||
extern int gMouseLeftButtonDownTimestamp;
|
||||
extern int gMousePreviousEvent;
|
||||
extern unsigned short gSixteenBppPalette[256];
|
||||
extern Rect _scr_size;
|
||||
extern int gRedMask;
|
||||
extern int gGreenMask;
|
||||
extern int gBlueMask;
|
||||
extern int gBlueShift;
|
||||
extern int gRedShift;
|
||||
extern int gGreenShift;
|
||||
extern void (*_scr_blit)(unsigned char* src, int src_pitch, int a3, int src_x, int src_y, int src_width, int src_height, int dest_x, int dest_y);
|
||||
extern void (*_zero_mem)();
|
||||
extern bool gMmxSupported;
|
||||
extern unsigned char gLastVideoModePalette[268];
|
||||
extern KeyboardEvent gKeyboardEventsQueue[KEY_QUEUE_SIZE];
|
||||
extern LogicalKeyEntry gLogicalKeyEntries[256];
|
||||
extern unsigned char gPressedPhysicalKeys[256];
|
||||
extern unsigned int _kb_idle_start_time;
|
||||
extern KeyboardEvent gLastKeyboardEvent;
|
||||
extern int gKeyboardLayout;
|
||||
extern unsigned char gPressedPhysicalKeysCount;
|
||||
|
||||
int coreInit(int a1);
|
||||
void coreExit();
|
||||
int _get_input();
|
||||
void _process_bk();
|
||||
void enqueueInputEvent(int a1);
|
||||
int dequeueInputEvent();
|
||||
void inputEventQueueReset();
|
||||
void tickersExecute();
|
||||
void tickersAdd(TickerProc* fn);
|
||||
void tickersRemove(TickerProc* fn);
|
||||
void tickersEnable();
|
||||
void tickersDisable();
|
||||
void pauseGame();
|
||||
int pauseHandlerDefaultImpl();
|
||||
void pauseHandlerConfigure(int keyCode, PauseHandler* fn);
|
||||
void takeScreenshot();
|
||||
void screenshotBlitter(unsigned char* src, int src_pitch, int a3, int x, int y, int width, int height, int dest_x, int dest_y);
|
||||
int screenshotHandlerDefaultImpl(int width, int height, unsigned char* data, unsigned char* palette);
|
||||
void screenshotHandlerConfigure(int keyCode, ScreenshotHandler* handler);
|
||||
unsigned int _get_time();
|
||||
void coreDelayProcessingEvents(unsigned int ms);
|
||||
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 buildNormalizedQwertyKeys();
|
||||
void _GNW95_hook_input(int a1);
|
||||
int _GNW95_input_init();
|
||||
int _GNW95_hook_keyboard(int a1);
|
||||
LRESULT CALLBACK _GNW95_keyboard_hook(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
void _GNW95_process_message();
|
||||
void _GNW95_clear_time_stamps();
|
||||
void _GNW95_process_key(KeyboardData* data);
|
||||
void _GNW95_lost_focus();
|
||||
int mouseInit();
|
||||
void mouseFree();
|
||||
void mousePrepareDefaultCursor();
|
||||
int mouseSetFrame(unsigned char* a1, int width, int height, int pitch, int a5, int a6, int a7);
|
||||
void _mouse_anim();
|
||||
void mouseShowCursor();
|
||||
void mouseHideCursor();
|
||||
void _mouse_info();
|
||||
void _mouse_simulate_input(int delta_x, int delta_y, int buttons);
|
||||
bool _mouse_in(int left, int top, int right, int bottom);
|
||||
bool _mouse_click_in(int left, int top, int right, int bottom);
|
||||
void mouseGetRect(Rect* rect);
|
||||
void mouseGetPosition(int* out_x, int* out_y);
|
||||
void _mouse_set_position(int a1, int a2);
|
||||
void _mouse_clip();
|
||||
int mouseGetEvent();
|
||||
bool cursorIsHidden();
|
||||
void _mouse_get_raw_state(int* out_x, int* out_y, int* out_buttons);
|
||||
void mouseSetSensitivity(double value);
|
||||
void mmxSetEnabled(bool a1);
|
||||
int _init_mode_320_200();
|
||||
int _init_mode_320_400();
|
||||
int _init_mode_640_480_16();
|
||||
int _init_mode_640_480();
|
||||
int _init_mode_640_400();
|
||||
int _init_mode_800_600();
|
||||
int _init_mode_1024_768();
|
||||
int _init_mode_1280_1024();
|
||||
void _get_start_mode_();
|
||||
void _zero_vid_mem();
|
||||
int _GNW95_init_mode_ex(int width, int height, int bpp);
|
||||
int _init_vesa_mode(int width, int height);
|
||||
int _GNW95_init_window();
|
||||
int getShiftForBitMask(int mask);
|
||||
int directDrawInit(int width, int height, int bpp);
|
||||
void directDrawFree();
|
||||
void directDrawSetPaletteInRange(unsigned char* a1, int a2, int a3);
|
||||
void directDrawSetPalette(unsigned char* palette);
|
||||
unsigned char* directDrawGetPalette();
|
||||
void _GNW95_ShowRect(unsigned char* src, int src_pitch, int a3, int src_x, int src_y, int src_width, int src_height, int dest_x, int dest_y);
|
||||
void _GNW95_MouseShowRect16(unsigned char* src, int srcPitch, int a3, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY);
|
||||
void _GNW95_ShowRect16(unsigned char* src, int srcPitch, int a3, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY);
|
||||
void _GNW95_MouseShowTransRect16(unsigned char* src, int srcPitch, int a3, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, unsigned char keyColor);
|
||||
void _GNW95_zero_vid_mem();
|
||||
int keyboardInit();
|
||||
void keyboardFree();
|
||||
void keyboardReset();
|
||||
int _kb_getch();
|
||||
void keyboardDisable();
|
||||
void keyboardEnable();
|
||||
int keyboardIsDisabled();
|
||||
void keyboardSetLayout(int new_language);
|
||||
int keyboardGetLayout();
|
||||
void _kb_simulate_key(int a1);
|
||||
int _kb_next_ascii_English_US();
|
||||
int keyboardDequeueLogicalKeyCode();
|
||||
void keyboardBuildQwertyConfiguration();
|
||||
void keyboardBuildFrenchConfiguration();
|
||||
void keyboardBuildGermanConfiguration();
|
||||
void keyboardBuildItalianConfiguration();
|
||||
void keyboardBuildSpanishConfiguration();
|
||||
void _kb_init_lock_status();
|
||||
int keyboardPeekEvent(int index, KeyboardEvent** keyboardEventPtr);
|
||||
bool _vcr_record(const char* fileName);
|
||||
int _vcr_stop(void);
|
||||
int _vcr_status();
|
||||
int _vcr_update();
|
||||
bool _vcr_clear_buffer();
|
||||
int _vcr_dump_buffer();
|
||||
bool _vcr_save_record(STRUCT_51E2F0* ptr, File* stream);
|
||||
bool _vcr_load_record(STRUCT_51E2F0* ptr, File* stream);
|
||||
|
||||
#endif /* CORE_H */
|
|
@ -0,0 +1,266 @@
|
|||
#include "credits.h"
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
#include "cycle.h"
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
#include "game_mouse.h"
|
||||
#include "memory.h"
|
||||
#include "message.h"
|
||||
#include "palette.h"
|
||||
#include "sound.h"
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// 0x56D740
|
||||
File* gCreditsFile;
|
||||
|
||||
// 0x56D744
|
||||
int gCreditsWindowNameColor;
|
||||
|
||||
// 0x56D748
|
||||
int gCreditsWindowTitleFont;
|
||||
|
||||
// 0x56D74C
|
||||
int gCreditsWindowNameFont;
|
||||
|
||||
// 0x56D750
|
||||
int gCreditsWindowTitleColor;
|
||||
|
||||
// 0x42C860
|
||||
void creditsOpen(const char* filePath, int backgroundFid, bool useReversedStyle)
|
||||
{
|
||||
int oldFont = fontGetCurrent();
|
||||
|
||||
colorPaletteLoad("color.pal");
|
||||
|
||||
if (useReversedStyle) {
|
||||
gCreditsWindowTitleColor = _colorTable[18917];
|
||||
gCreditsWindowNameFont = 103;
|
||||
gCreditsWindowTitleFont = 104;
|
||||
gCreditsWindowNameColor = _colorTable[13673];
|
||||
} else {
|
||||
gCreditsWindowTitleColor = _colorTable[13673];
|
||||
gCreditsWindowNameFont = 104;
|
||||
gCreditsWindowTitleFont = 103;
|
||||
gCreditsWindowNameColor = _colorTable[18917];
|
||||
}
|
||||
|
||||
soundContinueAll();
|
||||
|
||||
char localizedPath[MAX_PATH];
|
||||
if (_message_make_path(localizedPath, filePath)) {
|
||||
gCreditsFile = fileOpen(localizedPath, "rt");
|
||||
if (gCreditsFile != NULL) {
|
||||
soundContinueAll();
|
||||
|
||||
colorCycleDisable();
|
||||
gameMouseSetCursor(MOUSE_CURSOR_NONE);
|
||||
|
||||
bool cursorWasHidden = cursorIsHidden();
|
||||
if (cursorWasHidden) {
|
||||
mouseShowCursor();
|
||||
}
|
||||
|
||||
int window = windowCreate(0, 0, CREDITS_WINDOW_WIDTH, CREDITS_WINDOW_HEIGHT, _colorTable[0], 20);
|
||||
soundContinueAll();
|
||||
if (window != -1) {
|
||||
unsigned char* windowBuffer = windowGetBuffer(window);
|
||||
if (windowBuffer != NULL) {
|
||||
unsigned char* backgroundBuffer = internal_malloc(CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT);
|
||||
if (backgroundBuffer) {
|
||||
soundContinueAll();
|
||||
|
||||
memset(backgroundBuffer, _colorTable[0], CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT);
|
||||
|
||||
if (backgroundFid != -1) {
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
Art* frm = artLock(backgroundFid, &backgroundFrmHandle);
|
||||
if (frm != NULL) {
|
||||
int width = artGetWidth(frm, 0, 0);
|
||||
int height = artGetHeight(frm, 0, 0);
|
||||
unsigned char* backgroundFrmData = artGetFrameData(frm, 0, 0);
|
||||
blitBufferToBuffer(backgroundFrmData,
|
||||
width,
|
||||
height,
|
||||
width,
|
||||
backgroundBuffer + CREDITS_WINDOW_WIDTH * ((CREDITS_WINDOW_HEIGHT - height) / 2) + (CREDITS_WINDOW_WIDTH - width) / 2,
|
||||
CREDITS_WINDOW_WIDTH);
|
||||
artUnlock(backgroundFrmHandle);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* intermediateBuffer = internal_malloc(CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT);
|
||||
if (intermediateBuffer != NULL) {
|
||||
memset(intermediateBuffer, 0, CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT);
|
||||
|
||||
fontSetCurrent(gCreditsWindowTitleFont);
|
||||
int titleFontLineHeight = fontGetLineHeight();
|
||||
|
||||
fontSetCurrent(gCreditsWindowNameFont);
|
||||
int nameFontLineHeight = fontGetLineHeight();
|
||||
|
||||
int lineHeight = nameFontLineHeight + (titleFontLineHeight >= nameFontLineHeight ? titleFontLineHeight - nameFontLineHeight : 0);
|
||||
int stringBufferSize = CREDITS_WINDOW_WIDTH * lineHeight;
|
||||
unsigned char* stringBuffer = internal_malloc(stringBufferSize);
|
||||
if (stringBuffer != NULL) {
|
||||
blitBufferToBuffer(backgroundBuffer,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
CREDITS_WINDOW_HEIGHT,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
windowBuffer,
|
||||
CREDITS_WINDOW_WIDTH);
|
||||
|
||||
windowRefresh(window);
|
||||
|
||||
paletteFadeTo(_cmap);
|
||||
|
||||
unsigned char* v40 = intermediateBuffer + CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT - CREDITS_WINDOW_WIDTH;
|
||||
char str[260];
|
||||
int font;
|
||||
int color;
|
||||
unsigned int tick = 0;
|
||||
bool stop = false;
|
||||
while (creditsFileParseNextLine(str, &font, &color)) {
|
||||
fontSetCurrent(font);
|
||||
|
||||
int v19 = fontGetStringWidth(str);
|
||||
if (v19 >= CREDITS_WINDOW_WIDTH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(stringBuffer, 0, stringBufferSize);
|
||||
fontDrawText(stringBuffer, str, CREDITS_WINDOW_WIDTH, CREDITS_WINDOW_WIDTH, color);
|
||||
|
||||
unsigned char* dest = intermediateBuffer + CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT - CREDITS_WINDOW_WIDTH + (CREDITS_WINDOW_WIDTH - v19) / 2;
|
||||
unsigned char* src = stringBuffer;
|
||||
for (int index = 0; index < lineHeight; index++) {
|
||||
if (_get_input() != -1) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
|
||||
memmove(intermediateBuffer, intermediateBuffer + CREDITS_WINDOW_WIDTH, CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT - CREDITS_WINDOW_WIDTH);
|
||||
memcpy(dest, src, v19);
|
||||
|
||||
blitBufferToBuffer(backgroundBuffer,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
CREDITS_WINDOW_HEIGHT,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
windowBuffer,
|
||||
CREDITS_WINDOW_WIDTH);
|
||||
|
||||
blitBufferToBufferTrans(intermediateBuffer,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
CREDITS_WINDOW_HEIGHT,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
windowBuffer,
|
||||
CREDITS_WINDOW_WIDTH);
|
||||
|
||||
while (getTicksSince(tick) < CREDITS_WINDOW_SCROLLING_DELAY) {
|
||||
}
|
||||
|
||||
tick = _get_time();
|
||||
|
||||
windowRefresh(window);
|
||||
|
||||
src += CREDITS_WINDOW_WIDTH;
|
||||
}
|
||||
|
||||
if (stop) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!stop) {
|
||||
for (int index = 0; index < CREDITS_WINDOW_HEIGHT; index++) {
|
||||
if (_get_input() != -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
memmove(intermediateBuffer, intermediateBuffer + CREDITS_WINDOW_WIDTH, CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT - CREDITS_WINDOW_WIDTH);
|
||||
memset(intermediateBuffer + CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT - CREDITS_WINDOW_WIDTH, 0, CREDITS_WINDOW_WIDTH);
|
||||
|
||||
blitBufferToBuffer(backgroundBuffer,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
CREDITS_WINDOW_HEIGHT,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
windowBuffer,
|
||||
CREDITS_WINDOW_WIDTH);
|
||||
|
||||
blitBufferToBufferTrans(intermediateBuffer,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
CREDITS_WINDOW_HEIGHT,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
windowBuffer,
|
||||
CREDITS_WINDOW_WIDTH);
|
||||
|
||||
while (getTicksSince(tick) < CREDITS_WINDOW_SCROLLING_DELAY) {
|
||||
}
|
||||
|
||||
tick = _get_time();
|
||||
|
||||
windowRefresh(window);
|
||||
}
|
||||
}
|
||||
|
||||
internal_free(stringBuffer);
|
||||
}
|
||||
internal_free(intermediateBuffer);
|
||||
}
|
||||
internal_free(backgroundBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
soundContinueAll();
|
||||
paletteFadeTo(gPaletteBlack);
|
||||
soundContinueAll();
|
||||
windowDestroy(window);
|
||||
}
|
||||
|
||||
if (cursorWasHidden) {
|
||||
mouseHideCursor();
|
||||
}
|
||||
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
colorCycleEnable();
|
||||
fileClose(gCreditsFile);
|
||||
}
|
||||
}
|
||||
|
||||
fontSetCurrent(oldFont);
|
||||
}
|
||||
|
||||
// 0x42CE6C
|
||||
bool creditsFileParseNextLine(char* dest, int* font, int* color)
|
||||
{
|
||||
char string[256];
|
||||
while (fileReadString(string, 256, gCreditsFile)) {
|
||||
char* pch;
|
||||
if (string[0] == ';') {
|
||||
continue;
|
||||
} else if (string[0] == '@') {
|
||||
*font = gCreditsWindowTitleFont;
|
||||
*color = gCreditsWindowTitleColor;
|
||||
pch = string + 1;
|
||||
} else if (string[0] == '#') {
|
||||
*font = gCreditsWindowNameFont;
|
||||
*color = _colorTable[17969];
|
||||
pch = string + 1;
|
||||
} else {
|
||||
*font = gCreditsWindowNameFont;
|
||||
*color = gCreditsWindowNameColor;
|
||||
pch = string;
|
||||
}
|
||||
|
||||
strcpy(dest, pch);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef CREDITS_H
|
||||
#define CREDITS_H
|
||||
|
||||
#include "db.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define CREDITS_WINDOW_WIDTH (640)
|
||||
#define CREDITS_WINDOW_HEIGHT (480)
|
||||
#define CREDITS_WINDOW_SCROLLING_DELAY (38)
|
||||
|
||||
extern File* gCreditsFile;
|
||||
extern int gCreditsWindowNameColor;
|
||||
extern int gCreditsWindowTitleFont;
|
||||
extern int gCreditsWindowNameFont;
|
||||
extern int gCreditsWindowTitleColor;
|
||||
|
||||
void creditsOpen(const char* path, int fid, bool useReversedStyle);
|
||||
bool creditsFileParseNextLine(char* dest, int* font, int* color);
|
||||
|
||||
#endif /* CREDITS_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,128 @@
|
|||
#ifndef CRITTER_H
|
||||
#define CRITTER_H
|
||||
|
||||
#include "db.h"
|
||||
#include "message.h"
|
||||
#include "obj_types.h"
|
||||
#include "proto_types.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// Maximum length of dude's name length.
|
||||
#define DUDE_NAME_MAX_LENGTH (32)
|
||||
|
||||
// The number of effects caused by radiation.
|
||||
//
|
||||
// A radiation effect is an identifier and does not have it's own name. It's
|
||||
// stat is specified in [gRadiationEffectStats], and it's amount is specified
|
||||
// in [gRadiationEffectPenalties] for every [RadiationLevel].
|
||||
#define RADIATION_EFFECT_COUNT 8
|
||||
|
||||
// Radiation levels.
|
||||
//
|
||||
// The names of levels are taken from Fallout 3, comments from Fallout 2.
|
||||
typedef enum RadiationLevel {
|
||||
// Very nauseous.
|
||||
RADIATION_LEVEL_NONE,
|
||||
|
||||
// Slightly fatigued.
|
||||
RADIATION_LEVEL_MINOR,
|
||||
|
||||
// Vomiting does not stop.
|
||||
RADIATION_LEVEL_ADVANCED,
|
||||
|
||||
// Hair is falling out.
|
||||
RADIATION_LEVEL_CRITICAL,
|
||||
|
||||
// Skin is falling off.
|
||||
RADIATION_LEVEL_DEADLY,
|
||||
|
||||
// Intense agony.
|
||||
RADIATION_LEVEL_FATAL,
|
||||
|
||||
// The number of radiation levels.
|
||||
RADIATION_LEVEL_COUNT,
|
||||
} RadiationLevel;
|
||||
|
||||
typedef enum DudeState {
|
||||
DUDE_STATE_SNEAKING = 0,
|
||||
DUDE_STATE_LEVEL_UP_AVAILABLE = 3,
|
||||
DUDE_STATE_ADDICTED = 4,
|
||||
} DudeState;
|
||||
|
||||
extern char _aCorpse[];
|
||||
extern char byte_501494[];
|
||||
|
||||
extern char* _name_critter;
|
||||
extern const int gRadiationEnduranceModifiers[RADIATION_LEVEL_COUNT];
|
||||
extern const int gRadiationEffectStats[RADIATION_EFFECT_COUNT];
|
||||
extern const int gRadiationEffectPenalties[RADIATION_LEVEL_COUNT][RADIATION_EFFECT_COUNT];
|
||||
extern Object* _critterClearObj;
|
||||
|
||||
extern MessageList gCritterMessageList;
|
||||
extern char gDudeName[DUDE_NAME_MAX_LENGTH];
|
||||
extern int _sneak_working;
|
||||
extern int gKillsByType[KILL_TYPE_COUNT];
|
||||
extern int _old_rad_level;
|
||||
|
||||
int critterInit();
|
||||
void critterReset();
|
||||
void critterExit();
|
||||
int critterLoad(File* stream);
|
||||
int critterSave(File* stream);
|
||||
char* critterGetName(Object* obj);
|
||||
void critterProtoDataCopy(CritterProtoData* dest, CritterProtoData* src);
|
||||
int dudeSetName(const char* name);
|
||||
void dudeResetName();
|
||||
int critterGetHitPoints(Object* critter);
|
||||
int critterAdjustHitPoints(Object* critter, int amount);
|
||||
int critterGetPoison(Object* critter);
|
||||
int critterAdjustPoison(Object* obj, int amount);
|
||||
int poisonEventProcess(Object* obj, void* data);
|
||||
int critterGetRadiation(Object* critter);
|
||||
int critterAdjustRadiation(Object* obj, int amount);
|
||||
int _critter_check_rads(Object* critter);
|
||||
int _get_rad_damage_level(Object* obj, void* data);
|
||||
int _clear_rad_damage(Object* obj, void* data);
|
||||
void _process_rads(Object* obj, int radiationLevel, bool direction);
|
||||
int radiationEventProcess(Object* obj, void* data);
|
||||
int radiationEventRead(File* stream, void** dataPtr);
|
||||
int radiationEventWrite(File* stream, void* data);
|
||||
int critterGetDamageType(Object* critter);
|
||||
int killsIncByType(int killType);
|
||||
int killsGetByType(int killType);
|
||||
int killsLoad(File* stream);
|
||||
int killsSave(File* stream);
|
||||
int critterGetKillType(Object* critter);
|
||||
char* killTypeGetName(int killType);
|
||||
char* killTypeGetDescription(int killType);
|
||||
int _critter_heal_hours(Object* obj, int a2);
|
||||
int _critterClearObjDrugs(Object* obj, void* data);
|
||||
void critterKill(Object* critter, int anim, bool a3);
|
||||
int critterGetExp(Object* critter);
|
||||
bool critterIsActive(Object* critter);
|
||||
bool critterIsDead(Object* critter);
|
||||
bool critterIsCrippled(Object* critter);
|
||||
bool _critter_is_prone(Object* critter);
|
||||
int critterGetBodyType(Object* critter);
|
||||
int gcdLoad(const char* path);
|
||||
int protoCritterDataRead(File* stream, CritterProtoData* critterData);
|
||||
int gcdSave(const char* path);
|
||||
int protoCritterDataWrite(File* stream, CritterProtoData* critterData);
|
||||
void dudeDisableState(int state);
|
||||
void dudeEnableState(int state);
|
||||
void dudeToggleState(int state);
|
||||
bool dudeHasState(int state);
|
||||
int sneakEventProcess(Object* obj, void* data);
|
||||
int _critter_sneak_clear(Object* obj, void* data);
|
||||
bool dudeIsSneaking();
|
||||
int knockoutEventProcess(Object* obj, void* data);
|
||||
int _critter_wake_clear(Object* obj, void* data);
|
||||
int _critter_set_who_hit_me(Object* a1, Object* a2);
|
||||
bool _critter_can_obj_dude_rest();
|
||||
int critterGetMovementPointCostAdjustedForCrippledLegs(Object* critter, int a2);
|
||||
bool critterIsEncumbered(Object* critter);
|
||||
bool critterIsFleeing(Object* a1);
|
||||
bool _critter_flag_check(int pid, int flag);
|
||||
|
||||
#endif /* CRITTER_H */
|
|
@ -0,0 +1,329 @@
|
|||
#include "cycle.h"
|
||||
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
#include "game_config.h"
|
||||
#include "palette.h"
|
||||
|
||||
// 0x51843C
|
||||
int gColorCycleSpeedFactor = 1;
|
||||
|
||||
// TODO: Convert colors to RGB.
|
||||
// clang-format off
|
||||
|
||||
// Green.
|
||||
//
|
||||
// 0x518440
|
||||
unsigned char _slime[12] = {
|
||||
0, 108, 0,
|
||||
11, 115, 7,
|
||||
27, 123, 15,
|
||||
43, 131, 27,
|
||||
};
|
||||
|
||||
// Light gray?
|
||||
//
|
||||
// 0x51844C
|
||||
unsigned char _shoreline[18] = {
|
||||
83, 63, 43,
|
||||
75, 59, 43,
|
||||
67, 55, 39,
|
||||
63, 51, 39,
|
||||
55, 47, 35,
|
||||
51, 43, 35,
|
||||
};
|
||||
|
||||
// Orange.
|
||||
//
|
||||
// 0x51845E
|
||||
unsigned char _fire_slow[15] = {
|
||||
255, 0, 0,
|
||||
215, 0, 0,
|
||||
147, 43, 11,
|
||||
255, 119, 0,
|
||||
255, 59, 0,
|
||||
};
|
||||
|
||||
// Red.
|
||||
//
|
||||
// 0x51846D
|
||||
unsigned char _fire_fast[15] = {
|
||||
71, 0, 0,
|
||||
123, 0, 0,
|
||||
179, 0, 0,
|
||||
123, 0, 0,
|
||||
71, 0, 0,
|
||||
};
|
||||
|
||||
// Light blue.
|
||||
//
|
||||
// 0x51847C
|
||||
unsigned char _monitors[15] = {
|
||||
107, 107, 111,
|
||||
99, 103, 127,
|
||||
87, 107, 143,
|
||||
0, 147, 163,
|
||||
107, 187, 255,
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
||||
// 0x51848C
|
||||
bool gColorCycleInitialized = false;
|
||||
|
||||
// 0x518490
|
||||
bool gColorCycleEnabled = false;
|
||||
|
||||
// 0x518494
|
||||
int _slime_start = 0;
|
||||
|
||||
// 0x518498
|
||||
int _shoreline_start = 0;
|
||||
|
||||
// 0x51849C
|
||||
int _fire_slow_start = 0;
|
||||
|
||||
// 0x5184A0
|
||||
int _fire_fast_start = 0;
|
||||
|
||||
// 0x5184A4
|
||||
int _monitors_start = 0;
|
||||
|
||||
// 0x5184A8
|
||||
unsigned char _bobber_red = 0;
|
||||
|
||||
// 0x5184A9
|
||||
signed char _bobber_diff = -4;
|
||||
|
||||
// 0x56D7D0
|
||||
unsigned int gColorCycleTimestamp3;
|
||||
|
||||
// 0x56D7D4
|
||||
unsigned int gColorCycleTimestamp1;
|
||||
|
||||
// 0x56D7D8
|
||||
unsigned int gColorCycleTimestamp2;
|
||||
|
||||
// 0x56D7DC
|
||||
unsigned int gColorCycleTimestamp4;
|
||||
|
||||
// 0x42E780
|
||||
void colorCycleInit()
|
||||
{
|
||||
if (gColorCycleInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool colorCycling;
|
||||
if (!configGetBool(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_COLOR_CYCLING_KEY, &colorCycling)) {
|
||||
colorCycling = true;
|
||||
}
|
||||
|
||||
if (!colorCycling) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int index = 0; index < 12; index++) {
|
||||
_slime[index] >>= 2;
|
||||
}
|
||||
|
||||
for (int index = 0; index < 18; index++) {
|
||||
_shoreline[index] >>= 2;
|
||||
}
|
||||
|
||||
for (int index = 0; index < 15; index++) {
|
||||
_fire_slow[index] >>= 2;
|
||||
}
|
||||
|
||||
for (int index = 0; index < 15; index++) {
|
||||
_fire_fast[index] >>= 2;
|
||||
}
|
||||
|
||||
for (int index = 0; index < 15; index++) {
|
||||
_monitors[index] >>= 2;
|
||||
}
|
||||
|
||||
tickersAdd(colorCycleTicker);
|
||||
|
||||
gColorCycleInitialized = true;
|
||||
gColorCycleEnabled = true;
|
||||
|
||||
int cycleSpeedFactor;
|
||||
if (!configGetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CYCLE_SPEED_FACTOR_KEY, &cycleSpeedFactor)) {
|
||||
cycleSpeedFactor = 1;
|
||||
}
|
||||
|
||||
cycleSetSpeedFactor(cycleSpeedFactor);
|
||||
}
|
||||
|
||||
// 0x42E8CC
|
||||
void colorCycleReset()
|
||||
{
|
||||
if (gColorCycleInitialized) {
|
||||
gColorCycleTimestamp1 = 0;
|
||||
gColorCycleTimestamp2 = 0;
|
||||
gColorCycleTimestamp3 = 0;
|
||||
gColorCycleTimestamp4 = 0;
|
||||
tickersAdd(colorCycleTicker);
|
||||
gColorCycleEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x42E90C
|
||||
void colorCycleFree()
|
||||
{
|
||||
if (gColorCycleInitialized) {
|
||||
tickersRemove(colorCycleTicker);
|
||||
gColorCycleInitialized = false;
|
||||
gColorCycleEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x42E930
|
||||
void colorCycleDisable()
|
||||
{
|
||||
gColorCycleEnabled = false;
|
||||
}
|
||||
|
||||
// 0x42E93C
|
||||
void colorCycleEnable()
|
||||
{
|
||||
gColorCycleEnabled = true;
|
||||
}
|
||||
|
||||
// 0x42E948
|
||||
bool colorCycleEnabled()
|
||||
{
|
||||
return gColorCycleEnabled;
|
||||
}
|
||||
|
||||
// 0x42E950
|
||||
void cycleSetSpeedFactor(int value)
|
||||
{
|
||||
gColorCycleSpeedFactor = value;
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CYCLE_SPEED_FACTOR_KEY, value);
|
||||
}
|
||||
|
||||
// 0x42E97C
|
||||
void colorCycleTicker()
|
||||
{
|
||||
if (!gColorCycleEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
|
||||
unsigned char* palette = _getSystemPalette();
|
||||
unsigned int time = _get_time();
|
||||
|
||||
if (getTicksBetween(time, gColorCycleTimestamp1) >= COLOR_CYCLE_PERIOD_1 * gColorCycleSpeedFactor) {
|
||||
changed = true;
|
||||
gColorCycleTimestamp1 = time;
|
||||
|
||||
int paletteIndex = 229 * 3;
|
||||
|
||||
for (int index = _slime_start; index < 12; index++) {
|
||||
palette[paletteIndex++] = _slime[index];
|
||||
}
|
||||
|
||||
for (int index = 0; index < _slime_start; index++) {
|
||||
palette[paletteIndex++] = _slime[index];
|
||||
}
|
||||
|
||||
_slime_start -= 3;
|
||||
if (_slime_start < 0) {
|
||||
_slime_start = 9;
|
||||
}
|
||||
|
||||
paletteIndex = 248 * 3;
|
||||
|
||||
for (int index = _shoreline_start; index < 18; index++) {
|
||||
palette[paletteIndex++] = _shoreline[index];
|
||||
}
|
||||
|
||||
for (int index = 0; index < _shoreline_start; index++) {
|
||||
palette[paletteIndex++] = _shoreline[index];
|
||||
}
|
||||
|
||||
_shoreline_start -= 3;
|
||||
if (_shoreline_start < 0) {
|
||||
_shoreline_start = 15;
|
||||
}
|
||||
|
||||
paletteIndex = 238 * 3;
|
||||
|
||||
for (int index = _fire_slow_start; index < 15; index++) {
|
||||
palette[paletteIndex++] = _fire_slow[index];
|
||||
}
|
||||
|
||||
for (int index = 0; index < _fire_slow_start; index++) {
|
||||
palette[paletteIndex++] = _fire_slow[index];
|
||||
}
|
||||
|
||||
_fire_slow_start -= 3;
|
||||
if (_fire_slow_start < 0) {
|
||||
_fire_slow_start = 12;
|
||||
}
|
||||
}
|
||||
|
||||
if (getTicksBetween(time, gColorCycleTimestamp2) >= COLOR_CYCLE_PERIOD_2 * gColorCycleSpeedFactor) {
|
||||
changed = true;
|
||||
gColorCycleTimestamp2 = time;
|
||||
|
||||
int paletteIndex = 243 * 3;
|
||||
|
||||
for (int index = _fire_fast_start; index < 15; index++) {
|
||||
palette[paletteIndex++] = _fire_fast[index];
|
||||
}
|
||||
|
||||
for (int index = 0; index < _fire_fast_start; index++) {
|
||||
palette[paletteIndex++] = _fire_fast[index];
|
||||
}
|
||||
|
||||
_fire_fast_start -= 3;
|
||||
if (_fire_fast_start < 0) {
|
||||
_fire_fast_start = 12;
|
||||
}
|
||||
}
|
||||
|
||||
if (getTicksBetween(time, gColorCycleTimestamp3) >= COLOR_CYCLE_PERIOD_3 * gColorCycleSpeedFactor) {
|
||||
changed = true;
|
||||
gColorCycleTimestamp3 = time;
|
||||
|
||||
int paletteIndex = 233 * 3;
|
||||
|
||||
for (int index = _monitors_start; index < 15; index++) {
|
||||
palette[paletteIndex++] = _monitors[index];
|
||||
}
|
||||
|
||||
for (int index = 0; index < _monitors_start; index++) {
|
||||
palette[paletteIndex++] = _monitors[index];
|
||||
}
|
||||
|
||||
_monitors_start -= 3;
|
||||
|
||||
if (_monitors_start < 0) {
|
||||
_monitors_start = 12;
|
||||
}
|
||||
}
|
||||
|
||||
if (getTicksBetween(time, gColorCycleTimestamp4) >= COLOR_CYCLE_PERIOD_4 * gColorCycleSpeedFactor) {
|
||||
changed = true;
|
||||
gColorCycleTimestamp4 = time;
|
||||
|
||||
if (_bobber_red == 0 || _bobber_red == 60) {
|
||||
_bobber_diff = -_bobber_diff;
|
||||
}
|
||||
|
||||
_bobber_red += _bobber_diff;
|
||||
|
||||
int paletteIndex = 254 * 3;
|
||||
palette[paletteIndex++] = _bobber_red;
|
||||
palette[paletteIndex++] = 0;
|
||||
palette[paletteIndex++] = 0;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
paletteSetEntriesInRange(palette + 229 * 3, 229, 255);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef CYCLE_H
|
||||
#define CYCLE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define COLOR_CYCLE_PERIOD_1 (200U)
|
||||
#define COLOR_CYCLE_PERIOD_2 (142U)
|
||||
#define COLOR_CYCLE_PERIOD_3 (100U)
|
||||
#define COLOR_CYCLE_PERIOD_4 (33U)
|
||||
|
||||
extern int gColorCycleSpeedFactor;
|
||||
extern unsigned char _slime[12];
|
||||
extern unsigned char _shoreline[18];
|
||||
extern unsigned char _fire_slow[15];
|
||||
extern unsigned char _fire_fast[15];
|
||||
extern unsigned char _monitors[15];
|
||||
extern bool gColorCycleEnabled;
|
||||
extern bool gColorCycleInitialized;
|
||||
|
||||
extern unsigned int gColorCycleTimestamp3;
|
||||
extern unsigned int gColorCycleTimestamp1;
|
||||
extern unsigned int gColorCycleTimestamp2;
|
||||
extern unsigned int gColorCycleTimestamp4;
|
||||
|
||||
void colorCycleInit();
|
||||
void colorCycleReset();
|
||||
void colorCycleFree();
|
||||
void colorCycleDisable();
|
||||
void colorCycleEnable();
|
||||
bool colorCycleEnabled();
|
||||
void cycleSetSpeedFactor(int value);
|
||||
void colorCycleTicker();
|
||||
|
||||
#endif /* CYCLE_H */
|
|
@ -0,0 +1,10 @@
|
|||
#include "datafile.h"
|
||||
|
||||
// 0x56D7E0
|
||||
unsigned char _pal[768];
|
||||
|
||||
// 0x42F0E4
|
||||
unsigned char* _datafileGetPalette()
|
||||
{
|
||||
return _pal;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef DATAFILE_H
|
||||
#define DATAFILE_H
|
||||
|
||||
extern unsigned char _pal[768];
|
||||
|
||||
unsigned char* _datafileGetPalette();
|
||||
|
||||
#endif /* DATAFILE_H */
|
|
@ -0,0 +1,734 @@
|
|||
#include "db.h"
|
||||
|
||||
#include "xfile.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Generic file progress report handler.
|
||||
//
|
||||
// 0x51DEEC
|
||||
FileReadProgressHandler* gFileReadProgressHandler = NULL;
|
||||
|
||||
// Bytes read so far while tracking progress.
|
||||
//
|
||||
// Once this value reaches [gFileReadProgressChunkSize] the handler is called
|
||||
// and this value resets to zero.
|
||||
//
|
||||
// 0x51DEF0
|
||||
int gFileReadProgressBytesRead = 0;
|
||||
|
||||
// The number of bytes to read between calls to progress handler.
|
||||
//
|
||||
// 0x673040
|
||||
int gFileReadProgressChunkSize;
|
||||
|
||||
// 0x673044
|
||||
FileList* gFileListHead;
|
||||
|
||||
// Opens file database.
|
||||
//
|
||||
// Returns -1 if [filePath1] was specified, but could not be opened by the
|
||||
// underlying xbase implementation. Result of opening [filePath2] is ignored.
|
||||
// Returns 0 on success.
|
||||
//
|
||||
// NOTE: There are two unknown parameters passed via edx and ecx. The [a2] is
|
||||
// always 0 at the calling sites, and [a4] is always 1. Both parameters are not
|
||||
// used, so it's impossible to figure out their meaning.
|
||||
//
|
||||
// 0x4C5D30
|
||||
int dbOpen(const char* filePath1, int a2, const char* filePath2, int a4)
|
||||
{
|
||||
if (filePath1 != NULL) {
|
||||
if (!xbaseOpen(filePath1)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (filePath2 != NULL) {
|
||||
xbaseOpen(filePath2);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4C5D58
|
||||
bool _db_total()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4C5D60
|
||||
void dbExit()
|
||||
{
|
||||
xbaseReopenAll(NULL);
|
||||
}
|
||||
|
||||
// TODO: sizePtr should be long*.
|
||||
//
|
||||
// 0x4C5D68
|
||||
int dbGetFileSize(const char* filePath, int* sizePtr)
|
||||
{
|
||||
assert(filePath); // "filename", "db.c", 108
|
||||
assert(sizePtr); // "de", "db.c", 109
|
||||
|
||||
File* stream = xfileOpen(filePath, "rb");
|
||||
if (stream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*sizePtr = xfileGetSize(stream);
|
||||
|
||||
xfileClose(stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4C5DD4
|
||||
int dbGetFileContents(const char* filePath, void* ptr)
|
||||
{
|
||||
assert(filePath); // "filename", "db.c", 141
|
||||
assert(ptr); // "buf", "db.c", 142
|
||||
|
||||
File* stream = xfileOpen(filePath, "rb");
|
||||
if (stream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
long size = xfileGetSize(stream);
|
||||
if (gFileReadProgressHandler != NULL) {
|
||||
unsigned char* byteBuffer = (unsigned char*)ptr;
|
||||
|
||||
long remainingSize = size;
|
||||
long chunkSize = gFileReadProgressChunkSize - gFileReadProgressBytesRead;
|
||||
|
||||
while (remainingSize >= chunkSize) {
|
||||
size_t bytesRead = xfileRead(byteBuffer, sizeof(*byteBuffer), chunkSize, stream);
|
||||
byteBuffer += bytesRead;
|
||||
remainingSize -= bytesRead;
|
||||
|
||||
gFileReadProgressBytesRead = 0;
|
||||
gFileReadProgressHandler();
|
||||
|
||||
chunkSize = gFileReadProgressChunkSize;
|
||||
}
|
||||
|
||||
if (remainingSize != 0) {
|
||||
gFileReadProgressBytesRead += xfileRead(byteBuffer, sizeof(*byteBuffer), remainingSize, stream);
|
||||
}
|
||||
} else {
|
||||
xfileRead(ptr, 1, size, stream);
|
||||
}
|
||||
|
||||
xfileClose(stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4C5EB4
|
||||
int fileClose(File* stream)
|
||||
{
|
||||
return xfileClose(stream);
|
||||
}
|
||||
|
||||
// 0x4C5EC8
|
||||
File* fileOpen(const char* filename, const char* mode)
|
||||
{
|
||||
return xfileOpen(filename, mode);
|
||||
}
|
||||
|
||||
// 0x4C5ED0
|
||||
int filePrintFormatted(File* stream, const char* format, ...)
|
||||
{
|
||||
assert(format); // "format", "db.c", 224
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
int rc = xfilePrintFormattedArgs(stream, format, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// 0x4C5F24
|
||||
int fileReadChar(File* stream)
|
||||
{
|
||||
if (gFileReadProgressHandler != NULL) {
|
||||
int ch = xfileReadChar(stream);
|
||||
|
||||
gFileReadProgressBytesRead++;
|
||||
if (gFileReadProgressBytesRead >= gFileReadProgressChunkSize) {
|
||||
gFileReadProgressHandler();
|
||||
gFileReadProgressBytesRead = 0;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
return xfileReadChar(stream);
|
||||
}
|
||||
|
||||
// 0x4C5F70
|
||||
char* fileReadString(char* string, size_t size, File* stream)
|
||||
{
|
||||
if (gFileReadProgressHandler != NULL) {
|
||||
if (xfileReadString(string, size, stream) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gFileReadProgressBytesRead += strlen(string);
|
||||
while (gFileReadProgressBytesRead >= gFileReadProgressChunkSize) {
|
||||
gFileReadProgressHandler();
|
||||
gFileReadProgressBytesRead -= gFileReadProgressChunkSize;
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
return xfileReadString(string, size, stream);
|
||||
}
|
||||
|
||||
// 0x4C5FEC
|
||||
int fileWriteString(const char* string, File* stream)
|
||||
{
|
||||
return xfileWriteString(string, stream);
|
||||
}
|
||||
|
||||
// 0x4C5FFC
|
||||
size_t fileRead(void* ptr, size_t size, size_t count, File* stream)
|
||||
{
|
||||
if (gFileReadProgressHandler != NULL) {
|
||||
unsigned char* byteBuffer = (unsigned char*)ptr;
|
||||
|
||||
size_t totalBytesRead = 0;
|
||||
long remainingSize = size * count;
|
||||
long chunkSize = gFileReadProgressChunkSize - gFileReadProgressBytesRead;
|
||||
|
||||
while (remainingSize >= chunkSize) {
|
||||
size_t bytesRead = xfileRead(byteBuffer, sizeof(*byteBuffer), chunkSize, stream);
|
||||
byteBuffer += bytesRead;
|
||||
totalBytesRead += bytesRead;
|
||||
remainingSize -= bytesRead;
|
||||
|
||||
gFileReadProgressBytesRead = 0;
|
||||
gFileReadProgressHandler();
|
||||
|
||||
chunkSize = gFileReadProgressChunkSize;
|
||||
}
|
||||
|
||||
if (remainingSize != 0) {
|
||||
size_t bytesRead = xfileRead(byteBuffer, sizeof(*byteBuffer), remainingSize, stream);
|
||||
gFileReadProgressBytesRead += bytesRead;
|
||||
totalBytesRead += bytesRead;
|
||||
}
|
||||
|
||||
return totalBytesRead / size;
|
||||
}
|
||||
|
||||
return xfileRead(ptr, size, count, stream);
|
||||
}
|
||||
|
||||
// 0x4C60B8
|
||||
size_t fileWrite(const void* buf, size_t size, size_t count, File* stream)
|
||||
{
|
||||
return xfileWrite(buf, size, count, stream);
|
||||
}
|
||||
|
||||
// 0x4C60C0
|
||||
int fileSeek(File* stream, long offset, int origin)
|
||||
{
|
||||
return xfileSeek(stream, offset, origin);
|
||||
}
|
||||
|
||||
// 0x4C60C8
|
||||
long fileTell(File* stream)
|
||||
{
|
||||
return xfileTell(stream);
|
||||
}
|
||||
|
||||
// 0x4C60D0
|
||||
void fileRewind(File* stream)
|
||||
{
|
||||
xfileRewind(stream);
|
||||
}
|
||||
|
||||
// 0x4C60D8
|
||||
int fileEof(File* stream)
|
||||
{
|
||||
return xfileEof(stream);
|
||||
}
|
||||
|
||||
// NOTE: Not sure about signness.
|
||||
//
|
||||
// 0x4C60E0
|
||||
int fileReadUInt8(File* stream, unsigned char* valuePtr)
|
||||
{
|
||||
int value = fileReadChar(stream);
|
||||
if (value == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*valuePtr = value & 0xFF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Not sure about signness.
|
||||
//
|
||||
// 0x4C60F4
|
||||
int fileReadInt16(File* stream, short* valuePtr)
|
||||
{
|
||||
unsigned char high;
|
||||
// NOTE: Uninline.
|
||||
if (fileReadUInt8(stream, &high) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char low;
|
||||
// NOTE: Uninline.
|
||||
if (fileReadUInt8(stream, &low) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*valuePtr = (high << 8) | low;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Probably uncollapsed 0x4C60F4. There are only couple of places where
|
||||
// the game reads/writes 16-bit integers. I'm not sure there are unsigned
|
||||
// shorts used, but there are definitely signed (art offsets can be both
|
||||
// positive and negative). Provided just in case.
|
||||
int fileReadUInt16(File* stream, unsigned short* valuePtr)
|
||||
{
|
||||
return fileReadInt16(stream, (short*)valuePtr);
|
||||
}
|
||||
|
||||
// 0x4C614C
|
||||
int fileReadInt32(File* stream, int* valuePtr)
|
||||
{
|
||||
int value;
|
||||
|
||||
if (xfileRead(&value, 4, 1, stream) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*valuePtr = ((value >> 24) & 0xFF) | ((value >> 8) & 0xFF00) | ((value << 8) & 0xFF0000) | ((value << 24) & 0xFF000000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Uncollapsed 0x4C614C. The opposite of [_db_fwriteLong]. It can be either
|
||||
// signed vs. unsigned variant, as well as int vs. long. It's provided here to
|
||||
// identify places where data was written with [_db_fwriteLong].
|
||||
int _db_freadInt(File* stream, int* valuePtr)
|
||||
{
|
||||
return fileReadInt32(stream, valuePtr);
|
||||
}
|
||||
|
||||
// NOTE: Probably uncollapsed 0x4C614C.
|
||||
int fileReadUInt32(File* stream, unsigned int* valuePtr)
|
||||
{
|
||||
return _db_freadInt(stream, (int*)valuePtr);
|
||||
}
|
||||
|
||||
// NOTE: Uncollapsed 0x4C614C. The opposite of [fileWriteFloat].
|
||||
int fileReadFloat(File* stream, float* valuePtr)
|
||||
{
|
||||
return fileReadInt32(stream, (int*)valuePtr);
|
||||
}
|
||||
|
||||
int fileReadBool(File* stream, bool* valuePtr)
|
||||
{
|
||||
int value;
|
||||
if (fileReadInt32(stream, &value) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*valuePtr = (value != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Not sure about signness.
|
||||
//
|
||||
// 0x4C61AC
|
||||
int fileWriteUInt8(File* stream, unsigned char value)
|
||||
{
|
||||
return xfileWriteChar(value, stream);
|
||||
};
|
||||
|
||||
// 0x4C61C8
|
||||
int fileWriteInt16(File* stream, short value)
|
||||
{
|
||||
// NOTE: Uninline.
|
||||
if (fileWriteUInt8(stream, (value >> 8) & 0xFF) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
if (fileWriteUInt8(stream, value & 0xFF) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Probably uncollapsed 0x4C61C8.
|
||||
int fileWriteUInt16(File* stream, unsigned short value)
|
||||
{
|
||||
return fileWriteInt16(stream, (short)value);
|
||||
}
|
||||
|
||||
// NOTE: Not sure about signness and int vs. long.
|
||||
//
|
||||
// 0x4C6214
|
||||
int fileWriteInt32(File* stream, int value)
|
||||
{
|
||||
// NOTE: Uninline.
|
||||
return _db_fwriteLong(stream, value);
|
||||
}
|
||||
|
||||
// NOTE: Can either be signed vs. unsigned variant of [fileWriteInt32],
|
||||
// or int vs. long.
|
||||
//
|
||||
// 0x4C6244
|
||||
int _db_fwriteLong(File* stream, int value)
|
||||
{
|
||||
if (fileWriteInt16(stream, (value >> 16) & 0xFFFF) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fileWriteInt16(stream, value & 0xFFFF) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Probably uncollapsed 0x4C6214 or 0x4C6244.
|
||||
int fileWriteUInt32(File* stream, unsigned int value)
|
||||
{
|
||||
return _db_fwriteLong(stream, (int)value);
|
||||
}
|
||||
|
||||
// 0x4C62C4
|
||||
int fileWriteFloat(File* stream, float value)
|
||||
{
|
||||
// NOTE: Uninline.
|
||||
return _db_fwriteLong(stream, *(int*)&value);
|
||||
}
|
||||
|
||||
int fileWriteBool(File* stream, bool value)
|
||||
{
|
||||
return _db_fwriteLong(stream, value ? 1 : 0);
|
||||
}
|
||||
|
||||
// 0x4C62FC
|
||||
int fileReadUInt8List(File* stream, unsigned char* arr, int count)
|
||||
{
|
||||
for (int index = 0; index < count; index++) {
|
||||
unsigned char ch;
|
||||
// NOTE: Uninline.
|
||||
if (fileReadUInt8(stream, &ch) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
arr[index] = ch;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Probably uncollapsed 0x4C62FC. There are couple of places where
|
||||
// [fileReadUInt8List] is used to read strings of fixed length. I'm not
|
||||
// pretty sure this function existed in the original code, but at least
|
||||
// it increases visibility of these places.
|
||||
int fileReadFixedLengthString(File* stream, char* string, int length)
|
||||
{
|
||||
return fileReadUInt8List(stream, (unsigned char*)string, length);
|
||||
}
|
||||
|
||||
// 0x4C6330
|
||||
int fileReadInt16List(File* stream, short* arr, int count)
|
||||
{
|
||||
for (int index = 0; index < count; index++) {
|
||||
short value;
|
||||
// NOTE: Uninline.
|
||||
if (fileReadInt16(stream, &value) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
arr[index] = value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Probably uncollapsed 0x4C6330.
|
||||
int fileReadUInt16List(File* stream, unsigned short* arr, int count)
|
||||
{
|
||||
return fileReadInt16List(stream, (short*)arr, count);
|
||||
}
|
||||
|
||||
// NOTE: Not sure about signed/unsigned int/long.
|
||||
//
|
||||
// 0x4C63BC
|
||||
int fileReadInt32List(File* stream, int* arr, int count)
|
||||
{
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fileRead(arr, sizeof(*arr) * count, 1, stream) < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int index = 0; index < count; index++) {
|
||||
int value = arr[index];
|
||||
arr[index] = ((value >> 24) & 0xFF) | ((value >> 8) & 0xFF00) | ((value << 8) & 0xFF0000) | ((value << 24) & 0xFF000000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Uncollapsed 0x4C63BC. The opposite of [_db_fwriteLongCount].
|
||||
int _db_freadIntCount(File* stream, int* arr, int count)
|
||||
{
|
||||
return fileReadInt32List(stream, arr, count);
|
||||
}
|
||||
|
||||
// NOTE: Probably uncollapsed 0x4C63BC.
|
||||
int fileReadUInt32List(File* stream, unsigned int* arr, int count)
|
||||
{
|
||||
return fileReadInt32List(stream, (int*)arr, count);
|
||||
}
|
||||
|
||||
// 0x4C6464
|
||||
int fileWriteUInt8List(File* stream, unsigned char* arr, int count)
|
||||
{
|
||||
for (int index = 0; index < count; index++) {
|
||||
// NOTE: Uninline.
|
||||
if (fileWriteUInt8(stream, arr[index]) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Probably uncollapsed 0x4C6464. See [fileReadFixedLengthString].
|
||||
int fileWriteFixedLengthString(File* stream, char* string, int length)
|
||||
{
|
||||
return fileWriteUInt8List(stream, (unsigned char*)string, length);
|
||||
}
|
||||
|
||||
// 0x4C6490
|
||||
int fileWriteInt16List(File* stream, short* arr, int count)
|
||||
{
|
||||
for (int index = 0; index < count; index++) {
|
||||
// NOTE: Uninline.
|
||||
if (fileWriteInt16(stream, arr[index]) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Probably uncollapsed 0x4C6490.
|
||||
int fileWriteUInt16List(File* stream, unsigned short* arr, int count)
|
||||
{
|
||||
return fileWriteInt16List(stream, (short*)arr, count);
|
||||
}
|
||||
|
||||
// NOTE: Can be either signed/unsigned + int/long variant.
|
||||
//
|
||||
// 0x4C64F8
|
||||
int fileWriteInt32List(File* stream, int* arr, int count)
|
||||
{
|
||||
for (int index = 0; index < count; index++) {
|
||||
// NOTE: Uninline.
|
||||
if (_db_fwriteLong(stream, arr[index]) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Not sure about signed/unsigned int/long.
|
||||
//
|
||||
// 0x4C6550
|
||||
int _db_fwriteLongCount(File* stream, int* arr, int count)
|
||||
{
|
||||
for (int index = 0; index < count; index++) {
|
||||
int value = arr[index];
|
||||
|
||||
// NOTE: Uninline.
|
||||
if (fileWriteInt16(stream, (value >> 16) & 0xFFFF) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
if (fileWriteInt16(stream, value & 0xFFFF) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Probably uncollapsed 0x4C64F8 or 0x4C6550.
|
||||
int fileWriteUInt32List(File* stream, unsigned int* arr, int count)
|
||||
{
|
||||
return fileWriteInt32List(stream, (int*)arr, count);
|
||||
}
|
||||
|
||||
// 0x4C6628
|
||||
int fileNameListInit(const char* pattern, char*** fileNameListPtr, int a3, int a4)
|
||||
{
|
||||
FileList* fileList = malloc(sizeof(*fileList));
|
||||
if (fileList == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(fileList, 0, sizeof(*fileList));
|
||||
|
||||
XList* xlist = &(fileList->xlist);
|
||||
if (!xlistInit(pattern, xlist)) {
|
||||
free(fileList);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int length = 0;
|
||||
if (xlist->fileNamesLength != 0) {
|
||||
qsort(xlist->fileNames, xlist->fileNamesLength, sizeof(*xlist->fileNames), _db_list_compare);
|
||||
|
||||
int fileNamesLength = xlist->fileNamesLength;
|
||||
for (int index = 0; index < fileNamesLength - 1; index++) {
|
||||
if (stricmp(xlist->fileNames[index], xlist->fileNames[index + 1]) == 0) {
|
||||
char* temp = xlist->fileNames[index + 1];
|
||||
memmove(&(xlist->fileNames[index + 1]), &(xlist->fileNames[index + 2]), sizeof(*xlist->fileNames) * (xlist->fileNamesLength - index - 1));
|
||||
xlist->fileNames[xlist->fileNamesLength - 1] = temp;
|
||||
|
||||
fileNamesLength--;
|
||||
index--;
|
||||
}
|
||||
}
|
||||
|
||||
bool v1 = *pattern == '*';
|
||||
|
||||
for (int index = 0; index < fileNamesLength; index += 1) {
|
||||
const char* name = xlist->fileNames[index];
|
||||
char dir[_MAX_DIR];
|
||||
char fileName[_MAX_FNAME];
|
||||
char extension[_MAX_EXT];
|
||||
_splitpath(name, NULL, dir, fileName, extension);
|
||||
|
||||
bool v2 = false;
|
||||
if (v1) {
|
||||
char* pch = dir;
|
||||
while (*pch != '\0' && *pch != '\\') {
|
||||
pch++;
|
||||
}
|
||||
v2 = *pch != '\0';
|
||||
}
|
||||
|
||||
if (!v2) {
|
||||
sprintf(xlist->fileNames[index], "%s%s", fileName, extension);
|
||||
length++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileList->next = gFileListHead;
|
||||
gFileListHead = fileList;
|
||||
|
||||
*fileNameListPtr = xlist->fileNames;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// 0x4C6868
|
||||
void fileNameListFree(char*** fileNameListPtr, int a2)
|
||||
{
|
||||
if (gFileListHead == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileList* currentFileList = gFileListHead;
|
||||
FileList* previousFileList = gFileListHead;
|
||||
while (*fileNameListPtr != currentFileList->xlist.fileNames) {
|
||||
previousFileList = currentFileList;
|
||||
currentFileList = currentFileList->next;
|
||||
if (currentFileList == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (previousFileList == gFileListHead) {
|
||||
gFileListHead = currentFileList->next;
|
||||
} else {
|
||||
previousFileList->next = currentFileList->next;
|
||||
}
|
||||
|
||||
xlistFree(&(currentFileList->xlist));
|
||||
|
||||
free(currentFileList);
|
||||
}
|
||||
|
||||
// NOTE: This function does nothing. It was probably used to set memory procs
|
||||
// for building file name list.
|
||||
//
|
||||
// 0x4C68B8
|
||||
void _db_register_mem(MallocProc* mallocProc, StrdupProc* strdupProc, FreeProc* freeProc)
|
||||
{
|
||||
}
|
||||
|
||||
// TODO: Return type should be long.
|
||||
//
|
||||
// 0x4C68BC
|
||||
int fileGetSize(File* stream)
|
||||
{
|
||||
return xfileGetSize(stream);
|
||||
}
|
||||
|
||||
// 0x4C68C4
|
||||
void fileSetReadProgressHandler(FileReadProgressHandler* handler, int size)
|
||||
{
|
||||
if (handler != NULL && size != 0) {
|
||||
gFileReadProgressHandler = handler;
|
||||
gFileReadProgressChunkSize = size;
|
||||
} else {
|
||||
gFileReadProgressHandler = NULL;
|
||||
gFileReadProgressChunkSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This function is called when fallout2.cfg has "hashing" enabled, but
|
||||
// it does nothing. It's impossible to guess it's name.
|
||||
//
|
||||
// 0x4C68E4
|
||||
void _db_enable_hash_table_()
|
||||
{
|
||||
}
|
||||
|
||||
// 0x4C68E8
|
||||
int _db_list_compare(const void* p1, const void* p2)
|
||||
{
|
||||
return stricmp(*(const char**)p1, *(const char**)p2);
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
#ifndef DB_H
|
||||
#define DB_H
|
||||
|
||||
#include "memory_defs.h"
|
||||
#include "xfile.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef XFile File;
|
||||
typedef void FileReadProgressHandler();
|
||||
typedef char* StrdupProc(const char* string);
|
||||
|
||||
typedef struct FileList {
|
||||
XList xlist;
|
||||
struct FileList* next;
|
||||
} FileList;
|
||||
|
||||
extern FileReadProgressHandler* gFileReadProgressHandler;
|
||||
extern int gFileReadProgressBytesRead;
|
||||
|
||||
extern int gFileReadProgressChunkSize;
|
||||
extern FileList* gFileListHead;
|
||||
|
||||
int dbOpen(const char* filePath1, int a2, const char* filePath2, int a4);
|
||||
int _db_current(int a1);
|
||||
bool _db_total();
|
||||
void dbExit();
|
||||
int dbGetFileSize(const char* filePath, int* sizePtr);
|
||||
int dbGetFileContents(const char* filePath, void* ptr);
|
||||
int fileClose(File* stream);
|
||||
File* fileOpen(const char* filename, const char* mode);
|
||||
int filePrintFormatted(File* stream, const char* format, ...);
|
||||
int fileReadChar(File* stream);
|
||||
char* fileReadString(char* str, size_t size, File* stream);
|
||||
int fileWriteString(const char* s, File* stream);
|
||||
size_t fileRead(void* buf, size_t size, size_t count, File* stream);
|
||||
size_t fileWrite(const void* buf, size_t size, size_t count, File* stream);
|
||||
int fileSeek(File* stream, long offset, int origin);
|
||||
long fileTell(File* stream);
|
||||
void fileRewind(File* stream);
|
||||
int fileEof(File* stream);
|
||||
int fileReadUInt8(File* stream, unsigned char* valuePtr);
|
||||
int fileReadInt16(File* stream, short* valuePtr);
|
||||
int fileReadUInt16(File* stream, unsigned short* valuePtr);
|
||||
int fileReadInt32(File* stream, int* valuePtr);
|
||||
int fileReadUInt32(File* stream, unsigned int* valuePtr);
|
||||
int _db_freadInt(File* stream, int* valuePtr);
|
||||
int fileReadFloat(File* stream, float* valuePtr);
|
||||
int fileReadBool(File* stream, bool* valuePtr);
|
||||
int fileWriteUInt8(File* stream, unsigned char value);
|
||||
int fileWriteInt16(File* stream, short value);
|
||||
int fileWriteUInt16(File* stream, unsigned short value);
|
||||
int fileWriteInt32(File* stream, int value);
|
||||
int _db_fwriteLong(File* stream, int value);
|
||||
int fileWriteUInt32(File* stream, unsigned int value);
|
||||
int fileWriteFloat(File* stream, float value);
|
||||
int fileWriteBool(File* stream, bool value);
|
||||
int fileReadUInt8List(File* stream, unsigned char* arr, int count);
|
||||
int fileReadFixedLengthString(File* stream, char* string, int length);
|
||||
int fileReadInt16List(File* stream, short* arr, int count);
|
||||
int fileReadUInt16List(File* stream, unsigned short* arr, int count);
|
||||
int fileReadInt32List(File* stream, int* arr, int count);
|
||||
int _db_freadIntCount(File* stream, int* arr, int count);
|
||||
int fileReadUInt32List(File* stream, unsigned int* arr, int count);
|
||||
int fileWriteUInt8List(File* stream, unsigned char* arr, int count);
|
||||
int fileWriteFixedLengthString(File* stream, char* string, int length);
|
||||
int fileWriteInt16List(File* stream, short* arr, int count);
|
||||
int fileWriteUInt16List(File* stream, unsigned short* arr, int count);
|
||||
int fileWriteInt32List(File* stream, int* arr, int count);
|
||||
int _db_fwriteLongCount(File* stream, int* arr, int count);
|
||||
int fileWriteUInt32List(File* stream, unsigned int* arr, int count);
|
||||
int fileNameListInit(const char* pattern, char*** fileNames, int a3, int a4);
|
||||
void fileNameListFree(char*** fileNames, int a2);
|
||||
void _db_register_mem(MallocProc* mallocProc, StrdupProc* strdupProc, FreeProc* freeProc);
|
||||
int fileGetSize(File* stream);
|
||||
void fileSetReadProgressHandler(FileReadProgressHandler* handler, int size);
|
||||
void _db_enable_hash_table_();
|
||||
int _db_list_compare(const void* p1, const void* p2);
|
||||
|
||||
#endif /* DB_H */
|
|
@ -0,0 +1,620 @@
|
|||
#include "dbox.h"
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "game_sound.h"
|
||||
#include "message.h"
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
#include "word_wrap.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// 0x5108C8
|
||||
const int gDialogBoxBackgroundFrmIds[DIALOG_TYPE_COUNT] = {
|
||||
218, // MEDIALOG.FRM - Medium generic dialog box
|
||||
217, // LGDIALOG.FRM - Large generic dialog box
|
||||
};
|
||||
|
||||
// 0x5108D0
|
||||
const int _ytable[DIALOG_TYPE_COUNT] = {
|
||||
23,
|
||||
27,
|
||||
};
|
||||
|
||||
// 0x5108D8
|
||||
const int _xtable[DIALOG_TYPE_COUNT] = {
|
||||
29,
|
||||
29,
|
||||
};
|
||||
|
||||
// 0x5108E0
|
||||
const int _doneY[DIALOG_TYPE_COUNT] = {
|
||||
81,
|
||||
98,
|
||||
};
|
||||
|
||||
// 0x5108E8
|
||||
const int _doneX[DIALOG_TYPE_COUNT] = {
|
||||
51,
|
||||
37,
|
||||
};
|
||||
|
||||
// 0x5108F0
|
||||
const int _dblines[DIALOG_TYPE_COUNT] = {
|
||||
5,
|
||||
6,
|
||||
};
|
||||
|
||||
// 0x510900
|
||||
int _flgids[7] = {
|
||||
224, // loadbox.frm - character editor
|
||||
8, // lilredup.frm - little red button up
|
||||
9, // lilreddn.frm - little red button down
|
||||
181, // dnarwoff.frm - character editor
|
||||
182, // dnarwon.frm - character editor
|
||||
199, // uparwoff.frm - character editor
|
||||
200, // uparwon.frm - character editor
|
||||
};
|
||||
|
||||
// 0x51091C
|
||||
int _flgids2[7] = {
|
||||
225, // savebox.frm - character editor
|
||||
8, // lilredup.frm - little red button up
|
||||
9, // lilreddn.frm - little red button down
|
||||
181, // dnarwoff.frm - character editor
|
||||
182, // dnarwon.frm - character editor
|
||||
199, // uparwoff.frm - character editor
|
||||
200, // uparwon.frm - character editor
|
||||
};
|
||||
|
||||
// 0x41CF20
|
||||
int showDialogBox(const char* title, const char** body, int bodyLength, int x, int y, int titleColor, const char* a8, int bodyColor, int flags)
|
||||
{
|
||||
MessageList messageList;
|
||||
MessageListItem messageListItem;
|
||||
int savedFont = fontGetCurrent();
|
||||
|
||||
bool v86 = false;
|
||||
|
||||
bool hasTwoButtons = false;
|
||||
if (a8 != NULL) {
|
||||
hasTwoButtons = true;
|
||||
}
|
||||
|
||||
bool hasTitle = false;
|
||||
if (title != NULL) {
|
||||
hasTitle = true;
|
||||
}
|
||||
|
||||
if ((flags & DIALOG_BOX_YES_NO) != 0) {
|
||||
hasTwoButtons = true;
|
||||
flags |= DIALOG_BOX_LARGE;
|
||||
flags &= ~DIALOG_BOX_0x20;
|
||||
}
|
||||
|
||||
int maximumLineWidth = 0;
|
||||
if (hasTitle) {
|
||||
maximumLineWidth = fontGetStringWidth(title);
|
||||
}
|
||||
|
||||
int linesCount = 0;
|
||||
for (int index = 0; index < bodyLength; index++) {
|
||||
// NOTE: Calls [fontGetStringWidth] twice because of [max] macro.
|
||||
maximumLineWidth = max(fontGetStringWidth(body[index]), maximumLineWidth);
|
||||
linesCount++;
|
||||
}
|
||||
|
||||
int dialogType;
|
||||
if ((flags & DIALOG_BOX_LARGE) != 0 || hasTwoButtons) {
|
||||
dialogType = DIALOG_TYPE_LARGE;
|
||||
} else if ((flags & DIALOG_BOX_MEDIUM) != 0) {
|
||||
dialogType = DIALOG_TYPE_MEDIUM;
|
||||
} else {
|
||||
if (hasTitle) {
|
||||
linesCount++;
|
||||
}
|
||||
|
||||
dialogType = maximumLineWidth > 168 || linesCount > 5
|
||||
? DIALOG_TYPE_LARGE
|
||||
: DIALOG_TYPE_MEDIUM;
|
||||
}
|
||||
|
||||
CacheEntry* backgroundHandle;
|
||||
int backgroundWidth;
|
||||
int backgroundHeight;
|
||||
int fid = buildFid(6, gDialogBoxBackgroundFrmIds[dialogType], 0, 0, 0);
|
||||
unsigned char* background = artLockFrameDataReturningSize(fid, &backgroundHandle, &backgroundWidth, &backgroundHeight);
|
||||
if (background == NULL) {
|
||||
fontSetCurrent(savedFont);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int win = windowCreate(x, y, backgroundWidth, backgroundHeight, 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);
|
||||
|
||||
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;
|
||||
|
||||
if ((flags & DIALOG_BOX_0x20) == 0) {
|
||||
int doneBoxFid = buildFid(6, 209, 0, 0, 0);
|
||||
doneBox = artLockFrameDataReturningSize(doneBoxFid, &doneBoxHandle, &doneBoxWidth, &doneBoxHeight);
|
||||
if (doneBox == NULL) {
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int downButtonFid = buildFid(6, 9, 0, 0, 0);
|
||||
downButton = artLockFrameDataReturningSize(downButtonFid, &downButtonHandle, &downButtonWidth, &downButtonHeight);
|
||||
if (downButton == NULL) {
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int upButtonFid = buildFid(6, 8, 0, 0, 0);
|
||||
upButton = artLockFrameData(upButtonFid, 0, 0, &upButtonHandle);
|
||||
if (upButton == NULL) {
|
||||
artUnlock(downButtonHandle);
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
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);
|
||||
|
||||
if (!messageListInit(&messageList)) {
|
||||
artUnlock(upButtonHandle);
|
||||
artUnlock(downButtonHandle);
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char path[MAX_PATH];
|
||||
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;
|
||||
}
|
||||
|
||||
fontSetCurrent(103);
|
||||
|
||||
// 100 - DONE
|
||||
// 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]);
|
||||
}
|
||||
|
||||
int btn = buttonCreate(win, v27 + 13, _doneY[dialogType] + 4, downButtonWidth, downButtonHeight, -1, -1, -1, 500, upButton, downButton, NULL, BUTTON_FLAG_TRANSPARENT);
|
||||
if (btn != -1) {
|
||||
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
|
||||
v86 = true;
|
||||
}
|
||||
|
||||
if (hasTwoButtons && dialogType == DIALOG_TYPE_LARGE) {
|
||||
if (v86) {
|
||||
if ((flags & DIALOG_BOX_YES_NO) != 0) {
|
||||
a8 = getmsg(&messageList, &messageListItem, 102);
|
||||
}
|
||||
|
||||
fontSetCurrent(103);
|
||||
|
||||
blitBufferToBufferTrans(doneBox,
|
||||
doneBoxWidth,
|
||||
doneBoxHeight,
|
||||
doneBoxWidth,
|
||||
windowBuf + backgroundWidth * _doneY[dialogType] + _doneX[dialogType] + doneBoxWidth + 24,
|
||||
backgroundWidth);
|
||||
|
||||
fontDrawText(windowBuf + backgroundWidth * (_doneY[dialogType] + 3) + _doneX[dialogType] + doneBoxWidth + 59,
|
||||
a8, backgroundWidth, backgroundWidth, _colorTable[18979]);
|
||||
|
||||
int btn = buttonCreate(win,
|
||||
doneBoxWidth + _doneX[dialogType] + 37,
|
||||
_doneY[dialogType] + 4,
|
||||
downButtonWidth,
|
||||
downButtonHeight,
|
||||
-1, -1, -1, 501, upButton, downButton, 0, BUTTON_FLAG_TRANSPARENT);
|
||||
if (btn != -1) {
|
||||
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
} else {
|
||||
int doneBoxFid = buildFid(6, 209, 0, 0, 0);
|
||||
unsigned char* doneBox = artLockFrameDataReturningSize(doneBoxFid, &doneBoxHandle, &doneBoxWidth, &doneBoxHeight);
|
||||
if (doneBox == NULL) {
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int downButtonFid = buildFid(6, 9, 0, 0, 0);
|
||||
unsigned char* downButton = artLockFrameDataReturningSize(downButtonFid, &downButtonHandle, &downButtonWidth, &downButtonHeight);
|
||||
if (downButton == NULL) {
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int upButtonFid = buildFid(6, 8, 0, 0, 0);
|
||||
unsigned char* upButton = artLockFrameData(upButtonFid, 0, 0, &upButtonHandle);
|
||||
if (upButton == NULL) {
|
||||
artUnlock(downButtonHandle);
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!messageListInit(&messageList)) {
|
||||
artUnlock(upButtonHandle);
|
||||
artUnlock(downButtonHandle);
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
windowDestroy(win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char path[MAX_PATH];
|
||||
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);
|
||||
|
||||
fontSetCurrent(103);
|
||||
|
||||
fontDrawText(windowBuf + backgroundWidth * (_doneY[dialogType] + 3) + _doneX[dialogType] + 35,
|
||||
a8, backgroundWidth, backgroundWidth, _colorTable[18979]);
|
||||
|
||||
int btn = buttonCreate(win,
|
||||
_doneX[dialogType] + 13,
|
||||
_doneY[dialogType] + 4,
|
||||
downButtonWidth,
|
||||
downButtonHeight,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
501,
|
||||
upButton,
|
||||
downButton,
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (btn != -1) {
|
||||
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
|
||||
v86 = true;
|
||||
}
|
||||
}
|
||||
|
||||
fontSetCurrent(101);
|
||||
|
||||
int v23 = _ytable[dialogType];
|
||||
|
||||
if ((flags & DIALOG_BOX_NO_VERTICAL_CENTERING) == 0) {
|
||||
int v41 = _dblines[dialogType] * fontGetLineHeight() / 2 + v23;
|
||||
v23 = v41 - ((bodyLength + 1) * fontGetLineHeight() / 2);
|
||||
}
|
||||
|
||||
if (hasTitle) {
|
||||
if ((flags & DIALOG_BOX_NO_HORIZONTAL_CENTERING) != 0) {
|
||||
fontDrawText(windowBuf + backgroundWidth * v23 + _xtable[dialogType], title, backgroundWidth, backgroundWidth, titleColor);
|
||||
} else {
|
||||
int length = fontGetStringWidth(title);
|
||||
fontDrawText(windowBuf + backgroundWidth * v23 + (backgroundWidth - length) / 2, title, backgroundWidth, backgroundWidth, titleColor);
|
||||
}
|
||||
v23 += fontGetLineHeight();
|
||||
}
|
||||
|
||||
for (int v94 = 0; v94 < bodyLength; v94++) {
|
||||
int len = fontGetStringWidth(body[v94]);
|
||||
if (len <= backgroundWidth - 26) {
|
||||
if ((flags & DIALOG_BOX_NO_HORIZONTAL_CENTERING) != 0) {
|
||||
fontDrawText(windowBuf + backgroundWidth * v23 + _xtable[dialogType], body[v94], backgroundWidth, backgroundWidth, bodyColor);
|
||||
} else {
|
||||
int length = fontGetStringWidth(body[v94]);
|
||||
fontDrawText(windowBuf + backgroundWidth * v23 + (backgroundWidth - length) / 2, body[v94], backgroundWidth, backgroundWidth, bodyColor);
|
||||
}
|
||||
v23 += fontGetLineHeight();
|
||||
} else {
|
||||
short beginnings[WORD_WRAP_MAX_COUNT];
|
||||
short count;
|
||||
if (wordWrap(body[v94], backgroundWidth - 26, beginnings, &count) != 0) {
|
||||
debugPrint("\nError: dialog_out");
|
||||
}
|
||||
|
||||
for (int v48 = 1; v48 < count; v48++) {
|
||||
int v51 = beginnings[v48] - beginnings[v48 - 1];
|
||||
if (v51 >= 260) {
|
||||
v51 = 259;
|
||||
}
|
||||
|
||||
char string[260];
|
||||
strncpy(string, body[v94] + beginnings[v48 - 1], v51);
|
||||
string[v51] = '\0';
|
||||
|
||||
if ((flags & DIALOG_BOX_NO_HORIZONTAL_CENTERING) != 0) {
|
||||
fontDrawText(windowBuf + backgroundWidth * v23 + _xtable[dialogType], string, backgroundWidth, backgroundWidth, bodyColor);
|
||||
} else {
|
||||
int length = fontGetStringWidth(string);
|
||||
fontDrawText(windowBuf + backgroundWidth * v23 + (backgroundWidth - length) / 2, string, backgroundWidth, backgroundWidth, bodyColor);
|
||||
}
|
||||
v23 += fontGetLineHeight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
windowRefresh(win);
|
||||
|
||||
int rc = -1;
|
||||
while (rc == -1) {
|
||||
int keyCode = _get_input();
|
||||
|
||||
if (keyCode == 500) {
|
||||
rc = 1;
|
||||
} else if (keyCode == KEY_RETURN) {
|
||||
soundPlayFile("ib1p1xx1");
|
||||
rc = 1;
|
||||
} else if (keyCode == KEY_ESCAPE || keyCode == 501) {
|
||||
rc = 0;
|
||||
} else {
|
||||
if ((flags & 0x10) != 0) {
|
||||
if (keyCode == KEY_UPPERCASE_Y || keyCode == KEY_LOWERCASE_Y) {
|
||||
rc = 1;
|
||||
} else if (keyCode == KEY_UPPERCASE_N || keyCode == KEY_LOWERCASE_N) {
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
windowDestroy(win);
|
||||
artUnlock(backgroundHandle);
|
||||
fontSetCurrent(savedFont);
|
||||
|
||||
if (v86) {
|
||||
artUnlock(doneBoxHandle);
|
||||
artUnlock(downButtonHandle);
|
||||
artUnlock(upButtonHandle);
|
||||
messageListFree(&messageList);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// 0x41EA78
|
||||
int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLength, int x, int y, int flags)
|
||||
{
|
||||
int oldFont = fontGetCurrent();
|
||||
|
||||
unsigned char* frmBuffers[7];
|
||||
CacheEntry* frmHandles[7];
|
||||
Size frmSizes[7];
|
||||
|
||||
for (int index = 0; index < 7; index++) {
|
||||
int fid = buildFid(6, _flgids2[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]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int win = windowCreate(x, y, frmSizes[0].width, frmSizes[0].height, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
|
||||
if (win == -1) {
|
||||
for (int index = 0; index < 7; index++) {
|
||||
artUnlock(frmHandles[index]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char* windowBuffer = windowGetBuffer(win);
|
||||
memcpy(windowBuffer, frmBuffers[0], frmSizes[0].width * frmSizes[0].height);
|
||||
|
||||
MessageList messageList;
|
||||
MessageListItem messageListItem;
|
||||
|
||||
if (!messageListInit(&messageList)) {
|
||||
windowDestroy(win);
|
||||
|
||||
for (int index = 0; index < 7; index++) {
|
||||
artUnlock(frmHandles[index]);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char path[MAX_PATH];
|
||||
sprintf(path, "%s%s", asc_5186C8, "DBOX.MSG");
|
||||
|
||||
if (!messageListLoad(&messageList, path)) {
|
||||
windowDestroy(win);
|
||||
|
||||
for (int index = 0; index < 7; index++) {
|
||||
artUnlock(frmHandles[index]);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
fontSetCurrent(103);
|
||||
|
||||
// DONE
|
||||
const char* done = getmsg(&messageList, &messageListItem, 100);
|
||||
fontDrawText(windowBuffer + frmSizes[0].width * 213 + 79, done, frmSizes[0].width, frmSizes[0].width, _colorTable[18979]);
|
||||
|
||||
// CANCEL
|
||||
const char* cancel = getmsg(&messageList, &messageListItem, 103);
|
||||
fontDrawText(windowBuffer + frmSizes[0].width * 213 + 182, cancel, frmSizes[0].width, frmSizes[0].width, _colorTable[18979]);
|
||||
|
||||
int doneBtn = buttonCreate(win,
|
||||
58,
|
||||
214,
|
||||
frmSizes[2].width,
|
||||
frmSizes[2].height,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
500,
|
||||
frmBuffers[1],
|
||||
frmBuffers[2],
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (doneBtn != -1) {
|
||||
buttonSetCallbacks(doneBtn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
|
||||
int cancelBtn = buttonCreate(win,
|
||||
163,
|
||||
214,
|
||||
frmSizes[2].width,
|
||||
frmSizes[2].height,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
501,
|
||||
frmBuffers[1],
|
||||
frmBuffers[2],
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (cancelBtn != -1) {
|
||||
buttonSetCallbacks(cancelBtn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
|
||||
int scrollUpBtn = buttonCreate(win,
|
||||
36,
|
||||
44,
|
||||
frmSizes[6].width,
|
||||
frmSizes[6].height,
|
||||
-1,
|
||||
505,
|
||||
506,
|
||||
505,
|
||||
frmBuffers[5],
|
||||
frmBuffers[6],
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (scrollUpBtn != -1) {
|
||||
buttonSetCallbacks(cancelBtn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
|
||||
int scrollDownButton = buttonCreate(win,
|
||||
36,
|
||||
44 + frmSizes[6].height,
|
||||
frmSizes[4].width,
|
||||
frmSizes[4].height,
|
||||
-1,
|
||||
503,
|
||||
504,
|
||||
503,
|
||||
frmBuffers[3],
|
||||
frmBuffers[4],
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (scrollUpBtn != -1) {
|
||||
buttonSetCallbacks(cancelBtn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
|
||||
buttonCreate(
|
||||
win,
|
||||
55,
|
||||
49,
|
||||
190,
|
||||
124,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
502,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
if (a1 != NULL) {
|
||||
fontDrawText(windowBuffer + frmSizes[0].width * 16 + 49, a1, frmSizes[0].width, frmSizes[0].width, _colorTable[18979]);
|
||||
}
|
||||
}
|
||||
|
||||
// 0x41FBDC
|
||||
void _PrntFlist(unsigned char* buffer, char** fileList, int pageOffset, int fileListLength, int selectedIndex, int pitch)
|
||||
{
|
||||
int lineHeight = fontGetLineHeight();
|
||||
int y = 49;
|
||||
bufferFill(buffer + y * pitch + 55, 190, 124, pitch, 100);
|
||||
if (fileListLength != 0) {
|
||||
if (fileListLength - pageOffset > 12) {
|
||||
fileListLength = 12;
|
||||
}
|
||||
|
||||
for (int index = 0; index < fileListLength; index++) {
|
||||
int color = index == selectedIndex ? _colorTable[32747] : _colorTable[992];
|
||||
fontDrawText(buffer + y * index + 55, fileList[index], pitch, pitch, color);
|
||||
y += lineHeight;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef DBOX_H
|
||||
#define DBOX_H
|
||||
|
||||
typedef enum DialogBoxOptions {
|
||||
DIALOG_BOX_LARGE = 0x01,
|
||||
DIALOG_BOX_MEDIUM = 0x02,
|
||||
DIALOG_BOX_NO_HORIZONTAL_CENTERING = 0x04,
|
||||
DIALOG_BOX_NO_VERTICAL_CENTERING = 0x08,
|
||||
DIALOG_BOX_YES_NO = 0x10,
|
||||
DIALOG_BOX_0x20 = 0x20,
|
||||
} DialogBoxOptions;
|
||||
|
||||
typedef enum DialogType {
|
||||
DIALOG_TYPE_MEDIUM,
|
||||
DIALOG_TYPE_LARGE,
|
||||
DIALOG_TYPE_COUNT,
|
||||
} DialogType;
|
||||
|
||||
extern const int gDialogBoxBackgroundFrmIds[DIALOG_TYPE_COUNT];
|
||||
extern const int _ytable[DIALOG_TYPE_COUNT];
|
||||
extern const int _xtable[DIALOG_TYPE_COUNT];
|
||||
extern const int _doneY[DIALOG_TYPE_COUNT];
|
||||
extern const int _doneX[DIALOG_TYPE_COUNT];
|
||||
extern const int _dblines[DIALOG_TYPE_COUNT];
|
||||
extern int _flgids[7];
|
||||
extern int _flgids2[7];
|
||||
|
||||
int showDialogBox(const char* title, const char** body, int bodyLength, int x, int y, int titleColor, const char* a8, int bodyColor, int flags);
|
||||
int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLength, int x, int y, int flags);
|
||||
void _PrntFlist(unsigned char* buffer, char** fileList, int pageOffset, int fileListLength, int selectedIndex, int pitch);
|
||||
|
||||
#endif /* DBOX_H */
|
|
@ -0,0 +1,225 @@
|
|||
#include "debug.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "window_manager_private.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
// 0x51DEF8
|
||||
FILE* _fd = NULL;
|
||||
|
||||
// 0x51DEFC
|
||||
int _curx = 0;
|
||||
|
||||
// 0x51DF00
|
||||
int _cury = 0;
|
||||
|
||||
// 0x51DF04
|
||||
DebugPrintProc* gDebugPrintProc = NULL;
|
||||
|
||||
// 0x4C6CD0
|
||||
void _GNW_debug_init()
|
||||
{
|
||||
atexit(_debug_exit);
|
||||
}
|
||||
|
||||
// 0x4C6CDC
|
||||
void _debug_register_mono()
|
||||
{
|
||||
if (gDebugPrintProc != _debug_mono) {
|
||||
if (_fd != NULL) {
|
||||
fclose(_fd);
|
||||
_fd = NULL;
|
||||
}
|
||||
|
||||
gDebugPrintProc = _debug_mono;
|
||||
_debug_clear();
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C6D18
|
||||
void _debug_register_log(const char* fileName, const char* mode)
|
||||
{
|
||||
if ((mode[0] == 'w' && mode[1] == 'a') && mode[1] == 't') {
|
||||
if (_fd != NULL) {
|
||||
fclose(_fd);
|
||||
}
|
||||
|
||||
_fd = fopen(fileName, mode);
|
||||
gDebugPrintProc = _debug_log;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C6D5C
|
||||
void _debug_register_screen()
|
||||
{
|
||||
if (gDebugPrintProc != _debug_screen) {
|
||||
if (_fd != NULL) {
|
||||
fclose(_fd);
|
||||
_fd = NULL;
|
||||
}
|
||||
|
||||
gDebugPrintProc = _debug_screen;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C6D90
|
||||
void _debug_register_env()
|
||||
{
|
||||
const char* type = getenv("DEBUGACTIVE");
|
||||
if (type == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
char* copy = internal_malloc(strlen(type) + 1);
|
||||
if (copy == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy(copy, type);
|
||||
strlwr(copy);
|
||||
|
||||
if (strcmp(copy, "mono") == 0) {
|
||||
// NOTE: Uninline.
|
||||
_debug_register_mono();
|
||||
} else if (strcmp(copy, "log") == 0) {
|
||||
_debug_register_log("debug.log", "wt");
|
||||
} else if (strcmp(copy, "screen") == 0) {
|
||||
// NOTE: Uninline.
|
||||
_debug_register_screen();
|
||||
} else if (strcmp(copy, "gnw") == 0) {
|
||||
if (gDebugPrintProc != _win_debug) {
|
||||
if (_fd != NULL) {
|
||||
fclose(_fd);
|
||||
_fd = NULL;
|
||||
}
|
||||
|
||||
gDebugPrintProc = _win_debug;
|
||||
}
|
||||
}
|
||||
|
||||
internal_free(copy);
|
||||
}
|
||||
|
||||
// 0x4C6F18
|
||||
void _debug_register_func(DebugPrintProc* proc)
|
||||
{
|
||||
if (gDebugPrintProc != proc) {
|
||||
if (_fd != NULL) {
|
||||
fclose(_fd);
|
||||
_fd = NULL;
|
||||
}
|
||||
|
||||
gDebugPrintProc = proc;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C6F48
|
||||
int debugPrint(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
int rc;
|
||||
|
||||
if (gDebugPrintProc != NULL) {
|
||||
char string[260];
|
||||
vsprintf(string, format, args);
|
||||
|
||||
rc = gDebugPrintProc(string);
|
||||
} else {
|
||||
#ifdef _DEBUG
|
||||
char string[260];
|
||||
vsprintf(string, format, args);
|
||||
OutputDebugStringA(string);
|
||||
#endif
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// 0x4C6F94
|
||||
int _debug_puts(char* string)
|
||||
{
|
||||
if (gDebugPrintProc != NULL) {
|
||||
return gDebugPrintProc(string);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x4C6FAC
|
||||
void _debug_clear()
|
||||
{
|
||||
// TODO: Something with segments.
|
||||
}
|
||||
|
||||
// 0x4C7004
|
||||
int _debug_mono(char* string)
|
||||
{
|
||||
if (gDebugPrintProc == _debug_mono) {
|
||||
while (*string != '\0') {
|
||||
char ch = *string++;
|
||||
_debug_putc(ch);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4C7028
|
||||
int _debug_log(char* string)
|
||||
{
|
||||
if (gDebugPrintProc == _debug_log) {
|
||||
if (_fd == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fprintf(_fd, string) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fflush(_fd) == EOF) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4C7068
|
||||
int _debug_screen(char* string)
|
||||
{
|
||||
if (gDebugPrintProc == _debug_screen) {
|
||||
printf(string);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4C709C
|
||||
void _debug_putc()
|
||||
{
|
||||
// TODO: Something with segments.
|
||||
}
|
||||
|
||||
// 0x4C71AC
|
||||
void _debug_scroll()
|
||||
{
|
||||
// TODO: Something with segments.
|
||||
}
|
||||
|
||||
// 0x4C71E8
|
||||
void _debug_exit(void)
|
||||
{
|
||||
if (_fd != NULL) {
|
||||
fclose(_fd);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef int(DebugPrintProc)(char* string);
|
||||
|
||||
extern FILE* _fd;
|
||||
extern int _curx;
|
||||
extern int _cury;
|
||||
extern DebugPrintProc* gDebugPrintProc;
|
||||
|
||||
void _GNW_debug_init();
|
||||
void _debug_register_mono();
|
||||
void _debug_register_log(const char* fileName, const char* mode);
|
||||
void _debug_register_screen();
|
||||
void _debug_register_env();
|
||||
void _debug_register_func(DebugPrintProc* proc);
|
||||
int debugPrint(const char* format, ...);
|
||||
int _debug_puts(char* string);
|
||||
void _debug_clear();
|
||||
int _debug_mono(char* string);
|
||||
int _debug_log(char* string);
|
||||
int _debug_screen(char* string);
|
||||
void _debug_putc();
|
||||
void _debug_exit(void);
|
||||
|
||||
#endif /* DEBUG_H */
|
|
@ -0,0 +1,828 @@
|
|||
#include "dfile.h"
|
||||
|
||||
#include "fpattern.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static_assert(sizeof(DBase) == 20, "wrong size");
|
||||
static_assert(sizeof(DBaseEntry) == 20, "wrong size");
|
||||
static_assert(sizeof(DFile) == 44, "wrong size");
|
||||
static_assert(sizeof(DFileFindData) == 524, "wrong size");
|
||||
|
||||
// Reads .DAT file contents.
|
||||
//
|
||||
// 0x4E4F58
|
||||
DBase* dbaseOpen(const char* filePath)
|
||||
{
|
||||
assert(filePath); // "filename", "dfile.c", 74
|
||||
|
||||
FILE* stream = fopen(filePath, "rb");
|
||||
if (stream == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBase* dbase = malloc(sizeof(*dbase));
|
||||
if (dbase == NULL) {
|
||||
fclose(stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(dbase, 0, sizeof(*dbase));
|
||||
|
||||
// Get file size, and reposition stream to read footer, which contains two
|
||||
// 32-bits ints.
|
||||
int fileSize = filelength(fileno(stream));
|
||||
if (fseek(stream, fileSize - sizeof(int) * 2, SEEK_SET) != 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Read the size of entries table.
|
||||
int entriesDataSize;
|
||||
if (fread(&entriesDataSize, sizeof(entriesDataSize), 1, stream) != 1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Read the size of entire dbase content.
|
||||
//
|
||||
// NOTE: It appears that this approach allows existence of arbitrary data in
|
||||
// the beginning of the .DAT file.
|
||||
int dbaseDataSize;
|
||||
if (fread(&dbaseDataSize, sizeof(dbaseDataSize), 1, stream) != 1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Reposition stream to the beginning of the entries table.
|
||||
if (fseek(stream, fileSize - entriesDataSize - sizeof(int) * 2, SEEK_SET) != 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (fread(&(dbase->entriesLength), sizeof(dbase->entriesLength), 1, stream) != 1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
dbase->entries = malloc(sizeof(*dbase->entries) * dbase->entriesLength);
|
||||
if (dbase->entries == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
memset(dbase->entries, 0, sizeof(*dbase->entries) * dbase->entriesLength);
|
||||
|
||||
// Read entries one by one, stopping on any error.
|
||||
int entryIndex;
|
||||
for (entryIndex = 0; entryIndex < dbase->entriesLength; entryIndex++) {
|
||||
DBaseEntry* entry = &(dbase->entries[entryIndex]);
|
||||
|
||||
int pathLength;
|
||||
if (fread(&pathLength, sizeof(pathLength), 1, stream) != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
entry->path = malloc(pathLength + 1);
|
||||
if (entry->path == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (fread(entry->path, pathLength, 1, stream) != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
entry->path[pathLength] = '\0';
|
||||
|
||||
if (fread(&(entry->compressed), sizeof(entry->compressed), 1, stream) != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (fread(&(entry->uncompressedSize), sizeof(entry->uncompressedSize), 1, stream) != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (fread(&(entry->dataSize), sizeof(entry->dataSize), 1, stream) != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (fread(&(entry->dataOffset), sizeof(entry->dataOffset), 1, stream) != 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entryIndex < dbase->entriesLength) {
|
||||
// We haven't reached the end, which means there was an error while
|
||||
// reading entries.
|
||||
goto err;
|
||||
}
|
||||
|
||||
dbase->path = strdup(filePath);
|
||||
dbase->dataOffset = fileSize - dbaseDataSize;
|
||||
|
||||
fclose(stream);
|
||||
|
||||
return dbase;
|
||||
|
||||
err:
|
||||
|
||||
dbaseClose(dbase);
|
||||
|
||||
fclose(stream);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Closes [dbase], all open file handles, frees all associated resources,
|
||||
// including the [dbase] itself.
|
||||
//
|
||||
// 0x4E5270
|
||||
bool dbaseClose(DBase* dbase)
|
||||
{
|
||||
assert(dbase); // "dbase", "dfile.c", 173
|
||||
|
||||
DFile* curr = dbase->dfileHead;
|
||||
while (curr != NULL) {
|
||||
DFile* next = curr->next;
|
||||
dfileClose(curr);
|
||||
curr = next;
|
||||
}
|
||||
|
||||
if (dbase->entries != NULL) {
|
||||
for (int index = 0; index < dbase->entriesLength; index++) {
|
||||
DBaseEntry* entry = &(dbase->entries[index]);
|
||||
char* entryName = entry->path;
|
||||
if (entryName != NULL) {
|
||||
free(entryName);
|
||||
}
|
||||
}
|
||||
free(dbase->entries);
|
||||
}
|
||||
|
||||
if (dbase->path != NULL) {
|
||||
free(dbase->path);
|
||||
}
|
||||
|
||||
memset(dbase, 0, sizeof(*dbase));
|
||||
|
||||
free(dbase);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4E5308
|
||||
bool dbaseFindFirstEntry(DBase* dbase, DFileFindData* findFileData, const char* pattern)
|
||||
{
|
||||
for (int index = 0; index < dbase->entriesLength; index++) {
|
||||
DBaseEntry* entry = &(dbase->entries[index]);
|
||||
if (fpattern_match(pattern, entry->path)) {
|
||||
strcpy(findFileData->fileName, entry->path);
|
||||
strcpy(findFileData->pattern, pattern);
|
||||
findFileData->index = index;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x4E53A0
|
||||
bool dbaseFindNextEntry(DBase* dbase, DFileFindData* findFileData)
|
||||
{
|
||||
for (int index = findFileData->index + 1; index < dbase->entriesLength; index++) {
|
||||
DBaseEntry* entry = &(dbase->entries[index]);
|
||||
if (fpattern_match(findFileData->pattern, entry->path)) {
|
||||
strcpy(findFileData->fileName, entry->path);
|
||||
findFileData->index = index;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x4E541C
|
||||
bool dbaseFindClose(DBase* dbase, DFileFindData* findFileData)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// [filelength].
|
||||
//
|
||||
// 0x4E5424
|
||||
long dfileGetSize(DFile* stream)
|
||||
{
|
||||
return stream->entry->uncompressedSize;
|
||||
}
|
||||
|
||||
// [fclose].
|
||||
//
|
||||
// 0x4E542C
|
||||
int dfileClose(DFile* stream)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 253
|
||||
|
||||
int rc = 0;
|
||||
|
||||
if (stream->entry->compressed == 1) {
|
||||
if (inflateEnd(stream->decompressionStream) != Z_OK) {
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (stream->decompressionStream != NULL) {
|
||||
free(stream->decompressionStream);
|
||||
}
|
||||
|
||||
if (stream->decompressionBuffer != NULL) {
|
||||
free(stream->decompressionBuffer);
|
||||
}
|
||||
|
||||
if (stream->stream != NULL) {
|
||||
fclose(stream->stream);
|
||||
}
|
||||
|
||||
// Loop thru open file handles and find previous to remove current handle
|
||||
// from linked list.
|
||||
//
|
||||
// NOTE: Compiled code is slightly different.
|
||||
DFile* curr = stream->dbase->dfileHead;
|
||||
DFile* prev = NULL;
|
||||
while (curr != NULL) {
|
||||
if (curr == stream) {
|
||||
break;
|
||||
}
|
||||
|
||||
prev = curr;
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
if (curr != NULL) {
|
||||
if (prev == NULL) {
|
||||
stream->dbase->dfileHead = stream->next;
|
||||
} else {
|
||||
prev->next = stream->next;
|
||||
}
|
||||
}
|
||||
|
||||
memset(stream, 0, sizeof(*stream));
|
||||
|
||||
free(stream);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// [fopen].
|
||||
//
|
||||
// 0x4E5504
|
||||
DFile* dfileOpen(DBase* dbase, const char* filePath, const char* mode)
|
||||
{
|
||||
assert(dbase); // dfile.c, 295
|
||||
assert(filePath); // dfile.c, 296
|
||||
assert(mode); // dfile.c, 297
|
||||
|
||||
return dfileOpenInternal(dbase, filePath, mode, 0);
|
||||
}
|
||||
|
||||
// [vfprintf].
|
||||
//
|
||||
// 0x4E56C0
|
||||
int dfilePrintFormattedArgs(DFile* stream, const char* format, va_list args)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 368
|
||||
assert(format); // "format", "dfile.c", 369
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// [fgetc].
|
||||
//
|
||||
// This function reports \r\n sequence as one character \n, even though it
|
||||
// consumes two characters from the underlying stream.
|
||||
//
|
||||
// 0x4E5700
|
||||
int dfileReadChar(DFile* stream)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 384
|
||||
|
||||
if ((stream->flags & DFILE_EOF) != 0 || (stream->flags & DFILE_ERROR) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((stream->flags & DFILE_HAS_UNGETC) != 0) {
|
||||
stream->flags &= ~DFILE_HAS_UNGETC;
|
||||
return stream->ungotten;
|
||||
}
|
||||
|
||||
int ch = dfileReadCharInternal(stream);
|
||||
if (ch == -1) {
|
||||
stream->flags |= DFILE_EOF;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
// [fgets].
|
||||
//
|
||||
// Both Windows (\r\n) and Unix (\n) line endings are recognized. Windows
|
||||
// line ending is reported as \n.
|
||||
//
|
||||
// 0x4E5764
|
||||
char* dfileReadString(char* string, int size, DFile* stream)
|
||||
{
|
||||
assert(string); // "s", "dfile.c", 407
|
||||
assert(size); // "n", "dfile.c", 408
|
||||
assert(stream); // "stream", "dfile.c", 409
|
||||
|
||||
if ((stream->flags & DFILE_EOF) != 0 || (stream->flags & DFILE_ERROR) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* pch = string;
|
||||
|
||||
if ((stream->flags & DFILE_HAS_UNGETC) != 0) {
|
||||
*pch++ = stream->ungotten & 0xFF;
|
||||
size--;
|
||||
stream->flags &= ~DFILE_HAS_UNGETC;
|
||||
}
|
||||
|
||||
// Read up to size - 1 characters one by one saving space for the null
|
||||
// terminator.
|
||||
for (int index = 0; index < size - 1; index++) {
|
||||
int ch = dfileReadCharInternal(stream);
|
||||
if (ch == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
*pch++ = ch & 0xFF;
|
||||
|
||||
if (ch == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pch == string) {
|
||||
// No character was set into the buffer.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*pch = '\0';
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
// [fputc].
|
||||
//
|
||||
// 0x4E5830
|
||||
int dfileWriteChar(int ch, DFile* stream)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 437
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// [fputs].
|
||||
//
|
||||
// 0x4E5854
|
||||
int dfileWriteString(const char* string, DFile* stream)
|
||||
{
|
||||
assert(string); // "s", "dfile.c", 448
|
||||
assert(stream); // "stream", "dfile.c", 449
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// [fread].
|
||||
//
|
||||
// 0x4E58FC
|
||||
size_t dfileRead(void* ptr, size_t size, size_t count, DFile* stream)
|
||||
{
|
||||
assert(ptr); // "ptr", "dfile.c", 499
|
||||
assert(stream); // "stream", dfile.c, 500
|
||||
|
||||
if ((stream->flags & DFILE_EOF) != 0 || (stream->flags & DFILE_ERROR) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t remainingSize = stream->entry->uncompressedSize - stream->position;
|
||||
if ((stream->flags & DFILE_HAS_UNGETC) != 0) {
|
||||
remainingSize++;
|
||||
}
|
||||
|
||||
size_t bytesToRead = size * count;
|
||||
if (remainingSize < bytesToRead) {
|
||||
bytesToRead = remainingSize;
|
||||
stream->flags |= DFILE_EOF;
|
||||
}
|
||||
|
||||
size_t extraBytesRead = 0;
|
||||
if ((stream->flags & DFILE_HAS_UNGETC) != 0) {
|
||||
unsigned char* byteBuffer = ptr;
|
||||
*byteBuffer++ = stream->ungotten & 0xFF;
|
||||
ptr = byteBuffer;
|
||||
|
||||
bytesToRead--;
|
||||
|
||||
stream->flags &= ~DFILE_HAS_UNGETC;
|
||||
extraBytesRead = 1;
|
||||
}
|
||||
|
||||
size_t bytesRead;
|
||||
if (stream->entry->compressed == 1) {
|
||||
if (!dfileReadCompressed(stream, ptr, bytesToRead)) {
|
||||
stream->flags |= DFILE_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
bytesRead = bytesToRead;
|
||||
} else {
|
||||
bytesRead = fread(ptr, 1, bytesToRead, stream->stream) + extraBytesRead;
|
||||
stream->position += bytesRead;
|
||||
}
|
||||
|
||||
return bytesRead / size;
|
||||
}
|
||||
|
||||
// [fwrite].
|
||||
//
|
||||
// 0x4E59F8
|
||||
size_t dfileWrite(const void* ptr, size_t size, size_t count, DFile* stream)
|
||||
{
|
||||
assert(ptr); // "ptr", "dfile.c", 538
|
||||
assert(stream); // "stream", "dfile.c", 539
|
||||
|
||||
return count - 1;
|
||||
}
|
||||
|
||||
// [fseek].
|
||||
//
|
||||
// 0x4E5A74
|
||||
int dfileSeek(DFile* stream, long offset, int origin)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 569
|
||||
|
||||
if ((stream->flags & DFILE_ERROR) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((stream->flags & DFILE_TEXT) != 0) {
|
||||
if (offset != 0 && origin != SEEK_SET) {
|
||||
// NOTE: For unknown reason this function does not allow arbitrary
|
||||
// seeks in text streams, whether compressed or not. It only
|
||||
// supports rewinding. Probably because of reading functions which
|
||||
// handle \r\n sequence as \n.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
long offsetFromBeginning;
|
||||
switch (origin) {
|
||||
case SEEK_SET:
|
||||
offsetFromBeginning = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
offsetFromBeginning = stream->position + offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
offsetFromBeginning = stream->entry->uncompressedSize + offset;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (offsetFromBeginning >= stream->entry->uncompressedSize) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
long pos = stream->position;
|
||||
if (offsetFromBeginning == pos) {
|
||||
stream->flags &= ~(DFILE_HAS_UNGETC | DFILE_EOF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (offsetFromBeginning != 0) {
|
||||
if (stream->entry->compressed == 1) {
|
||||
if (offsetFromBeginning < pos) {
|
||||
// We cannot go backwards in compressed stream, so the only way
|
||||
// is to start from the beginning.
|
||||
dfileRewind(stream);
|
||||
}
|
||||
|
||||
// Consume characters one by one until we reach specified offset.
|
||||
while (offsetFromBeginning > stream->position) {
|
||||
if (dfileReadCharInternal(stream) == -1) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (fseek(stream->stream, offsetFromBeginning - pos, SEEK_CUR) != 0) {
|
||||
stream->flags |= DFILE_ERROR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// FIXME: I'm not sure what this assignment means. This field is
|
||||
// only meaningful when reading compressed streams.
|
||||
stream->compressedBytesRead = offsetFromBeginning;
|
||||
}
|
||||
|
||||
stream->flags &= ~(DFILE_HAS_UNGETC | DFILE_EOF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fseek(stream->stream, stream->dbase->dataOffset + stream->entry->dataOffset, SEEK_SET) != 0) {
|
||||
stream->flags |= DFILE_ERROR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (inflateEnd(stream->decompressionStream) != Z_OK) {
|
||||
stream->flags |= DFILE_ERROR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
stream->decompressionStream->zalloc = Z_NULL;
|
||||
stream->decompressionStream->zfree = Z_NULL;
|
||||
stream->decompressionStream->opaque = Z_NULL;
|
||||
stream->decompressionStream->next_in = stream->decompressionBuffer;
|
||||
stream->decompressionStream->avail_in = 0;
|
||||
|
||||
if (inflateInit(stream->decompressionStream) != Z_OK) {
|
||||
stream->flags |= DFILE_ERROR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
stream->position = 0;
|
||||
stream->compressedBytesRead = 0;
|
||||
stream->flags &= ~(DFILE_HAS_UNGETC | DFILE_EOF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// [ftell].
|
||||
//
|
||||
// 0x4E5C88
|
||||
long dfileTell(DFile* stream)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 654
|
||||
|
||||
return stream->position;
|
||||
}
|
||||
|
||||
// [rewind].
|
||||
//
|
||||
// 0x4E5CB0
|
||||
void dfileRewind(DFile* stream)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 664
|
||||
|
||||
dfileSeek(stream, 0, SEEK_SET);
|
||||
|
||||
stream->flags &= ~DFILE_ERROR;
|
||||
}
|
||||
|
||||
// [feof].
|
||||
//
|
||||
// 0x4E5D10
|
||||
int dfileEof(DFile* stream)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 685
|
||||
|
||||
return stream->flags & DFILE_EOF;
|
||||
}
|
||||
|
||||
// The [bsearch] comparison callback, which is used to find [DBaseEntry] for
|
||||
// specified [filePath].
|
||||
//
|
||||
// 0x4E5D70
|
||||
int dbaseFindEntryByFilePath(const void* a1, const void* a2)
|
||||
{
|
||||
const char* filePath = (const char*)a1;
|
||||
DBaseEntry* entry = (DBaseEntry*)a2;
|
||||
|
||||
return stricmp(filePath, entry->path);
|
||||
}
|
||||
|
||||
// 0x4E5D9C
|
||||
DFile* dfileOpenInternal(DBase* dbase, const char* filePath, const char* mode, DFile* dfile)
|
||||
{
|
||||
DBaseEntry* entry = bsearch(filePath, dbase->entries, dbase->entriesLength, sizeof(*dbase->entries), dbaseFindEntryByFilePath);
|
||||
if (entry == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (mode[0] != 'r') {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (dfile == NULL) {
|
||||
dfile = malloc(sizeof(*dfile));
|
||||
if (dfile == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(dfile, 0, sizeof(*dfile));
|
||||
dfile->dbase = dbase;
|
||||
dfile->next = dbase->dfileHead;
|
||||
dbase->dfileHead = dfile;
|
||||
} else {
|
||||
if (dbase != dfile->dbase) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (dfile->stream != NULL) {
|
||||
fclose(dfile->stream);
|
||||
dfile->stream = NULL;
|
||||
}
|
||||
|
||||
dfile->compressedBytesRead = 0;
|
||||
dfile->position = 0;
|
||||
dfile->flags = 0;
|
||||
}
|
||||
|
||||
dfile->entry = entry;
|
||||
|
||||
// Open stream to .DAT file.
|
||||
dfile->stream = fopen(dbase->path, "rb");
|
||||
if (dfile->stream == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Relocate stream to the beginning of data for specified entry.
|
||||
if (fseek(dfile->stream, dbase->dataOffset + entry->dataOffset, SEEK_SET) != 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (entry->compressed == 1) {
|
||||
// Entry is compressed, setup decompression stream and decompression
|
||||
// buffer. This step is not needed when previous instance of dfile is
|
||||
// passed via parameter, which might already have stream and
|
||||
// buffer allocated.
|
||||
if (dfile->decompressionStream == NULL) {
|
||||
dfile->decompressionStream = malloc(sizeof(*dfile->decompressionStream));
|
||||
if (dfile->decompressionStream == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
dfile->decompressionBuffer = malloc(DFILE_DECOMPRESSION_BUFFER_SIZE);
|
||||
if (dfile->decompressionBuffer == NULL) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
dfile->decompressionStream->zalloc = Z_NULL;
|
||||
dfile->decompressionStream->zfree = Z_NULL;
|
||||
dfile->decompressionStream->opaque = Z_NULL;
|
||||
dfile->decompressionStream->next_in = dfile->decompressionBuffer;
|
||||
dfile->decompressionStream->avail_in = 0;
|
||||
|
||||
if (inflateInit(dfile->decompressionStream) != Z_OK) {
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
// Entry is not compressed, there is no need to keep decompression
|
||||
// stream and decompression buffer (in case [dfile] was passed via
|
||||
// parameter).
|
||||
if (dfile->decompressionStream != NULL) {
|
||||
free(dfile->decompressionStream);
|
||||
dfile->decompressionStream = NULL;
|
||||
}
|
||||
|
||||
if (dfile->decompressionBuffer != NULL) {
|
||||
free(dfile->decompressionBuffer);
|
||||
dfile->decompressionBuffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode[1] == 't') {
|
||||
dfile->flags |= DFILE_TEXT;
|
||||
}
|
||||
|
||||
return dfile;
|
||||
|
||||
err:
|
||||
|
||||
if (dfile != NULL) {
|
||||
dfileClose(dfile);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 0x4E5F9C
|
||||
int dfileReadCharInternal(DFile* stream)
|
||||
{
|
||||
if (stream->entry->compressed == 1) {
|
||||
char ch;
|
||||
if (!dfileReadCompressed(stream, &ch, sizeof(ch))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((stream->flags & DFILE_TEXT) != 0) {
|
||||
// NOTE: I'm not sure if they are comparing as chars or ints. Since
|
||||
// character literals are ints, let's cast read characters to int as
|
||||
// well.
|
||||
if (ch == '\r') {
|
||||
char nextCh;
|
||||
if (dfileReadCompressed(stream, &nextCh, sizeof(nextCh))) {
|
||||
if (nextCh == '\n') {
|
||||
ch = nextCh;
|
||||
} else {
|
||||
// NOTE: Uninline.
|
||||
dfileUngetCompressed(stream, nextCh & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ch & 0xFF;
|
||||
}
|
||||
|
||||
if (stream->position >= stream->entry->uncompressedSize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ch = fgetc(stream->stream);
|
||||
if (ch != -1) {
|
||||
if ((stream->flags & DFILE_TEXT) != 0) {
|
||||
// This is a text stream, attempt to detect \r\n sequence.
|
||||
if (ch == '\r') {
|
||||
if (stream->position + 1 < stream->entry->uncompressedSize) {
|
||||
int nextCh = fgetc(stream->stream);
|
||||
if (nextCh == '\n') {
|
||||
ch = nextCh;
|
||||
stream->position++;
|
||||
} else {
|
||||
ungetc(nextCh, stream->stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stream->position++;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
// 0x4E6078
|
||||
bool dfileReadCompressed(DFile* stream, void* ptr, size_t size)
|
||||
{
|
||||
if ((stream->flags & DFILE_HAS_COMPRESSED_UNGETC) != 0) {
|
||||
unsigned char* byteBuffer = ptr;
|
||||
*byteBuffer++ = stream->compressedUngotten & 0xFF;
|
||||
ptr = byteBuffer;
|
||||
|
||||
size--;
|
||||
|
||||
stream->flags &= ~DFILE_HAS_COMPRESSED_UNGETC;
|
||||
stream->position++;
|
||||
|
||||
if (size == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
stream->decompressionStream->next_out = ptr;
|
||||
stream->decompressionStream->avail_out = size;
|
||||
|
||||
do {
|
||||
if (stream->decompressionStream->avail_out == 0) {
|
||||
// Everything was decompressed.
|
||||
break;
|
||||
}
|
||||
|
||||
if (stream->decompressionStream->avail_in == 0) {
|
||||
// No more unprocessed data, request next chunk.
|
||||
size_t bytesToRead = stream->entry->dataSize - stream->compressedBytesRead;
|
||||
if (bytesToRead > DFILE_DECOMPRESSION_BUFFER_SIZE) {
|
||||
bytesToRead = DFILE_DECOMPRESSION_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
if (fread(stream->decompressionBuffer, bytesToRead, 1, stream->stream) != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
stream->decompressionStream->avail_in = bytesToRead;
|
||||
stream->decompressionStream->next_in = stream->decompressionBuffer;
|
||||
|
||||
stream->compressedBytesRead += bytesToRead;
|
||||
}
|
||||
} while (inflate(stream->decompressionStream, Z_NO_FLUSH) == Z_OK);
|
||||
|
||||
if (stream->decompressionStream->avail_out != 0) {
|
||||
// There are some data still waiting, which means there was in error
|
||||
// during decompression loop above.
|
||||
return false;
|
||||
}
|
||||
|
||||
stream->position += size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4E613C
|
||||
void dfileUngetCompressed(DFile* stream, int ch)
|
||||
{
|
||||
stream->compressedUngotten = ch;
|
||||
stream->flags |= DFILE_HAS_COMPRESSED_UNGETC;
|
||||
stream->position--;
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
#ifndef DFILE_H
|
||||
#define DFILE_H
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <zlib.h>
|
||||
|
||||
// The size of decompression buffer for reading compressed [DFile]s.
|
||||
#define DFILE_DECOMPRESSION_BUFFER_SIZE (0x400)
|
||||
|
||||
// Specifies that [DFile] has unget character.
|
||||
//
|
||||
// NOTE: There is an unused function at 0x4E5894 which ungets one character and
|
||||
// stores it in [ungotten]. Since that function is not used, this flag will
|
||||
// never be set.
|
||||
#define DFILE_HAS_UNGETC (0x01)
|
||||
|
||||
// Specifies that [DFile] has reached end of stream.
|
||||
#define DFILE_EOF (0x02)
|
||||
|
||||
// Specifies that [DFile] is in error state.
|
||||
//
|
||||
// [dfileRewind] can be used to clear this flag.
|
||||
#define DFILE_ERROR (0x04)
|
||||
|
||||
// Specifies that [DFile] was opened in text mode.
|
||||
#define DFILE_TEXT (0x08)
|
||||
|
||||
// Specifies that [DFile] has unget compressed character.
|
||||
#define DFILE_HAS_COMPRESSED_UNGETC (0x10)
|
||||
|
||||
typedef struct DBase DBase;
|
||||
typedef struct DBaseEntry DBaseEntry;
|
||||
typedef struct DFile DFile;
|
||||
|
||||
// A representation of .DAT file.
|
||||
typedef struct DBase {
|
||||
// The path of .DAT file that this structure represents.
|
||||
char* path;
|
||||
|
||||
// The offset to the beginning of data section of .DAT file.
|
||||
int dataOffset;
|
||||
|
||||
// The number of entries.
|
||||
int entriesLength;
|
||||
|
||||
// The array of entries.
|
||||
DBaseEntry* entries;
|
||||
|
||||
// The head of linked list of open file handles.
|
||||
DFile* dfileHead;
|
||||
} DBase;
|
||||
|
||||
typedef struct DBaseEntry {
|
||||
char* path;
|
||||
unsigned char compressed;
|
||||
int uncompressedSize;
|
||||
int dataSize;
|
||||
int dataOffset;
|
||||
} DBaseEntry;
|
||||
|
||||
// A handle to open entry in .DAT file.
|
||||
typedef struct DFile {
|
||||
DBase* dbase;
|
||||
DBaseEntry* entry;
|
||||
int flags;
|
||||
|
||||
// The stream of .DAT file opened for reading in binary mode.
|
||||
//
|
||||
// This stream is not shared across open handles. Instead every [DFile]
|
||||
// opens it's own stream via [fopen], which is then closed via [fclose] in
|
||||
// [dfileClose].
|
||||
FILE* stream;
|
||||
|
||||
// The inflate stream used to decompress data.
|
||||
//
|
||||
// This value is NULL if entry is not compressed.
|
||||
z_streamp decompressionStream;
|
||||
|
||||
// The decompression buffer of size [DFILE_DECOMPRESSION_BUFFER_SIZE].
|
||||
//
|
||||
// This value is NULL if entry is not compressed.
|
||||
unsigned char* decompressionBuffer;
|
||||
|
||||
// The last ungot character.
|
||||
//
|
||||
// See [DFILE_HAS_UNGETC] notes.
|
||||
int ungotten;
|
||||
|
||||
// The last ungot compressed character.
|
||||
//
|
||||
// This value is used when reading compressed text streams to detect
|
||||
// Windows end of line sequence \r\n.
|
||||
int compressedUngotten;
|
||||
|
||||
// The number of bytes read so far from compressed stream.
|
||||
//
|
||||
// This value is only used when reading compressed streams. The range is
|
||||
// 0..entry->dataSize.
|
||||
int compressedBytesRead;
|
||||
|
||||
// The position in read stream.
|
||||
//
|
||||
// This value is tracked in terms of uncompressed data (even in compressed
|
||||
// streams). The range is 0..entry->uncompressedSize.
|
||||
long position;
|
||||
|
||||
// Next [DFile] in linked list.
|
||||
//
|
||||
// [DFile]s are stored in [DBase] in reverse order, so it's actually a
|
||||
// previous opened file, not next.
|
||||
DFile* next;
|
||||
} DFile;
|
||||
|
||||
typedef struct DFileFindData {
|
||||
// The name of file that was found during previous search.
|
||||
char fileName[MAX_PATH];
|
||||
|
||||
// The pattern to search.
|
||||
//
|
||||
// This value is set automatically when [dbaseFindFirstEntry] succeeds so
|
||||
// that subsequent calls to [dbaseFindNextEntry] know what to look for.
|
||||
char pattern[MAX_PATH];
|
||||
|
||||
// The index of entry that was found during previous search.
|
||||
//
|
||||
// This value is set automatically when [dbaseFindFirstEntry] and
|
||||
// [dbaseFindNextEntry] succeed so that subsequent calls to [dbaseFindNextEntry]
|
||||
// knows where to start search from.
|
||||
int index;
|
||||
} DFileFindData;
|
||||
|
||||
DBase* dbaseOpen(const char* filename);
|
||||
bool dbaseClose(DBase* dbase);
|
||||
bool dbaseFindFirstEntry(DBase* dbase, DFileFindData* findFileData, const char* pattern);
|
||||
bool dbaseFindNextEntry(DBase* dbase, DFileFindData* findFileData);
|
||||
bool dbaseFindClose(DBase* dbase, DFileFindData* findFileData);
|
||||
long dfileGetSize(DFile* stream);
|
||||
int dfileClose(DFile* stream);
|
||||
DFile* dfileOpen(DBase* dbase, const char* filename, const char* mode);
|
||||
int dfilePrintFormattedArgs(DFile* stream, const char* format, va_list args);
|
||||
int dfileReadChar(DFile* stream);
|
||||
char* dfileReadString(char* str, int size, DFile* stream);
|
||||
int dfileWriteChar(int ch, DFile* stream);
|
||||
int dfileWriteString(const char* s, DFile* stream);
|
||||
size_t dfileRead(void* ptr, size_t size, size_t count, DFile* stream);
|
||||
size_t dfileWrite(const void* ptr, size_t size, size_t count, DFile* stream);
|
||||
int dfileSeek(DFile* stream, long offset, int origin);
|
||||
long dfileTell(DFile* stream);
|
||||
void dfileRewind(DFile* stream);
|
||||
int dfileEof(DFile* stream);
|
||||
int dbaseFindEntryByFilePath(const void* a1, const void* a2);
|
||||
DFile* dfileOpenInternal(DBase* dbase, const char* filename, const char* mode, DFile* a4);
|
||||
int dfileReadCharInternal(DFile* stream);
|
||||
bool dfileReadCompressed(DFile* stream, void* ptr, size_t size);
|
||||
void dfileUngetCompressed(DFile* stream, int ch);
|
||||
|
||||
#endif /* DFILE_H */
|
|
@ -0,0 +1,733 @@
|
|||
#include "dialog.h"
|
||||
|
||||
#include "core.h"
|
||||
#include "memory_manager.h"
|
||||
#include "movie.h"
|
||||
#include "text_font.h"
|
||||
#include "widget.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// 0x501623
|
||||
const float flt_501623 = 31.0;
|
||||
|
||||
// 0x501627
|
||||
const float flt_501627 = 31.0;
|
||||
|
||||
// 0x5184B4
|
||||
int _tods = -1;
|
||||
|
||||
// 0x5184B8
|
||||
int _topDialogLine = 0;
|
||||
|
||||
// 0x5184BC
|
||||
int _topDialogReply = 0;
|
||||
|
||||
// 0x5184E4
|
||||
DialogFunc1* _replyWinDrawCallback = NULL;
|
||||
|
||||
// 0x5184E8
|
||||
DialogFunc2* _optionsWinDrawCallback = NULL;
|
||||
|
||||
// 0x5184EC
|
||||
int gDialogBorderX = 7;
|
||||
|
||||
// 0x5184F0
|
||||
int gDialogBorderY = 7;
|
||||
|
||||
// 0x5184F4
|
||||
int gDialogOptionSpacing = 5;
|
||||
|
||||
// 0x5184F8
|
||||
int _replyRGBset = 0;
|
||||
|
||||
// 0x5184FC
|
||||
int _optionRGBset = 0;
|
||||
|
||||
// 0x518500
|
||||
int _exitDialog = 0;
|
||||
|
||||
// 0x518504
|
||||
int _inDialog = 0;
|
||||
|
||||
// 0x518508
|
||||
int _mediaFlag = 2;
|
||||
|
||||
// 0x56DAE0
|
||||
STRUCT_56DAE0 _dialog[4];
|
||||
|
||||
// Reply flags.
|
||||
//
|
||||
// 0x56DB60
|
||||
short word_56DB60;
|
||||
|
||||
// 0x56DB64
|
||||
int dword_56DB64;
|
||||
|
||||
// 0x56DB68
|
||||
int dword_56DB68;
|
||||
|
||||
// 0x56DB6C
|
||||
int dword_56DB6C;
|
||||
|
||||
// 0x56DB70
|
||||
int dword_56DB70;
|
||||
|
||||
// 0x56DB74
|
||||
int _rand2plus;
|
||||
|
||||
// 0x56DB7C
|
||||
int dword_56DB7C;
|
||||
|
||||
// 0x56DB80
|
||||
int dword_56DB80;
|
||||
|
||||
// 0x56DB84
|
||||
int dword_56DB84;
|
||||
|
||||
// 0x56DB88
|
||||
int dword_56DB88;
|
||||
|
||||
// 0x56DB8C
|
||||
int dword_56DB8C;
|
||||
|
||||
// 0x56DB90
|
||||
int _replyPlaying;
|
||||
|
||||
// 0x56DB94
|
||||
int _replyWin = -1;
|
||||
|
||||
// 0x56DB98
|
||||
int gDialogReplyColorG;
|
||||
|
||||
// 0x56DB9C
|
||||
int gDialogReplyColorB;
|
||||
|
||||
// 0x56DBA4
|
||||
int gDialogOptionColorG;
|
||||
|
||||
// 0x56DBA8
|
||||
int gDialogReplyColorR;
|
||||
|
||||
// 0x56DBAC
|
||||
int gDialogOptionColorB;
|
||||
|
||||
// 0x56DBB0
|
||||
int gDialogOptionColorR;
|
||||
|
||||
// 0x56DBB4
|
||||
int _downButton;
|
||||
|
||||
// 0x56DBB8
|
||||
int dword_56DBB8;
|
||||
|
||||
// 0x56DBBC
|
||||
int dword_56DBBC;
|
||||
|
||||
// 0x56DBC0
|
||||
void* off_56DBC0;
|
||||
|
||||
// 0x56DBC4
|
||||
void* off_56DBC4;
|
||||
|
||||
// 0x56DBC8
|
||||
void* off_56DBC8;
|
||||
|
||||
// 0x56DBCC
|
||||
void* off_56DBCC;
|
||||
|
||||
// 0x56DBD0
|
||||
char* gDialogReplyTitle;
|
||||
|
||||
// 0x56DBD4
|
||||
int _upButton;
|
||||
|
||||
// 0x56DBD8
|
||||
int dword_56DBD8;
|
||||
|
||||
// 0x56DBDC
|
||||
int dword_56DBDC;
|
||||
|
||||
// 0x56DBE0
|
||||
void* off_56DBE0;
|
||||
|
||||
// 0x56DBE4
|
||||
void* off_56DBE4;
|
||||
|
||||
// 0x56DBE8
|
||||
void* off_56DBE8;
|
||||
|
||||
// 0x56DBEC
|
||||
void* off_56DBEC;
|
||||
|
||||
// 0x42F434
|
||||
STRUCT_56DAE0_FIELD_4* _getReply()
|
||||
{
|
||||
STRUCT_56DAE0_FIELD_4* v0;
|
||||
STRUCT_56DAE0_FIELD_4_FIELD_C* v1;
|
||||
|
||||
v0 = &(_dialog[_tods].field_4[_dialog[_tods].field_C]);
|
||||
if (v0->field_C == NULL) {
|
||||
v0->field_14 = 1;
|
||||
v1 = internal_malloc_safe(sizeof(STRUCT_56DAE0_FIELD_4_FIELD_C), __FILE__, __LINE__); // "..\\int\\DIALOG.C", 789
|
||||
} else {
|
||||
v0->field_14++;
|
||||
v1 = internal_realloc_safe(v0->field_C, sizeof(STRUCT_56DAE0_FIELD_4_FIELD_C) * v0->field_14, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 793
|
||||
}
|
||||
v0->field_C = v1;
|
||||
|
||||
return v0;
|
||||
}
|
||||
|
||||
// 0x42F4C0
|
||||
void _replyAddOption(const char* a1, const char* a2, int a3)
|
||||
{
|
||||
STRUCT_56DAE0_FIELD_4* v18;
|
||||
int v17;
|
||||
char* v14;
|
||||
char* v15;
|
||||
|
||||
v18 = _getReply();
|
||||
v17 = v18->field_14 - 1;
|
||||
v18->field_C[v17].field_8 = 2;
|
||||
|
||||
if (a1 != NULL) {
|
||||
v14 = internal_malloc_safe(strlen(a1) + 1, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 805
|
||||
strcpy(v14, a1);
|
||||
v18->field_C[v17].field_0 = v14;
|
||||
} else {
|
||||
v18->field_C[v17].field_0 = NULL;
|
||||
}
|
||||
|
||||
if (a2 != NULL) {
|
||||
v15 = internal_malloc_safe(strlen(a2) + 1, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 810
|
||||
strcpy(v15, a2);
|
||||
v18->field_C[v17].field_4 = v15;
|
||||
} else {
|
||||
v18->field_C[v17].field_4 = NULL;
|
||||
}
|
||||
|
||||
v18->field_C[v17].field_18 = widgetGetFont();
|
||||
v18->field_C[v17].field_1A = word_56DB60;
|
||||
v18->field_C[v17].field_14 = a3;
|
||||
}
|
||||
|
||||
// 0x42F624
|
||||
void _replyAddOptionProc(const char* a1, const char* a2, int a3)
|
||||
{
|
||||
STRUCT_56DAE0_FIELD_4* v5;
|
||||
int v13;
|
||||
char* v11;
|
||||
|
||||
v5 = _getReply();
|
||||
v13 = v5->field_14 - 1;
|
||||
|
||||
v5->field_C[v13].field_8 = 1;
|
||||
|
||||
if (a1 != NULL) {
|
||||
v11 = internal_malloc_safe(strlen(a1) + 1, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 830
|
||||
strcpy(v11, a1);
|
||||
v5->field_C[v13].field_0 = v11;
|
||||
} else {
|
||||
v5->field_C[v13].field_0 = NULL;
|
||||
}
|
||||
|
||||
v5->field_C[v13].field_4 = (char*)a2;
|
||||
|
||||
v5->field_C[v13].field_18 = widgetGetFont();
|
||||
v5->field_C[v13].field_1A = word_56DB60;
|
||||
v5->field_C[v13].field_14 = a3;
|
||||
}
|
||||
|
||||
// 0x42F714
|
||||
void _optionFree(STRUCT_56DAE0_FIELD_4_FIELD_C* a1)
|
||||
{
|
||||
if (a1->field_0 != NULL) {
|
||||
internal_free_safe(a1->field_0, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 844
|
||||
}
|
||||
|
||||
if (a1->field_8 == 2) {
|
||||
if (a1->field_4 != NULL) {
|
||||
internal_free_safe(a1->field_4, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 846
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x42F754
|
||||
void _replyFree()
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
STRUCT_56DAE0* ptr;
|
||||
STRUCT_56DAE0_FIELD_4* v6;
|
||||
|
||||
ptr = &(_dialog[_tods]);
|
||||
for (i = 0; i < ptr->field_8; i++) {
|
||||
v6 = &(_dialog[_tods].field_4[i]);
|
||||
|
||||
if (v6->field_C != NULL) {
|
||||
for (j = 0; j < v6->field_14; j++) {
|
||||
_optionFree(&(v6->field_C[j]));
|
||||
}
|
||||
|
||||
internal_free_safe(v6->field_C, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 857
|
||||
}
|
||||
|
||||
if (v6->field_8 != NULL) {
|
||||
internal_free_safe(v6->field_8, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 860
|
||||
}
|
||||
|
||||
if (v6->field_4 != NULL) {
|
||||
internal_free_safe(v6->field_4, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 862
|
||||
}
|
||||
|
||||
if (v6->field_0 != NULL) {
|
||||
internal_free_safe(v6->field_0, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 864
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr->field_4 != NULL) {
|
||||
internal_free_safe(ptr->field_4, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 867
|
||||
}
|
||||
}
|
||||
|
||||
// 0x42FB94
|
||||
int _endDialog()
|
||||
{
|
||||
if (_tods == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_topDialogReply = _dialog[_tods].field_10;
|
||||
_replyFree();
|
||||
|
||||
if (gDialogReplyTitle != NULL) {
|
||||
internal_free_safe(gDialogReplyTitle, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 986
|
||||
gDialogReplyTitle = NULL;
|
||||
}
|
||||
|
||||
--_tods;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x42FC70
|
||||
void _printLine(int win, char** strings, int strings_num, int a4, int a5, int a6, int a7, int a8, int a9)
|
||||
{
|
||||
int i;
|
||||
int v11;
|
||||
|
||||
for (i = 0; i < strings_num; i++) {
|
||||
v11 = a7 + i * fontGetLineHeight();
|
||||
_windowPrintBuf(win, strings[i], strlen(strings[i]), a4, a5 + a7, a6, v11, a8, a9);
|
||||
}
|
||||
}
|
||||
|
||||
// 0x42FCF0
|
||||
void _printStr(int win, char* a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9)
|
||||
{
|
||||
char** strings;
|
||||
int strings_num;
|
||||
|
||||
strings = _windowWordWrap(a2, a3, 0, &strings_num);
|
||||
_printLine(win, strings, strings_num, a3, a4, a5, a6, a7, a8);
|
||||
_windowFreeWordList(strings, strings_num);
|
||||
}
|
||||
|
||||
// 0x430104
|
||||
int _abortReply(int a1)
|
||||
{
|
||||
int result;
|
||||
int y;
|
||||
int x;
|
||||
|
||||
if (_replyPlaying == 2) {
|
||||
return _moviePlaying() == 0;
|
||||
} else if (_replyPlaying == 3) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = 1;
|
||||
if (a1) {
|
||||
if (_replyWin != -1) {
|
||||
if (!(mouseGetEvent() & 0x10)) {
|
||||
result = 0;
|
||||
} else {
|
||||
mouseGetPosition(&x, &y);
|
||||
|
||||
if (windowGetAtPoint(x, y) != _replyWin) {
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// 0x430180
|
||||
void _endReply()
|
||||
{
|
||||
if (_replyPlaying != 2) {
|
||||
if (_replyPlaying == 1) {
|
||||
if (!(_mediaFlag & 2) && _replyWin != -1) {
|
||||
windowDestroy(_replyWin);
|
||||
_replyWin = -1;
|
||||
}
|
||||
} else if (_replyPlaying != 3 && _replyWin != -1) {
|
||||
windowDestroy(_replyWin);
|
||||
_replyWin = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4301E8
|
||||
void _drawStr(int win, char* str, int font, int width, int height, int left, int top, int a8, int a9, int a10)
|
||||
{
|
||||
int old_font;
|
||||
Rect rect;
|
||||
|
||||
old_font = widgetGetFont();
|
||||
widgetSetFont(font);
|
||||
|
||||
_printStr(win, str, width, height, left, top, a8, a9, a10);
|
||||
|
||||
rect.left = left;
|
||||
rect.top = top;
|
||||
rect.right = width + left;
|
||||
rect.bottom = height + top;
|
||||
windowRefreshRect(win, &rect);
|
||||
widgetSetFont(old_font);
|
||||
}
|
||||
|
||||
// 0x430D40
|
||||
int _dialogStart(Program* a1)
|
||||
{
|
||||
STRUCT_56DAE0* ptr;
|
||||
|
||||
if (_tods == 3) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ptr = &(_dialog[_tods]);
|
||||
ptr->field_0 = a1;
|
||||
ptr->field_4 = 0;
|
||||
ptr->field_8 = 0;
|
||||
ptr->field_C = -1;
|
||||
ptr->field_10 = -1;
|
||||
ptr->field_14 = 1;
|
||||
ptr->field_10 = 1;
|
||||
|
||||
_tods++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x430DB8
|
||||
int _dialogRestart()
|
||||
{
|
||||
if (_tods == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
_dialog[_tods].field_10 = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x430DE4
|
||||
int _dialogGotoReply(const char* a1)
|
||||
{
|
||||
STRUCT_56DAE0* ptr;
|
||||
STRUCT_56DAE0_FIELD_4* v5;
|
||||
int i;
|
||||
|
||||
if (_tods == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a1 != NULL) {
|
||||
ptr = &(_dialog[_tods]);
|
||||
for (i = 0; i < ptr->field_8; i++) {
|
||||
v5 = &(ptr->field_4[i]);
|
||||
if (v5->field_4 != NULL && stricmp(v5->field_4, a1) == 0) {
|
||||
ptr->field_10 = i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
_dialog[_tods].field_10 = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x430E84
|
||||
int dialogSetReplyTitle(const char* a1)
|
||||
{
|
||||
if (gDialogReplyTitle != NULL) {
|
||||
internal_free_safe(gDialogReplyTitle, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2561
|
||||
}
|
||||
|
||||
if (a1 != NULL) {
|
||||
gDialogReplyTitle = internal_malloc_safe(strlen(a1) + 1, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2564
|
||||
strcpy(gDialogReplyTitle, a1);
|
||||
} else {
|
||||
gDialogReplyTitle = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x430EFC
|
||||
int _dialogReply(const char* a1, const char* a2)
|
||||
{
|
||||
// TODO: Incomplete.
|
||||
// _replyAddNew(a1, a2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x430F04
|
||||
int _dialogOption(const char* a1, const char* a2)
|
||||
{
|
||||
if (_dialog[_tods].field_C == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_replyAddOption(a1, a2, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x430F38
|
||||
int _dialogOptionProc(const char* a1, const char* a2)
|
||||
{
|
||||
if (_dialog[_tods].field_C == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
_replyAddOptionProc(a1, a2, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x431184
|
||||
int _dialogGetExitPoint()
|
||||
{
|
||||
return _topDialogLine + (_topDialogReply << 16);
|
||||
}
|
||||
|
||||
// 0x431198
|
||||
int _dialogQuit()
|
||||
{
|
||||
if (_inDialog) {
|
||||
_exitDialog = 1;
|
||||
} else {
|
||||
_endDialog();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4311B8
|
||||
int dialogSetOptionWindow(int a1, int a2, int a3, int a4, int a5)
|
||||
{
|
||||
dword_56DB6C = a1;
|
||||
dword_56DB70 = a2;
|
||||
dword_56DB64 = a3;
|
||||
dword_56DB68 = a4;
|
||||
_rand2plus = a5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4311E0
|
||||
int dialogSetReplyWindow(int a1, int a2, int a3, int a4, int a5)
|
||||
{
|
||||
dword_56DB84 = a1;
|
||||
dword_56DB88 = a2;
|
||||
dword_56DB7C = a3;
|
||||
dword_56DB80 = a4;
|
||||
dword_56DB8C = a5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x431208
|
||||
int dialogSetBorder(int a1, int a2)
|
||||
{
|
||||
gDialogBorderX = a1;
|
||||
gDialogBorderY = a2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x431218
|
||||
int _dialogSetScrollUp(int a1, int a2, void* a3, void* a4, void* a5, void* a6, int a7)
|
||||
{
|
||||
_upButton = a1;
|
||||
dword_56DBD8 = a2;
|
||||
|
||||
if (off_56DBE0 != NULL) {
|
||||
internal_free_safe(off_56DBE0, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2750
|
||||
}
|
||||
off_56DBE0 = a3;
|
||||
|
||||
if (off_56DBE4 != NULL) {
|
||||
internal_free_safe(off_56DBE4, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2752
|
||||
}
|
||||
off_56DBE4 = a4;
|
||||
|
||||
if (off_56DBE8 != NULL) {
|
||||
internal_free_safe(off_56DBE8, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2754
|
||||
}
|
||||
off_56DBE8 = a5;
|
||||
|
||||
if (off_56DBEC != NULL) {
|
||||
internal_free_safe(off_56DBEC, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2756
|
||||
}
|
||||
off_56DBEC = a5;
|
||||
|
||||
dword_56DBDC = a7;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4312C0
|
||||
int _dialogSetScrollDown(int a1, int a2, void* a3, void* a4, void* a5, void* a6, int a7)
|
||||
{
|
||||
_downButton = a1;
|
||||
dword_56DBB8 = a2;
|
||||
|
||||
if (off_56DBC0 != NULL) {
|
||||
internal_free_safe(off_56DBC0, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2765
|
||||
}
|
||||
off_56DBC0 = a3;
|
||||
|
||||
if (off_56DBC4 != NULL) {
|
||||
internal_free_safe(off_56DBC4, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2767
|
||||
}
|
||||
off_56DBC4 = a4;
|
||||
|
||||
if (off_56DBC8 != NULL) {
|
||||
internal_free_safe(off_56DBC8, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2769
|
||||
}
|
||||
off_56DBC8 = a5;
|
||||
|
||||
if (off_56DBCC != NULL) {
|
||||
internal_free_safe(off_56DBCC, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2771
|
||||
}
|
||||
off_56DBCC = a6;
|
||||
|
||||
dword_56DBBC = a7;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x431368
|
||||
int dialogSetOptionSpacing(int value)
|
||||
{
|
||||
gDialogOptionSpacing = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x431370
|
||||
int dialogSetOptionColor(float a1, float a2, float a3)
|
||||
{
|
||||
gDialogOptionColorR = (int)(a1 * flt_501623);
|
||||
gDialogOptionColorG = (int)(a2 * flt_501623);
|
||||
gDialogOptionColorB = (int)(a3 * flt_501623);
|
||||
|
||||
_optionRGBset = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4313C8
|
||||
int dialogSetReplyColor(float a1, float a2, float a3)
|
||||
{
|
||||
gDialogReplyColorR = (int)(a1 * flt_501627);
|
||||
gDialogReplyColorG = (int)(a2 * flt_501627);
|
||||
gDialogReplyColorB = (int)(a3 * flt_501627);
|
||||
|
||||
_replyRGBset = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x431420
|
||||
int _dialogSetOptionFlags(int flags)
|
||||
{
|
||||
word_56DB60 = flags & 0xFFFF;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 0x431434
|
||||
void _dialogClose()
|
||||
{
|
||||
if (off_56DBE0) {
|
||||
internal_free_safe(off_56DBE0, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2818
|
||||
}
|
||||
|
||||
if (off_56DBE4) {
|
||||
internal_free_safe(off_56DBE4, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2819
|
||||
}
|
||||
|
||||
if (off_56DBE8) {
|
||||
internal_free_safe(off_56DBE8, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2820
|
||||
}
|
||||
|
||||
if (off_56DBEC) {
|
||||
internal_free_safe(off_56DBEC, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2821
|
||||
}
|
||||
|
||||
if (off_56DBC0) {
|
||||
internal_free_safe(off_56DBC0, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2823
|
||||
}
|
||||
|
||||
if (off_56DBC4) {
|
||||
internal_free_safe(off_56DBC4, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2824
|
||||
}
|
||||
|
||||
if (off_56DBC8) {
|
||||
internal_free_safe(off_56DBC8, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2825
|
||||
}
|
||||
|
||||
if (off_56DBCC) {
|
||||
internal_free_safe(off_56DBCC, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 2826
|
||||
}
|
||||
}
|
||||
|
||||
// 0x431518
|
||||
int _dialogGetDialogDepth()
|
||||
{
|
||||
return _tods;
|
||||
}
|
||||
|
||||
// 0x431520
|
||||
void _dialogRegisterWinDrawCallbacks(DialogFunc1* a1, DialogFunc2* a2)
|
||||
{
|
||||
_replyWinDrawCallback = a1;
|
||||
_optionsWinDrawCallback = a2;
|
||||
}
|
||||
|
||||
// 0x431530
|
||||
int _dialogToggleMediaFlag(int a1)
|
||||
{
|
||||
if ((a1 & _mediaFlag) == a1) {
|
||||
_mediaFlag &= ~a1;
|
||||
} else {
|
||||
_mediaFlag |= a1;
|
||||
}
|
||||
|
||||
return _mediaFlag;
|
||||
}
|
||||
|
||||
// 0x431554
|
||||
int _dialogGetMediaFlag()
|
||||
{
|
||||
return _mediaFlag;
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
#ifndef DIALOG_H
|
||||
#define DIALOG_H
|
||||
|
||||
#include "interpreter.h"
|
||||
|
||||
typedef void DialogFunc1(int win);
|
||||
typedef void DialogFunc2(int win);
|
||||
|
||||
typedef struct STRUCT_56DAE0_FIELD_4_FIELD_C {
|
||||
char* field_0;
|
||||
char* field_4;
|
||||
int field_8;
|
||||
int field_C;
|
||||
int field_10;
|
||||
int field_14;
|
||||
short field_18;
|
||||
short field_1A;
|
||||
} STRUCT_56DAE0_FIELD_4_FIELD_C;
|
||||
|
||||
typedef struct STRUCT_56DAE0_FIELD_4 {
|
||||
void* field_0;
|
||||
char* field_4;
|
||||
void* field_8;
|
||||
STRUCT_56DAE0_FIELD_4_FIELD_C* field_C;
|
||||
int field_10;
|
||||
int field_14;
|
||||
int field_18; // probably font number
|
||||
} STRUCT_56DAE0_FIELD_4;
|
||||
|
||||
typedef struct STRUCT_56DAE0 {
|
||||
Program* field_0;
|
||||
STRUCT_56DAE0_FIELD_4* field_4;
|
||||
int field_8;
|
||||
int field_C;
|
||||
int field_10;
|
||||
int field_14;
|
||||
int field_18;
|
||||
} STRUCT_56DAE0;
|
||||
|
||||
extern const float flt_501623;
|
||||
extern const float flt_501627;
|
||||
|
||||
extern int _tods;
|
||||
extern int _topDialogLine;
|
||||
extern int _topDialogReply;
|
||||
extern DialogFunc1* _replyWinDrawCallback;
|
||||
extern DialogFunc2* _optionsWinDrawCallback;
|
||||
extern int gDialogBorderX;
|
||||
extern int gDialogBorderY;
|
||||
extern int gDialogOptionSpacing;
|
||||
extern int _replyRGBset;
|
||||
extern int _optionRGBset;
|
||||
extern int _exitDialog;
|
||||
extern int _inDialog;
|
||||
extern int _mediaFlag;
|
||||
|
||||
extern STRUCT_56DAE0 _dialog[4];
|
||||
extern short word_56DB60;
|
||||
extern int dword_56DB64;
|
||||
extern int dword_56DB68;
|
||||
extern int dword_56DB6C;
|
||||
extern int dword_56DB70;
|
||||
extern int _rand2plus;
|
||||
extern int dword_56DB7C;
|
||||
extern int dword_56DB80;
|
||||
extern int dword_56DB84;
|
||||
extern int dword_56DB88;
|
||||
extern int dword_56DB8C;
|
||||
extern int _replyPlaying;
|
||||
extern int _replyWin;
|
||||
extern int gDialogReplyColorG;
|
||||
extern int gDialogReplyColorB;
|
||||
extern int gDialogOptionColorG;
|
||||
extern int gDialogReplyColorR;
|
||||
extern int gDialogOptionColorB;
|
||||
extern int gDialogOptionColorR;
|
||||
extern int _downButton;
|
||||
extern int dword_56DBB8;
|
||||
extern int dword_56DBBC;
|
||||
extern void* off_56DBC0;
|
||||
extern void* off_56DBC4;
|
||||
extern void* off_56DBC8;
|
||||
extern void* off_56DBCC;
|
||||
extern char* gDialogReplyTitle;
|
||||
extern int _upButton;
|
||||
extern int dword_56DBD8;
|
||||
extern int dword_56DBDC;
|
||||
extern void* off_56DBE0;
|
||||
extern void* off_56DBE4;
|
||||
extern void* off_56DBE8;
|
||||
extern void* off_56DBEC;
|
||||
|
||||
STRUCT_56DAE0_FIELD_4* _getReply();
|
||||
void _replyAddOption(const char* a1, const char* a2, int a3);
|
||||
void _replyAddOptionProc(const char* a1, const char* a2, int a3);
|
||||
void _optionFree(STRUCT_56DAE0_FIELD_4_FIELD_C* a1);
|
||||
void _replyFree();
|
||||
int _endDialog();
|
||||
void _printLine(int win, char** strings, int strings_num, int a4, int a5, int a6, int a7, int a8, int a9);
|
||||
void _printStr(int win, char* a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9);
|
||||
int _abortReply(int a1);
|
||||
void _endReply();
|
||||
void _drawStr(int win, char* a2, int font, int width, int height, int left, int top, int a8, int a9, int a10);
|
||||
int _dialogStart(Program* a1);
|
||||
int _dialogRestart();
|
||||
int _dialogGotoReply(const char* a1);
|
||||
int dialogSetReplyTitle(const char* a1);
|
||||
int _dialogReply(const char* a1, const char* a2);
|
||||
int _dialogOption(const char* a1, const char* a2);
|
||||
int _dialogOptionProc(const char* a1, const char* a2);
|
||||
int _dialogGetExitPoint();
|
||||
int _dialogQuit();
|
||||
int dialogSetOptionWindow(int a1, int a2, int a3, int a4, int a5);
|
||||
int dialogSetReplyWindow(int a1, int a2, int a3, int a4, int a5);
|
||||
int dialogSetBorder(int a1, int a2);
|
||||
int _dialogSetScrollUp(int a1, int a2, void* a3, void* a4, void* a5, void* a6, int a7);
|
||||
int _dialogSetScrollDown(int a1, int a2, void* a3, void* a4, void* a5, void* a6, int a7);
|
||||
int dialogSetOptionSpacing(int value);
|
||||
int dialogSetOptionColor(float a1, float a2, float a3);
|
||||
int dialogSetReplyColor(float a1, float a2, float a3);
|
||||
int _dialogSetOptionFlags(int flags);
|
||||
void _dialogClose();
|
||||
int _dialogGetDialogDepth();
|
||||
void _dialogRegisterWinDrawCallbacks(DialogFunc1* a1, DialogFunc2* a2);
|
||||
int _dialogToggleMediaFlag(int a1);
|
||||
int _dialogGetMediaFlag();
|
||||
|
||||
#endif /* DIALOG_H */
|
|
@ -0,0 +1,306 @@
|
|||
#include "dictionary.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// 0x51E408
|
||||
MallocProc* gDictionaryMallocProc = dictionaryMallocDefaultImpl;
|
||||
|
||||
// 0x51E40C
|
||||
ReallocProc* gDictionaryReallocProc = dictionaryReallocDefaultImpl;
|
||||
|
||||
// 0x51E410
|
||||
FreeProc* gDictionaryFreeProc = dictionaryFreeDefaultImpl;
|
||||
|
||||
// 0x4D9B90
|
||||
void* dictionaryMallocDefaultImpl(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
// 0x4D9B98
|
||||
void* dictionaryReallocDefaultImpl(void* ptr, size_t newSize)
|
||||
{
|
||||
return realloc(ptr, newSize);
|
||||
}
|
||||
|
||||
// 0x4D9BA0
|
||||
void dictionaryFreeDefaultImpl(void* ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
// 0x4D9BA8
|
||||
int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize, void* a4)
|
||||
{
|
||||
dictionary->entriesCapacity = initialCapacity;
|
||||
dictionary->valueSize = valueSize;
|
||||
dictionary->entriesLength = 0;
|
||||
|
||||
if (a4 != NULL) {
|
||||
// NOTE: There is some structure pointed by [a4] with 5 fields. They are
|
||||
// either memcopied or assigned one by one into field_10 - field_20
|
||||
// respectively. This parameter is always NULL, so I doubt it's possible
|
||||
// to understand it's meaning. There are some hints in the unused
|
||||
// functions though.
|
||||
assert(false && "Not implemented");
|
||||
} else {
|
||||
dictionary->field_10 = 0;
|
||||
dictionary->field_14 = 0;
|
||||
dictionary->field_18 = 0;
|
||||
dictionary->field_1C = 0;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
|
||||
if (initialCapacity != 0) {
|
||||
dictionary->entries = gDictionaryMallocProc(sizeof(*dictionary->entries) * initialCapacity);
|
||||
if (dictionary->entries == NULL) {
|
||||
rc = -1;
|
||||
}
|
||||
} else {
|
||||
dictionary->entries = NULL;
|
||||
}
|
||||
|
||||
if (rc != -1) {
|
||||
dictionary->marker = DICTIONARY_MARKER;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// 0x4D9C0C
|
||||
int dictionarySetCapacity(Dictionary* dictionary, int newCapacity)
|
||||
{
|
||||
if (dictionary->marker != DICTIONARY_MARKER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (newCapacity < dictionary->entriesLength) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DictionaryEntry* entries = gDictionaryReallocProc(dictionary->entries, sizeof(*dictionary->entries) * newCapacity);
|
||||
if (entries == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dictionary->entriesCapacity = newCapacity;
|
||||
dictionary->entries = entries;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4D9C48
|
||||
int dictionaryFree(Dictionary* dictionary)
|
||||
{
|
||||
if (dictionary->marker != DICTIONARY_MARKER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int index = 0; index < dictionary->entriesLength; index++) {
|
||||
DictionaryEntry* entry = &(dictionary->entries[index]);
|
||||
if (entry->key != NULL) {
|
||||
gDictionaryFreeProc(entry->key);
|
||||
}
|
||||
|
||||
if (entry->value != NULL) {
|
||||
gDictionaryFreeProc(entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionary->entries != NULL) {
|
||||
gDictionaryFreeProc(dictionary->entries);
|
||||
}
|
||||
|
||||
memset(dictionary, 0, sizeof(*dictionary));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Finds index for the given key.
|
||||
//
|
||||
// Returns 0 if key is found. Otherwise returns -1, in this case [indexPtr]
|
||||
// specifies an insertion point for given key.
|
||||
//
|
||||
// 0x4D9CC4
|
||||
int dictionaryFindIndexForKey(Dictionary* dictionary, const char* key, int* indexPtr)
|
||||
{
|
||||
if (dictionary->marker != DICTIONARY_MARKER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dictionary->entriesLength == 0) {
|
||||
*indexPtr = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int r = dictionary->entriesLength - 1;
|
||||
int l = 0;
|
||||
int mid = 0;
|
||||
int cmp = 0;
|
||||
while (r >= l) {
|
||||
mid = (l + r) / 2;
|
||||
|
||||
cmp = stricmp(key, dictionary->entries[mid].key);
|
||||
if (cmp == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmp > 0) {
|
||||
l = l + 1;
|
||||
} else {
|
||||
r = r - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmp == 0) {
|
||||
*indexPtr = mid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmp < 0) {
|
||||
*indexPtr = mid;
|
||||
} else {
|
||||
*indexPtr = mid + 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Returns the index of the entry for the specified key, or -1 if it's not
|
||||
// present in the dictionary.
|
||||
//
|
||||
// 0x4D9D5C
|
||||
int dictionaryGetIndexByKey(Dictionary* dictionary, const char* key)
|
||||
{
|
||||
if (dictionary->marker != DICTIONARY_MARKER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int index;
|
||||
if (dictionaryFindIndexForKey(dictionary, key, &index) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Adds key-value pair to the dictionary if the specified key is not already
|
||||
// present.
|
||||
//
|
||||
// Returns 0 on success, or -1 on any error (including key already exists
|
||||
// error).
|
||||
//
|
||||
// 0x4D9D88
|
||||
int dictionaryAddValue(Dictionary* dictionary, const char* key, const void* value)
|
||||
{
|
||||
if (dictionary->marker != DICTIONARY_MARKER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int newElementIndex;
|
||||
if (dictionaryFindIndexForKey(dictionary, key, &newElementIndex) == 0) {
|
||||
// Element for this key is already exists.
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dictionary->entriesLength == dictionary->entriesCapacity) {
|
||||
// Dictionary reached it's capacity and needs to be enlarged.
|
||||
if (dictionarySetCapacity(dictionary, 2 * (dictionary->entriesCapacity + 1)) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Make a copy of the key.
|
||||
char* keyCopy = gDictionaryMallocProc(strlen(key) + 1);
|
||||
if (keyCopy == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(keyCopy, key);
|
||||
|
||||
// Make a copy of the value.
|
||||
void* valueCopy = NULL;
|
||||
if (value != NULL && dictionary->valueSize != 0) {
|
||||
valueCopy = gDictionaryMallocProc(dictionary->valueSize);
|
||||
if (valueCopy == NULL) {
|
||||
gDictionaryFreeProc(keyCopy);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (valueCopy != NULL && dictionary->valueSize != 0) {
|
||||
memcpy(valueCopy, value, dictionary->valueSize);
|
||||
}
|
||||
|
||||
// Starting at the end of entries array loop backwards and move entries down
|
||||
// one by one until we reach insertion point.
|
||||
for (int index = dictionary->entriesLength; index > newElementIndex; index--) {
|
||||
DictionaryEntry* src = &(dictionary->entries[index - 1]);
|
||||
DictionaryEntry* dest = &(dictionary->entries[index]);
|
||||
memcpy(dest, src, sizeof(*dictionary->entries));
|
||||
}
|
||||
|
||||
DictionaryEntry* entry = &(dictionary->entries[newElementIndex]);
|
||||
entry->key = keyCopy;
|
||||
entry->value = valueCopy;
|
||||
|
||||
dictionary->entriesLength++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Removes key-value pair from the dictionary if specified key is present in
|
||||
// the dictionary.
|
||||
//
|
||||
// Returns 0 on success, -1 on any error (including key not present error).
|
||||
//
|
||||
// 0x4D9EE8
|
||||
int dictionaryRemoveValue(Dictionary* dictionary, const char* key)
|
||||
{
|
||||
if (dictionary->marker != DICTIONARY_MARKER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int indexToRemove;
|
||||
if (dictionaryFindIndexForKey(dictionary, key, &indexToRemove) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DictionaryEntry* entry = &(dictionary->entries[indexToRemove]);
|
||||
|
||||
// Free key and value (which are copies).
|
||||
gDictionaryFreeProc(entry->key);
|
||||
if (entry->value != NULL) {
|
||||
gDictionaryFreeProc(entry->value);
|
||||
}
|
||||
|
||||
dictionary->entriesLength--;
|
||||
|
||||
// Starting from the index of the entry we've just removed, loop thru the
|
||||
// remaining of the array and move entries up one by one.
|
||||
for (int index = indexToRemove; index < dictionary->entriesLength; index++) {
|
||||
DictionaryEntry* src = &(dictionary->entries[index + 1]);
|
||||
DictionaryEntry* dest = &(dictionary->entries[index]);
|
||||
memcpy(dest, src, sizeof(*dictionary->entries));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4DA498
|
||||
void dictionarySetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc)
|
||||
{
|
||||
if (mallocProc != NULL && reallocProc != NULL && freeProc != NULL) {
|
||||
gDictionaryMallocProc = mallocProc;
|
||||
gDictionaryReallocProc = reallocProc;
|
||||
gDictionaryFreeProc = freeProc;
|
||||
} else {
|
||||
gDictionaryMallocProc = dictionaryMallocDefaultImpl;
|
||||
gDictionaryReallocProc = dictionaryReallocDefaultImpl;
|
||||
gDictionaryFreeProc = dictionaryFreeDefaultImpl;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef DICTIONARY_H
|
||||
#define DICTIONARY_H
|
||||
|
||||
#include "memory_defs.h"
|
||||
|
||||
// NOTE: I guess this marker is used as a type discriminator for implementing
|
||||
// nested dictionaries. That's why every dictionary-related function starts
|
||||
// with a check for this value.
|
||||
#define DICTIONARY_MARKER 0xFEBAFEBA
|
||||
|
||||
// A tuple containing individual key-value pair of a dictionary.
|
||||
typedef struct DictionaryEntry {
|
||||
char* key;
|
||||
void* value;
|
||||
} DictionaryEntry;
|
||||
|
||||
// A collection of key/value pairs.
|
||||
//
|
||||
// The keys in dictionary are always strings. Internally dictionary entries
|
||||
// are kept sorted by the key. Both keys and values are copied when new entry
|
||||
// is added to dictionary. For this reason the size of the value's type is
|
||||
// provided during dictionary initialization.
|
||||
typedef struct Dictionary {
|
||||
int marker;
|
||||
|
||||
// The number of key/value pairs in the dictionary.
|
||||
int entriesLength;
|
||||
|
||||
// The capacity of key/value pairs in [entries] array.
|
||||
int entriesCapacity;
|
||||
|
||||
// The size of the dictionary values in bytes.
|
||||
size_t valueSize;
|
||||
|
||||
int field_10;
|
||||
int field_14;
|
||||
int field_18;
|
||||
int field_1C;
|
||||
int field_20;
|
||||
|
||||
// The array of key-value pairs.
|
||||
DictionaryEntry* entries;
|
||||
} Dictionary;
|
||||
|
||||
extern MallocProc* gDictionaryMallocProc;
|
||||
extern ReallocProc* gDictionaryReallocProc;
|
||||
extern FreeProc* gDictionaryFreeProc;
|
||||
|
||||
void* dictionaryMallocDefaultImpl(size_t size);
|
||||
void* dictionaryReallocDefaultImpl(void* ptr, size_t newSize);
|
||||
void dictionaryFreeDefaultImpl(void* ptr);
|
||||
int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize, void* a4);
|
||||
int dictionarySetCapacity(Dictionary* dictionary, int newCapacity);
|
||||
int dictionaryFree(Dictionary* dictionary);
|
||||
int dictionaryFindIndexForKey(Dictionary* dictionary, const char* key, int* index);
|
||||
int dictionaryGetIndexByKey(Dictionary* dictionary, const char* key);
|
||||
int dictionaryAddValue(Dictionary* dictionary, const char* key, const void* value);
|
||||
int dictionaryRemoveValue(Dictionary* dictionary, const char* key);
|
||||
void dictionarySetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc);
|
||||
|
||||
#endif /* DICTIONARY_H */
|
|
@ -0,0 +1,600 @@
|
|||
#include <initguid.h>
|
||||
|
||||
#include "dinput.h"
|
||||
|
||||
// NOTE: There is no such define in DirectX SDK. I've taken it from Wine at
|
||||
// https://github.com/wine-mirror/wine/blob/master/dlls/dinput/data_formats.c.
|
||||
#define DIDFT_OPTIONAL 0x80000000
|
||||
|
||||
// NOTE: This define is different in the newer DirectX. Check DirectX SDK 3.0
|
||||
// at https://github.com/masonmc/dxsdk3/blob/master/sdk/inc/dinput.h.
|
||||
#undef DIDFT_ANYINSTANCE
|
||||
#define DIDFT_ANYINSTANCE 0x0000FF00
|
||||
|
||||
// 0x4FCE90
|
||||
static const DIOBJECTDATAFORMAT dfDIMouse[] = {
|
||||
{ &GUID_XAxis, DIMOFS_X, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 },
|
||||
{ &GUID_YAxis, DIMOFS_Y, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 },
|
||||
{ &GUID_ZAxis, DIMOFS_Z, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 },
|
||||
{ NULL, DIMOFS_BUTTON0, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
|
||||
{ NULL, DIMOFS_BUTTON1, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
|
||||
{ NULL, DIMOFS_BUTTON2, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
|
||||
{ NULL, DIMOFS_BUTTON3, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
|
||||
};
|
||||
|
||||
// 0x4FCF00
|
||||
const DIDATAFORMAT c_dfDIMouse = {
|
||||
sizeof(DIDATAFORMAT),
|
||||
sizeof(DIOBJECTDATAFORMAT),
|
||||
DIDF_RELAXIS,
|
||||
sizeof(DIMOUSESTATE),
|
||||
sizeof(dfDIMouse) / sizeof(dfDIMouse[0]),
|
||||
(LPDIOBJECTDATAFORMAT)dfDIMouse
|
||||
};
|
||||
|
||||
// 0x4FCF20
|
||||
static const DIOBJECTDATAFORMAT dfDIKeyboard[] = {
|
||||
{ &GUID_Key, 0, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(0), 0 },
|
||||
{ &GUID_Key, 1, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(1), 0 },
|
||||
{ &GUID_Key, 2, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(2), 0 },
|
||||
{ &GUID_Key, 3, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(3), 0 },
|
||||
{ &GUID_Key, 4, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(4), 0 },
|
||||
{ &GUID_Key, 5, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(5), 0 },
|
||||
{ &GUID_Key, 6, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(6), 0 },
|
||||
{ &GUID_Key, 7, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(7), 0 },
|
||||
{ &GUID_Key, 8, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(8), 0 },
|
||||
{ &GUID_Key, 9, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(9), 0 },
|
||||
{ &GUID_Key, 10, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(10), 0 },
|
||||
{ &GUID_Key, 11, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(11), 0 },
|
||||
{ &GUID_Key, 12, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(12), 0 },
|
||||
{ &GUID_Key, 13, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(13), 0 },
|
||||
{ &GUID_Key, 14, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(14), 0 },
|
||||
{ &GUID_Key, 15, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(15), 0 },
|
||||
{ &GUID_Key, 16, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(16), 0 },
|
||||
{ &GUID_Key, 17, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(17), 0 },
|
||||
{ &GUID_Key, 18, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(18), 0 },
|
||||
{ &GUID_Key, 19, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(19), 0 },
|
||||
{ &GUID_Key, 20, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(20), 0 },
|
||||
{ &GUID_Key, 21, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(21), 0 },
|
||||
{ &GUID_Key, 22, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(22), 0 },
|
||||
{ &GUID_Key, 23, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(23), 0 },
|
||||
{ &GUID_Key, 24, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(24), 0 },
|
||||
{ &GUID_Key, 25, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(25), 0 },
|
||||
{ &GUID_Key, 26, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(26), 0 },
|
||||
{ &GUID_Key, 27, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(27), 0 },
|
||||
{ &GUID_Key, 28, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(28), 0 },
|
||||
{ &GUID_Key, 29, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(29), 0 },
|
||||
{ &GUID_Key, 30, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(30), 0 },
|
||||
{ &GUID_Key, 31, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(31), 0 },
|
||||
{ &GUID_Key, 32, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(32), 0 },
|
||||
{ &GUID_Key, 33, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(33), 0 },
|
||||
{ &GUID_Key, 34, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(34), 0 },
|
||||
{ &GUID_Key, 35, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(35), 0 },
|
||||
{ &GUID_Key, 36, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(36), 0 },
|
||||
{ &GUID_Key, 37, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(37), 0 },
|
||||
{ &GUID_Key, 38, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(38), 0 },
|
||||
{ &GUID_Key, 39, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(39), 0 },
|
||||
{ &GUID_Key, 40, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(40), 0 },
|
||||
{ &GUID_Key, 41, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(41), 0 },
|
||||
{ &GUID_Key, 42, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(42), 0 },
|
||||
{ &GUID_Key, 43, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(43), 0 },
|
||||
{ &GUID_Key, 44, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(44), 0 },
|
||||
{ &GUID_Key, 45, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(45), 0 },
|
||||
{ &GUID_Key, 46, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(46), 0 },
|
||||
{ &GUID_Key, 47, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(47), 0 },
|
||||
{ &GUID_Key, 48, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(48), 0 },
|
||||
{ &GUID_Key, 49, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(49), 0 },
|
||||
{ &GUID_Key, 50, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(50), 0 },
|
||||
{ &GUID_Key, 51, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(51), 0 },
|
||||
{ &GUID_Key, 52, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(52), 0 },
|
||||
{ &GUID_Key, 53, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(53), 0 },
|
||||
{ &GUID_Key, 54, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(54), 0 },
|
||||
{ &GUID_Key, 55, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(55), 0 },
|
||||
{ &GUID_Key, 56, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(56), 0 },
|
||||
{ &GUID_Key, 57, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(57), 0 },
|
||||
{ &GUID_Key, 58, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(58), 0 },
|
||||
{ &GUID_Key, 59, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(59), 0 },
|
||||
{ &GUID_Key, 60, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(60), 0 },
|
||||
{ &GUID_Key, 61, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(61), 0 },
|
||||
{ &GUID_Key, 62, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(62), 0 },
|
||||
{ &GUID_Key, 63, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(63), 0 },
|
||||
{ &GUID_Key, 64, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(64), 0 },
|
||||
{ &GUID_Key, 65, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(65), 0 },
|
||||
{ &GUID_Key, 66, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(66), 0 },
|
||||
{ &GUID_Key, 67, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(67), 0 },
|
||||
{ &GUID_Key, 68, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(68), 0 },
|
||||
{ &GUID_Key, 69, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(69), 0 },
|
||||
{ &GUID_Key, 70, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(70), 0 },
|
||||
{ &GUID_Key, 71, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(71), 0 },
|
||||
{ &GUID_Key, 72, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(72), 0 },
|
||||
{ &GUID_Key, 73, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(73), 0 },
|
||||
{ &GUID_Key, 74, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(74), 0 },
|
||||
{ &GUID_Key, 75, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(75), 0 },
|
||||
{ &GUID_Key, 76, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(76), 0 },
|
||||
{ &GUID_Key, 77, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(77), 0 },
|
||||
{ &GUID_Key, 78, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(78), 0 },
|
||||
{ &GUID_Key, 79, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(79), 0 },
|
||||
{ &GUID_Key, 80, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(80), 0 },
|
||||
{ &GUID_Key, 81, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(81), 0 },
|
||||
{ &GUID_Key, 82, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(82), 0 },
|
||||
{ &GUID_Key, 83, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(83), 0 },
|
||||
{ &GUID_Key, 84, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(84), 0 },
|
||||
{ &GUID_Key, 85, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(85), 0 },
|
||||
{ &GUID_Key, 86, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(86), 0 },
|
||||
{ &GUID_Key, 87, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(87), 0 },
|
||||
{ &GUID_Key, 88, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(88), 0 },
|
||||
{ &GUID_Key, 89, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(89), 0 },
|
||||
{ &GUID_Key, 90, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(90), 0 },
|
||||
{ &GUID_Key, 91, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(91), 0 },
|
||||
{ &GUID_Key, 92, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(92), 0 },
|
||||
{ &GUID_Key, 93, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(93), 0 },
|
||||
{ &GUID_Key, 94, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(94), 0 },
|
||||
{ &GUID_Key, 95, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(95), 0 },
|
||||
{ &GUID_Key, 96, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(96), 0 },
|
||||
{ &GUID_Key, 97, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(97), 0 },
|
||||
{ &GUID_Key, 98, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(98), 0 },
|
||||
{ &GUID_Key, 99, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(99), 0 },
|
||||
{ &GUID_Key, 100, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(100), 0 },
|
||||
{ &GUID_Key, 101, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(101), 0 },
|
||||
{ &GUID_Key, 102, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(102), 0 },
|
||||
{ &GUID_Key, 103, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(103), 0 },
|
||||
{ &GUID_Key, 104, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(104), 0 },
|
||||
{ &GUID_Key, 105, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(105), 0 },
|
||||
{ &GUID_Key, 106, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(106), 0 },
|
||||
{ &GUID_Key, 107, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(107), 0 },
|
||||
{ &GUID_Key, 108, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(108), 0 },
|
||||
{ &GUID_Key, 109, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(109), 0 },
|
||||
{ &GUID_Key, 110, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(110), 0 },
|
||||
{ &GUID_Key, 111, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(111), 0 },
|
||||
{ &GUID_Key, 112, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(112), 0 },
|
||||
{ &GUID_Key, 113, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(113), 0 },
|
||||
{ &GUID_Key, 114, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(114), 0 },
|
||||
{ &GUID_Key, 115, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(115), 0 },
|
||||
{ &GUID_Key, 116, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(116), 0 },
|
||||
{ &GUID_Key, 117, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(117), 0 },
|
||||
{ &GUID_Key, 118, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(118), 0 },
|
||||
{ &GUID_Key, 119, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(119), 0 },
|
||||
{ &GUID_Key, 120, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(120), 0 },
|
||||
{ &GUID_Key, 121, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(121), 0 },
|
||||
{ &GUID_Key, 122, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(122), 0 },
|
||||
{ &GUID_Key, 123, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(123), 0 },
|
||||
{ &GUID_Key, 124, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(124), 0 },
|
||||
{ &GUID_Key, 125, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(125), 0 },
|
||||
{ &GUID_Key, 126, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(126), 0 },
|
||||
{ &GUID_Key, 127, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(127), 0 },
|
||||
{ &GUID_Key, 128, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(128), 0 },
|
||||
{ &GUID_Key, 129, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(129), 0 },
|
||||
{ &GUID_Key, 130, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(130), 0 },
|
||||
{ &GUID_Key, 131, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(131), 0 },
|
||||
{ &GUID_Key, 132, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(132), 0 },
|
||||
{ &GUID_Key, 133, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(133), 0 },
|
||||
{ &GUID_Key, 134, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(134), 0 },
|
||||
{ &GUID_Key, 135, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(135), 0 },
|
||||
{ &GUID_Key, 136, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(136), 0 },
|
||||
{ &GUID_Key, 137, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(137), 0 },
|
||||
{ &GUID_Key, 138, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(138), 0 },
|
||||
{ &GUID_Key, 139, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(139), 0 },
|
||||
{ &GUID_Key, 140, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(140), 0 },
|
||||
{ &GUID_Key, 141, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(141), 0 },
|
||||
{ &GUID_Key, 142, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(142), 0 },
|
||||
{ &GUID_Key, 143, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(143), 0 },
|
||||
{ &GUID_Key, 144, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(144), 0 },
|
||||
{ &GUID_Key, 145, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(145), 0 },
|
||||
{ &GUID_Key, 146, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(146), 0 },
|
||||
{ &GUID_Key, 147, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(147), 0 },
|
||||
{ &GUID_Key, 148, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(148), 0 },
|
||||
{ &GUID_Key, 149, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(149), 0 },
|
||||
{ &GUID_Key, 150, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(150), 0 },
|
||||
{ &GUID_Key, 151, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(151), 0 },
|
||||
{ &GUID_Key, 152, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(152), 0 },
|
||||
{ &GUID_Key, 153, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(153), 0 },
|
||||
{ &GUID_Key, 154, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(154), 0 },
|
||||
{ &GUID_Key, 155, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(155), 0 },
|
||||
{ &GUID_Key, 156, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(156), 0 },
|
||||
{ &GUID_Key, 157, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(157), 0 },
|
||||
{ &GUID_Key, 158, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(158), 0 },
|
||||
{ &GUID_Key, 159, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(159), 0 },
|
||||
{ &GUID_Key, 160, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(160), 0 },
|
||||
{ &GUID_Key, 161, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(161), 0 },
|
||||
{ &GUID_Key, 162, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(162), 0 },
|
||||
{ &GUID_Key, 163, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(163), 0 },
|
||||
{ &GUID_Key, 164, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(164), 0 },
|
||||
{ &GUID_Key, 165, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(165), 0 },
|
||||
{ &GUID_Key, 166, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(166), 0 },
|
||||
{ &GUID_Key, 167, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(167), 0 },
|
||||
{ &GUID_Key, 168, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(168), 0 },
|
||||
{ &GUID_Key, 169, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(169), 0 },
|
||||
{ &GUID_Key, 170, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(170), 0 },
|
||||
{ &GUID_Key, 171, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(171), 0 },
|
||||
{ &GUID_Key, 172, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(172), 0 },
|
||||
{ &GUID_Key, 173, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(173), 0 },
|
||||
{ &GUID_Key, 174, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(174), 0 },
|
||||
{ &GUID_Key, 175, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(175), 0 },
|
||||
{ &GUID_Key, 176, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(176), 0 },
|
||||
{ &GUID_Key, 177, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(177), 0 },
|
||||
{ &GUID_Key, 178, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(178), 0 },
|
||||
{ &GUID_Key, 179, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(179), 0 },
|
||||
{ &GUID_Key, 180, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(180), 0 },
|
||||
{ &GUID_Key, 181, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(181), 0 },
|
||||
{ &GUID_Key, 182, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(182), 0 },
|
||||
{ &GUID_Key, 183, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(183), 0 },
|
||||
{ &GUID_Key, 184, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(184), 0 },
|
||||
{ &GUID_Key, 185, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(185), 0 },
|
||||
{ &GUID_Key, 186, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(186), 0 },
|
||||
{ &GUID_Key, 187, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(187), 0 },
|
||||
{ &GUID_Key, 188, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(188), 0 },
|
||||
{ &GUID_Key, 189, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(189), 0 },
|
||||
{ &GUID_Key, 190, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(190), 0 },
|
||||
{ &GUID_Key, 191, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(191), 0 },
|
||||
{ &GUID_Key, 192, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(192), 0 },
|
||||
{ &GUID_Key, 193, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(193), 0 },
|
||||
{ &GUID_Key, 194, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(194), 0 },
|
||||
{ &GUID_Key, 195, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(195), 0 },
|
||||
{ &GUID_Key, 196, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(196), 0 },
|
||||
{ &GUID_Key, 197, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(197), 0 },
|
||||
{ &GUID_Key, 198, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(198), 0 },
|
||||
{ &GUID_Key, 199, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(199), 0 },
|
||||
{ &GUID_Key, 200, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(200), 0 },
|
||||
{ &GUID_Key, 201, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(201), 0 },
|
||||
{ &GUID_Key, 202, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(202), 0 },
|
||||
{ &GUID_Key, 203, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(203), 0 },
|
||||
{ &GUID_Key, 204, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(204), 0 },
|
||||
{ &GUID_Key, 205, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(205), 0 },
|
||||
{ &GUID_Key, 206, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(206), 0 },
|
||||
{ &GUID_Key, 207, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(207), 0 },
|
||||
{ &GUID_Key, 208, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(208), 0 },
|
||||
{ &GUID_Key, 209, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(209), 0 },
|
||||
{ &GUID_Key, 210, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(210), 0 },
|
||||
{ &GUID_Key, 211, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(211), 0 },
|
||||
{ &GUID_Key, 212, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(212), 0 },
|
||||
{ &GUID_Key, 213, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(213), 0 },
|
||||
{ &GUID_Key, 214, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(214), 0 },
|
||||
{ &GUID_Key, 215, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(215), 0 },
|
||||
{ &GUID_Key, 216, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(216), 0 },
|
||||
{ &GUID_Key, 217, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(217), 0 },
|
||||
{ &GUID_Key, 218, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(218), 0 },
|
||||
{ &GUID_Key, 219, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(219), 0 },
|
||||
{ &GUID_Key, 220, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(220), 0 },
|
||||
{ &GUID_Key, 221, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(221), 0 },
|
||||
{ &GUID_Key, 222, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(222), 0 },
|
||||
{ &GUID_Key, 223, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(223), 0 },
|
||||
{ &GUID_Key, 224, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(224), 0 },
|
||||
{ &GUID_Key, 225, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(225), 0 },
|
||||
{ &GUID_Key, 226, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(226), 0 },
|
||||
{ &GUID_Key, 227, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(227), 0 },
|
||||
{ &GUID_Key, 228, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(228), 0 },
|
||||
{ &GUID_Key, 229, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(229), 0 },
|
||||
{ &GUID_Key, 230, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(230), 0 },
|
||||
{ &GUID_Key, 231, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(231), 0 },
|
||||
{ &GUID_Key, 232, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(232), 0 },
|
||||
{ &GUID_Key, 233, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(233), 0 },
|
||||
{ &GUID_Key, 234, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(234), 0 },
|
||||
{ &GUID_Key, 235, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(235), 0 },
|
||||
{ &GUID_Key, 236, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(236), 0 },
|
||||
{ &GUID_Key, 237, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(237), 0 },
|
||||
{ &GUID_Key, 238, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(238), 0 },
|
||||
{ &GUID_Key, 239, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(239), 0 },
|
||||
{ &GUID_Key, 240, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(240), 0 },
|
||||
{ &GUID_Key, 241, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(241), 0 },
|
||||
{ &GUID_Key, 242, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(242), 0 },
|
||||
{ &GUID_Key, 243, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(243), 0 },
|
||||
{ &GUID_Key, 244, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(244), 0 },
|
||||
{ &GUID_Key, 245, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(245), 0 },
|
||||
{ &GUID_Key, 246, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(246), 0 },
|
||||
{ &GUID_Key, 247, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(247), 0 },
|
||||
{ &GUID_Key, 248, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(248), 0 },
|
||||
{ &GUID_Key, 249, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(249), 0 },
|
||||
{ &GUID_Key, 250, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(250), 0 },
|
||||
{ &GUID_Key, 251, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(251), 0 },
|
||||
{ &GUID_Key, 252, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(252), 0 },
|
||||
{ &GUID_Key, 253, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(253), 0 },
|
||||
{ &GUID_Key, 254, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(254), 0 },
|
||||
{ &GUID_Key, 255, DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_MAKEINSTANCE(255), 0 },
|
||||
};
|
||||
|
||||
// 0x4FDF20
|
||||
static const DIDATAFORMAT c_dfDIKeyboard = {
|
||||
sizeof(DIDATAFORMAT),
|
||||
sizeof(DIOBJECTDATAFORMAT),
|
||||
DIDF_RELAXIS,
|
||||
256,
|
||||
sizeof(dfDIKeyboard) / sizeof(dfDIKeyboard[0]),
|
||||
(LPDIOBJECTDATAFORMAT)dfDIKeyboard
|
||||
};
|
||||
|
||||
// 0x51E458
|
||||
LPDIRECTINPUTA gDirectInput = NULL;
|
||||
|
||||
// 0x51E45C
|
||||
LPDIRECTINPUTDEVICEA gMouseDevice = NULL;
|
||||
|
||||
// 0x51E460
|
||||
LPDIRECTINPUTDEVICEA gKeyboardDevice = NULL;
|
||||
|
||||
// 0x51E464
|
||||
int gKeyboardDeviceDataIndex = 0;
|
||||
|
||||
// 0x51E468
|
||||
int gKeyboardDeviceDataLength = 0;
|
||||
|
||||
// 0x6B2560
|
||||
DIDEVICEOBJECTDATA gKeyboardDeviceData[KEYBOARD_DEVICE_DATA_CAPACITY];
|
||||
|
||||
// 0x4E0400
|
||||
bool directInputInit()
|
||||
{
|
||||
if (gDirectInput != NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT hr = gDirectInputCreateAProc(gInstance, DIRECTINPUT_VERSION, &gDirectInput, NULL);
|
||||
if (hr != DI_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!mouseDeviceInit()) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!keyboardDeviceInit()) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
err:
|
||||
|
||||
keyboardDeviceFree();
|
||||
mouseDeviceFree();
|
||||
|
||||
if (gDirectInput != NULL) {
|
||||
IDirectInput_Release(gDirectInput);
|
||||
gDirectInput = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x4E0478
|
||||
void directInputFree()
|
||||
{
|
||||
// NOTE: Uninline.
|
||||
keyboardDeviceFree();
|
||||
|
||||
// NOTE: Uninline.
|
||||
mouseDeviceFree();
|
||||
|
||||
if (gDirectInput != NULL) {
|
||||
IDirectInput_Release(gDirectInput);
|
||||
gDirectInput = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4E04E8
|
||||
bool mouseDeviceAcquire()
|
||||
{
|
||||
if (gMouseDevice == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT hr = IDirectInputDevice_Acquire(gMouseDevice);
|
||||
if (hr != DI_OK && hr != S_FALSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4E0514
|
||||
bool mouseDeviceUnacquire()
|
||||
{
|
||||
if (gMouseDevice == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT hr = IDirectInputDevice_Unacquire(gMouseDevice);
|
||||
if (hr != DI_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4E053C
|
||||
bool mouseDeviceGetData(MouseData* mouseState)
|
||||
{
|
||||
if (gMouseDevice == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mouseDeviceAcquire()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DIMOUSESTATE dims;
|
||||
HRESULT hr = IDirectInputDevice_GetDeviceState(gMouseDevice, sizeof(dims), &dims);
|
||||
if (hr != DI_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mouseState->x = dims.lX;
|
||||
mouseState->y = dims.lY;
|
||||
mouseState->buttons[0] = (dims.rgbButtons[0] & 0x80) != 0;
|
||||
mouseState->buttons[1] = (dims.rgbButtons[1] & 0x80) != 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4E05A8
|
||||
bool keyboardDeviceAcquire()
|
||||
{
|
||||
if (gKeyboardDevice == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT hr = IDirectInputDevice_Acquire(gKeyboardDevice);
|
||||
if (hr != DI_OK && hr != S_FALSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4E05D4
|
||||
bool keyboardDeviceUnacquire()
|
||||
{
|
||||
if (gKeyboardDevice == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT hr = IDirectInputDevice_Unacquire(gKeyboardDevice);
|
||||
if (hr != DI_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4E05FC
|
||||
bool keyboardDeviceReset()
|
||||
{
|
||||
if (gKeyboardDevice == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!keyboardDeviceAcquire()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD items = -1;
|
||||
HRESULT hr = IDirectInputDevice_GetDeviceData(gKeyboardDevice, sizeof(DIDEVICEOBJECTDATA), NULL, &items, 0);
|
||||
if (hr != DI_OK && hr != DI_BUFFEROVERFLOW) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4E0650
|
||||
bool keyboardDeviceGetData(KeyboardData* keyboardData)
|
||||
{
|
||||
if (gKeyboardDevice == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!keyboardDeviceAcquire()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gKeyboardDeviceDataIndex >= gKeyboardDeviceDataLength) {
|
||||
DWORD items = KEYBOARD_DEVICE_DATA_CAPACITY;
|
||||
HRESULT hr = IDirectInputDevice_GetDeviceData(gKeyboardDevice, sizeof(DIDEVICEOBJECTDATA), gKeyboardDeviceData, &items, 0);
|
||||
if (hr == DI_OK || hr == DI_BUFFEROVERFLOW) {
|
||||
gKeyboardDeviceDataLength = items;
|
||||
gKeyboardDeviceDataIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (gKeyboardDeviceDataIndex < gKeyboardDeviceDataLength) {
|
||||
DIDEVICEOBJECTDATA* entry = &(gKeyboardDeviceData[gKeyboardDeviceDataIndex]);
|
||||
keyboardData->key = entry->dwOfs & 0xFF;
|
||||
keyboardData->down = (entry->dwData & 0x80) != 0;
|
||||
gKeyboardDeviceDataIndex++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x4E070C
|
||||
bool mouseDeviceInit()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
hr = IDirectInput_CreateDevice(gDirectInput, &GUID_SysMouse, &gMouseDevice, NULL);
|
||||
if (hr != DI_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
hr = IDirectInputDevice_SetCooperativeLevel(gMouseDevice, gProgramWindow, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
|
||||
if (hr != DI_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
hr = IDirectInputDevice_SetDataFormat(gMouseDevice, &c_dfDIMouse);
|
||||
if (hr != DI_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
err:
|
||||
|
||||
// NOTE: Uninline.
|
||||
mouseDeviceFree();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x4E078C
|
||||
void mouseDeviceFree()
|
||||
{
|
||||
if (gMouseDevice != NULL) {
|
||||
IDirectInputDevice_Unacquire(gMouseDevice);
|
||||
IDirectInputDevice_Release(gMouseDevice);
|
||||
gMouseDevice = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4E07B8
|
||||
bool keyboardDeviceInit()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
hr = IDirectInput_CreateDevice(gDirectInput, &GUID_SysKeyboard, &gKeyboardDevice, NULL);
|
||||
if (hr != DI_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
hr = IDirectInputDevice_SetCooperativeLevel(gKeyboardDevice, gProgramWindow, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
|
||||
if (hr != DI_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
hr = IDirectInputDevice_SetDataFormat(gKeyboardDevice, &c_dfDIKeyboard);
|
||||
if (hr != DI_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
DIPROPDWORD dipdw;
|
||||
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
||||
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||
dipdw.diph.dwObj = 0;
|
||||
dipdw.diph.dwHow = DIPH_DEVICE;
|
||||
dipdw.dwData = KEYBOARD_DEVICE_DATA_CAPACITY;
|
||||
|
||||
hr = IDirectInputDevice_SetProperty(gKeyboardDevice, DIPROP_BUFFERSIZE, &(dipdw.diph));
|
||||
if (hr != DI_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
err:
|
||||
|
||||
// NOTE: Uninline.
|
||||
keyboardDeviceFree();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x4E0874
|
||||
void keyboardDeviceFree()
|
||||
{
|
||||
if (gKeyboardDevice != NULL) {
|
||||
IDirectInputDevice_Unacquire(gKeyboardDevice);
|
||||
IDirectInputDevice_Release(gKeyboardDevice);
|
||||
gKeyboardDevice = NULL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef DINPUT_H
|
||||
#define DINPUT_H
|
||||
|
||||
#include "win32.h"
|
||||
|
||||
#define KEYBOARD_DEVICE_DATA_CAPACITY (32)
|
||||
|
||||
typedef struct MouseData {
|
||||
int x;
|
||||
int y;
|
||||
unsigned char buttons[2];
|
||||
} MouseData;
|
||||
|
||||
typedef struct KeyboardData {
|
||||
char key;
|
||||
char down;
|
||||
} KeyboardData;
|
||||
|
||||
extern LPDIRECTINPUTA gDirectInput;
|
||||
extern LPDIRECTINPUTDEVICEA gMouseDevice;
|
||||
extern LPDIRECTINPUTDEVICEA gKeyboardDevice;
|
||||
extern int gKeyboardDeviceDataIndex;
|
||||
extern int gKeyboardDeviceDataLength;
|
||||
extern DIDEVICEOBJECTDATA gKeyboardDeviceData[KEYBOARD_DEVICE_DATA_CAPACITY];
|
||||
|
||||
bool directInputInit();
|
||||
void directInputFree();
|
||||
bool mouseDeviceAcquire();
|
||||
bool mouseDeviceUnacquire();
|
||||
bool mouseDeviceGetData(MouseData* mouseData);
|
||||
bool keyboardDeviceAcquire();
|
||||
bool keyboardDeviceUnacquire();
|
||||
bool keyboardDeviceReset();
|
||||
bool keyboardDeviceGetData(KeyboardData* keyboardData);
|
||||
bool mouseDeviceInit();
|
||||
void mouseDeviceFree();
|
||||
bool keyboardDeviceInit();
|
||||
void keyboardDeviceFree();
|
||||
|
||||
#endif /* DINPUT_H */
|
|
@ -0,0 +1,365 @@
|
|||
#include "display_monitor.h"
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "combat.h"
|
||||
#include "core.h"
|
||||
#include "draw.h"
|
||||
#include "game_mouse.h"
|
||||
#include "game_sound.h"
|
||||
#include "interface.h"
|
||||
#include "memory.h"
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// 0x51850C
|
||||
bool gDisplayMonitorInitialized = false;
|
||||
|
||||
// The rectangle that display monitor occupies in the main interface window.
|
||||
//
|
||||
// 0x518510
|
||||
const Rect gDisplayMonitorRect = {
|
||||
DISPLAY_MONITOR_X,
|
||||
DISPLAY_MONITOR_Y,
|
||||
DISPLAY_MONITOR_X + DISPLAY_MONITOR_WIDTH - 1,
|
||||
DISPLAY_MONITOR_Y + DISPLAY_MONITOR_HEIGHT - 1,
|
||||
};
|
||||
|
||||
// 0x518520
|
||||
int gDisplayMonitorScrollDownButton = -1;
|
||||
|
||||
// 0x518524
|
||||
int gDisplayMonitorScrollUpButton = -1;
|
||||
|
||||
// 0x56DBFC
|
||||
char gDisplayMonitorLines[DISPLAY_MONITOR_LINES_CAPACITY][DISPLAY_MONITOR_LINE_LENGTH];
|
||||
|
||||
// 0x56FB3C
|
||||
unsigned char* gDisplayMonitorBackgroundFrmData;
|
||||
|
||||
// 0x56FB40
|
||||
int _max_disp;
|
||||
|
||||
// 0x56FB44
|
||||
bool gDisplayMonitorEnabled;
|
||||
|
||||
// 0x56FB48
|
||||
int _disp_curr;
|
||||
|
||||
// 0x56FB4C
|
||||
int _intface_full_width;
|
||||
|
||||
// 0x56FB50
|
||||
int gDisplayMonitorLinesCapacity;
|
||||
|
||||
// 0x56FB54
|
||||
int _disp_start;
|
||||
|
||||
// 0x56FB58
|
||||
unsigned int gDisplayMonitorLastBeepTimestamp;
|
||||
|
||||
// 0x431610
|
||||
int displayMonitorInit()
|
||||
{
|
||||
if (!gDisplayMonitorInitialized) {
|
||||
int oldFont = fontGetCurrent();
|
||||
fontSetCurrent(DISPLAY_MONITOR_FONT);
|
||||
|
||||
gDisplayMonitorLinesCapacity = DISPLAY_MONITOR_LINES_CAPACITY;
|
||||
_max_disp = DISPLAY_MONITOR_HEIGHT / fontGetLineHeight();
|
||||
_disp_start = 0;
|
||||
_disp_curr = 0;
|
||||
fontSetCurrent(oldFont);
|
||||
|
||||
gDisplayMonitorBackgroundFrmData = internal_malloc(DISPLAY_MONITOR_WIDTH * DISPLAY_MONITOR_HEIGHT);
|
||||
if (gDisplayMonitorBackgroundFrmData == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
int backgroundFid = buildFid(6, 16, 0, 0, 0);
|
||||
Art* backgroundFrm = artLock(backgroundFid, &backgroundFrmHandle);
|
||||
if (backgroundFrm == NULL) {
|
||||
internal_free(gDisplayMonitorBackgroundFrmData);
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char* backgroundFrmData = artGetFrameData(backgroundFrm, 0, 0);
|
||||
_intface_full_width = artGetWidth(backgroundFrm, 0, 0);
|
||||
blitBufferToBuffer(backgroundFrmData + _intface_full_width * DISPLAY_MONITOR_Y + DISPLAY_MONITOR_X,
|
||||
DISPLAY_MONITOR_WIDTH,
|
||||
DISPLAY_MONITOR_HEIGHT,
|
||||
_intface_full_width,
|
||||
gDisplayMonitorBackgroundFrmData,
|
||||
DISPLAY_MONITOR_WIDTH);
|
||||
|
||||
artUnlock(backgroundFrmHandle);
|
||||
|
||||
gDisplayMonitorScrollUpButton = buttonCreate(gInterfaceBarWindow,
|
||||
DISPLAY_MONITOR_X,
|
||||
DISPLAY_MONITOR_Y,
|
||||
DISPLAY_MONITOR_WIDTH,
|
||||
DISPLAY_MONITOR_HALF_HEIGHT,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0);
|
||||
if (gDisplayMonitorScrollUpButton != -1) {
|
||||
buttonSetMouseCallbacks(gDisplayMonitorScrollUpButton,
|
||||
displayMonitorScrollUpOnMouseEnter,
|
||||
displayMonitorOnMouseExit,
|
||||
displayMonitorScrollUpOnMouseDown,
|
||||
NULL);
|
||||
}
|
||||
|
||||
gDisplayMonitorScrollDownButton = buttonCreate(gInterfaceBarWindow,
|
||||
DISPLAY_MONITOR_X,
|
||||
DISPLAY_MONITOR_Y + DISPLAY_MONITOR_HALF_HEIGHT,
|
||||
DISPLAY_MONITOR_WIDTH,
|
||||
DISPLAY_MONITOR_HEIGHT - DISPLAY_MONITOR_HALF_HEIGHT,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0);
|
||||
if (gDisplayMonitorScrollDownButton != -1) {
|
||||
buttonSetMouseCallbacks(gDisplayMonitorScrollDownButton,
|
||||
displayMonitorScrollDownOnMouseEnter,
|
||||
displayMonitorOnMouseExit,
|
||||
displayMonitorScrollDownOnMouseDown,
|
||||
NULL);
|
||||
}
|
||||
|
||||
gDisplayMonitorEnabled = true;
|
||||
gDisplayMonitorInitialized = true;
|
||||
|
||||
for (int index = 0; index < gDisplayMonitorLinesCapacity; index++) {
|
||||
gDisplayMonitorLines[index][0] = '\0';
|
||||
}
|
||||
|
||||
_disp_start = 0;
|
||||
_disp_curr = 0;
|
||||
|
||||
displayMonitorRefresh();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x431800
|
||||
int displayMonitorReset()
|
||||
{
|
||||
if (gDisplayMonitorInitialized) {
|
||||
for (int index = 0; index < gDisplayMonitorLinesCapacity; index++) {
|
||||
gDisplayMonitorLines[index][0] = '\0';
|
||||
}
|
||||
|
||||
_disp_start = 0;
|
||||
_disp_curr = 0;
|
||||
displayMonitorRefresh();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x43184C
|
||||
void displayMonitorExit()
|
||||
{
|
||||
if (gDisplayMonitorInitialized) {
|
||||
internal_free(gDisplayMonitorBackgroundFrmData);
|
||||
gDisplayMonitorInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x43186C
|
||||
void displayMonitorAddMessage(char* str)
|
||||
{
|
||||
if (!gDisplayMonitorInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
int oldFont = fontGetCurrent();
|
||||
fontSetCurrent(DISPLAY_MONITOR_FONT);
|
||||
|
||||
char knob = '\x95';
|
||||
|
||||
char knobString[2];
|
||||
knobString[0] = knob;
|
||||
knobString[1] = '\0';
|
||||
int knobWidth = fontGetStringWidth(knobString);
|
||||
|
||||
if (!isInCombat()) {
|
||||
unsigned int now = _get_bk_time();
|
||||
if (getTicksBetween(now, gDisplayMonitorLastBeepTimestamp) >= DISPLAY_MONITOR_BEEP_DELAY) {
|
||||
gDisplayMonitorLastBeepTimestamp = now;
|
||||
soundPlayFile("monitor");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Refactor these two loops.
|
||||
char* v1 = NULL;
|
||||
while (true) {
|
||||
while (fontGetStringWidth(str) < DISPLAY_MONITOR_WIDTH - _max_disp - knobWidth) {
|
||||
char* temp = gDisplayMonitorLines[_disp_start];
|
||||
int length;
|
||||
if (knob != '\0') {
|
||||
*temp++ = knob;
|
||||
length = DISPLAY_MONITOR_LINE_LENGTH - 2;
|
||||
knob = '\0';
|
||||
knobWidth = 0;
|
||||
} else {
|
||||
length = DISPLAY_MONITOR_LINE_LENGTH - 1;
|
||||
}
|
||||
strncpy(temp, str, length);
|
||||
gDisplayMonitorLines[_disp_start][DISPLAY_MONITOR_LINE_LENGTH - 1] = '\0';
|
||||
_disp_start = (_disp_start + 1) % gDisplayMonitorLinesCapacity;
|
||||
|
||||
if (v1 == NULL) {
|
||||
fontSetCurrent(oldFont);
|
||||
_disp_curr = _disp_start;
|
||||
displayMonitorRefresh();
|
||||
return;
|
||||
}
|
||||
|
||||
str = v1 + 1;
|
||||
*v1 = ' ';
|
||||
v1 = NULL;
|
||||
}
|
||||
|
||||
char* space = strrchr(str, ' ');
|
||||
if (space == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (v1 != NULL) {
|
||||
*v1 = ' ';
|
||||
}
|
||||
|
||||
v1 = space;
|
||||
if (space != NULL) {
|
||||
*space = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
char* temp = gDisplayMonitorLines[_disp_start];
|
||||
int length;
|
||||
if (knob != '\0') {
|
||||
temp++;
|
||||
gDisplayMonitorLines[_disp_start][0] = knob;
|
||||
length = DISPLAY_MONITOR_LINE_LENGTH - 2;
|
||||
knob = '\0';
|
||||
} else {
|
||||
length = DISPLAY_MONITOR_LINE_LENGTH - 1;
|
||||
}
|
||||
strncpy(temp, str, length);
|
||||
|
||||
gDisplayMonitorLines[_disp_start][DISPLAY_MONITOR_LINE_LENGTH - 1] = '\0';
|
||||
_disp_start = (_disp_start + 1) % gDisplayMonitorLinesCapacity;
|
||||
|
||||
fontSetCurrent(oldFont);
|
||||
_disp_curr = _disp_start;
|
||||
displayMonitorRefresh();
|
||||
}
|
||||
|
||||
// 0x431A78
|
||||
void displayMonitorRefresh()
|
||||
{
|
||||
if (!gDisplayMonitorInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char* buf = windowGetBuffer(gInterfaceBarWindow);
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
buf += _intface_full_width * DISPLAY_MONITOR_Y + DISPLAY_MONITOR_X;
|
||||
blitBufferToBuffer(gDisplayMonitorBackgroundFrmData,
|
||||
DISPLAY_MONITOR_WIDTH,
|
||||
DISPLAY_MONITOR_HEIGHT,
|
||||
DISPLAY_MONITOR_WIDTH,
|
||||
buf,
|
||||
_intface_full_width);
|
||||
|
||||
int oldFont = fontGetCurrent();
|
||||
fontSetCurrent(DISPLAY_MONITOR_FONT);
|
||||
|
||||
for (int index = 0; index < _max_disp; index++) {
|
||||
int stringIndex = (_disp_curr + gDisplayMonitorLinesCapacity + index - _max_disp) % gDisplayMonitorLinesCapacity;
|
||||
fontDrawText(buf + index * _intface_full_width * fontGetLineHeight(), gDisplayMonitorLines[stringIndex], DISPLAY_MONITOR_WIDTH, _intface_full_width, _colorTable[992]);
|
||||
|
||||
// Even though the display monitor is rectangular, it's graphic is not.
|
||||
// To give a feel of depth it's covered by some metal canopy and
|
||||
// considered inclined outwards. This way earlier messages appear a
|
||||
// little bit far from player's perspective. To implement this small
|
||||
// detail the destination buffer is incremented by 1.
|
||||
buf++;
|
||||
}
|
||||
|
||||
windowRefreshRect(gInterfaceBarWindow, &gDisplayMonitorRect);
|
||||
fontSetCurrent(oldFont);
|
||||
}
|
||||
|
||||
// 0x431B70
|
||||
void displayMonitorScrollUpOnMouseDown(int btn, int keyCode)
|
||||
{
|
||||
if ((gDisplayMonitorLinesCapacity + _disp_curr - 1) % gDisplayMonitorLinesCapacity != _disp_start) {
|
||||
_disp_curr = (gDisplayMonitorLinesCapacity + _disp_curr - 1) % gDisplayMonitorLinesCapacity;
|
||||
displayMonitorRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
// 0x431B9C
|
||||
void displayMonitorScrollDownOnMouseDown(int btn, int keyCode)
|
||||
{
|
||||
if (_disp_curr != _disp_start) {
|
||||
_disp_curr = (_disp_curr + 1) % gDisplayMonitorLinesCapacity;
|
||||
displayMonitorRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
// 0x431BC8
|
||||
void displayMonitorScrollUpOnMouseEnter(int btn, int keyCode)
|
||||
{
|
||||
gameMouseSetCursor(MOUSE_CURSOR_SMALL_ARROW_UP);
|
||||
}
|
||||
|
||||
// 0x431BD4
|
||||
void displayMonitorScrollDownOnMouseEnter(int btn, int keyCode)
|
||||
{
|
||||
gameMouseSetCursor(MOUSE_CURSOR_SMALL_ARROW_DOWN);
|
||||
}
|
||||
|
||||
// 0x431BE0
|
||||
void displayMonitorOnMouseExit(int btn, int keyCode)
|
||||
{
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
}
|
||||
|
||||
// 0x431BEC
|
||||
void displayMonitorDisable()
|
||||
{
|
||||
if (gDisplayMonitorEnabled) {
|
||||
buttonDisable(gDisplayMonitorScrollDownButton);
|
||||
buttonDisable(gDisplayMonitorScrollUpButton);
|
||||
gDisplayMonitorEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x431C14
|
||||
void displayMonitorEnable()
|
||||
{
|
||||
if (!gDisplayMonitorEnabled) {
|
||||
buttonEnable(gDisplayMonitorScrollDownButton);
|
||||
buttonEnable(gDisplayMonitorScrollUpButton);
|
||||
gDisplayMonitorEnabled = true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef DISPLAY_MONITOR_H
|
||||
#define DISPLAY_MONITOR_H
|
||||
|
||||
#include "geometry.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// The maximum number of lines display monitor can hold. Once this value
|
||||
// is reached earlier messages are thrown away.
|
||||
#define DISPLAY_MONITOR_LINES_CAPACITY (100)
|
||||
|
||||
// The maximum length of a string in display monitor (in characters).
|
||||
#define DISPLAY_MONITOR_LINE_LENGTH (80)
|
||||
|
||||
#define DISPLAY_MONITOR_X (23)
|
||||
#define DISPLAY_MONITOR_Y (24)
|
||||
#define DISPLAY_MONITOR_WIDTH (167)
|
||||
#define DISPLAY_MONITOR_HEIGHT (60)
|
||||
|
||||
#define DISPLAY_MONITOR_HALF_HEIGHT (DISPLAY_MONITOR_HEIGHT / 2)
|
||||
|
||||
#define DISPLAY_MONITOR_FONT (101)
|
||||
|
||||
#define DISPLAY_MONITOR_BEEP_DELAY (500U)
|
||||
|
||||
extern bool gDisplayMonitorInitialized;
|
||||
extern const Rect gDisplayMonitorRect;
|
||||
extern int gDisplayMonitorScrollDownButton;
|
||||
extern int gDisplayMonitorScrollUpButton;
|
||||
|
||||
extern char gDisplayMonitorLines[DISPLAY_MONITOR_LINES_CAPACITY][DISPLAY_MONITOR_LINE_LENGTH];
|
||||
extern unsigned char* gDisplayMonitorBackgroundFrmData;
|
||||
extern int _max_disp;
|
||||
extern bool gDisplayMonitorEnabled;
|
||||
extern int _disp_curr;
|
||||
extern int _intface_full_width;
|
||||
extern int gDisplayMonitorLinesCapacity;
|
||||
extern int _disp_start;
|
||||
extern unsigned int gDisplayMonitorLastBeepTimestamp;
|
||||
|
||||
int displayMonitorInit();
|
||||
int displayMonitorReset();
|
||||
void displayMonitorExit();
|
||||
void displayMonitorAddMessage(char* string);
|
||||
void displayMonitorRefresh();
|
||||
void displayMonitorScrollUpOnMouseDown(int btn, int keyCode);
|
||||
void displayMonitorScrollDownOnMouseDown(int btn, int keyCode);
|
||||
void displayMonitorScrollUpOnMouseEnter(int btn, int keyCode);
|
||||
void displayMonitorScrollDownOnMouseEnter(int btn, int keyCode);
|
||||
void displayMonitorOnMouseExit(int btn, int keyCode);
|
||||
void displayMonitorDisable();
|
||||
void displayMonitorEnable();
|
||||
|
||||
#endif /* DISPLAY_MONITOR_H */
|
|
@ -0,0 +1,328 @@
|
|||
#include "draw.h"
|
||||
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
#include "mmx.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// 0x4D2FC0
|
||||
void bufferDrawLine(unsigned char* buf, int pitch, int x1, int y1, int x2, int y2, int color)
|
||||
{
|
||||
int temp;
|
||||
int dx;
|
||||
int dy;
|
||||
unsigned char* p1;
|
||||
unsigned char* p2;
|
||||
unsigned char* p3;
|
||||
unsigned char* p4;
|
||||
|
||||
if (x1 == x2) {
|
||||
if (y1 > y2) {
|
||||
temp = y1;
|
||||
y1 = y2;
|
||||
y2 = temp;
|
||||
}
|
||||
|
||||
p1 = buf + pitch * y1 + x1;
|
||||
p2 = buf + pitch * y2 + x2;
|
||||
while (p1 < p2) {
|
||||
*p1 = color;
|
||||
*p2 = color;
|
||||
p1 += pitch;
|
||||
p2 -= pitch;
|
||||
}
|
||||
} else {
|
||||
if (x1 > x2) {
|
||||
temp = x1;
|
||||
x1 = x2;
|
||||
x2 = temp;
|
||||
|
||||
temp = y1;
|
||||
y1 = y2;
|
||||
y2 = temp;
|
||||
}
|
||||
|
||||
p1 = buf + pitch * y1 + x1;
|
||||
p2 = buf + pitch * y2 + x2;
|
||||
if (y1 == y2) {
|
||||
memset(p1, color, p2 - p1);
|
||||
} else {
|
||||
dx = x2 - x1;
|
||||
|
||||
int v23;
|
||||
int v22;
|
||||
int midX = x1 + (x2 - x1) / 2;
|
||||
if (y1 <= y2) {
|
||||
dy = y2 - y1;
|
||||
v23 = pitch;
|
||||
v22 = midX + ((y2 - y1) / 2 + y1) * pitch;
|
||||
} else {
|
||||
dy = y1 - y2;
|
||||
v23 = -pitch;
|
||||
v22 = midX + (y1 - (y1 - y2) / 2) * pitch;
|
||||
}
|
||||
|
||||
p3 = buf + v22;
|
||||
p4 = p3;
|
||||
|
||||
if (dx <= dy) {
|
||||
int v28 = dx - (dy / 2);
|
||||
int v29 = dy / 4;
|
||||
while (true) {
|
||||
*p1 = color;
|
||||
*p2 = color;
|
||||
*p3 = color;
|
||||
*p4 = color;
|
||||
|
||||
if (v29 == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (v28 >= 0) {
|
||||
p3++;
|
||||
p2--;
|
||||
p4--;
|
||||
p1++;
|
||||
v28 -= dy;
|
||||
}
|
||||
|
||||
p3 += v23;
|
||||
p2 -= v23;
|
||||
p4 -= v23;
|
||||
p1 += v23;
|
||||
v28 += dx;
|
||||
|
||||
v29--;
|
||||
}
|
||||
} else {
|
||||
int v26 = dy - (dx / 2);
|
||||
int v27 = dx / 4;
|
||||
while (true) {
|
||||
*p1 = color;
|
||||
*p2 = color;
|
||||
*p3 = color;
|
||||
*p4 = color;
|
||||
|
||||
if (v27 == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (v26 >= 0) {
|
||||
p3 += v23;
|
||||
p2 -= v23;
|
||||
p4 -= v23;
|
||||
p1 += v23;
|
||||
v26 -= dx;
|
||||
}
|
||||
|
||||
p3++;
|
||||
p2--;
|
||||
p4--;
|
||||
p1++;
|
||||
v26 += dy;
|
||||
|
||||
v27--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4D31A4
|
||||
void bufferDrawRect(unsigned char* buf, int pitch, int left, int top, int right, int bottom, int color)
|
||||
{
|
||||
bufferDrawLine(buf, pitch, left, top, right, top, color);
|
||||
bufferDrawLine(buf, pitch, left, bottom, right, bottom, color);
|
||||
bufferDrawLine(buf, pitch, left, top, left, bottom, color);
|
||||
bufferDrawLine(buf, pitch, right, top, right, bottom, color);
|
||||
}
|
||||
|
||||
// 0x4D322C
|
||||
void bufferDrawRectShadowed(unsigned char* buf, int pitch, int left, int top, int right, int bottom, int ltColor, int rbColor)
|
||||
{
|
||||
bufferDrawLine(buf, pitch, left, top, right, top, ltColor);
|
||||
bufferDrawLine(buf, pitch, left, bottom, right, bottom, rbColor);
|
||||
bufferDrawLine(buf, pitch, left, top, left, bottom, ltColor);
|
||||
bufferDrawLine(buf, pitch, right, top, right, bottom, rbColor);
|
||||
}
|
||||
|
||||
// 0x4D33F0
|
||||
void blitBufferToBufferStretch(unsigned char* src, int srcWidth, int srcHeight, int srcPitch, unsigned char* dest, int destWidth, int destHeight, int destPitch)
|
||||
{
|
||||
int heightRatio = (destHeight << 16) / srcHeight;
|
||||
int widthRatio = (destWidth << 16) / srcWidth;
|
||||
|
||||
int v1 = 0;
|
||||
int v2 = heightRatio;
|
||||
for (int srcY = 0; srcY < srcHeight; srcY += 1) {
|
||||
int v3 = widthRatio;
|
||||
int v4 = (heightRatio * srcY) >> 16;
|
||||
int v5 = v2 >> 16;
|
||||
int v6 = 0;
|
||||
|
||||
unsigned char* c = src + v1;
|
||||
for (int srcX = 0; srcX < srcWidth; srcX += 1) {
|
||||
int v7 = v3 >> 16;
|
||||
int v8 = v6 >> 16;
|
||||
|
||||
unsigned char* v9 = dest + destPitch * v4 + v8;
|
||||
for (int destY = v4; destY < v5; destY += 1) {
|
||||
for (int destX = v8; destX < v7; destX += 1) {
|
||||
*v9++ = *c;
|
||||
}
|
||||
v9 += destPitch;
|
||||
}
|
||||
|
||||
v3 += widthRatio;
|
||||
c++;
|
||||
v6 += widthRatio;
|
||||
}
|
||||
v1 += srcPitch;
|
||||
v2 += heightRatio;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4D3560
|
||||
void blitBufferToBufferStretchTrans(unsigned char* src, int srcWidth, int srcHeight, int srcPitch, unsigned char* dest, int destWidth, int destHeight, int destPitch)
|
||||
{
|
||||
int heightRatio = (destHeight << 16) / srcHeight;
|
||||
int widthRatio = (destWidth << 16) / srcWidth;
|
||||
|
||||
int v1 = 0;
|
||||
int v2 = heightRatio;
|
||||
for (int srcY = 0; srcY < srcHeight; srcY += 1) {
|
||||
int v3 = widthRatio;
|
||||
int v4 = (heightRatio * srcY) >> 16;
|
||||
int v5 = v2 >> 16;
|
||||
int v6 = 0;
|
||||
|
||||
unsigned char* c = src + v1;
|
||||
for (int srcX = 0; srcX < srcWidth; srcX += 1) {
|
||||
int v7 = v3 >> 16;
|
||||
int v8 = v6 >> 16;
|
||||
|
||||
if (*c != 0) {
|
||||
unsigned char* v9 = dest + destPitch * v4 + v8;
|
||||
for (int destY = v4; destY < v5; destY += 1) {
|
||||
for (int destX = v8; destX < v7; destX += 1) {
|
||||
*v9++ = *c;
|
||||
}
|
||||
v9 += destPitch;
|
||||
}
|
||||
}
|
||||
|
||||
v3 += widthRatio;
|
||||
c++;
|
||||
v6 += widthRatio;
|
||||
}
|
||||
v1 += srcPitch;
|
||||
v2 += heightRatio;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4D36D4
|
||||
void blitBufferToBuffer(unsigned char* src, int width, int height, int srcPitch, unsigned char* dest, int destPitch)
|
||||
{
|
||||
mmxBlit(dest, destPitch, src, srcPitch, width, height);
|
||||
}
|
||||
|
||||
// 0x4D3704
|
||||
void blitBufferToBufferTrans(unsigned char* src, int width, int height, int srcPitch, unsigned char* dest, int destPitch)
|
||||
{
|
||||
mmxBlitTrans(dest, destPitch, src, srcPitch, width, height);
|
||||
}
|
||||
|
||||
// 0x4D387C
|
||||
void bufferFill(unsigned char* buf, int width, int height, int pitch, int a5)
|
||||
{
|
||||
int y;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
memset(buf, a5, width);
|
||||
buf += pitch;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4D38E0
|
||||
void _buf_texture(unsigned char* buf, int width, int height, int pitch, void* a5, int a6, int a7)
|
||||
{
|
||||
// TODO: Incomplete.
|
||||
}
|
||||
|
||||
// 0x4D3A48
|
||||
void _lighten_buf(unsigned char* buf, int width, int height, int pitch)
|
||||
{
|
||||
int skip = pitch - width;
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
unsigned char p = *buf;
|
||||
*buf++ = _intensityColorTable[(p << 8) + 147];
|
||||
}
|
||||
buf += skip;
|
||||
}
|
||||
}
|
||||
|
||||
// Swaps two colors in the buffer.
|
||||
//
|
||||
// 0x4D3A8C
|
||||
void _swap_color_buf(unsigned char* buf, int width, int height, int pitch, int color1, int color2)
|
||||
{
|
||||
int step = pitch - width;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int v1 = *buf & 0xFF;
|
||||
if (v1 == color1) {
|
||||
*buf = color2 & 0xFF;
|
||||
} else if (v1 == color2) {
|
||||
*buf = color1 & 0xFF;
|
||||
}
|
||||
buf++;
|
||||
}
|
||||
buf += step;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4D3AE0
|
||||
void bufferOutline(unsigned char* buf, int width, int height, int pitch, int color)
|
||||
{
|
||||
unsigned char* ptr = buf + pitch;
|
||||
|
||||
bool cycle;
|
||||
for (int y = 0; y < height - 2; y++) {
|
||||
cycle = true;
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
if (*ptr != 0 && cycle) {
|
||||
*(ptr - 1) = color & 0xFF;
|
||||
cycle = false;
|
||||
} else if (*ptr == 0 && !cycle) {
|
||||
*ptr = color & 0xFF;
|
||||
cycle = true;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
ptr += pitch - width;
|
||||
}
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
ptr = buf + x;
|
||||
cycle = true;
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
if (*ptr != 0 && cycle) {
|
||||
// TODO: Check in debugger, might be a bug.
|
||||
*(ptr - pitch) = color & 0xFF;
|
||||
cycle = false;
|
||||
} else if (*ptr == 0 && !cycle) {
|
||||
*ptr = color & 0xFF;
|
||||
cycle = true;
|
||||
}
|
||||
|
||||
ptr += pitch;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef DRAW_H
|
||||
#define DRAW_H
|
||||
|
||||
void bufferDrawLine(unsigned char* buf, int pitch, int left, int top, int right, int bottom, int color);
|
||||
void bufferDrawRect(unsigned char* buf, int a2, int a3, int a4, int a5, int a6, int a7);
|
||||
void bufferDrawRectShadowed(unsigned char* buf, int a2, int a3, int a4, int a5, int a6, int a7, int a8);
|
||||
void blitBufferToBufferStretch(unsigned char* src, int srcWidth, int srcHeight, int srcPitch, unsigned char* dest, int destWidth, int destHeight, int destPitch);
|
||||
void blitBufferToBufferStretchTrans(unsigned char* src, int srcWidth, int srcHeight, int srcPitch, unsigned char* dest, int destWidth, int destHeight, int destPitch);
|
||||
void blitBufferToBuffer(unsigned char* src, int width, int height, int srcPitch, unsigned char* dest, int destPitch);
|
||||
void blitBufferToBufferTrans(unsigned char* src, int width, int height, int srcPitch, unsigned char* dest, int destPitch);
|
||||
void bufferFill(unsigned char* buf, int width, int height, int pitch, int a5);
|
||||
void _buf_texture(unsigned char* buf, int width, int height, int pitch, void* a5, int a6, int a7);
|
||||
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);
|
||||
|
||||
#endif /* DRAW_H */
|
|
@ -0,0 +1,42 @@
|
|||
#include "electronic_registration.h"
|
||||
|
||||
#include "game_config.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
// 0x440DD0
|
||||
void runElectronicRegistration()
|
||||
{
|
||||
int timesRun = 0;
|
||||
configGetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_TIMES_RUN_KEY, ×Run);
|
||||
if (timesRun > 0 && timesRun < 5) {
|
||||
char path[MAX_PATH];
|
||||
if (GetModuleFileNameA(NULL, path, sizeof(path)) != 0) {
|
||||
char* pch = strrchr(path, '\\');
|
||||
if (pch == NULL) {
|
||||
pch = path;
|
||||
}
|
||||
|
||||
strcpy(pch, "\\ereg");
|
||||
|
||||
STARTUPINFOA startupInfo;
|
||||
memset(&startupInfo, 0, sizeof(startupInfo));
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
|
||||
PROCESS_INFORMATION processInfo;
|
||||
|
||||
// FIXME: Leaking processInfo.hProcess and processInfo.hThread:
|
||||
// https://docs.microsoft.com/en-us/cpp/code-quality/c6335.
|
||||
if (CreateProcessA("ereg\\reg32a.exe", NULL, NULL, NULL, FALSE, 0, NULL, path, &startupInfo, &processInfo)) {
|
||||
WaitForSingleObject(processInfo.hProcess, INFINITE);
|
||||
}
|
||||
}
|
||||
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_TIMES_RUN_KEY, timesRun + 1);
|
||||
} else {
|
||||
if (timesRun == 0) {
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_TIMES_RUN_KEY, 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef ELECTRONIC_REGISTRATION_H
|
||||
#define ELECTRONIC_REGISTRATION_H
|
||||
|
||||
void runElectronicRegistration();
|
||||
|
||||
#endif /* ELECTRONIC_REGISTRATION_H */
|
|
@ -0,0 +1,647 @@
|
|||
#include "elevator.h"
|
||||
|
||||
#include "core.h"
|
||||
#include "cycle.h"
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
#include "game_mouse.h"
|
||||
#include "game_sound.h"
|
||||
#include "map.h"
|
||||
#include "pipboy.h"
|
||||
#include "scripts.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
// 0x43E950
|
||||
const int gElevatorFrmIds[ELEVATOR_FRM_COUNT] = {
|
||||
141, // ebut_in.frm - map elevator screen
|
||||
142, // ebut_out.frm - map elevator screen
|
||||
149, // gaj000.frm - map elevator screen
|
||||
};
|
||||
|
||||
// 0x43E95C
|
||||
const ElevatorBackground gElevatorBackgrounds[ELEVATOR_COUNT] = {
|
||||
{ 143, -1 },
|
||||
{ 143, 150 },
|
||||
{ 144, -1 },
|
||||
{ 144, 145 },
|
||||
{ 146, -1 },
|
||||
{ 146, 147 },
|
||||
{ 146, -1 },
|
||||
{ 146, 151 },
|
||||
{ 148, -1 },
|
||||
{ 146, -1 },
|
||||
{ 146, -1 },
|
||||
{ 146, 147 },
|
||||
{ 388, -1 },
|
||||
{ 143, 150 },
|
||||
{ 148, -1 },
|
||||
{ 148, -1 },
|
||||
{ 148, -1 },
|
||||
{ 143, 150 },
|
||||
{ 143, 150 },
|
||||
{ 143, 150 },
|
||||
{ 143, 150 },
|
||||
{ 143, 150 },
|
||||
{ 143, 150 },
|
||||
{ 143, 150 },
|
||||
};
|
||||
|
||||
// Number of levels for eleveators.
|
||||
//
|
||||
// 0x43EA1C
|
||||
const int gElevatorLevels[ELEVATOR_COUNT] = {
|
||||
4,
|
||||
2,
|
||||
3,
|
||||
2,
|
||||
3,
|
||||
2,
|
||||
3,
|
||||
3,
|
||||
3,
|
||||
3,
|
||||
3,
|
||||
2,
|
||||
4,
|
||||
2,
|
||||
3,
|
||||
3,
|
||||
3,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
};
|
||||
|
||||
// 0x43EA7C
|
||||
const ElevatorDescription gElevatorDescriptions[ELEVATOR_COUNT][ELEVATOR_LEVEL_MAX] = {
|
||||
{
|
||||
{ 14, 0, 18940 },
|
||||
{ 14, 1, 18936 },
|
||||
{ 15, 0, 21340 },
|
||||
{ 15, 1, 21340 },
|
||||
},
|
||||
{
|
||||
{ 13, 0, 20502 },
|
||||
{ 14, 0, 14912 },
|
||||
{ 0, 0, -1 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 33, 0, 12498 },
|
||||
{ 33, 1, 20094 },
|
||||
{ 34, 0, 17312 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 34, 0, 16140 },
|
||||
{ 34, 1, 16140 },
|
||||
{ 0, 0, -1 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 49, 0, 14920 },
|
||||
{ 49, 1, 15120 },
|
||||
{ 50, 0, 12944 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 50, 0, 24520 },
|
||||
{ 50, 1, 25316 },
|
||||
{ 0, 0, -1 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 42, 0, 22526 },
|
||||
{ 42, 1, 22526 },
|
||||
{ 42, 2, 22526 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 42, 2, 14086 },
|
||||
{ 43, 0, 14086 },
|
||||
{ 43, 2, 14086 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 40, 0, 14104 },
|
||||
{ 40, 1, 22504 },
|
||||
{ 40, 2, 17312 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 9, 0, 13704 },
|
||||
{ 9, 1, 23302 },
|
||||
{ 9, 2, 17308 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 28, 0, 19300 },
|
||||
{ 28, 1, 19300 },
|
||||
{ 28, 2, 20110 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 28, 2, 20118 },
|
||||
{ 29, 0, 21710 },
|
||||
{ 0, 0, -1 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 28, 0, 20122 },
|
||||
{ 28, 1, 20124 },
|
||||
{ 28, 2, 20940 },
|
||||
{ 29, 0, 22540 },
|
||||
},
|
||||
{
|
||||
{ 12, 1, 16052 },
|
||||
{ 12, 2, 14480 },
|
||||
{ 0, 0, -1 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 6, 0, 14104 },
|
||||
{ 6, 1, 22504 },
|
||||
{ 6, 2, 17312 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 30, 0, 14104 },
|
||||
{ 30, 1, 22504 },
|
||||
{ 30, 2, 17312 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 36, 0, 13704 },
|
||||
{ 36, 1, 23302 },
|
||||
{ 36, 2, 17308 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 39, 0, 17285 },
|
||||
{ 36, 0, 19472 },
|
||||
{ 0, 0, -1 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 109, 2, 10701 },
|
||||
{ 109, 1, 10705 },
|
||||
{ 0, 0, -1 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 109, 2, 14697 },
|
||||
{ 109, 1, 15099 },
|
||||
{ 0, 0, -1 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 109, 2, 23877 },
|
||||
{ 109, 1, 25481 },
|
||||
{ 0, 0, -1 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 109, 2, 26130 },
|
||||
{ 109, 1, 24721 },
|
||||
{ 0, 0, -1 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 137, 0, 23953 },
|
||||
{ 148, 1, 16526 },
|
||||
{ 0, 0, -1 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
{
|
||||
{ 62, 0, 13901 },
|
||||
{ 63, 1, 17923 },
|
||||
{ 0, 0, -1 },
|
||||
{ 0, 0, -1 },
|
||||
},
|
||||
};
|
||||
|
||||
// NOTE: These values are also used as key bindings.
|
||||
//
|
||||
// 0x43EEFC
|
||||
const char gElevatorLevelLabels[ELEVATOR_COUNT][ELEVATOR_LEVEL_MAX] = {
|
||||
{ '1', '2', '3', '4' },
|
||||
{ 'G', '1', '\0', '\0' },
|
||||
{ '1', '2', '3', '\0' },
|
||||
{ '3', '4', '\0', '\0' },
|
||||
{ '1', '2', '3', '\0' },
|
||||
{ '3', '4', '\0', '\0' },
|
||||
{ '1', '2', '3', '\0' },
|
||||
{ '3', '4', '6', '\0' },
|
||||
{ '1', '2', '3', '\0' },
|
||||
{ '1', '2', '3', '\0' },
|
||||
{ '1', '2', '3', '\0' },
|
||||
{ '3', '4', '\0', '\0' },
|
||||
{ '1', '2', '3', '4' },
|
||||
{ '1', '2', '\0', '\0' },
|
||||
{ '1', '2', '3', '\0' },
|
||||
{ '1', '2', '3', '\0' },
|
||||
{ '1', '2', '3', '\0' },
|
||||
{ '1', '2', '\0', '\0' },
|
||||
{ '1', '2', '\0', '\0' },
|
||||
{ '1', '2', '\0', '\0' },
|
||||
{ '1', '2', '\0', '\0' },
|
||||
{ '1', '2', '\0', '\0' },
|
||||
{ '1', '2', '\0', '\0' },
|
||||
{ '1', '2', '\0', '\0' },
|
||||
};
|
||||
|
||||
// 0x51862C
|
||||
const char* gElevatorSoundEffects[ELEVATOR_LEVEL_MAX - 1][ELEVATOR_LEVEL_MAX] = {
|
||||
{
|
||||
"ELV1_1",
|
||||
"ELV1_1",
|
||||
"ERROR",
|
||||
"ERROR",
|
||||
},
|
||||
{
|
||||
"ELV1_2",
|
||||
"ELV1_2",
|
||||
"ELV1_1",
|
||||
"ERROR",
|
||||
},
|
||||
{
|
||||
"ELV1_3",
|
||||
"ELV1_3",
|
||||
"ELV2_3",
|
||||
"ELV1_1",
|
||||
},
|
||||
};
|
||||
|
||||
// 0x570A2C
|
||||
Size gElevatorFrmSizes[ELEVATOR_FRM_COUNT];
|
||||
|
||||
// 0x570A44
|
||||
int gElevatorBackgroundFrmWidth;
|
||||
|
||||
// 0x570A48
|
||||
int gElevatorBackgroundFrmHeight;
|
||||
|
||||
// 0x570A4C
|
||||
int gElevatorPanelFrmWidth;
|
||||
|
||||
// 0x570A50
|
||||
int gElevatorPanelFrmHeight;
|
||||
|
||||
// 0x570A54
|
||||
int gElevatorWindow;
|
||||
|
||||
// 0x570A58
|
||||
CacheEntry* gElevatorFrmHandles[ELEVATOR_FRM_COUNT];
|
||||
|
||||
// 0x570A64
|
||||
CacheEntry* gElevatorBackgroundFrmHandle;
|
||||
|
||||
// 0x570A68
|
||||
CacheEntry* gElevatorPanelFrmHandle;
|
||||
|
||||
// 0x570A6C
|
||||
unsigned char* gElevatorWindowBuffer;
|
||||
|
||||
// 0x570A70
|
||||
bool gElevatorWindowIsoWasEnabled;
|
||||
|
||||
// 0x570A74
|
||||
unsigned char* gElevatorFrmData[ELEVATOR_FRM_COUNT];
|
||||
|
||||
// 0x570A80
|
||||
unsigned char* gElevatorBackgroundFrmData;
|
||||
|
||||
// 0x570A84
|
||||
unsigned char* gElevatorPanelFrmData;
|
||||
|
||||
// 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) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (elevatorWindowInit(elevator) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const ElevatorDescription* elevatorDescription = gElevatorDescriptions[elevator];
|
||||
|
||||
int index;
|
||||
for (index = 0; index < ELEVATOR_LEVEL_MAX; index++) {
|
||||
if (elevatorDescription[index].map == *mapPtr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < ELEVATOR_LEVEL_MAX) {
|
||||
if (elevatorDescription[*elevationPtr + index].tile != -1) {
|
||||
*elevationPtr += index;
|
||||
}
|
||||
}
|
||||
|
||||
if (elevator == ELEVATOR_SIERRA_2) {
|
||||
if (*elevationPtr <= 2) {
|
||||
*elevationPtr -= 2;
|
||||
} else {
|
||||
*elevationPtr -= 3;
|
||||
}
|
||||
} else if (elevator == ELEVATOR_MILITARY_BASE_LOWER) {
|
||||
if (*elevationPtr >= 2) {
|
||||
*elevationPtr -= 2;
|
||||
}
|
||||
} else if (elevator == ELEVATOR_MILITARY_BASE_UPPER && *elevationPtr == 4) {
|
||||
*elevationPtr -= 2;
|
||||
}
|
||||
|
||||
if (*elevationPtr > 3) {
|
||||
*elevationPtr -= 3;
|
||||
}
|
||||
|
||||
debugPrint("\n the start elev level %d\n", *elevationPtr);
|
||||
|
||||
int v18 = (gElevatorFrmSizes[ELEVATOR_FRM_GAUGE].width * gElevatorFrmSizes[ELEVATOR_FRM_GAUGE].height) / 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);
|
||||
windowRefresh(gElevatorWindow);
|
||||
|
||||
bool done = false;
|
||||
int keyCode;
|
||||
while (!done) {
|
||||
keyCode = _get_input();
|
||||
if (keyCode == KEY_ESCAPE) {
|
||||
done = true;
|
||||
}
|
||||
|
||||
if (keyCode >= 500 && keyCode < 504) {
|
||||
done = true;
|
||||
}
|
||||
|
||||
if (keyCode > 0 && keyCode < 500) {
|
||||
int level = elevatorGetLevelFromKeyCode(elevator, keyCode);
|
||||
if (level != 0) {
|
||||
keyCode = 500 + level - 1;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keyCode != KEY_ESCAPE) {
|
||||
keyCode -= 500;
|
||||
|
||||
if (*elevationPtr != keyCode) {
|
||||
float v43 = (float)(gElevatorLevels[elevator] - 1) / 12.0f;
|
||||
|
||||
unsigned int delay = (unsigned int)(v43 * 276.92307);
|
||||
|
||||
if (keyCode < *elevationPtr) {
|
||||
v43 = -v43;
|
||||
}
|
||||
|
||||
int numberOfLevelsTravelled = keyCode - *elevationPtr;
|
||||
if (numberOfLevelsTravelled < 0) {
|
||||
numberOfLevelsTravelled = -numberOfLevelsTravelled;
|
||||
}
|
||||
|
||||
soundPlayFile(gElevatorSoundEffects[gElevatorLevels[elevator] - 2][numberOfLevelsTravelled]);
|
||||
|
||||
float v41 = (float)keyCode * v42;
|
||||
float v44 = (float)(*elevationPtr) * v42;
|
||||
do {
|
||||
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);
|
||||
|
||||
windowRefresh(gElevatorWindow);
|
||||
|
||||
while (getTicksSince(tick) < delay) {
|
||||
}
|
||||
} while ((v43 <= 0.0 || v44 < v41) && (v43 > 0.0 || v44 > v41));
|
||||
|
||||
coreDelayProcessingEvents(200);
|
||||
}
|
||||
}
|
||||
|
||||
elevatorWindowFree();
|
||||
|
||||
if (keyCode != KEY_ESCAPE) {
|
||||
const ElevatorDescription* description = &(elevatorDescription[keyCode]);
|
||||
*mapPtr = description->map;
|
||||
*elevationPtr = description->elevation;
|
||||
*tilePtr = description->tile;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x43F324
|
||||
int elevatorWindowInit(int elevator)
|
||||
{
|
||||
gElevatorWindowIsoWasEnabled = isoDisable();
|
||||
colorCycleDisable();
|
||||
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
gameMouseObjectsHide();
|
||||
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
scriptsDisable();
|
||||
|
||||
int index;
|
||||
for (index = 0; index < ELEVATOR_FRM_COUNT; index++) {
|
||||
int fid = buildFid(6, gElevatorFrmIds[index], 0, 0, 0);
|
||||
gElevatorFrmData[index] = artLockFrameDataReturningSize(fid, &(gElevatorFrmHandles[index]), &(gElevatorFrmSizes[index].width), &(gElevatorFrmSizes[index].height));
|
||||
if (gElevatorFrmData[index] == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index != ELEVATOR_FRM_COUNT) {
|
||||
for (int reversedIndex = index - 1; reversedIndex >= 0; reversedIndex--) {
|
||||
artUnlock(gElevatorFrmHandles[reversedIndex]);
|
||||
}
|
||||
|
||||
if (gElevatorWindowIsoWasEnabled) {
|
||||
isoEnable();
|
||||
}
|
||||
|
||||
colorCycleEnable();
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gElevatorPanelFrmData = ELEVATOR_BACKGROUND_NULL;
|
||||
gElevatorBackgroundFrmData = ELEVATOR_BACKGROUND_NULL;
|
||||
|
||||
const ElevatorBackground* elevatorBackground = &(gElevatorBackgrounds[elevator]);
|
||||
bool backgroundsLoaded = true;
|
||||
|
||||
int backgroundFid = buildFid(6, elevatorBackground->backgroundFrmId, 0, 0, 0);
|
||||
gElevatorBackgroundFrmData = artLockFrameDataReturningSize(backgroundFid, &gElevatorBackgroundFrmHandle, &gElevatorBackgroundFrmWidth, &gElevatorBackgroundFrmHeight);
|
||||
if (gElevatorBackgroundFrmData != NULL) {
|
||||
if (elevatorBackground->panelFrmId != -1) {
|
||||
int panelFid = buildFid(6, elevatorBackground->panelFrmId, 0, 0, 0);
|
||||
gElevatorPanelFrmData = artLockFrameDataReturningSize(panelFid, &gElevatorPanelFrmHandle, &gElevatorPanelFrmWidth, &gElevatorPanelFrmHeight);
|
||||
if (gElevatorPanelFrmData == NULL) {
|
||||
gElevatorPanelFrmData = ELEVATOR_BACKGROUND_NULL;
|
||||
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);
|
||||
}
|
||||
|
||||
for (int index = 0; index < ELEVATOR_FRM_COUNT; index++) {
|
||||
artUnlock(gElevatorFrmHandles[index]);
|
||||
}
|
||||
|
||||
if (gElevatorWindowIsoWasEnabled) {
|
||||
isoEnable();
|
||||
}
|
||||
|
||||
colorCycleEnable();
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gElevatorWindow = windowCreate(
|
||||
(640 - gElevatorBackgroundFrmWidth) / 2,
|
||||
(379 - gElevatorBackgroundFrmHeight) / 2,
|
||||
gElevatorBackgroundFrmWidth,
|
||||
gElevatorBackgroundFrmHeight,
|
||||
256,
|
||||
WINDOW_FLAG_0x10 | WINDOW_FLAG_0x02);
|
||||
if (gElevatorWindow == -1) {
|
||||
if (gElevatorBackgroundFrmData != ELEVATOR_BACKGROUND_NULL) {
|
||||
artUnlock(gElevatorBackgroundFrmHandle);
|
||||
}
|
||||
|
||||
if (gElevatorPanelFrmData != ELEVATOR_BACKGROUND_NULL) {
|
||||
artUnlock(gElevatorPanelFrmHandle);
|
||||
}
|
||||
|
||||
for (int index = 0; index < ELEVATOR_FRM_COUNT; index++) {
|
||||
artUnlock(gElevatorFrmHandles[index]);
|
||||
}
|
||||
|
||||
if (gElevatorWindowIsoWasEnabled) {
|
||||
isoEnable();
|
||||
}
|
||||
|
||||
colorCycleEnable();
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gElevatorWindowBuffer = windowGetBuffer(gElevatorWindow);
|
||||
memcpy(gElevatorWindowBuffer, (unsigned char*)gElevatorBackgroundFrmData, gElevatorBackgroundFrmWidth * gElevatorBackgroundFrmHeight);
|
||||
|
||||
if (gElevatorPanelFrmData != ELEVATOR_BACKGROUND_NULL) {
|
||||
blitBufferToBuffer((unsigned char*)gElevatorPanelFrmData,
|
||||
gElevatorPanelFrmWidth,
|
||||
gElevatorPanelFrmHeight,
|
||||
gElevatorPanelFrmWidth,
|
||||
gElevatorWindowBuffer + gElevatorBackgroundFrmWidth * (gElevatorBackgroundFrmHeight - gElevatorPanelFrmHeight),
|
||||
gElevatorBackgroundFrmWidth);
|
||||
}
|
||||
|
||||
int y = 40;
|
||||
for (int level = 0; level < gElevatorLevels[elevator]; level++) {
|
||||
int btn = buttonCreate(gElevatorWindow,
|
||||
13,
|
||||
y,
|
||||
gElevatorFrmSizes[ELEVATOR_FRM_BUTTON_DOWN].width,
|
||||
gElevatorFrmSizes[ELEVATOR_FRM_BUTTON_DOWN].height,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
500 + level,
|
||||
gElevatorFrmData[ELEVATOR_FRM_BUTTON_UP],
|
||||
gElevatorFrmData[ELEVATOR_FRM_BUTTON_DOWN],
|
||||
NULL,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (btn != -1) {
|
||||
buttonSetCallbacks(btn, _gsound_red_butt_press, NULL);
|
||||
}
|
||||
y += 60;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x43F6D0
|
||||
void elevatorWindowFree()
|
||||
{
|
||||
windowDestroy(gElevatorWindow);
|
||||
|
||||
if (gElevatorBackgroundFrmData != ELEVATOR_BACKGROUND_NULL) {
|
||||
artUnlock(gElevatorBackgroundFrmHandle);
|
||||
}
|
||||
|
||||
if (gElevatorPanelFrmData != ELEVATOR_BACKGROUND_NULL) {
|
||||
artUnlock(gElevatorPanelFrmHandle);
|
||||
}
|
||||
|
||||
for (int index = 0; index < ELEVATOR_FRM_COUNT; index++) {
|
||||
artUnlock(gElevatorFrmHandles[index]);
|
||||
}
|
||||
|
||||
scriptsEnable();
|
||||
|
||||
if (gElevatorWindowIsoWasEnabled) {
|
||||
isoEnable();
|
||||
}
|
||||
|
||||
colorCycleEnable();
|
||||
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
}
|
||||
|
||||
// 0x43F73C
|
||||
int elevatorGetLevelFromKeyCode(int elevator, int keyCode)
|
||||
{
|
||||
// TODO: Check if result is really unused?
|
||||
toupper(keyCode);
|
||||
|
||||
for (int index = 0; index < ELEVATOR_LEVEL_MAX; index++) {
|
||||
char c = gElevatorLevelLabels[elevator][index];
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == (char)(keyCode & 0xFF)) {
|
||||
return index + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
#ifndef ELEVATOR_H
|
||||
#define ELEVATOR_H
|
||||
|
||||
#include "art.h"
|
||||
#include "geometry.h"
|
||||
|
||||
// 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))
|
||||
|
||||
typedef enum Elevator {
|
||||
ELEVATOR_BROTHERHOOD_OF_STEEL_MAIN,
|
||||
ELEVATOR_BROTHERHOOD_OF_STEEL_SURFACE,
|
||||
ELEVATOR_MASTER_UPPER,
|
||||
ELEVATOR_MASTER_LOWER,
|
||||
ELEVATOR_MILITARY_BASE_UPPER,
|
||||
ELEVATOR_MILITARY_BASE_LOWER,
|
||||
ELEVATOR_GLOW_UPPER,
|
||||
ELEVATOR_GLOW_LOWER,
|
||||
ELEVATOR_VAULT_13,
|
||||
ELEVATOR_NECROPOLIS,
|
||||
ELEVATOR_SIERRA_1,
|
||||
ELEVATOR_SIERRA_2,
|
||||
ELEVATOR_SIERRA_SERVICE,
|
||||
ELEVATOR_COUNT = 24,
|
||||
} Elevator;
|
||||
|
||||
typedef enum ElevatorFrm {
|
||||
ELEVATOR_FRM_BUTTON_DOWN,
|
||||
ELEVATOR_FRM_BUTTON_UP,
|
||||
ELEVATOR_FRM_GAUGE,
|
||||
ELEVATOR_FRM_COUNT,
|
||||
} ElevatorFrm;
|
||||
|
||||
typedef struct ElevatorBackground {
|
||||
int backgroundFrmId;
|
||||
int panelFrmId;
|
||||
} ElevatorBackground;
|
||||
|
||||
typedef struct ElevatorDescription {
|
||||
int map;
|
||||
int elevation;
|
||||
int tile;
|
||||
} ElevatorDescription;
|
||||
|
||||
extern const int gElevatorFrmIds[ELEVATOR_FRM_COUNT];
|
||||
extern const ElevatorBackground gElevatorBackgrounds[ELEVATOR_COUNT];
|
||||
extern const int gElevatorLevels[ELEVATOR_COUNT];
|
||||
extern const ElevatorDescription gElevatorDescriptions[ELEVATOR_COUNT][ELEVATOR_LEVEL_MAX];
|
||||
extern const char gElevatorLevelLabels[ELEVATOR_COUNT][ELEVATOR_LEVEL_MAX];
|
||||
|
||||
extern const char* gElevatorSoundEffects[ELEVATOR_LEVEL_MAX - 1][ELEVATOR_LEVEL_MAX];
|
||||
|
||||
extern Size gElevatorFrmSizes[ELEVATOR_FRM_COUNT];
|
||||
extern int gElevatorBackgroundFrmWidth;
|
||||
extern int gElevatorBackgroundFrmHeight;
|
||||
extern int gElevatorPanelFrmWidth;
|
||||
extern int gElevatorPanelFrmHeight;
|
||||
extern int gElevatorWindow;
|
||||
extern CacheEntry* gElevatorFrmHandles[ELEVATOR_FRM_COUNT];
|
||||
extern CacheEntry* gElevatorBackgroundFrmHandle;
|
||||
extern CacheEntry* gElevatorPanelFrmHandle;
|
||||
extern unsigned char* gElevatorWindowBuffer;
|
||||
extern bool gElevatorWindowIsoWasEnabled;
|
||||
extern unsigned char* gElevatorFrmData[ELEVATOR_FRM_COUNT];
|
||||
extern unsigned char* gElevatorBackgroundFrmData;
|
||||
extern unsigned char* gElevatorPanelFrmData;
|
||||
|
||||
int elevatorSelectLevel(int elevator, int* mapPtr, int* elevationPtr, int* tilePtr);
|
||||
int elevatorWindowInit(int elevator);
|
||||
void elevatorWindowFree();
|
||||
int elevatorGetLevelFromKeyCode(int elevator, int keyCode);
|
||||
|
||||
#endif /* ELEVATOR_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,92 @@
|
|||
#ifndef ENDGAME_H
|
||||
#define ENDGAME_H
|
||||
|
||||
// Provides [MAX_PATH].
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum EndgameDeathEndingReason {
|
||||
// Dude died.
|
||||
ENDGAME_DEATH_ENDING_REASON_DEATH = 0,
|
||||
|
||||
// 13 years passed.
|
||||
ENDGAME_DEATH_ENDING_REASON_TIMEOUT = 2,
|
||||
} EndgameDeathEndingReason;
|
||||
|
||||
typedef struct EndgameDeathEnding {
|
||||
int gvar;
|
||||
int value;
|
||||
int worldAreaKnown;
|
||||
int worldAreaNotKnown;
|
||||
int min_level;
|
||||
int percentage;
|
||||
char voiceOverBaseName[16];
|
||||
|
||||
// This flag denotes that the conditions for this ending is met and it was
|
||||
// selected as a candidate for final random selection.
|
||||
bool enabled;
|
||||
} EndgameDeathEnding;
|
||||
|
||||
typedef struct EndgameEnding {
|
||||
int gvar;
|
||||
int value;
|
||||
int art_num;
|
||||
char voiceOverBaseName[12];
|
||||
int direction;
|
||||
} EndgameEnding;
|
||||
|
||||
extern char _aEnglish_2[];
|
||||
|
||||
extern int gEndgameEndingSubtitlesLength;
|
||||
extern int gEndgameEndingSubtitlesCharactersCount;
|
||||
extern int gEndgameEndingSubtitlesCurrentLine;
|
||||
extern int _endgame_maybe_done;
|
||||
extern EndgameDeathEnding* gEndgameDeathEndings;
|
||||
extern int gEndgameDeathEndingsLength;
|
||||
|
||||
extern char gEndgameDeathEndingFileName[40];
|
||||
extern bool gEndgameEndingVoiceOverSpeechLoaded;
|
||||
extern char gEndgameEndingSubtitlesLocalizedPath[MAX_PATH];
|
||||
extern bool gEndgameEndingSpeechEnded;
|
||||
extern EndgameEnding* gEndgameEndings;
|
||||
extern char** gEndgameEndingSubtitles;
|
||||
extern bool gEndgameEndingSubtitlesEnabled;
|
||||
extern bool gEndgameEndingSubtitlesEnded;
|
||||
extern bool _endgame_map_enabled;
|
||||
extern bool _endgame_mouse_state;
|
||||
extern int gEndgameEndingsLength;
|
||||
extern bool gEndgameEndingVoiceOverSubtitlesLoaded;
|
||||
extern unsigned int gEndgameEndingSubtitlesReferenceTime;
|
||||
extern unsigned int* gEndgameEndingSubtitlesTimings;
|
||||
extern int gEndgameEndingSlideshowOldFont;
|
||||
extern unsigned char* gEndgameEndingSlideshowWindowBuffer;
|
||||
extern int gEndgameEndingSlideshowWindow;
|
||||
|
||||
void endgamePlaySlideshow();
|
||||
void endgamePlayMovie();
|
||||
void endgameEndingRenderPanningScene(int direction, const char* narratorFileName);
|
||||
void endgameEndingRenderStaticScene(int fid, const char* narratorFileName);
|
||||
int endgameEndingHandleContinuePlaying();
|
||||
int endgameEndingSlideshowWindowInit();
|
||||
void endgameEndingSlideshowWindowFree();
|
||||
void endgameEndingVoiceOverInit(const char* fname);
|
||||
void endgameEndingVoiceOverReset();
|
||||
void endgameEndingVoiceOverFree();
|
||||
void endgameEndingLoadPalette(int type, int id);
|
||||
void _endgame_voiceover_callback();
|
||||
int endgameEndingSubtitlesLoad(const char* filePath);
|
||||
void endgameEndingRefreshSubtitles();
|
||||
void endgameEndingSubtitlesFree();
|
||||
void _endgame_movie_callback();
|
||||
void _endgame_movie_bk_process();
|
||||
int endgameEndingInit();
|
||||
void endgameEndingFree();
|
||||
int endgameDeathEndingInit();
|
||||
int endgameDeathEndingExit();
|
||||
void endgameSetupDeathEnding(int reason);
|
||||
int endgameDeathEndingValidate(int* percentage);
|
||||
char* endgameDeathEndingGetFileName();
|
||||
|
||||
#endif /* ENDGAME_H */
|
|
@ -0,0 +1,325 @@
|
|||
#include "export.h"
|
||||
|
||||
#include "interpreter_lib.h"
|
||||
#include "memory_manager.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
// 0x570C00
|
||||
ExternalProcedure gExternalProcedures[1013];
|
||||
|
||||
// 0x57BA1C
|
||||
ExternalVariable gExternalVariables[1013];
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x440F10
|
||||
unsigned int _hashName(const char* identifier)
|
||||
{
|
||||
unsigned int v1 = 0;
|
||||
const char* pch = identifier;
|
||||
while (*pch != '\0') {
|
||||
int ch = *pch & 0xFF;
|
||||
v1 += (tolower(ch) & 0xFF) + (v1 * 8) + (v1 >> 29);
|
||||
pch++;
|
||||
}
|
||||
|
||||
v1 = v1 % 1013;
|
||||
return v1;
|
||||
}
|
||||
|
||||
// 0x440F58
|
||||
ExternalProcedure* externalProcedureFind(const char* identifier)
|
||||
{
|
||||
// NOTE: Uninline.
|
||||
unsigned int v1 = _hashName(identifier);
|
||||
unsigned int v2 = v1;
|
||||
|
||||
ExternalProcedure* externalProcedure = &(gExternalProcedures[v1]);
|
||||
if (externalProcedure->program != NULL) {
|
||||
if (stricmp(externalProcedure->name, identifier) == 0) {
|
||||
return externalProcedure;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
v1 += 7;
|
||||
if (v1 >= 1013) {
|
||||
v1 -= 1013;
|
||||
}
|
||||
|
||||
externalProcedure = &(gExternalProcedures[v1]);
|
||||
if (externalProcedure->program != NULL) {
|
||||
if (stricmp(externalProcedure->name, identifier) == 0) {
|
||||
return externalProcedure;
|
||||
}
|
||||
}
|
||||
} while (v1 != v2);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 0x441018
|
||||
ExternalProcedure* externalProcedureAdd(const char* identifier)
|
||||
{
|
||||
// NOTE: Uninline.
|
||||
unsigned int v1 = _hashName(identifier);
|
||||
unsigned int a2 = v1;
|
||||
|
||||
ExternalProcedure* externalProcedure = &(gExternalProcedures[v1]);
|
||||
if (externalProcedure->name[0] == '\0') {
|
||||
return externalProcedure;
|
||||
}
|
||||
|
||||
do {
|
||||
v1 += 7;
|
||||
if (v1 >= 1013) {
|
||||
v1 -= 1013;
|
||||
}
|
||||
|
||||
externalProcedure = &(gExternalProcedures[v1]);
|
||||
if (externalProcedure->name[0] == '\0') {
|
||||
return externalProcedure;
|
||||
}
|
||||
} while (v1 != a2);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 0x4410AC
|
||||
ExternalVariable* externalVariableFind(const char* identifier)
|
||||
{
|
||||
// NOTE: Uninline.
|
||||
unsigned int v1 = _hashName(identifier);
|
||||
unsigned int v2 = v1;
|
||||
|
||||
ExternalVariable* exportedVariable = &(gExternalVariables[v1]);
|
||||
if (stricmp(exportedVariable->name, identifier) == 0) {
|
||||
return exportedVariable;
|
||||
}
|
||||
|
||||
do {
|
||||
exportedVariable = &(gExternalVariables[v1]);
|
||||
if (exportedVariable->name[0] == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
v1 += 7;
|
||||
if (v1 >= 1013) {
|
||||
v1 -= 1013;
|
||||
}
|
||||
|
||||
exportedVariable = &(gExternalVariables[v1]);
|
||||
if (stricmp(exportedVariable->name, identifier) == 0) {
|
||||
return exportedVariable;
|
||||
}
|
||||
} while (v1 != v2);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 0x44118C
|
||||
ExternalVariable* externalVariableAdd(const char* identifier)
|
||||
{
|
||||
// NOTE: Uninline.
|
||||
unsigned int v1 = _hashName(identifier);
|
||||
unsigned int v2 = v1;
|
||||
|
||||
ExternalVariable* exportedVariable = &(gExternalVariables[v1]);
|
||||
if (exportedVariable->name[0] == '\0') {
|
||||
return exportedVariable;
|
||||
}
|
||||
|
||||
do {
|
||||
v1 += 7;
|
||||
if (v1 >= 1013) {
|
||||
v1 -= 1013;
|
||||
}
|
||||
|
||||
exportedVariable = &(gExternalVariables[v1]);
|
||||
if (exportedVariable->name[0] == '\0') {
|
||||
return exportedVariable;
|
||||
}
|
||||
} while (v1 != v2);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 0x44127C
|
||||
int externalVariableSetValue(Program* program, const char* name, opcode_t opcode, int data)
|
||||
{
|
||||
ExternalVariable* exportedVariable = externalVariableFind(name);
|
||||
if (exportedVariable == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((exportedVariable->type & 0xF7FF) == VALUE_TYPE_STRING) {
|
||||
internal_free_safe(exportedVariable->stringValue, __FILE__, __LINE__); // "..\\int\\EXPORT.C", 169
|
||||
}
|
||||
|
||||
if ((opcode & 0xF7FF) == VALUE_TYPE_STRING) {
|
||||
if (program != NULL) {
|
||||
const char* stringValue = programGetString(program, opcode, data);
|
||||
exportedVariable->type = VALUE_TYPE_DYNAMIC_STRING;
|
||||
|
||||
exportedVariable->stringValue = internal_malloc_safe(strlen(stringValue) + 1, __FILE__, __LINE__); // "..\\int\\EXPORT.C", 175
|
||||
strcpy(exportedVariable->stringValue, stringValue);
|
||||
}
|
||||
} else {
|
||||
exportedVariable->value = data;
|
||||
exportedVariable->type = opcode;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4413D4
|
||||
int externalVariableGetValue(Program* program, const char* name, opcode_t* opcodePtr, int* dataPtr)
|
||||
{
|
||||
ExternalVariable* exportedVariable = externalVariableFind(name);
|
||||
if (exportedVariable == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
*opcodePtr = exportedVariable->type;
|
||||
|
||||
if ((exportedVariable->type & 0xF7FF) == VALUE_TYPE_STRING) {
|
||||
*dataPtr = programPushString(program, exportedVariable->stringValue);
|
||||
} else {
|
||||
*dataPtr = exportedVariable->value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4414B8
|
||||
int externalVariableCreate(Program* program, const char* identifier)
|
||||
{
|
||||
const char* programName = program->name;
|
||||
ExternalVariable* exportedVariable = externalVariableFind(identifier);
|
||||
|
||||
if (exportedVariable != NULL) {
|
||||
if (stricmp(exportedVariable->programName, programName) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((exportedVariable->type & 0xF7FF) == VALUE_TYPE_STRING) {
|
||||
internal_free_safe(exportedVariable->stringValue, __FILE__, __LINE__); // "..\\int\\EXPORT.C", 234
|
||||
}
|
||||
} else {
|
||||
exportedVariable = externalVariableAdd(identifier);
|
||||
if (exportedVariable == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
strncpy(exportedVariable->name, identifier, 31);
|
||||
|
||||
exportedVariable->programName = internal_malloc_safe(strlen(programName) + 1, __FILE__, __LINE__); // // "..\\int\\EXPORT.C", 243
|
||||
strcpy(exportedVariable->programName, programName);
|
||||
}
|
||||
|
||||
exportedVariable->type = VALUE_TYPE_INT;
|
||||
exportedVariable->value = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4414FC
|
||||
void _removeProgramReferences(Program* program)
|
||||
{
|
||||
for (int index = 0; index < 1013; index++) {
|
||||
ExternalProcedure* externalProcedure = &(gExternalProcedures[index]);
|
||||
if (externalProcedure->program == program) {
|
||||
externalProcedure->name[0] = '\0';
|
||||
externalProcedure->program = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x44152C
|
||||
void _initExport()
|
||||
{
|
||||
_interpretRegisterProgramDeleteCallback(_removeProgramReferences);
|
||||
}
|
||||
|
||||
// 0x441538
|
||||
void externalVariablesClear()
|
||||
{
|
||||
for (int index = 0; index < 1013; index++) {
|
||||
ExternalVariable* exportedVariable = &(gExternalVariables[index]);
|
||||
|
||||
if (exportedVariable->name[0] != '\0') {
|
||||
internal_free_safe(exportedVariable->programName, __FILE__, __LINE__); // ..\\int\\EXPORT.C, 274
|
||||
}
|
||||
|
||||
if (exportedVariable->type == VALUE_TYPE_DYNAMIC_STRING) {
|
||||
internal_free_safe(exportedVariable->stringValue, __FILE__, __LINE__); // ..\\int\\EXPORT.C, 276
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x44158C
|
||||
Program* externalProcedureGetProgram(const char* identifier, int* addressPtr, int* argumentCountPtr)
|
||||
{
|
||||
ExternalProcedure* externalProcedure = externalProcedureFind(identifier);
|
||||
if (externalProcedure == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (externalProcedure->program == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*addressPtr = externalProcedure->address;
|
||||
*argumentCountPtr = externalProcedure->argumentCount;
|
||||
|
||||
return externalProcedure->program;
|
||||
}
|
||||
|
||||
// 0x4415B0
|
||||
int externalProcedureCreate(Program* program, const char* identifier, int address, int argumentCount)
|
||||
{
|
||||
ExternalProcedure* externalProcedure = externalProcedureFind(identifier);
|
||||
if (externalProcedure != NULL) {
|
||||
if (program != externalProcedure->program) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
externalProcedure = externalProcedureAdd(identifier);
|
||||
if (externalProcedure == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
strncpy(externalProcedure->name, identifier, 31);
|
||||
}
|
||||
|
||||
externalProcedure->argumentCount = argumentCount;
|
||||
externalProcedure->address = address;
|
||||
externalProcedure->program = program;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x441824
|
||||
void _exportClearAllVariables()
|
||||
{
|
||||
for (int index = 0; index < 1013; index++) {
|
||||
ExternalVariable* exportedVariable = &(gExternalVariables[index]);
|
||||
if (exportedVariable->name[0] != '\0') {
|
||||
if ((exportedVariable->type & 0xF7FF) == VALUE_TYPE_STRING) {
|
||||
if (exportedVariable->stringValue != NULL) {
|
||||
internal_free_safe(exportedVariable->stringValue, __FILE__, __LINE__); // "..\\int\\EXPORT.C", 387
|
||||
}
|
||||
}
|
||||
|
||||
if (exportedVariable->programName != NULL) {
|
||||
internal_free_safe(exportedVariable->programName, __FILE__, __LINE__); // "..\\int\\EXPORT.C", 393
|
||||
exportedVariable->programName = NULL;
|
||||
}
|
||||
|
||||
exportedVariable->name[0] = '\0';
|
||||
exportedVariable->type = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef EXPORT_H
|
||||
#define EXPORT_H
|
||||
|
||||
#include "interpreter.h"
|
||||
|
||||
typedef struct ExternalVariable {
|
||||
char name[32];
|
||||
char* programName;
|
||||
opcode_t type;
|
||||
union {
|
||||
int value;
|
||||
char* stringValue;
|
||||
};
|
||||
} ExternalVariable;
|
||||
|
||||
typedef struct ExternalProcedure {
|
||||
char name[32];
|
||||
Program* program;
|
||||
int argumentCount;
|
||||
int address;
|
||||
} ExternalProcedure;
|
||||
|
||||
extern ExternalProcedure gExternalProcedures[1013];
|
||||
extern ExternalVariable gExternalVariables[1013];
|
||||
|
||||
ExternalProcedure* externalProcedureFind(const char* identifier);
|
||||
ExternalProcedure* externalProcedureAdd(const char* identifier);
|
||||
ExternalVariable* externalVariableFind(const char* identifier);
|
||||
ExternalVariable* externalVariableAdd(const char* identifier);
|
||||
int externalVariableSetValue(Program* program, const char* identifier, opcode_t opcode, int data);
|
||||
int externalVariableGetValue(Program* program, const char* name, opcode_t* opcodePtr, int* dataPtr);
|
||||
int externalVariableCreate(Program* program, const char* identifier);
|
||||
void _removeProgramReferences(Program* program);
|
||||
void _initExport();
|
||||
void externalVariablesClear();
|
||||
Program* externalProcedureGetProgram(const char* identifier, int* addressPtr, int* argumentCountPtr);
|
||||
int externalProcedureCreate(Program* program, const char* identifier, int address, int argumentCount);
|
||||
void _exportClearAllVariables();
|
||||
|
||||
#endif /* EXPORT_H */
|
|
@ -0,0 +1,63 @@
|
|||
#include "file_find.h"
|
||||
|
||||
// 0x4E6380
|
||||
bool fileFindFirst(const char* path, DirectoryFileFindData* findData)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
findData->hFind = FindFirstFileA(path, &(findData->ffd));
|
||||
if (findData->hFind == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
#elif defined(__WATCOMC__)
|
||||
findData->dir = opendir(path);
|
||||
if (findData->dir == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
findData->entry = readdir(findData->dir);
|
||||
if (findData->entry == NULL) {
|
||||
closedir(findData->dir);
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
#error Not implemented
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4E63A8
|
||||
bool fileFindNext(DirectoryFileFindData* findData)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
if (!FindNextFileA(findData->hFind, &(findData->ffd))) {
|
||||
return false;
|
||||
}
|
||||
#elif defined(__WATCOMC__)
|
||||
findData->entry = readdir(findData->dir);
|
||||
if (findData->entry == NULL) {
|
||||
closedir(findData->dir);
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
#error Not implemented
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4E63CC
|
||||
bool findFindClose(DirectoryFileFindData* findData)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
FindClose(findData->hFind);
|
||||
#elif defined(__WATCOMC__)
|
||||
if (closedir(findData->dir) != 0) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
#error Not implemented
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef FILE_FIND_H
|
||||
#define FILE_FIND_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
// NOTE: This structure is significantly different from what was in the
|
||||
// original code. Watcom provides opendir/readdir/closedir implementations,
|
||||
// that use Win32 FindFirstFile/FindNextFile under the hood, which in turn
|
||||
// is designed to deal with patterns.
|
||||
//
|
||||
// The first attempt was to use `dirent` implementation by Toni Ronkko
|
||||
// (https://github.com/tronkko/dirent), however it appears to be incompatible
|
||||
// with what is provided by Watcom. Toni's implementation adds `*` wildcard
|
||||
// unconditionally implying `opendir` accepts directory name only, which I
|
||||
// guess is fine when your goal is compliance with POSIX implementation.
|
||||
// However in Watcom `opendir` can handle file patterns gracefully. The problem
|
||||
// can be seen during game startup when cleaning MAPS directory using
|
||||
// MAPS\*.SAV pattern. Toni's implementation tries to convert that to pattern
|
||||
// for Win32 API, thus making it MAPS\*.SAV\*, which is obviously incorrect
|
||||
// path/pattern for any implementation.
|
||||
//
|
||||
// Eventually I've decided to go with compiler-specific implementation, keeping
|
||||
// original implementation for Watcom (not tested). I'm not sure it will work
|
||||
// in other compilers, so for now just stick with the error.
|
||||
typedef struct DirectoryFileFindData {
|
||||
#if defined(_MSC_VER)
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATAA ffd;
|
||||
#elif defined(__WATCOMC__)
|
||||
DIR* dir;
|
||||
struct dirent* entry;
|
||||
#else
|
||||
#error Not implemented
|
||||
#endif
|
||||
} DirectoryFileFindData;
|
||||
|
||||
bool fileFindFirst(const char* path, DirectoryFileFindData* findData);
|
||||
bool fileFindNext(DirectoryFileFindData* findData);
|
||||
bool findFindClose(DirectoryFileFindData* findData);
|
||||
|
||||
#endif /* FILE_FIND_H */
|
|
@ -0,0 +1,144 @@
|
|||
// NOTE: For unknown reason functions in this module use __stdcall instead
|
||||
// of regular __usercall.
|
||||
|
||||
#include "file_utils.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
// 0x452740
|
||||
int fileCopyDecompressed(const char* existingFilePath, const char* newFilePath)
|
||||
{
|
||||
FILE* stream = fopen(existingFilePath, "rb");
|
||||
if (stream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int magic[2];
|
||||
magic[0] = fgetc(stream);
|
||||
magic[1] = fgetc(stream);
|
||||
fclose(stream);
|
||||
|
||||
if (magic[0] == 0x1F && magic[1] == 0x8B) {
|
||||
gzFile inStream = gzopen(existingFilePath, "rb");
|
||||
FILE* outStream = fopen(newFilePath, "wb");
|
||||
|
||||
if (inStream != NULL && outStream != NULL) {
|
||||
for (;;) {
|
||||
int ch = gzgetc(inStream);
|
||||
if (ch == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
fputc(ch, outStream);
|
||||
}
|
||||
|
||||
gzclose(inStream);
|
||||
fclose(outStream);
|
||||
} else {
|
||||
if (inStream != NULL) {
|
||||
gzclose(inStream);
|
||||
}
|
||||
|
||||
if (outStream != NULL) {
|
||||
fclose(outStream);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
CopyFileA(existingFilePath, newFilePath, FALSE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x452804
|
||||
int fileCopyCompressed(const char* existingFilePath, const char* newFilePath)
|
||||
{
|
||||
FILE* inStream = fopen(existingFilePath, "rb");
|
||||
if (inStream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int magic[2];
|
||||
magic[0] = fgetc(inStream);
|
||||
magic[1] = fgetc(inStream);
|
||||
rewind(inStream);
|
||||
|
||||
if (magic[0] == 0x1F && magic[1] == 0x8B) {
|
||||
// Source file is already gzipped, there is no need to do anything
|
||||
// besides copying.
|
||||
fclose(inStream);
|
||||
CopyFileA(existingFilePath, newFilePath, FALSE);
|
||||
} else {
|
||||
gzFile outStream = gzopen(newFilePath, "wb");
|
||||
if (outStream == NULL) {
|
||||
fclose(inStream);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Copy byte-by-byte.
|
||||
for (;;) {
|
||||
int ch = fgetc(inStream);
|
||||
if (ch == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
gzputc(outStream, ch);
|
||||
}
|
||||
|
||||
fclose(inStream);
|
||||
gzclose(outStream);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: Check, implementation looks odd.
|
||||
int _gzdecompress_file(const char* existingFilePath, const char* newFilePath)
|
||||
{
|
||||
FILE* stream = fopen(existingFilePath, "rb");
|
||||
if (stream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int magic[2];
|
||||
magic[0] = fgetc(stream);
|
||||
magic[1] = fgetc(stream);
|
||||
fclose(stream);
|
||||
|
||||
// TODO: Is it broken?
|
||||
if (magic[0] != 0x1F || magic[1] != 0x8B) {
|
||||
gzFile gzstream = gzopen(existingFilePath, "rb");
|
||||
if (gzstream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
stream = fopen(newFilePath, "wb");
|
||||
if (stream == NULL) {
|
||||
gzclose(gzstream);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int ch = gzgetc(gzstream);
|
||||
if (ch == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
fputc(ch, stream);
|
||||
}
|
||||
|
||||
gzclose(gzstream);
|
||||
fclose(stream);
|
||||
} else {
|
||||
CopyFileA(existingFilePath, newFilePath, FALSE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef FILE_UTILS_H
|
||||
#define FILE_UTILS_H
|
||||
|
||||
int fileCopyDecompressed(const char* existingFilePath, const char* newFilePath);
|
||||
int fileCopyCompressed(const char* existingFilePath, const char* newFilePath);
|
||||
int _gzdecompress_file(const char* existingFilePath, const char* newFilePath);
|
||||
|
||||
#endif /* FILE_UTILS_H */
|
|
@ -0,0 +1,337 @@
|
|||
#include "font_manager.h"
|
||||
|
||||
#include "color.h"
|
||||
#include "db.h"
|
||||
#include "memory_manager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// 0x518680
|
||||
bool gInterfaceFontsInitialized = false;
|
||||
|
||||
// 0x518684
|
||||
int gInterfaceFontsLength = 0;
|
||||
|
||||
// 0x518688
|
||||
FontManager gModernFontManager = {
|
||||
100,
|
||||
110,
|
||||
interfaceFontSetCurrentImpl,
|
||||
interfaceFontDrawImpl,
|
||||
interfaceFontGetLineHeightImpl,
|
||||
interfaceFontGetStringWidthImpl,
|
||||
interfaceFontGetCharacterWidthImpl,
|
||||
interfaceFontGetMonospacedStringWidthImpl,
|
||||
interfaceFontGetLetterSpacingImpl,
|
||||
interfaceFontGetBufferSizeImpl,
|
||||
interfaceFontGetMonospacedCharacterWidthImpl,
|
||||
};
|
||||
|
||||
// 0x586838
|
||||
InterfaceFontDescriptor gInterfaceFontDescriptors[INTERFACE_FONT_MAX];
|
||||
|
||||
// 0x58E938
|
||||
int gCurrentInterfaceFont;
|
||||
|
||||
// 0x58E93C
|
||||
InterfaceFontDescriptor* gCurrentInterfaceFontDescriptor;
|
||||
|
||||
// 0x441C80
|
||||
int interfaceFontsInit()
|
||||
{
|
||||
int currentFont = -1;
|
||||
|
||||
for (int font = 0; font < INTERFACE_FONT_MAX; font++) {
|
||||
if (interfaceFontLoad(font) == -1) {
|
||||
gInterfaceFontDescriptors[font].field_0 = 0;
|
||||
gInterfaceFontDescriptors[font].data = NULL;
|
||||
} else {
|
||||
++gInterfaceFontsLength;
|
||||
|
||||
if (currentFont == -1) {
|
||||
currentFont = font;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentFont == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gInterfaceFontsInitialized = true;
|
||||
|
||||
interfaceFontSetCurrentImpl(currentFont + 100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x441CEC
|
||||
void interfaceFontsExit()
|
||||
{
|
||||
for (int font = 0; font < INTERFACE_FONT_MAX; font++) {
|
||||
if (gInterfaceFontDescriptors[font].data != NULL) {
|
||||
internal_free_safe(gInterfaceFontDescriptors[font].data, __FILE__, __LINE__); // FONTMGR.C, 124
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x441D20
|
||||
int interfaceFontLoad(int font_index)
|
||||
{
|
||||
InterfaceFontDescriptor* fontDescriptor = &(gInterfaceFontDescriptors[font_index]);
|
||||
|
||||
char path[56];
|
||||
sprintf(path, "font%d.aaf", font_index);
|
||||
|
||||
File* stream = fileOpen(path, "rb");
|
||||
if (stream == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int fileSize = fileGetSize(stream);
|
||||
|
||||
int sig;
|
||||
if (fileRead(&sig, 4, 1, stream) != 1) goto err;
|
||||
|
||||
sig = _byteswap_ulong(sig);
|
||||
if (sig != 0x41414646) goto err;
|
||||
|
||||
if (fileRead(&(fontDescriptor->field_0), 2, 1, stream) != 1) goto err;
|
||||
fontDescriptor->field_0 = _byteswap_ushort(fontDescriptor->field_0);
|
||||
|
||||
if (fileRead(&(fontDescriptor->letterSpacing), 2, 1, stream) != 1) goto err;
|
||||
fontDescriptor->letterSpacing = _byteswap_ushort(fontDescriptor->letterSpacing);
|
||||
|
||||
if (fileRead(&(fontDescriptor->wordSpacing), 2, 1, stream) != 1) goto err;
|
||||
fontDescriptor->wordSpacing = _byteswap_ushort(fontDescriptor->wordSpacing);
|
||||
|
||||
if (fileRead(&(fontDescriptor->field_6), 2, 1, stream) != 1) goto err;
|
||||
fontDescriptor->field_6 = _byteswap_ushort(fontDescriptor->field_6);
|
||||
|
||||
for (int index = 0; index < 256; index++) {
|
||||
InterfaceFontGlyph* glyph = &(fontDescriptor->glyphs[index]);
|
||||
|
||||
if (fileRead(&(glyph->width), 2, 1, stream) != 1) goto err;
|
||||
glyph->width = _byteswap_ushort(glyph->width);
|
||||
|
||||
if (fileRead(&(glyph->field_2), 2, 1, stream) != 1) goto err;
|
||||
glyph->field_2 = _byteswap_ushort(glyph->field_2);
|
||||
|
||||
if (fileRead(&(glyph->field_4), 4, 1, stream) != 1) goto err;
|
||||
glyph->field_4 = _byteswap_ulong(glyph->field_4);
|
||||
}
|
||||
|
||||
fileSize -= sizeof(InterfaceFontDescriptor);
|
||||
|
||||
fontDescriptor->data = internal_malloc_safe(fileSize, __FILE__, __LINE__); // FONTMGR.C, 259
|
||||
if (fontDescriptor->data == NULL) goto err;
|
||||
|
||||
if (fileRead(fontDescriptor->data, fileSize, 1, stream) != 1) {
|
||||
internal_free_safe(fontDescriptor->data, __FILE__, __LINE__); // FONTMGR.C, 268
|
||||
goto err;
|
||||
}
|
||||
|
||||
fileClose(stream);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
fileClose(stream);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x442120
|
||||
void interfaceFontSetCurrentImpl(int font)
|
||||
{
|
||||
if (!gInterfaceFontsInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
font -= 100;
|
||||
|
||||
if (gInterfaceFontDescriptors[font].data != NULL) {
|
||||
gCurrentInterfaceFont = font;
|
||||
gCurrentInterfaceFontDescriptor = &(gInterfaceFontDescriptors[font]);
|
||||
}
|
||||
}
|
||||
|
||||
// 0x442168
|
||||
int interfaceFontGetLineHeightImpl()
|
||||
{
|
||||
if (!gInterfaceFontsInitialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return gCurrentInterfaceFontDescriptor->field_6 + gCurrentInterfaceFontDescriptor->field_0;
|
||||
}
|
||||
|
||||
// 0x442188
|
||||
int interfaceFontGetStringWidthImpl(const char* string)
|
||||
{
|
||||
if (!gInterfaceFontsInitialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* pch = string;
|
||||
int width = 0;
|
||||
|
||||
while (*pch != '\0') {
|
||||
int v3;
|
||||
int v4;
|
||||
|
||||
if (*pch == ' ') {
|
||||
v3 = gCurrentInterfaceFontDescriptor->letterSpacing;
|
||||
v4 = gCurrentInterfaceFontDescriptor->wordSpacing;
|
||||
} else {
|
||||
v3 = gCurrentInterfaceFontDescriptor->glyphs[*pch & 0xFF].width;
|
||||
v4 = gCurrentInterfaceFontDescriptor->letterSpacing;
|
||||
}
|
||||
width += v3 + v4;
|
||||
|
||||
pch++;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
// 0x4421DC
|
||||
int interfaceFontGetCharacterWidthImpl(int ch)
|
||||
{
|
||||
int width;
|
||||
|
||||
if (!gInterfaceFontsInitialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ch == ' ') {
|
||||
width = gCurrentInterfaceFontDescriptor->wordSpacing;
|
||||
} else {
|
||||
width = gCurrentInterfaceFontDescriptor->glyphs[ch].width;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
// 0x442210
|
||||
int interfaceFontGetMonospacedStringWidthImpl(const char* str)
|
||||
{
|
||||
if (!gInterfaceFontsInitialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return interfaceFontGetMonospacedCharacterWidthImpl() * strlen(str);
|
||||
}
|
||||
|
||||
// 0x442240
|
||||
int interfaceFontGetLetterSpacingImpl()
|
||||
{
|
||||
if (!gInterfaceFontsInitialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return gCurrentInterfaceFontDescriptor->letterSpacing;
|
||||
}
|
||||
|
||||
// 0x442258
|
||||
int interfaceFontGetBufferSizeImpl(const char* str)
|
||||
{
|
||||
if (!gInterfaceFontsInitialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return interfaceFontGetStringWidthImpl(str) * interfaceFontGetLineHeightImpl();
|
||||
}
|
||||
|
||||
// 0x442278
|
||||
int interfaceFontGetMonospacedCharacterWidthImpl()
|
||||
{
|
||||
if (!gInterfaceFontsInitialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int v1;
|
||||
if (gCurrentInterfaceFontDescriptor->wordSpacing <= gCurrentInterfaceFontDescriptor->field_8) {
|
||||
v1 = gCurrentInterfaceFontDescriptor->field_6;
|
||||
} else {
|
||||
v1 = gCurrentInterfaceFontDescriptor->letterSpacing;
|
||||
}
|
||||
|
||||
return v1 + gCurrentInterfaceFontDescriptor->field_0;
|
||||
}
|
||||
|
||||
// 0x4422B4
|
||||
void interfaceFontDrawImpl(unsigned char* buf, const char* string, int length, int pitch, int color)
|
||||
{
|
||||
if (!gInterfaceFontsInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((color & FONT_SHADOW) != 0) {
|
||||
color &= ~FONT_SHADOW;
|
||||
// NOTE: Other font options preserved. This is different from text font
|
||||
// shadows.
|
||||
interfaceFontDrawImpl(buf + pitch + 1, string, length, pitch, (color & ~0xFF) | _colorTable[0]);
|
||||
}
|
||||
|
||||
unsigned char* palette = _getColorBlendTable(color & 0xFF);
|
||||
|
||||
int monospacedCharacterWidth;
|
||||
if ((color & FONT_MONO) != 0) {
|
||||
// NOTE: Uninline.
|
||||
monospacedCharacterWidth = interfaceFontGetMonospacedCharacterWidthImpl();
|
||||
}
|
||||
|
||||
unsigned char* ptr = buf;
|
||||
while (*string != '\0') {
|
||||
char ch = *string++;
|
||||
|
||||
int characterWidth;
|
||||
if (ch == ' ') {
|
||||
characterWidth = gCurrentInterfaceFontDescriptor->wordSpacing;
|
||||
} else {
|
||||
characterWidth = gCurrentInterfaceFontDescriptor->glyphs[ch & 0xFF].width;
|
||||
}
|
||||
|
||||
unsigned char* end;
|
||||
if ((color & FONT_MONO) != 0) {
|
||||
end = ptr + monospacedCharacterWidth;
|
||||
ptr += (monospacedCharacterWidth - characterWidth - gCurrentInterfaceFontDescriptor->letterSpacing) / 2;
|
||||
} else {
|
||||
end = ptr + characterWidth + gCurrentInterfaceFontDescriptor->letterSpacing;
|
||||
}
|
||||
|
||||
if (end - buf > length) {
|
||||
break;
|
||||
}
|
||||
|
||||
InterfaceFontGlyph* glyph = &(gCurrentInterfaceFontDescriptor->glyphs[ch & 0xFF]);
|
||||
unsigned char* glyphDataPtr = gCurrentInterfaceFontDescriptor->data + glyph->field_4;
|
||||
|
||||
// Skip blank pixels (difference between font's line height and glyph height).
|
||||
ptr += (gCurrentInterfaceFontDescriptor->field_0 - glyph->field_2) * pitch;
|
||||
|
||||
for (int y = 0; y < glyph->field_2; y++) {
|
||||
for (int x = 0; x < glyph->width; x++) {
|
||||
unsigned char byte = *glyphDataPtr++;
|
||||
|
||||
*ptr++ = palette[(byte << 8) + *ptr];
|
||||
}
|
||||
|
||||
ptr += pitch - glyph->width;
|
||||
}
|
||||
|
||||
ptr = end;
|
||||
}
|
||||
|
||||
if ((color & FONT_UNDERLINE) != 0) {
|
||||
int length = ptr - buf;
|
||||
unsigned char* underlinePtr = buf + pitch * (gCurrentInterfaceFontDescriptor->field_0 - 1);
|
||||
for (int index = 0; index < length; index++) {
|
||||
*underlinePtr++ = color & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
_freeColorBlendTable(color & 0xFF);
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef FONT_MANAGER_H
|
||||
#define FONT_MANAGER_H
|
||||
|
||||
#include "text_font.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// The maximum number of interface fonts.
|
||||
#define INTERFACE_FONT_MAX (16)
|
||||
|
||||
typedef struct InterfaceFontGlyph {
|
||||
short width;
|
||||
short field_2;
|
||||
int field_4;
|
||||
} InterfaceFontGlyph;
|
||||
|
||||
typedef struct InterfaceFontDescriptor {
|
||||
short field_0;
|
||||
short letterSpacing;
|
||||
short wordSpacing;
|
||||
short field_6;
|
||||
short field_8;
|
||||
short field_A;
|
||||
InterfaceFontGlyph glyphs[256];
|
||||
unsigned char* data;
|
||||
} InterfaceFontDescriptor;
|
||||
|
||||
extern bool gInterfaceFontsInitialized;
|
||||
extern int gInterfaceFontsLength;
|
||||
extern FontManager gModernFontManager;
|
||||
|
||||
extern InterfaceFontDescriptor gInterfaceFontDescriptors[INTERFACE_FONT_MAX];
|
||||
extern int gCurrentInterfaceFont;
|
||||
extern InterfaceFontDescriptor* gCurrentInterfaceFontDescriptor;
|
||||
|
||||
int interfaceFontsInit();
|
||||
void interfaceFontsExit();
|
||||
int interfaceFontLoad(int font);
|
||||
void interfaceFontSetCurrentImpl(int font);
|
||||
int interfaceFontGetLineHeightImpl();
|
||||
int interfaceFontGetStringWidthImpl(const char* string);
|
||||
int interfaceFontGetCharacterWidthImpl(int ch);
|
||||
int interfaceFontGetMonospacedStringWidthImpl(const char* string);
|
||||
int interfaceFontGetLetterSpacingImpl();
|
||||
int interfaceFontGetBufferSizeImpl(const char* string);
|
||||
int interfaceFontGetMonospacedCharacterWidthImpl();
|
||||
void interfaceFontDrawImpl(unsigned char* buf, const char* string, int length, int pitch, int color);
|
||||
|
||||
#endif /* FONT_MANAGER_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,44 @@
|
|||
#ifndef GAME_H
|
||||
#define GAME_H
|
||||
|
||||
#include "game_vars.h"
|
||||
#include "message.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern char _aGame_0[];
|
||||
|
||||
extern bool gGameUiDisabled;
|
||||
extern int _game_state_cur;
|
||||
extern bool gIsMapper;
|
||||
extern int* gGameGlobalVars;
|
||||
extern int gGameGlobalVarsLength;
|
||||
extern const char* asc_5186C8;
|
||||
extern int _game_user_wants_to_quit;
|
||||
|
||||
extern MessageList gMiscMessageList;
|
||||
extern int _master_db_handle;
|
||||
extern int _critter_db_handle;
|
||||
|
||||
int gameInitWithOptions(const char* windowTitle, bool isMapper, int a3, int a4, int argc, char** argv);
|
||||
void gameReset();
|
||||
void gameExit();
|
||||
int gameHandleKey(int eventCode, bool isInCombatMode);
|
||||
void gameUiDisable(int a1);
|
||||
void gameUiEnable();
|
||||
bool gameUiIsDisabled();
|
||||
int gameGetGlobalVar(int var);
|
||||
int gameSetGlobalVar(int var, int value);
|
||||
int gameLoadGlobalVars();
|
||||
int globalVarsRead(const char* path, const char* section, int* out_vars_num, int** out_vars);
|
||||
int _game_state();
|
||||
int _game_state_request(int a1);
|
||||
void _game_state_update();
|
||||
int gameTakeScreenshot(int width, int height, unsigned char* buffer, unsigned char* palette);
|
||||
void gameFreeGlobalVars();
|
||||
void showHelp();
|
||||
int showQuitConfirmationDialog();
|
||||
int gameDbInit();
|
||||
void showSplash();
|
||||
|
||||
#endif /* GAME_H */
|
|
@ -0,0 +1,180 @@
|
|||
#include "game_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// A flag indicating if [gGameConfig] was initialized.
|
||||
//
|
||||
// 0x5186D0
|
||||
bool gGameConfigInitialized = false;
|
||||
|
||||
// fallout2.cfg
|
||||
//
|
||||
// 0x58E950
|
||||
Config gGameConfig;
|
||||
|
||||
// NOTE: There are additional 4 bytes following this array at 0x58EA7C, which
|
||||
// probably means it's size is 264 bytes.
|
||||
//
|
||||
// 0x58E978
|
||||
char gGameConfigFilePath[FILENAME_MAX];
|
||||
|
||||
// Inits main game config.
|
||||
//
|
||||
// [isMapper] is a flag indicating whether we're initing config for a main
|
||||
// game, or a mapper. This value is `false` for the game itself.
|
||||
//
|
||||
// [argc] and [argv] are command line arguments. The engine assumes there is
|
||||
// at least 1 element which is executable path at index 0. There is no
|
||||
// additional check for [argc], so it will crash if you pass NULL, or an empty
|
||||
// array into [argv].
|
||||
//
|
||||
// The executable path from [argv] is used resolve path to `fallout2.cfg`,
|
||||
// which should be in the same folder. This function provide defaults if
|
||||
// `fallout2.cfg` is not present, or cannot be read for any reason.
|
||||
//
|
||||
// Finally, this function merges key-value pairs from [argv] if any, see
|
||||
// [configParseCommandLineArguments] for expected format.
|
||||
//
|
||||
// 0x444570
|
||||
bool gameConfigInit(bool isMapper, int argc, char** argv)
|
||||
{
|
||||
if (gGameConfigInitialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!configInit(&gGameConfig)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize defaults.
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_EXECUTABLE_KEY, "game");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_DAT_KEY, "master.dat");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_PATCHES_KEY, "data");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_DAT_KEY, "critter.dat");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CRITTER_PATCHES_KEY, "data");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_LANGUAGE_KEY, ENGLISH);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_SCROLL_LOCK_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_INTERRUPT_WALK_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_ART_CACHE_SIZE_KEY, 8);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_COLOR_CYCLING_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_HASHING_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_SPLASH_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_FREE_SPACE_KEY, 20480);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_GAME_DIFFICULTY_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_DIFFICULTY_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_VIOLENCE_LEVEL_KEY, 3);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_TARGET_HIGHLIGHT_KEY, 2);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_ITEM_HIGHLIGHT_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_LOOKS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_MESSAGES_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_TAUNTS_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_LANGUAGE_FILTER_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_RUNNING_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_SUBTITLES_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_SPEED_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_PLAYER_SPEED_KEY, 0);
|
||||
configSetDouble(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_TEXT_BASE_DELAY_KEY, 3.5);
|
||||
configSetDouble(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_TEXT_LINE_DELAY_KEY, 1.399994);
|
||||
configSetDouble(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_BRIGHTNESS_KEY, 1.0);
|
||||
configSetDouble(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_MOUSE_SENSITIVITY_KEY, 1.0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_INITIALIZE_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_DEVICE_KEY, -1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_PORT_KEY, -1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_IRQ_KEY, -1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_DMA_KEY, -1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SOUNDS_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SPEECH_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MASTER_VOLUME_KEY, 22281);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_VOLUME_KEY, 22281);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SNDFX_VOLUME_KEY, 22281);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_SPEECH_VOLUME_KEY, 22281);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_CACHE_SIZE_KEY, 448);
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH1_KEY, "sound\\music\\");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SOUND_KEY, GAME_CONFIG_MUSIC_PATH2_KEY, "sound\\music\\");
|
||||
configSetString(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_MODE_KEY, "environment");
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_SHOW_TILE_NUM_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_SHOW_SCRIPT_MESSAGES_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_SHOW_LOAD_INFO_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_OUTPUT_MAP_DATA_INFO_KEY, 0);
|
||||
|
||||
if (isMapper) {
|
||||
configSetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_EXECUTABLE_KEY, "mapper");
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_OVERRIDE_LIBRARIAN_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_LIBRARIAN_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_USE_ART_NOT_PROTOS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_REBUILD_PROTOS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_FIX_MAP_OBJECTS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_FIX_MAP_INVENTORY_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_IGNORE_REBUILD_ERRORS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SHOW_PID_NUMBERS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SAVE_TEXT_MAPS_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_RUN_MAPPER_AS_GAME_KEY, 0);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_DEFAULT_F8_AS_GAME_KEY, 1);
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SORT_SCRIPT_LIST_KEY, 0);
|
||||
}
|
||||
|
||||
// Make `fallout2.cfg` file path.
|
||||
char* executable = argv[0];
|
||||
char* ch = strrchr(executable, '\\');
|
||||
if (ch != NULL) {
|
||||
*ch = '\0';
|
||||
sprintf(gGameConfigFilePath, "%s\\%s", executable, GAME_CONFIG_FILE_NAME);
|
||||
*ch = '\\';
|
||||
} else {
|
||||
strcpy(gGameConfigFilePath, GAME_CONFIG_FILE_NAME);
|
||||
}
|
||||
|
||||
// Read contents of `fallout2.cfg` into config. The values from the file
|
||||
// will override the defaults above.
|
||||
configRead(&gGameConfig, gGameConfigFilePath, false);
|
||||
|
||||
// Add key-values from command line, which overrides both defaults and
|
||||
// whatever was loaded from `fallout2.cfg`.
|
||||
configParseCommandLineArguments(&gGameConfig, argc, argv);
|
||||
|
||||
gGameConfigInitialized = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Saves game config into `fallout2.cfg`.
|
||||
//
|
||||
// 0x444C14
|
||||
bool gameConfigSave()
|
||||
{
|
||||
if (!gGameConfigInitialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!configWrite(&gGameConfig, gGameConfigFilePath, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Frees game config, optionally saving it.
|
||||
//
|
||||
// 0x444C3C
|
||||
bool gameConfigExit(bool shouldSave)
|
||||
{
|
||||
if (!gGameConfigInitialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
if (shouldSave) {
|
||||
if (!configWrite(&gGameConfig, gGameConfigFilePath, false)) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
configFree(&gGameConfig);
|
||||
|
||||
gGameConfigInitialized = false;
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
#ifndef GAME_CONFIG_H
|
||||
#define GAME_CONFIG_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// The file name of the main config file.
|
||||
#define GAME_CONFIG_FILE_NAME "fallout2.cfg"
|
||||
|
||||
#define GAME_CONFIG_SYSTEM_KEY "system"
|
||||
#define GAME_CONFIG_PREFERENCES_KEY "preferences"
|
||||
#define GAME_CONFIG_SOUND_KEY "sound"
|
||||
#define GAME_CONFIG_MAPPER_KEY "mapper"
|
||||
#define GAME_CONFIG_DEBUG_KEY "debug"
|
||||
|
||||
#define GAME_CONFIG_EXECUTABLE_KEY "executable"
|
||||
#define GAME_CONFIG_MASTER_DAT_KEY "master_dat"
|
||||
#define GAME_CONFIG_MASTER_PATCHES_KEY "master_patches"
|
||||
#define GAME_CONFIG_CRITTER_DAT_KEY "critter_dat"
|
||||
#define GAME_CONFIG_CRITTER_PATCHES_KEY "critter_patches"
|
||||
#define GAME_CONFIG_LANGUAGE_KEY "language"
|
||||
#define GAME_CONFIG_SCROLL_LOCK_KEY "scroll_lock"
|
||||
#define GAME_CONFIG_INTERRUPT_WALK_KEY "interrupt_walk"
|
||||
#define GAME_CONFIG_ART_CACHE_SIZE_KEY "art_cache_size"
|
||||
#define GAME_CONFIG_COLOR_CYCLING_KEY "color_cycling"
|
||||
#define GAME_CONFIG_CYCLE_SPEED_FACTOR_KEY "cycle_speed_factor"
|
||||
#define GAME_CONFIG_HASHING_KEY "hashing"
|
||||
#define GAME_CONFIG_SPLASH_KEY "splash"
|
||||
#define GAME_CONFIG_FREE_SPACE_KEY "free_space"
|
||||
#define GAME_CONFIG_TIMES_RUN_KEY "times_run"
|
||||
#define GAME_CONFIG_GAME_DIFFICULTY_KEY "game_difficulty"
|
||||
#define GAME_CONFIG_RUNNING_BURNING_GUY_KEY "running_burning_guy"
|
||||
#define GAME_CONFIG_COMBAT_DIFFICULTY_KEY "combat_difficulty"
|
||||
#define GAME_CONFIG_VIOLENCE_LEVEL_KEY "violence_level"
|
||||
#define GAME_CONFIG_TARGET_HIGHLIGHT_KEY "target_highlight"
|
||||
#define GAME_CONFIG_ITEM_HIGHLIGHT_KEY "item_highlight"
|
||||
#define GAME_CONFIG_COMBAT_LOOKS_KEY "combat_looks"
|
||||
#define GAME_CONFIG_COMBAT_MESSAGES_KEY "combat_messages"
|
||||
#define GAME_CONFIG_COMBAT_TAUNTS_KEY "combat_taunts"
|
||||
#define GAME_CONFIG_LANGUAGE_FILTER_KEY "language_filter"
|
||||
#define GAME_CONFIG_RUNNING_KEY "running"
|
||||
#define GAME_CONFIG_SUBTITLES_KEY "subtitles"
|
||||
#define GAME_CONFIG_COMBAT_SPEED_KEY "combat_speed"
|
||||
#define GAME_CONFIG_PLAYER_SPEED_KEY "player_speed"
|
||||
#define GAME_CONFIG_TEXT_BASE_DELAY_KEY "text_base_delay"
|
||||
#define GAME_CONFIG_TEXT_LINE_DELAY_KEY "text_line_delay"
|
||||
#define GAME_CONFIG_BRIGHTNESS_KEY "brightness"
|
||||
#define GAME_CONFIG_MOUSE_SENSITIVITY_KEY "mouse_sensitivity"
|
||||
#define GAME_CONFIG_INITIALIZE_KEY "initialize"
|
||||
#define GAME_CONFIG_DEVICE_KEY "device"
|
||||
#define GAME_CONFIG_PORT_KEY "port"
|
||||
#define GAME_CONFIG_IRQ_KEY "irq"
|
||||
#define GAME_CONFIG_DMA_KEY "dma"
|
||||
#define GAME_CONFIG_SOUNDS_KEY "sounds"
|
||||
#define GAME_CONFIG_MUSIC_KEY "music"
|
||||
#define GAME_CONFIG_SPEECH_KEY "speech"
|
||||
#define GAME_CONFIG_MASTER_VOLUME_KEY "master_volume"
|
||||
#define GAME_CONFIG_MUSIC_VOLUME_KEY "music_volume"
|
||||
#define GAME_CONFIG_SNDFX_VOLUME_KEY "sndfx_volume"
|
||||
#define GAME_CONFIG_SPEECH_VOLUME_KEY "speech_volume"
|
||||
#define GAME_CONFIG_CACHE_SIZE_KEY "cache_size"
|
||||
#define GAME_CONFIG_MUSIC_PATH1_KEY "music_path1"
|
||||
#define GAME_CONFIG_MUSIC_PATH2_KEY "music_path2"
|
||||
#define GAME_CONFIG_DEBUG_SFXC_KEY "debug_sfxc"
|
||||
#define GAME_CONFIG_MODE_KEY "mode"
|
||||
#define GAME_CONFIG_SHOW_TILE_NUM_KEY "show_tile_num"
|
||||
#define GAME_CONFIG_SHOW_SCRIPT_MESSAGES_KEY "show_script_messages"
|
||||
#define GAME_CONFIG_SHOW_LOAD_INFO_KEY "show_load_info"
|
||||
#define GAME_CONFIG_OUTPUT_MAP_DATA_INFO_KEY "output_map_data_info"
|
||||
#define GAME_CONFIG_EXECUTABLE_KEY "executable"
|
||||
#define GAME_CONFIG_OVERRIDE_LIBRARIAN_KEY "override_librarian"
|
||||
#define GAME_CONFIG_LIBRARIAN_KEY "librarian"
|
||||
#define GAME_CONFIG_USE_ART_NOT_PROTOS_KEY "use_art_not_protos"
|
||||
#define GAME_CONFIG_REBUILD_PROTOS_KEY "rebuild_protos"
|
||||
#define GAME_CONFIG_FIX_MAP_OBJECTS_KEY "fix_map_objects"
|
||||
#define GAME_CONFIG_FIX_MAP_INVENTORY_KEY "fix_map_inventory"
|
||||
#define GAME_CONFIG_IGNORE_REBUILD_ERRORS_KEY "ignore_rebuild_errors"
|
||||
#define GAME_CONFIG_SHOW_PID_NUMBERS_KEY "show_pid_numbers"
|
||||
#define GAME_CONFIG_SAVE_TEXT_MAPS_KEY "save_text_maps"
|
||||
#define GAME_CONFIG_RUN_MAPPER_AS_GAME_KEY "run_mapper_as_game"
|
||||
#define GAME_CONFIG_DEFAULT_F8_AS_GAME_KEY "default_f8_as_game"
|
||||
#define GAME_CONFIG_SORT_SCRIPT_LIST_KEY "sort_script_list"
|
||||
#define GAME_CONFIG_PLAYER_SPEEDUP_KEY "player_speedup"
|
||||
|
||||
#define ENGLISH "english"
|
||||
#define FRENCH "french"
|
||||
#define GERMAN "german"
|
||||
#define ITALIAN "italian"
|
||||
#define SPANISH "spanish"
|
||||
|
||||
typedef enum GameDifficulty {
|
||||
GAME_DIFFICULTY_EASY,
|
||||
GAME_DIFFICULTY_NORMAL,
|
||||
GAME_DIFFICULTY_HARD,
|
||||
} GameDifficulty;
|
||||
|
||||
typedef enum CombatDifficulty {
|
||||
COMBAT_DIFFICULTY_EASY,
|
||||
COMBAT_DIFFICULTY_NORMAL,
|
||||
COMBAT_DIFFICULTY_HARD,
|
||||
} CombatDifficulty;
|
||||
|
||||
typedef enum ViolenceLevel {
|
||||
VIOLENCE_LEVEL_NONE,
|
||||
VIOLENCE_LEVEL_MINIMAL,
|
||||
VIOLENCE_LEVEL_NORMAL,
|
||||
VIOLENCE_LEVEL_MAXIMUM_BLOOD,
|
||||
} ViolenceLevel;
|
||||
|
||||
typedef enum TargetHighlight {
|
||||
TARGET_HIGHLIGHT_OFF,
|
||||
TARGET_HIGHLIGHT_ON,
|
||||
TARGET_HIGHLIGHT_TARGETING_ONLY,
|
||||
} TargetHighlight;
|
||||
|
||||
extern bool gGameConfigInitialized;
|
||||
extern Config gGameConfig;
|
||||
extern char gGameConfigFilePath[];
|
||||
|
||||
bool gameConfigInit(bool isMapper, int argc, char** argv);
|
||||
bool gameConfigSave();
|
||||
bool gameConfigExit(bool shouldSave);
|
||||
|
||||
#endif /* GAME_CONFIG_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,287 @@
|
|||
#ifndef GAME_DIALOG_H
|
||||
#define GAME_DIALOG_H
|
||||
|
||||
#include "art.h"
|
||||
#include "geometry.h"
|
||||
#include "interpreter.h"
|
||||
#include "lips.h"
|
||||
#include "message.h"
|
||||
#include "obj_types.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define DIALOG_REVIEW_ENTRIES_CAPACITY 80
|
||||
|
||||
#define DIALOG_OPTION_ENTRIES_CAPACITY 30
|
||||
|
||||
typedef enum GameDialogReviewWindowButton {
|
||||
GAME_DIALOG_REVIEW_WINDOW_BUTTON_SCROLL_UP,
|
||||
GAME_DIALOG_REVIEW_WINDOW_BUTTON_SCROLL_DOWN,
|
||||
GAME_DIALOG_REVIEW_WINDOW_BUTTON_DONE,
|
||||
GAME_DIALOG_REVIEW_WINDOW_BUTTON_COUNT,
|
||||
} GameDialogReviewWindowButton;
|
||||
|
||||
typedef enum GameDialogReviewWindowButtonFrm {
|
||||
GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_ARROW_UP_NORMAL,
|
||||
GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_ARROW_UP_PRESSED,
|
||||
GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_ARROW_DOWN_NORMAL,
|
||||
GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_ARROW_DOWN_PRESSED,
|
||||
GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_DONE_NORMAL,
|
||||
GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_DONE_PRESSED,
|
||||
GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_COUNT,
|
||||
} GameDialogReviewWindowButtonFrm;
|
||||
|
||||
typedef enum GameDialogReaction {
|
||||
GAME_DIALOG_REACTION_GOOD = 49,
|
||||
GAME_DIALOG_REACTION_NEUTRAL = 50,
|
||||
GAME_DIALOG_REACTION_BAD = 51,
|
||||
} GameDialogReaction;
|
||||
|
||||
typedef struct GameDialogReviewEntry {
|
||||
int replyMessageListId;
|
||||
int replyMessageId;
|
||||
// Can be NULL.
|
||||
char* replyText;
|
||||
int optionMessageListId;
|
||||
int optionMessageId;
|
||||
char* optionText;
|
||||
} GameDialogReviewEntry;
|
||||
|
||||
typedef struct GameDialogOptionEntry {
|
||||
int messageListId;
|
||||
int messageId;
|
||||
int reaction;
|
||||
int proc;
|
||||
int btn;
|
||||
int field_14;
|
||||
char text[900];
|
||||
int field_39C;
|
||||
} GameDialogOptionEntry;
|
||||
|
||||
// Provides button configuration for party member combat control and
|
||||
// customization interface.
|
||||
typedef struct GameDialogButtonData {
|
||||
int x;
|
||||
int y;
|
||||
int upFrmId;
|
||||
int downFrmId;
|
||||
int disabledFrmId;
|
||||
CacheEntry* upFrmHandle;
|
||||
CacheEntry* downFrmHandle;
|
||||
CacheEntry* disabledFrmHandle;
|
||||
int keyCode;
|
||||
int value;
|
||||
} GameDialogButtonData;
|
||||
|
||||
typedef struct STRUCT_5189E4 {
|
||||
int messageId;
|
||||
int value;
|
||||
} STRUCT_5189E4;
|
||||
|
||||
typedef enum PartyMemberCustomizationOption {
|
||||
PARTY_MEMBER_CUSTOMIZATION_OPTION_AREA_ATTACK_MODE,
|
||||
PARTY_MEMBER_CUSTOMIZATION_OPTION_RUN_AWAY_MODE,
|
||||
PARTY_MEMBER_CUSTOMIZATION_OPTION_BEST_WEAPON,
|
||||
PARTY_MEMBER_CUSTOMIZATION_OPTION_DISTANCE,
|
||||
PARTY_MEMBER_CUSTOMIZATION_OPTION_ATTACK_WHO,
|
||||
PARTY_MEMBER_CUSTOMIZATION_OPTION_CHEM_USE,
|
||||
PARTY_MEMBER_CUSTOMIZATION_OPTION_COUNT,
|
||||
} PartyMemberCustomizationOption;
|
||||
|
||||
extern int _Dogs[3];
|
||||
|
||||
extern int _dialog_state_fix;
|
||||
extern int gGameDialogOptionEntriesLength;
|
||||
extern int gGameDialogReviewEntriesLength;
|
||||
extern unsigned char* gGameDialogDisplayBuffer;
|
||||
extern int gGameDialogReplyWindow;
|
||||
extern int gGameDialogOptionsWindow;
|
||||
extern bool _gdialog_window_created;
|
||||
extern int _boxesWereDisabled;
|
||||
extern int gGameDialogFidgetFid;
|
||||
extern CacheEntry* gGameDialogFidgetFrmHandle;
|
||||
extern Art* gGameDialogFidgetFrm;
|
||||
extern int gGameDialogBackground;
|
||||
extern int _lipsFID;
|
||||
extern int _lipsFID;
|
||||
extern Art* _lipsFp;
|
||||
extern bool gGameDialogLipSyncStarted;
|
||||
extern int _dialogue_state;
|
||||
extern int _dialogue_switch_mode;
|
||||
extern int _gdialog_state;
|
||||
extern bool _gdDialogWentOff;
|
||||
extern bool _gdDialogTurnMouseOff;
|
||||
extern int _gdReenterLevel;
|
||||
extern bool _gdReplyTooBig;
|
||||
extern Object* _peon_table_obj;
|
||||
extern Object* _barterer_table_obj;
|
||||
extern Object* _barterer_temp_obj;
|
||||
extern int gGameDialogBarterModifier;
|
||||
extern int gGameDialogBackgroundWindow;
|
||||
extern int gGameDialogWindow;
|
||||
extern Rect _backgrndRects[8];
|
||||
extern int _talk_need_to_center;
|
||||
extern bool _can_start_new_fidget;
|
||||
extern int _gd_replyWin;
|
||||
extern int _gd_optionsWin;
|
||||
extern int gGameDialogOldMusicVolume;
|
||||
extern int gGameDialogOldCenterTile;
|
||||
extern int gGameDialogOldDudeTile;
|
||||
extern unsigned char* _light_BlendTable;
|
||||
extern unsigned char* _dark_BlendTable;
|
||||
extern int _dialogue_just_started;
|
||||
extern int _dialogue_seconds_since_last_input;
|
||||
extern CacheEntry* gGameDialogReviewWindowButtonFrmHandles[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_COUNT];
|
||||
extern CacheEntry* _reviewBackKey;
|
||||
extern CacheEntry* gGameDialogReviewWindowBackgroundFrmHandle;
|
||||
extern unsigned char* gGameDialogReviewWindowBackgroundFrmData;
|
||||
extern const int gGameDialogReviewWindowButtonWidths[GAME_DIALOG_REVIEW_WINDOW_BUTTON_COUNT];
|
||||
extern const int gGameDialogReviewWindowButtonHeights[GAME_DIALOG_REVIEW_WINDOW_BUTTON_COUNT];
|
||||
extern int gGameDialogReviewWindowButtonFrmIds[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_COUNT];
|
||||
extern Object* gGameDialogSpeaker;
|
||||
extern bool gGameDialogSpeakerIsPartyMember;
|
||||
extern int gGameDialogHeadFid;
|
||||
extern int gGameDialogSid;
|
||||
extern int _head_phoneme_lookup[PHONEME_COUNT];
|
||||
extern int _phone_anim;
|
||||
extern int _loop_cnt;
|
||||
extern unsigned int _tocksWaiting;
|
||||
extern const char* _react_strs[3];
|
||||
extern int _dialogue_subwin_len;
|
||||
extern GameDialogButtonData gGameDialogDispositionButtonsData[5];
|
||||
extern STRUCT_5189E4 _custom_settings[PARTY_MEMBER_CUSTOMIZATION_OPTION_COUNT][6];
|
||||
extern GameDialogButtonData _custom_button_info[PARTY_MEMBER_CUSTOMIZATION_OPTION_COUNT];
|
||||
extern int _totalHotx;
|
||||
|
||||
extern int _custom_current_selected[PARTY_MEMBER_CUSTOMIZATION_OPTION_COUNT];
|
||||
extern MessageList gCustomMessageList;
|
||||
extern unsigned char _light_GrayTable[256];
|
||||
extern unsigned char _dark_GrayTable[256];
|
||||
extern unsigned char* _backgrndBufs[8];
|
||||
extern Rect _optionRect;
|
||||
extern Rect _replyRect;
|
||||
extern GameDialogReviewEntry gDialogReviewEntries[DIALOG_REVIEW_ENTRIES_CAPACITY];
|
||||
extern int _custom_buttons_start;
|
||||
extern int _control_buttons_start;
|
||||
extern int gGameDialogReviewWindowOldFont;
|
||||
extern CacheEntry* gGameDialogRedButtonUpFrmHandle;
|
||||
extern int _gdialog_buttons[9];
|
||||
extern CacheEntry* gGameDialogUpperHighlightFrmHandle;
|
||||
extern CacheEntry* gGameDialogReviewButtonUpFrmHandle;
|
||||
extern int gGameDialogLowerHighlightFrmHeight;
|
||||
extern CacheEntry* gGameDialogReviewButtonDownFrmHandle;
|
||||
extern unsigned char* gGameDialogRedButtonDownFrmData;
|
||||
extern int gGameDialogLowerHighlightFrmWidth;
|
||||
extern unsigned char* gGameDialogRedButtonUpFrmData;
|
||||
extern int gGameDialogUpperHighlightFrmWidth;
|
||||
extern Art* gGameDialogLowerHighlightFrm;
|
||||
extern int gGameDialogUpperHighlightFrmHeight;
|
||||
extern CacheEntry* gGameDialogRedButtonDownFrmHandle;
|
||||
extern CacheEntry* gGameDialogLowerHighlightFrmHandle;
|
||||
extern Art* gGameDialogUpperHighlightFrm;
|
||||
extern int _oldFont;
|
||||
extern unsigned int gGameDialogFidgetLastUpdateTimestamp;
|
||||
extern int gGameDialogFidgetReaction;
|
||||
extern Program* gDialogReplyProgram;
|
||||
extern int gDialogReplyMessageListId;
|
||||
extern int gDialogReplyMessageId;
|
||||
extern int dword_58F4E0;
|
||||
extern char gDialogReplyText[900];
|
||||
extern GameDialogOptionEntry gDialogOptionEntries[DIALOG_OPTION_ENTRIES_CAPACITY];
|
||||
extern int _talkOldFont;
|
||||
extern unsigned int gGameDialogFidgetUpdateDelay;
|
||||
extern int gGameDialogFidgetFrmCurrentFrame;
|
||||
|
||||
int gameDialogInit();
|
||||
int _gdialogReset();
|
||||
int gameDialogReset();
|
||||
int gameDialogExit();
|
||||
bool _gdialogActive();
|
||||
void gameDialogEnter(Object* a1, int a2);
|
||||
void _gdialogSystemEnter();
|
||||
void gameDialogStartLips(const char* a1);
|
||||
void gameDialogEndLips();
|
||||
int gameDialogEnable();
|
||||
int gameDialogDisable();
|
||||
int _gdialogInitFromScript(int headFid, int reaction);
|
||||
int _gdialogExitFromScript();
|
||||
void gameDialogSetBackground(int a1);
|
||||
void gameDialogRenderSupplementaryMessage(char* msg);
|
||||
int _gdialogStart();
|
||||
int _gdialogSayMessage();
|
||||
int gameDialogAddMessageOptionWithProcIdentifier(int messageListId, int messageId, const char* a3, int reaction);
|
||||
int gameDialogAddTextOptionWithProcIdentifier(int messageListId, const char* text, const char* a3, int reaction);
|
||||
int gameDialogAddMessageOptionWithProc(int messageListId, int messageId, int proc, int reaction);
|
||||
int gameDialogAddTextOptionWithProc(int messageListId, const char* text, int proc, int reaction);
|
||||
int gameDialogSetMessageReply(Program* a1, int a2, int a3);
|
||||
int gameDialogSetTextReply(Program* a1, int a2, const char* a3);
|
||||
int _gdialogGo();
|
||||
void _gdialogUpdatePartyStatus();
|
||||
int gameDialogAddMessageOption(int a1, int a2, int a3);
|
||||
int gameDialogAddTextOption(int a1, const char* a2, int a3);
|
||||
int gameDialogReviewWindowInit(int* win);
|
||||
int gameDialogReviewWindowFree(int* win);
|
||||
int gameDialogShowReview();
|
||||
void gameDialogReviewButtonOnMouseUp(int btn, int keyCode);
|
||||
void gameDialogReviewWindowUpdate(int win, int origin);
|
||||
void dialogReviewEntriesClear();
|
||||
int gameDialogAddReviewMessage(int messageListId, int messageId);
|
||||
int gameDialogAddReviewText(const char* text);
|
||||
int gameDialogSetReviewOptionMessage(int messageListId, int messageId);
|
||||
int gameDialogSetReviewOptionText(const char* text);
|
||||
int _gdProcessInit();
|
||||
void _gdProcessCleanup();
|
||||
int _gdProcessExit();
|
||||
void gameDialogRenderCaps();
|
||||
int _gdProcess();
|
||||
int _gdProcessChoice(int a1);
|
||||
void gameDialogOptionOnMouseEnter(int a1);
|
||||
void gameDialogOptionOnMouseExit(int a1);
|
||||
void gameDialogRenderReply();
|
||||
void _gdProcessUpdate();
|
||||
int _gdCreateHeadWindow();
|
||||
void _gdDestroyHeadWindow();
|
||||
void _gdSetupFidget(int headFid, int reaction);
|
||||
void gameDialogWaitForFidgetToComplete();
|
||||
void _gdPlayTransition(int a1);
|
||||
void _reply_arrow_up(int btn, int a2);
|
||||
void _reply_arrow_down(int btn, int a2);
|
||||
void _reply_arrow_restore(int btn, int a2);
|
||||
void _demo_copy_title(int win);
|
||||
void _demo_copy_options(int win);
|
||||
void _gDialogRefreshOptionsRect(int win, Rect* drawRect);
|
||||
void gameDialogTicker();
|
||||
void _talk_to_critter_reacts(int a1);
|
||||
void _gdialog_scroll_subwin(int a1, int a2, unsigned char* a3, unsigned char* a4, unsigned char* a5, int a6, int a7);
|
||||
int _text_num_lines(const char* a1, int a2);
|
||||
int gameDialogDrawText(unsigned char* buffer, Rect* rect, char* string, int* a4, int height, int pitch, int color, int a7);
|
||||
void gameDialogSetBarterModifier(int modifier);
|
||||
int gameDialogBarter(int modifier);
|
||||
void _barter_end_to_talk_to();
|
||||
int _gdialog_barter_create_win();
|
||||
void _gdialog_barter_destroy_win();
|
||||
void _gdialog_barter_cleanup_tables();
|
||||
int partyMemberControlWindowInit();
|
||||
void partyMemberControlWindowFree();
|
||||
void partyMemberControlWindowUpdate();
|
||||
void gameDialogCombatControlButtonOnMouseUp(int a1, int a2);
|
||||
int _gdPickAIUpdateMsg(Object* obj);
|
||||
int _gdCanBarter();
|
||||
void partyMemberControlWindowHandleEvents();
|
||||
int partyMemberCustomizationWindowInit();
|
||||
void partyMemberCustomizationWindowFree();
|
||||
void partyMemberCustomizationWindowHandleEvents();
|
||||
void partyMemberCustomizationWindowUpdate();
|
||||
void _gdCustomSelectRedraw(unsigned char* dest, int pitch, int type, int selectedIndex);
|
||||
int _gdCustomSelect(int a1);
|
||||
void _gdCustomUpdateSetting(int option, int value);
|
||||
void gameDialogBarterButtonUpMouseUp(int btn, int a2);
|
||||
int _gdialog_window_create();
|
||||
void _gdialog_window_destroy();
|
||||
int gameDialogWindowRenderBackground();
|
||||
int _talkToRefreshDialogWindowRect(Rect* rect);
|
||||
void gameDialogRenderHighlight(unsigned char* src, int srcWidth, int srcHeight, int srcPitch, unsigned char* dest, int x, int y, int destPitch, unsigned char* a9, unsigned char* a10);
|
||||
void gameDialogRenderTalkingHead(Art* art, int frame);
|
||||
void gameDialogPrepareHighlights();
|
||||
|
||||
#endif /* GAME_DIALOG_H */
|
|
@ -0,0 +1,34 @@
|
|||
#include "game_memory.h"
|
||||
|
||||
#include "db.h"
|
||||
#include "dictionary.h"
|
||||
#include "memory.h"
|
||||
#include "memory_manager.h"
|
||||
|
||||
// 0x44B250
|
||||
int gameMemoryInit()
|
||||
{
|
||||
dictionarySetMemoryProcs(internal_malloc, internal_realloc, internal_free);
|
||||
_db_register_mem(internal_malloc, internal_strdup, internal_free);
|
||||
memoryManagerSetProcs(gameMemoryMalloc, gameMemoryRealloc, gameMemoryFree);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x44B294
|
||||
void* gameMemoryMalloc(size_t size)
|
||||
{
|
||||
return internal_malloc(size);
|
||||
}
|
||||
|
||||
// 0x44B29C
|
||||
void* gameMemoryRealloc(void* ptr, size_t newSize)
|
||||
{
|
||||
return internal_realloc(ptr, newSize);
|
||||
}
|
||||
|
||||
// 0x44B2A4
|
||||
void gameMemoryFree(void* ptr)
|
||||
{
|
||||
internal_free(ptr);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef GAME_MEMORY_H
|
||||
#define GAME_MEMORY_H
|
||||
|
||||
#include "memory_defs.h"
|
||||
|
||||
int gameMemoryInit();
|
||||
void* gameMemoryMalloc(size_t size);
|
||||
void* gameMemoryRealloc(void* ptr, size_t newSize);
|
||||
void gameMemoryFree(void* ptr);
|
||||
|
||||
#endif /* GAME_MEMORY_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,190 @@
|
|||
#ifndef GAME_MOUSE_H
|
||||
#define GAME_MOUSE_H
|
||||
|
||||
#include "art.h"
|
||||
#include "geometry.h"
|
||||
#include "obj_types.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum ScrollableDirections {
|
||||
SCROLLABLE_W = 0x01,
|
||||
SCROLLABLE_E = 0x02,
|
||||
SCROLLABLE_N = 0x04,
|
||||
SCROLLABLE_S = 0x08,
|
||||
} ScrollableDirections;
|
||||
|
||||
typedef enum GameMouseMode {
|
||||
GAME_MOUSE_MODE_MOVE,
|
||||
GAME_MOUSE_MODE_ARROW,
|
||||
GAME_MOUSE_MODE_CROSSHAIR,
|
||||
GAME_MOUSE_MODE_USE_CROSSHAIR,
|
||||
GAME_MOUSE_MODE_USE_FIRST_AID,
|
||||
GAME_MOUSE_MODE_USE_DOCTOR,
|
||||
GAME_MOUSE_MODE_USE_LOCKPICK,
|
||||
GAME_MOUSE_MODE_USE_STEAL,
|
||||
GAME_MOUSE_MODE_USE_TRAPS,
|
||||
GAME_MOUSE_MODE_USE_SCIENCE,
|
||||
GAME_MOUSE_MODE_USE_REPAIR,
|
||||
GAME_MOUSE_MODE_COUNT,
|
||||
FIRST_GAME_MOUSE_MODE_SKILL = GAME_MOUSE_MODE_USE_FIRST_AID,
|
||||
GAME_MOUSE_MODE_SKILL_COUNT = GAME_MOUSE_MODE_COUNT - FIRST_GAME_MOUSE_MODE_SKILL,
|
||||
} GameMouseMode;
|
||||
|
||||
typedef enum GameMouseActionMenuItem {
|
||||
GAME_MOUSE_ACTION_MENU_ITEM_CANCEL = 0,
|
||||
GAME_MOUSE_ACTION_MENU_ITEM_DROP = 1,
|
||||
GAME_MOUSE_ACTION_MENU_ITEM_INVENTORY = 2,
|
||||
GAME_MOUSE_ACTION_MENU_ITEM_LOOK = 3,
|
||||
GAME_MOUSE_ACTION_MENU_ITEM_ROTATE = 4,
|
||||
GAME_MOUSE_ACTION_MENU_ITEM_TALK = 5,
|
||||
GAME_MOUSE_ACTION_MENU_ITEM_USE = 6,
|
||||
GAME_MOUSE_ACTION_MENU_ITEM_UNLOAD = 7,
|
||||
GAME_MOUSE_ACTION_MENU_ITEM_USE_SKILL = 8,
|
||||
GAME_MOUSE_ACTION_MENU_ITEM_PUSH = 9,
|
||||
GAME_MOUSE_ACTION_MENU_ITEM_COUNT,
|
||||
} GameMouseActionMenuItem;
|
||||
|
||||
typedef enum MouseCursorType {
|
||||
MOUSE_CURSOR_NONE,
|
||||
MOUSE_CURSOR_ARROW,
|
||||
MOUSE_CURSOR_SMALL_ARROW_UP,
|
||||
MOUSE_CURSOR_SMALL_ARROW_DOWN,
|
||||
MOUSE_CURSOR_SCROLL_NW,
|
||||
MOUSE_CURSOR_SCROLL_N,
|
||||
MOUSE_CURSOR_SCROLL_NE,
|
||||
MOUSE_CURSOR_SCROLL_E,
|
||||
MOUSE_CURSOR_SCROLL_SE,
|
||||
MOUSE_CURSOR_SCROLL_S,
|
||||
MOUSE_CURSOR_SCROLL_SW,
|
||||
MOUSE_CURSOR_SCROLL_W,
|
||||
MOUSE_CURSOR_SCROLL_NW_INVALID,
|
||||
MOUSE_CURSOR_SCROLL_N_INVALID,
|
||||
MOUSE_CURSOR_SCROLL_NE_INVALID,
|
||||
MOUSE_CURSOR_SCROLL_E_INVALID,
|
||||
MOUSE_CURSOR_SCROLL_SE_INVALID,
|
||||
MOUSE_CURSOR_SCROLL_S_INVALID,
|
||||
MOUSE_CURSOR_SCROLL_SW_INVALID,
|
||||
MOUSE_CURSOR_SCROLL_W_INVALID,
|
||||
MOUSE_CURSOR_CROSSHAIR,
|
||||
MOUSE_CURSOR_PLUS,
|
||||
MOUSE_CURSOR_DESTROY,
|
||||
MOUSE_CURSOR_USE_CROSSHAIR,
|
||||
MOUSE_CURSOR_WATCH,
|
||||
MOUSE_CURSOR_WAIT_PLANET,
|
||||
MOUSE_CURSOR_WAIT_WATCH,
|
||||
MOUSE_CURSOR_TYPE_COUNT,
|
||||
FIRST_GAME_MOUSE_ANIMATED_CURSOR = MOUSE_CURSOR_WAIT_PLANET,
|
||||
} MouseCursorType;
|
||||
|
||||
extern bool gGameMouseInitialized;
|
||||
extern int _gmouse_enabled;
|
||||
extern int _gmouse_mapper_mode;
|
||||
extern int _gmouse_click_to_scroll;
|
||||
extern int _gmouse_scrolling_enabled;
|
||||
extern int gGameMouseCursor;
|
||||
extern CacheEntry* gGameMouseCursorFrmHandle;
|
||||
extern const int gGameMouseCursorFrmIds[MOUSE_CURSOR_TYPE_COUNT];
|
||||
extern bool gGameMouseObjectsInitialized;
|
||||
extern bool _gmouse_3d_hover_test;
|
||||
extern unsigned int _gmouse_3d_last_move_time;
|
||||
extern Art* gGameMouseActionMenuFrm;
|
||||
extern CacheEntry* gGameMouseActionMenuFrmHandle;
|
||||
extern int gGameMouseActionMenuFrmWidth;
|
||||
extern int gGameMouseActionMenuFrmHeight;
|
||||
extern int gGameMouseActionMenuFrmDataSize;
|
||||
extern int _gmouse_3d_menu_frame_hot_x;
|
||||
extern int _gmouse_3d_menu_frame_hot_y;
|
||||
extern unsigned char* gGameMouseActionMenuFrmData;
|
||||
extern Art* gGameMouseActionPickFrm;
|
||||
extern CacheEntry* gGameMouseActionPickFrmHandle;
|
||||
extern int gGameMouseActionPickFrmWidth;
|
||||
extern int gGameMouseActionPickFrmHeight;
|
||||
extern int gGameMouseActionPickFrmDataSize;
|
||||
extern int _gmouse_3d_pick_frame_hot_x;
|
||||
extern int _gmouse_3d_pick_frame_hot_y;
|
||||
extern unsigned char* gGameMouseActionPickFrmData;
|
||||
extern Art* gGameMouseActionHitFrm;
|
||||
extern CacheEntry* gGameMouseActionHitFrmHandle;
|
||||
extern int gGameMouseActionHitFrmWidth;
|
||||
extern int gGameMouseActionHitFrmHeight;
|
||||
extern int gGameMouseActionHitFrmDataSize;
|
||||
extern unsigned char* gGameMouseActionHitFrmData;
|
||||
extern Art* gGameMouseBouncingCursorFrm;
|
||||
extern CacheEntry* gGameMouseBouncingCursorFrmHandle;
|
||||
extern int gGameMouseBouncingCursorFrmWidth;
|
||||
extern int gGameMouseBouncingCursorFrmHeight;
|
||||
extern int gGameMouseBouncingCursorFrmDataSize;
|
||||
extern unsigned char* gGameMouseBouncingCursorFrmData;
|
||||
extern Art* gGameMouseHexCursorFrm;
|
||||
extern CacheEntry* gGameMouseHexCursorFrmHandle;
|
||||
extern int gGameMouseHexCursorFrmWidth;
|
||||
extern int gGameMouseHexCursorHeight;
|
||||
extern int gGameMouseHexCursorDataSize;
|
||||
extern unsigned char* gGameMouseHexCursorFrmData;
|
||||
extern unsigned char gGameMouseActionMenuItemsLength;
|
||||
extern unsigned char* _gmouse_3d_menu_actions_start;
|
||||
extern unsigned char gGameMouseActionMenuHighlightedItemIndex;
|
||||
extern const short gGameMouseActionMenuItemFrmIds[GAME_MOUSE_ACTION_MENU_ITEM_COUNT];
|
||||
extern int _gmouse_3d_modes_enabled;
|
||||
extern int gGameMouseMode;
|
||||
extern int gGameMouseModeFrmIds[GAME_MOUSE_MODE_COUNT];
|
||||
extern const int gGameMouseModeSkills[GAME_MOUSE_MODE_SKILL_COUNT];
|
||||
extern int gGameMouseAnimatedCursorNextFrame;
|
||||
extern unsigned int gGameMouseAnimatedCursorLastUpdateTimestamp;
|
||||
extern int _gmouse_bk_last_cursor;
|
||||
extern bool gGameMouseItemHighlightEnabled;
|
||||
extern Object* gGameMouseHighlightedItem;
|
||||
extern bool _gmouse_clicked_on_edge;
|
||||
extern int dword_518D9C;
|
||||
|
||||
extern int gGameMouseActionMenuItems[GAME_MOUSE_ACTION_MENU_ITEM_COUNT];
|
||||
extern int gGameMouseLastX;
|
||||
extern int gGameMouseLastY;
|
||||
extern Object* gGameMouseBouncingCursor;
|
||||
extern Object* gGameMouseHexCursor;
|
||||
extern Object* gGameMousePointedObject;
|
||||
|
||||
int gameMouseInit();
|
||||
int gameMouseReset();
|
||||
void gameMouseExit();
|
||||
void _gmouse_enable();
|
||||
void _gmouse_disable(int a1);
|
||||
void _gmouse_enable_scrolling();
|
||||
void _gmouse_disable_scrolling();
|
||||
int _gmouse_get_click_to_scroll();
|
||||
int _gmouse_is_scrolling();
|
||||
void gameMouseRefresh();
|
||||
void _gmouse_handle_event(int mouseX, int mouseY, int mouseState);
|
||||
int gameMouseSetCursor(int cursor);
|
||||
int gameMouseGetCursor();
|
||||
void _gmouse_3d_enable_modes();
|
||||
void gameMouseSetMode(int a1);
|
||||
int gameMouseGetMode();
|
||||
void gameMouseCycleMode();
|
||||
void _gmouse_3d_refresh();
|
||||
int gameMouseSetBouncingCursorFid(int fid);
|
||||
void gameMouseResetBouncingCursorFid();
|
||||
void gameMouseObjectsShow();
|
||||
void gameMouseObjectsHide();
|
||||
bool gameMouseObjectsIsVisible();
|
||||
Object* gameMouseGetObjectUnderCursor(int objectType, bool a2, int elevation);
|
||||
int gameMouseRenderPrimaryAction(int x, int y, int menuItem, int width, int height);
|
||||
int _gmouse_3d_pick_frame_hot(int* a1, int* a2);
|
||||
int gameMouseRenderActionMenuItems(int x, int y, const int* menuItems, int menuItemsCount, int width, int height);
|
||||
int gameMouseHighlightActionMenuItemAtIndex(int menuItemIndex);
|
||||
int gameMouseRenderAccuracy(const char* string, int color);
|
||||
int gameMouseRenderActionPoints(const char* string, int color);
|
||||
void gameMouseLoadItemHighlight();
|
||||
int gameMouseObjectsInit();
|
||||
int gameMouseObjectsReset();
|
||||
void gameMouseObjectsFree();
|
||||
int gameMouseActionMenuInit();
|
||||
void gameMouseActionMenuFree();
|
||||
int gameMouseUpdateHexCursorFid(Rect* rect);
|
||||
int _gmouse_3d_move_to(int x, int y, int elevation, Rect* a4);
|
||||
int gameMouseHandleScrolling(int x, int y, int cursor);
|
||||
void _gmouse_remove_item_outline(Object* object);
|
||||
int objectIsDoor(Object* object);
|
||||
|
||||
#endif /* GAME_MOUSE_H */
|
|
@ -0,0 +1,339 @@
|
|||
#include "game_movie.h"
|
||||
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
#include "cycle.h"
|
||||
#include "debug.h"
|
||||
#include "game.h"
|
||||
#include "game_config.h"
|
||||
#include "game_mouse.h"
|
||||
#include "game_sound.h"
|
||||
#include "movie.h"
|
||||
#include "movie_effect.h"
|
||||
#include "palette.h"
|
||||
#include "text_font.h"
|
||||
#include "widget.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// 0x50352A
|
||||
const float flt_50352A = 0.032258064f;
|
||||
|
||||
// 0x518DA0
|
||||
const char* gMovieFileNames[MOVIE_COUNT] = {
|
||||
"iplogo.mve",
|
||||
"intro.mve",
|
||||
"elder.mve",
|
||||
"vsuit.mve",
|
||||
"afailed.mve",
|
||||
"adestroy.mve",
|
||||
"car.mve",
|
||||
"cartucci.mve",
|
||||
"timeout.mve",
|
||||
"tanker.mve",
|
||||
"enclave.mve",
|
||||
"derrick.mve",
|
||||
"artimer1.mve",
|
||||
"artimer2.mve",
|
||||
"artimer3.mve",
|
||||
"artimer4.mve",
|
||||
"credits.mve",
|
||||
};
|
||||
|
||||
// 0x518DE4
|
||||
char* gMoviePaletteFilePaths[MOVIE_COUNT] = {
|
||||
NULL,
|
||||
"art\\cuts\\introsub.pal",
|
||||
"art\\cuts\\eldersub.pal",
|
||||
NULL,
|
||||
"art\\cuts\\artmrsub.pal",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"art\\cuts\\artmrsub.pal",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"art\\cuts\\artmrsub.pal",
|
||||
"art\\cuts\\artmrsub.pal",
|
||||
"art\\cuts\\artmrsub.pal",
|
||||
"art\\cuts\\artmrsub.pal",
|
||||
"art\\cuts\\crdtssub.pal",
|
||||
};
|
||||
|
||||
// 0x518E28
|
||||
bool gGameMovieIsPlaying = false;
|
||||
|
||||
// 0x518E2C
|
||||
bool gGameMovieFaded = false;
|
||||
|
||||
// 0x596C78
|
||||
unsigned char gGameMoviesSeen[MOVIE_COUNT];
|
||||
|
||||
// 0x596C89
|
||||
char gGameMovieSubtitlesFilePath[MAX_PATH];
|
||||
|
||||
// gmovie_init
|
||||
// 0x44E5C0
|
||||
int gameMoviesInit()
|
||||
{
|
||||
int v1 = 0;
|
||||
if (backgroundSoundIsEnabled()) {
|
||||
v1 = backgroundSoundGetVolume();
|
||||
}
|
||||
|
||||
movieSetVolume(v1);
|
||||
|
||||
movieSetBuildSubtitleFilePathProc(gameMovieBuildSubtitlesFilePath);
|
||||
|
||||
memset(gGameMoviesSeen, 0, sizeof(gGameMoviesSeen));
|
||||
|
||||
gGameMovieIsPlaying = false;
|
||||
gGameMovieFaded = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x44E60C
|
||||
void gameMoviesReset()
|
||||
{
|
||||
memset(gGameMoviesSeen, 0, sizeof(gGameMoviesSeen));
|
||||
|
||||
gGameMovieIsPlaying = false;
|
||||
gGameMovieFaded = false;
|
||||
}
|
||||
|
||||
// 0x44E638
|
||||
int gameMoviesLoad(File* stream)
|
||||
{
|
||||
if (fileRead(gGameMoviesSeen, sizeof(*gGameMoviesSeen), MOVIE_COUNT, stream) != MOVIE_COUNT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x44E664
|
||||
int gameMoviesSave(File* stream)
|
||||
{
|
||||
if (fileWrite(gGameMoviesSeen, sizeof(*gGameMoviesSeen), MOVIE_COUNT, stream) != MOVIE_COUNT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// gmovie_play
|
||||
// 0x44E690
|
||||
int gameMoviePlay(int movie, int flags)
|
||||
{
|
||||
gGameMovieIsPlaying = true;
|
||||
|
||||
const char* movieFileName = gMovieFileNames[movie];
|
||||
debugPrint("\nPlaying movie: %s\n", movieFileName);
|
||||
|
||||
char* language;
|
||||
if (!configGetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_LANGUAGE_KEY, &language)) {
|
||||
debugPrint("\ngmovie_play() - Error: Unable to determine language!\n");
|
||||
gGameMovieIsPlaying = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char movieFilePath[MAX_PATH];
|
||||
int movieFileSize;
|
||||
bool movieFound = false;
|
||||
|
||||
if (stricmp(language, ENGLISH) != 0) {
|
||||
sprintf(movieFilePath, "art\\%s\\cuts\\%s", language, gMovieFileNames[movie]);
|
||||
movieFound = dbGetFileSize(movieFilePath, &movieFileSize) == 0;
|
||||
}
|
||||
|
||||
if (!movieFound) {
|
||||
sprintf(movieFilePath, "art\\cuts\\%s", gMovieFileNames[movie]);
|
||||
movieFound = dbGetFileSize(movieFilePath, &movieFileSize) == 0;
|
||||
}
|
||||
|
||||
if (!movieFound) {
|
||||
debugPrint("\ngmovie_play() - Error: Unable to open %s\n", gMovieFileNames[movie]);
|
||||
gGameMovieIsPlaying = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((flags & GAME_MOVIE_FADE_IN) != 0) {
|
||||
paletteFadeTo(gPaletteBlack);
|
||||
gGameMovieFaded = true;
|
||||
}
|
||||
|
||||
int win = windowCreate(0, 0, 640, 480, 0, WINDOW_FLAG_0x10);
|
||||
if (win == -1) {
|
||||
gGameMovieIsPlaying = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((flags & GAME_MOVIE_STOP_MUSIC) != 0) {
|
||||
backgroundSoundDelete();
|
||||
} else if ((flags & GAME_MOVIE_PAUSE_MUSIC) != 0) {
|
||||
backgroundSoundPause();
|
||||
}
|
||||
|
||||
windowRefresh(win);
|
||||
|
||||
bool subtitlesEnabled = false;
|
||||
int v1 = 4;
|
||||
configGetBool(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_SUBTITLES_KEY, &subtitlesEnabled);
|
||||
if (subtitlesEnabled) {
|
||||
char* subtitlesFilePath = gameMovieBuildSubtitlesFilePath(movieFilePath);
|
||||
|
||||
int subtitlesFileSize;
|
||||
if (dbGetFileSize(subtitlesFilePath, &subtitlesFileSize) == 0) {
|
||||
v1 = 12;
|
||||
} else {
|
||||
subtitlesEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
movieSetFlags(v1);
|
||||
|
||||
int oldTextColor;
|
||||
int oldFont;
|
||||
if (subtitlesEnabled) {
|
||||
char* subtitlesPaletteFilePath;
|
||||
if (gMoviePaletteFilePaths[movie] != NULL) {
|
||||
subtitlesPaletteFilePath = gMoviePaletteFilePaths[movie];
|
||||
} else {
|
||||
subtitlesPaletteFilePath = "art\\cuts\\subtitle.pal";
|
||||
}
|
||||
|
||||
colorPaletteLoad(subtitlesPaletteFilePath);
|
||||
|
||||
oldTextColor = widgetGetTextColor();
|
||||
widgetSetTextColor(1.0, 1.0, 1.0);
|
||||
|
||||
oldFont = fontGetCurrent();
|
||||
widgetSetFont(101);
|
||||
}
|
||||
|
||||
bool cursorWasHidden = cursorIsHidden();
|
||||
if (cursorWasHidden) {
|
||||
gameMouseSetCursor(MOUSE_CURSOR_NONE);
|
||||
mouseShowCursor();
|
||||
}
|
||||
|
||||
while (mouseGetEvent() != 0) {
|
||||
_mouse_info();
|
||||
}
|
||||
|
||||
mouseHideCursor();
|
||||
colorCycleDisable();
|
||||
|
||||
movieEffectsLoad(movieFilePath);
|
||||
|
||||
_zero_vid_mem();
|
||||
_movieRun(win, movieFilePath);
|
||||
|
||||
int v11 = 0;
|
||||
int buttons;
|
||||
do {
|
||||
if (!_moviePlaying() || _game_user_wants_to_quit || _get_input() != -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
int x;
|
||||
int y;
|
||||
_mouse_get_raw_state(&x, &y, &buttons);
|
||||
|
||||
v11 |= buttons;
|
||||
} while ((v11 & 1) == 0 && (v11 & 2) == 0 || (buttons & 1) != 0 || (buttons & 2) != 0);
|
||||
|
||||
_movieStop();
|
||||
_moviefx_stop();
|
||||
_movieUpdate();
|
||||
paletteSetEntries(gPaletteBlack);
|
||||
|
||||
gGameMoviesSeen[movie] = 1;
|
||||
|
||||
colorCycleEnable();
|
||||
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
|
||||
if (!cursorWasHidden) {
|
||||
mouseShowCursor();
|
||||
}
|
||||
|
||||
if (subtitlesEnabled) {
|
||||
colorPaletteLoad("color.pal");
|
||||
|
||||
widgetSetFont(oldFont);
|
||||
|
||||
float r = (float)((_Color2RGB_(oldTextColor) & 0x7C00) >> 10) * flt_50352A;
|
||||
float g = (float)((_Color2RGB_(oldTextColor) & 0x3E0) >> 5) * flt_50352A;
|
||||
float b = (float)(_Color2RGB_(oldTextColor) & 0x1F) * flt_50352A;
|
||||
widgetSetTextColor(r, g, b);
|
||||
}
|
||||
|
||||
windowDestroy(win);
|
||||
|
||||
if ((flags & GAME_MOVIE_PAUSE_MUSIC) != 0) {
|
||||
backgroundSoundResume();
|
||||
}
|
||||
|
||||
if ((flags & GAME_MOVIE_FADE_OUT) != 0) {
|
||||
if (!subtitlesEnabled) {
|
||||
colorPaletteLoad("color.pal");
|
||||
}
|
||||
|
||||
paletteFadeTo(_cmap);
|
||||
gGameMovieFaded = false;
|
||||
}
|
||||
|
||||
gGameMovieIsPlaying = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x44EAE4
|
||||
void gameMovieFadeOut()
|
||||
{
|
||||
if (gGameMovieFaded) {
|
||||
paletteFadeTo(_cmap);
|
||||
gGameMovieFaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x44EB04
|
||||
bool gameMovieIsSeen(int movie)
|
||||
{
|
||||
return gGameMoviesSeen[movie] == 1;
|
||||
}
|
||||
|
||||
// 0x44EB14
|
||||
bool gameMovieIsPlaying()
|
||||
{
|
||||
return gGameMovieIsPlaying;
|
||||
}
|
||||
|
||||
// 0x44EB1C
|
||||
char* gameMovieBuildSubtitlesFilePath(char* movieFilePath)
|
||||
{
|
||||
char* language;
|
||||
configGetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_LANGUAGE_KEY, &language);
|
||||
|
||||
char* path = movieFilePath;
|
||||
|
||||
char* separator = strrchr(path, '\\');
|
||||
if (separator != NULL) {
|
||||
path = separator + 1;
|
||||
}
|
||||
|
||||
sprintf(gGameMovieSubtitlesFilePath, "text\\%s\\cuts\\%s", language, path);
|
||||
|
||||
char* pch = strrchr(gGameMovieSubtitlesFilePath, '.');
|
||||
if (*pch != '\0') {
|
||||
*pch = '\0';
|
||||
}
|
||||
|
||||
strcpy(gGameMovieSubtitlesFilePath + strlen(gGameMovieSubtitlesFilePath), ".SVE");
|
||||
|
||||
return gGameMovieSubtitlesFilePath;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef GAME_MOVIE_H
|
||||
#define GAME_MOVIE_H
|
||||
|
||||
#include "db.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
typedef enum GameMovieFlags {
|
||||
GAME_MOVIE_FADE_IN = 0x01,
|
||||
GAME_MOVIE_FADE_OUT = 0x02,
|
||||
GAME_MOVIE_STOP_MUSIC = 0x04,
|
||||
GAME_MOVIE_PAUSE_MUSIC = 0x08,
|
||||
} GameMovieFlags;
|
||||
|
||||
typedef enum GameMovie {
|
||||
MOVIE_IPLOGO,
|
||||
MOVIE_INTRO,
|
||||
MOVIE_ELDER,
|
||||
MOVIE_VSUIT,
|
||||
MOVIE_AFAILED,
|
||||
MOVIE_ADESTROY,
|
||||
MOVIE_CAR,
|
||||
MOVIE_CARTUCCI,
|
||||
MOVIE_TIMEOUT,
|
||||
MOVIE_TANKER,
|
||||
MOVIE_ENCLAVE,
|
||||
MOVIE_DERRICK,
|
||||
MOVIE_ARTIMER1,
|
||||
MOVIE_ARTIMER2,
|
||||
MOVIE_ARTIMER3,
|
||||
MOVIE_ARTIMER4,
|
||||
MOVIE_CREDITS,
|
||||
MOVIE_COUNT,
|
||||
} GameMovie;
|
||||
|
||||
extern const float flt_50352A;
|
||||
|
||||
extern const char* gMovieFileNames[MOVIE_COUNT];
|
||||
extern char* gMoviePaletteFilePaths[MOVIE_COUNT];
|
||||
extern bool gGameMovieIsPlaying;
|
||||
extern bool gGameMovieFaded;
|
||||
|
||||
extern char gGameMovieSubtitlesFilePath[MAX_PATH];
|
||||
extern unsigned char gGameMoviesSeen[MOVIE_COUNT];
|
||||
|
||||
int gameMoviesInit();
|
||||
void gameMoviesReset();
|
||||
int gameMoviesLoad(File* stream);
|
||||
int gameMoviesSave(File* stream);
|
||||
int gameMoviePlay(int movie, int flags);
|
||||
void gameMovieFadeOut();
|
||||
bool gameMovieIsSeen(int movie);
|
||||
bool gameMovieIsPlaying();
|
||||
char* gameMovieBuildSubtitlesFilePath(char* movieFilePath);
|
||||
|
||||
#endif /* GAME_MOVIE_H */
|
|
@ -0,0 +1,25 @@
|
|||
#include "game_palette.h"
|
||||
|
||||
#include "color.h"
|
||||
|
||||
// 0x44EBC0
|
||||
int _HighRGB_(int a1)
|
||||
{
|
||||
// TODO: Some strange bit arithmetic.
|
||||
int v1 = _Color2RGB_(a1);
|
||||
int r = (v1 & 0x7C00) >> 10;
|
||||
int g = (v1 & 0x3E0) >> 5;
|
||||
int b = (v1 & 0x1F);
|
||||
|
||||
int result = g;
|
||||
if (r > result) {
|
||||
result = r;
|
||||
}
|
||||
|
||||
result = result & 0xFF;
|
||||
if (result <= b) {
|
||||
result = b;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef GAME_PALETTE_H
|
||||
#define GAME_PALETTE_H
|
||||
|
||||
int _HighRGB_(int a1);
|
||||
|
||||
#endif /* GAME_PALETTE_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,166 @@
|
|||
#ifndef GAME_SOUND_H
|
||||
#define GAME_SOUND_H
|
||||
|
||||
#include "obj_types.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
typedef enum WeaponSoundEffect {
|
||||
WEAPON_SOUND_EFFECT_READY,
|
||||
WEAPON_SOUND_EFFECT_ATTACK,
|
||||
WEAPON_SOUND_EFFECT_OUT_OF_AMMO,
|
||||
WEAPON_SOUND_EFFECT_AMMO_FLYING,
|
||||
WEAPON_SOUND_EFFECT_HIT,
|
||||
WEAPON_SOUND_EFFECT_COUNT,
|
||||
} WeaponSoundEffect;
|
||||
|
||||
typedef enum SoundEffectActionType {
|
||||
SOUND_EFFECT_ACTION_TYPE_ACTIVE,
|
||||
SOUND_EFFECT_ACTION_TYPE_PASSIVE,
|
||||
} SoundEffectActionType;
|
||||
|
||||
typedef enum ScenerySoundEffect {
|
||||
SCENERY_SOUND_EFFECT_OPEN,
|
||||
SCENERY_SOUND_EFFECT_CLOSED,
|
||||
SCENERY_SOUND_EFFECT_LOCKED,
|
||||
SCENERY_SOUND_EFFECT_UNLOCKED,
|
||||
SCENERY_SOUND_EFFECT_USED,
|
||||
SCENERY_SOUND_EFFECT_COUNT,
|
||||
} ScenerySoundEffect;
|
||||
|
||||
typedef enum CharacterSoundEffect {
|
||||
CHARACTER_SOUND_EFFECT_UNUSED,
|
||||
CHARACTER_SOUND_EFFECT_KNOCKDOWN,
|
||||
CHARACTER_SOUND_EFFECT_PASS_OUT,
|
||||
CHARACTER_SOUND_EFFECT_DIE,
|
||||
CHARACTER_SOUND_EFFECT_CONTACT,
|
||||
} CharacterSoundEffect;
|
||||
|
||||
typedef void(SoundEndCallback)();
|
||||
|
||||
extern char _aSoundSfx[];
|
||||
extern char _aSoundMusic_0[];
|
||||
extern char _aSoundSpeech_0[];
|
||||
|
||||
extern bool gGameSoundInitialized;
|
||||
extern bool gGameSoundDebugEnabled;
|
||||
extern bool gMusicEnabled;
|
||||
extern int dword_518E3;
|
||||
extern int _gsound_background_fade;
|
||||
extern bool gSpeechEnabled;
|
||||
extern bool gSoundEffectsEnabled;
|
||||
extern int _gsound_active_effect_counter;
|
||||
extern Sound* gBackgroundSound;
|
||||
extern Sound* gSpeechSound;
|
||||
extern SoundEndCallback* gBackgroundSoundEndCallback;
|
||||
extern SoundEndCallback* gSpeechEndCallback;
|
||||
extern char _snd_lookup_weapon_type[WEAPON_SOUND_EFFECT_COUNT];
|
||||
extern char _snd_lookup_scenery_action[SCENERY_SOUND_EFFECT_COUNT];
|
||||
extern int _background_storage_requested;
|
||||
extern int _background_loop_requested;
|
||||
extern char* _sound_sfx_path;
|
||||
extern char* _sound_music_path1;
|
||||
extern char* _sound_music_path2;
|
||||
extern char* _sound_speech_path;
|
||||
extern int gMasterVolume;
|
||||
extern int gMusicVolume;
|
||||
extern int gSpeechVolume;
|
||||
extern int gSoundEffectsVolume;
|
||||
extern int _detectDevices;
|
||||
extern int _lastTime_1;
|
||||
|
||||
extern char _background_fname_copied[MAX_PATH];
|
||||
extern char _sfx_file_name[13];
|
||||
extern char gBackgroundSoundFileName[270];
|
||||
|
||||
int gameSoundInit();
|
||||
void gameSoundReset();
|
||||
int gameSoundExit();
|
||||
void soundEffectsEnable();
|
||||
void soundEffectsDisable();
|
||||
int soundEffectsIsEnabled();
|
||||
int gameSoundSetMasterVolume(int value);
|
||||
int gameSoundGetMasterVolume();
|
||||
int soundEffectsSetVolume(int value);
|
||||
int soundEffectsGetVolume();
|
||||
void backgroundSoundDisable();
|
||||
void backgroundSoundEnable();
|
||||
int backgroundSoundIsEnabled();
|
||||
void backgroundSoundSetVolume(int value);
|
||||
int backgroundSoundGetVolume();
|
||||
int _gsound_background_volume_get_set(int a1);
|
||||
void backgroundSoundSetEndCallback(SoundEndCallback* callback);
|
||||
int backgroundSoundGetDuration();
|
||||
int backgroundSoundLoad(const char* fileName, int a2, int a3, int a4);
|
||||
int _gsound_background_play_level_music(const char* a1, int a2);
|
||||
void backgroundSoundDelete();
|
||||
void backgroundSoundRestart(int value);
|
||||
void backgroundSoundPause();
|
||||
void backgroundSoundResume();
|
||||
void speechDisable();
|
||||
void speechEnable();
|
||||
int speechIsEnabled();
|
||||
void speechSetVolume(int value);
|
||||
int speechGetVolume();
|
||||
int _gsound_speech_volume_get_set(int volume);
|
||||
void speechSetEndCallback(SoundEndCallback* callback);
|
||||
int speechGetDuration();
|
||||
int speechLoad(const char* fname, int a2, int a3, int a4);
|
||||
int _gsound_speech_play_preloaded();
|
||||
void speechDelete();
|
||||
void speechPause();
|
||||
void speechResume();
|
||||
int _gsound_play_sfx_file_volume(const char* a1, int a2);
|
||||
Sound* soundEffectLoad(const char* name, Object* a2);
|
||||
Sound* soundEffectLoadWithVolume(const char* a1, Object* a2, int a3);
|
||||
void soundEffectDelete(Sound* a1);
|
||||
int _gsnd_anim_sound(Sound* a1);
|
||||
int soundEffectPlay(Sound* a1);
|
||||
int _gsound_compute_relative_volume(Object* obj);
|
||||
char* sfxBuildCharName(Object* a1, int anim, int extra);
|
||||
char* gameSoundBuildAmbientSoundEffectName(const char* a1);
|
||||
char* gameSoundBuildInterfaceName(const char* a1);
|
||||
char* sfxBuildWeaponName(int effectType, Object* weapon, int hitMode, Object* target);
|
||||
char* sfxBuildSceneryName(int actionType, int action, const char* name);
|
||||
char* sfxBuildOpenName(Object* a1, int a2);
|
||||
void _gsound_red_butt_press(int btn, int keyCode);
|
||||
void _gsound_red_butt_release(int btn, int keyCode);
|
||||
void _gsound_toggle_butt_press_(int btn, int keyCode);
|
||||
void _gsound_med_butt_press(int btn, int keyCode);
|
||||
void _gsound_med_butt_release(int btn, int keyCode);
|
||||
void _gsound_lrg_butt_press(int btn, int keyCode);
|
||||
void _gsound_lrg_butt_release(int btn, int keyCode);
|
||||
int soundPlayFile(const char* name);
|
||||
void _gsound_bkg_proc();
|
||||
int gameSoundFileOpen(const char* fname, int access, ...);
|
||||
long _gsound_write_();
|
||||
long gameSoundFileTellNotImplemented(int handle);
|
||||
int gameSoundFileWrite(int handle, const void* buf, unsigned int size);
|
||||
int gameSoundFileClose(int handle);
|
||||
int gameSoundFileRead(int handle, void* buf, unsigned int size);
|
||||
long gameSoundFileSeek(int handle, long offset, int origin);
|
||||
long gameSoundFileTell(int handle);
|
||||
long gameSoundFileGetSize(int handle);
|
||||
bool gameSoundIsCompressed(char* filePath);
|
||||
void speechCallback(void* userData, int a2);
|
||||
void backgroundSoundCallback(void* userData, int a2);
|
||||
void soundEffectCallback(void* userData, int a2);
|
||||
int _gsound_background_allocate(Sound** out_s, int a2, int a3);
|
||||
int gameSoundFindBackgroundSoundPathWithCopy(char* dest, const char* src);
|
||||
int gameSoundFindBackgroundSoundPath(char* dest, const char* src);
|
||||
int gameSoundFindSpeechSoundPath(char* dest, const char* src);
|
||||
void gameSoundDeleteOldMusicFile();
|
||||
int backgroundSoundPlay();
|
||||
int speechPlay();
|
||||
int _gsound_get_music_path(char** out_value, const char* key);
|
||||
Sound* _gsound_get_sound_ready_for_effect();
|
||||
bool _gsound_file_exists_f(const char* fname);
|
||||
int _gsound_setup_paths();
|
||||
int _gsound_sfx_q_start();
|
||||
int ambientSoundEffectEventProcess(Object* a1, void* a2);
|
||||
|
||||
#endif /* GAME_SOUND_H */
|
|
@ -0,0 +1,703 @@
|
|||
#ifndef GAME_VARS_H
|
||||
#define GAME_VARS_H
|
||||
|
||||
typedef enum GameGlobalVar {
|
||||
GVAR_PLAYER_REPUTATION,
|
||||
GVAR_CHILDKILLER_REPUTATION,
|
||||
GVAR_CHAMPION_REPUTATION,
|
||||
GVAR_BERSERKER_REPUTATION,
|
||||
GVAR_BAD_MONSTER,
|
||||
GVAR_GOOD_MONSTER,
|
||||
GVAR_PLAYER_MARRIED,
|
||||
GVAR_ENEMY_ARROYO,
|
||||
GVAR_KNOWLEDGE_HEALING_POWDER,
|
||||
GVAR_KILL_EVIL_PLANTS,
|
||||
GVAR_START_ARROYO_TRIAL,
|
||||
GVAR_REPUTATION_SLAVER,
|
||||
GVAR_REPUTATION_SLAVE_OWNER,
|
||||
GVAR_DEN_MOM_STATUS,
|
||||
GVAR_ENEMY_DEN,
|
||||
GVAR_EXILE_DEN,
|
||||
GVAR_DEN_ANNA_STATUS,
|
||||
GVAR_DEN_WAREHOUSE_ACCESS,
|
||||
GVAR_PLAYER_GOT_CAR,
|
||||
GVAR_DEN_VIC_STATUS,
|
||||
GVAR_DEN_MAGGIE_STILL,
|
||||
GVAR_NUKA_COLA_ADDICT,
|
||||
GVAR_BUFF_OUT_ADDICT,
|
||||
GVAR_MENTATS_ADDICT,
|
||||
GVAR_PSYCHO_ADDICT,
|
||||
GVAR_RADAWAY_ADDICT,
|
||||
GVAR_ALCOHOL_ADDICT,
|
||||
GVAR_LOAD_MAP_INDEX,
|
||||
GVAR_RUNNING_BURNING_GUY,
|
||||
GVAR_VIC_DEVICE,
|
||||
GVAR_SLAVE_RUN,
|
||||
GVAR_SLAVES_COUNT,
|
||||
GVAR_MAGGIE_STATUS,
|
||||
GVAR_SLAVES_LOST,
|
||||
GVAR_SLAVERS_LOST,
|
||||
GVAR_PIP_BOY_ANNA_DIARY,
|
||||
GVAR_FRANKIE_STATUS,
|
||||
GVAR_KARMA_HOLY_WARRIOR,
|
||||
GVAR_KARMA_GUARDIAN_OF_THE_WASTES,
|
||||
GVAR_KARMA_SHIELD_OF_HOPE,
|
||||
GVAR_KARMA_DEFENDER,
|
||||
GVAR_KARMA_WANDERER,
|
||||
GVAR_KARMA_BETRAYER,
|
||||
GVAR_KARMA_SWORD_OF_DESPAIR,
|
||||
GVAR_KARMA_SCOURGE_OF_THE_WASTE,
|
||||
GVAR_KARMA_DEMON_SPAWN,
|
||||
GVAR_MAP_EXIT_TILE,
|
||||
GVAR_TOWN_REP_ARROYO,
|
||||
GVAR_TOWN_REP_KLAMATH,
|
||||
GVAR_TOWN_REP_THE_DEN,
|
||||
GVAR_TOWN_REP_VAULT_CITY,
|
||||
GVAR_TOWN_REP_GECKO,
|
||||
GVAR_TOWN_REP_MODOC,
|
||||
GVAR_TOWN_REP_SIERRA_BASE,
|
||||
GVAR_TOWN_REP_BROKEN_HILLS,
|
||||
GVAR_TOWN_REP_NEW_RENO,
|
||||
GVAR_TOWN_REP_REDDING,
|
||||
GVAR_TOWN_REP_NCR,
|
||||
GVAR_TOWN_REP_BURIED_VAULT,
|
||||
GVAR_TOWN_REP_VAULT_13,
|
||||
GVAR_TOWN_REP_COLUSA,
|
||||
GVAR_TOWN_REP_SAN_FRANCISCO,
|
||||
GVAR_TOWN_REP_ENCLAVE,
|
||||
GVAR_TOWN_REP_ABBEY,
|
||||
GVAR_TOWN_REP_EPA,
|
||||
GVAR_TOWN_REP_PRIMITIVE_TRIBE,
|
||||
GVAR_TOWN_REP_RAIDERS,
|
||||
GVAR_MAP_NEXT_TILE,
|
||||
GVAR_ENEMY_KLAMATH,
|
||||
GVAR_TORR_HARMED,
|
||||
GVAR_TORR_DEAD,
|
||||
GVAR_TORR_MISSING,
|
||||
GVAR_TORR_SEARCH_SUCCESS,
|
||||
GVAR_TRAPPER_RETURNED,
|
||||
GVAR_DUNTONS_ANGRY,
|
||||
GVAR_RUSTLE_FAIL_VIOLENT,
|
||||
GVAR_RUSTLE_FAIL,
|
||||
GVAR_RUSTLE_SUCCESS,
|
||||
GVAR_TORR_GUARD_SUCCESS,
|
||||
GVAR_VAULT_CITIZEN,
|
||||
GVAR_VAULT_PLOW_PROBLEM,
|
||||
GVAR_VAULT_CITIZENSHIP,
|
||||
GVAR_VAULT_GECKO_PLANT,
|
||||
GVAR_VAULT_PLANT_STATUS,
|
||||
GVAR_VAULT_REDDING_PROBLEM,
|
||||
GVAR_JET_QUEST,
|
||||
GVAR_DAY_PASS_SHOWN,
|
||||
GVAR_VAULT_CITIZEN_TEST,
|
||||
GVAR_VAULT_RAIDERS,
|
||||
GVAR_VAULT_DELIVER_HOLODISK,
|
||||
GVAR_VAULT_FIND_THOMAS,
|
||||
GVAR_QUEST_VAULT_CITIZEN,
|
||||
GVAR_QUEST_PLOW_PROBLEM,
|
||||
GVAR_QUEST_GECKO_PLANT,
|
||||
GVAR_QUEST_REDDING_PROBLEM,
|
||||
GVAR_QUEST_JET_QUEST,
|
||||
GVAR_QUEST_RAIDERS,
|
||||
GVAR_QUEST_DELIVER_HOLODISK,
|
||||
GVAR_QUEST_FIND_THOMAS,
|
||||
GVAR_MODOC_KILL_ALL_BRAHMIN_TIME,
|
||||
GVAR_QUEST_VIC_DEVICE,
|
||||
GVAR_QUEST_MAGGIE_STILL,
|
||||
GVAR_QUEST_KILL_EVIL_PLANTS,
|
||||
GVAR_QUEST_RUSTLE_CATTLE,
|
||||
GVAR_BUST_SKEEVE,
|
||||
GVAR_DUDE_STOMACH,
|
||||
GVAR_MODOC_FAMILY_FEUD_SEED_ONE,
|
||||
GVAR_MODOC_FAMILY_FEUD_SEED_TWO,
|
||||
GVAR_MODOC_BRAHMIN_SEED,
|
||||
GVAR_MODOC_KARL_PIP,
|
||||
GVAR_MODOC_KARL_SEED,
|
||||
GVAR_MODOC_VERMIN_HUNTER_SEED,
|
||||
GVAR_MODOC_GHOST_FARM_SEED,
|
||||
GVAR_SLAG_ATTACK,
|
||||
GVAR_JONNY_STATE,
|
||||
GVAR_JONNY_TILE,
|
||||
GVAR_MODOC_BRAHMIN_ALIVE,
|
||||
GVAR_MODOC_DOGS_ALIVE,
|
||||
GVAR_MODOC_TOOL_FLAG,
|
||||
GVAR_MODOC_SLAUGHTER_BESS_TIME,
|
||||
GVAR_KARL_STATE,
|
||||
GVAR_MODOC_BODIES,
|
||||
GVAR_MODOC_SLAUGHTER_FLAG,
|
||||
GVAR_MODOC_ROSE_FLAG,
|
||||
GVAR_MODOC_TANNERY_FLAG,
|
||||
GVAR_MODOC_POST_FLAG,
|
||||
GVAR_HOSTILE_SLAVE_COUNT,
|
||||
GVAR_LADDIE_STATE,
|
||||
GVAR_LADDIE_TILE,
|
||||
GVAR_MODOC_JONNY_HOME,
|
||||
GVAR_MODOC_SPOKE_PROTECTOR,
|
||||
GVAR_MODOC_MESSAGE,
|
||||
GVAR_MUTATE,
|
||||
GVAR_MUTATE_WHEN,
|
||||
GVAR_SALVATORE_FAMILY_COUNTER,
|
||||
GVAR_BISHOP_FAMILY_COUNTER,
|
||||
GVAR_MORDINO_FAMILY_COUNTER,
|
||||
GVAR_ENEMY_VAULT_CITY,
|
||||
GVAR_VAULT_GET_LYNETTE_REWARD,
|
||||
GVAR_VAULT_GET_MCCLURE_PART,
|
||||
GVAR_VAULT_SERVANT,
|
||||
GVAR_VAULT_VILLAGE,
|
||||
GVAR_QUEST_VAULT_SERVANT,
|
||||
GVAR_QUEST_VAULT_VILLAGE,
|
||||
GVAR_VAULT_MONSTER_COUNT,
|
||||
GVAR_SERVANT_RAID_DATE,
|
||||
GVAR_ENEMY_VAULT_VILLAGE,
|
||||
GVAR_BROKEN_HILLS_FRAUD,
|
||||
GVAR_VAULT_BEEN_TO_RAIDERS,
|
||||
GVAR_SIERRA_BASE_CONTAMINATION_TIMER,
|
||||
GVAR_SIERRA_BASE_LEVEL_BREACH,
|
||||
GVAR_SIERRA_BASE_ALERT,
|
||||
GVAR_SIERRA_BASE_ENEMY,
|
||||
GVAR_SIERRA_BASE_POWER,
|
||||
GVAR_SIERRA_BASE_SECURITY,
|
||||
GVAR_BRAIN_BOT_BRAIN,
|
||||
GVAR_SIERRA_LOCKOUT,
|
||||
GVAR_SIERRA_PASSWORD,
|
||||
GVAR_GECKO_ECON_DISK,
|
||||
GVAR_GECKO_REQ_FORM,
|
||||
GVAR_GECKO_SKEETER_PART,
|
||||
GVAR_GECKO_ANKH,
|
||||
GVAR_DEN_SMITTY_PART,
|
||||
GVAR_MCCLURE_KNOWN,
|
||||
GVAR_HOLODISK_SIERRA_EVACUATION,
|
||||
GVAR_HOLODISK_SIERRA_MED_LOG,
|
||||
GVAR_HOLODISK_SIERRA_EXP_LOG,
|
||||
GVAR_GECKO_SKEETER_STATUS,
|
||||
GVAR_NCR_TANDI_WORK,
|
||||
GVAR_NCR_TANDI_JOB_ACCEPT,
|
||||
GVAR_NCR_BEAT_HOSS,
|
||||
GVAR_NCR_SQUAT_DEAL,
|
||||
GVAR_NCR_V15_DARION_DEAD,
|
||||
GVAR_NCR_V15_DARION_DEAL,
|
||||
GVAR_NEWRENO_SNUFF_WESTIN,
|
||||
GVAR_NEWRENO_SNUFF_CARLSON,
|
||||
GVAR_VAULT13_CLEAR,
|
||||
GVAR_NCR_SPY_KNOWN,
|
||||
GVAR_NCR_TANDI_WARN_CARLSON,
|
||||
GVAR_RUSTLE_ACCEPT,
|
||||
GVAR_RUSTLE_REFUSE,
|
||||
GVAR_RUSTLE_REWARD,
|
||||
GVAR_TORR_GUARD_STATUS,
|
||||
GVAR_ARROYO_SPEAR,
|
||||
GVAR_RUSTLE_OVER,
|
||||
GVAR_NCR_BRAHMIN_PROTECT,
|
||||
GVAR_NCR_DEATHCLAW_DEN,
|
||||
GVAR_SLAVE_RUN_KILLED,
|
||||
GVAR_DUNTON_DEAD,
|
||||
GVAR_NCR_CAR_JACKED,
|
||||
GVAR_NCR_MERK_WORK,
|
||||
GVAR_ARROYO_DOG,
|
||||
GVAR_HAVE_MUTATED,
|
||||
GVAR_MUTATE_STAGE,
|
||||
GVAR_PLAYER_SEX_LEVEL,
|
||||
GVAR_NCR_VORTIS_QUEST_STATE,
|
||||
GVAR_NCR_RANGERS_KNOWN,
|
||||
GVAR_SMILEY_STATUS,
|
||||
GVAR_STILL_STATUS,
|
||||
GVAR_STILL_FAILURE,
|
||||
GVAR_GRAVE_FLAGS_1,
|
||||
GVAR_GRAVE_FLAGS_2,
|
||||
GVAR_TORR_BRAHMIN_KILLED,
|
||||
GVAR_ENEMY_TORR,
|
||||
GVAR_ENEMY_DUNTON,
|
||||
GVAR_ENEMY_SMILEY,
|
||||
GVAR_NCR_SCMERK_HEREBEFORE,
|
||||
GVAR_NCR_SCMERK_HOSTILE,
|
||||
GVAR_NCR_SCMERK_PERSONAL_ENEMY,
|
||||
GVAR_NCR_SCMERK_STATUS,
|
||||
GVAR_NCR_SCMERK_SEED_STATUS,
|
||||
GVAR_NCR_LENNY_MET,
|
||||
GVAR_NCR_ELRON_ADJUST,
|
||||
GVAR_NCR_FAKE_VAULT13_MAP,
|
||||
GVAR_NCR_FAKE_VAULT13_HOLODISK,
|
||||
GVAR_MILITARY_BASE_FLAGS,
|
||||
GVAR_WRIGHT_FAMILY_COUNTER,
|
||||
GVAR_NCR_MIRA_STATE,
|
||||
GVAR_NCR_ROPE_KNOWN,
|
||||
GVAR_NEW_RENO_WARNING_TIMER,
|
||||
GVAR_HOLODISK_MB_OUTSIDE,
|
||||
GVAR_HOLODISK_MB_LEVEL_1,
|
||||
GVAR_HOLODISK_MB_LEVEL_2,
|
||||
GVAR_HOLODISK_MB_LEVEL_3,
|
||||
GVAR_HOLODISK_MB_LEVEL_4,
|
||||
GVAR_NCR_GTEGRD_ATTACK,
|
||||
GVAR_NCR_GATE_NIGHT,
|
||||
GVAR_NCR_ENCLAVE_INFO,
|
||||
GVAR_NCR_WESTIN_SEED,
|
||||
GVAR_NCR_DOROTHY_SEED,
|
||||
GVAR_NEW_RENO_MADE_MAN,
|
||||
GVAR_NEW_RENO_PRIZEFIGHTER,
|
||||
GVAR_NEW_RENO_PORN_STAR,
|
||||
GVAR_VAULT13_FOUND_GECK,
|
||||
GVAR_NCR_POWER_ON,
|
||||
GVAR_SULIK_FREE,
|
||||
GVAR_TORR_SEARCH_ACCEPT,
|
||||
GVAR_NCR_HENRY_HYPO,
|
||||
GVAR_ENEMY_GECKO,
|
||||
GVAR_GECKO_COOLANT,
|
||||
GVAR_NCR_POWERPLANT,
|
||||
GVAR_NCR_PLAYER_RANGER,
|
||||
GVAR_NCR_JACK_STATE,
|
||||
GVAR_8_BALL_TOILET_SECRET,
|
||||
GVAR_8_BALL_TRASH_SECRET,
|
||||
GVAR_NCR_GENERIC_STATE,
|
||||
GVAR_NEW_RENO_MCGEE_SEED,
|
||||
GVAR_NEW_RENO_MCGEE_KNOWN,
|
||||
GVAR_NEW_RENO_MCGEE_ATTACKED,
|
||||
GVAR_GECKO_BRAIN_DEAD,
|
||||
GVAR_GECKO_BRAIN_FRIEND,
|
||||
GVAR_SALVATORE_WARNINGS,
|
||||
GVAR_BISHOP_WARNINGS,
|
||||
GVAR_MORDINO_WARNINGS,
|
||||
GVAR_WRIGHT_WARNINGS,
|
||||
GVAR_NEW_RENO_BISHOP,
|
||||
GVAR_NCR_SNUFF_BISHOP,
|
||||
GVAR_NEW_RENO_CARLSON_PRICE,
|
||||
GVAR_NEW_RENO_WESTIN_PRICE,
|
||||
GVAR_NEW_RENO_HAS_REP_PRIZEFIGHTER,
|
||||
GVAR_NEW_RENO_ANGELA,
|
||||
GVAR_PLACEHOLDER_002,
|
||||
GVAR_NCR_ELISE_SEED,
|
||||
GVAR_NEW_RENO_MRS_BISHOP,
|
||||
GVAR_NCR_FELIX_SEED,
|
||||
GVAR_NCR_BISHOP_PRICE,
|
||||
GVAR_NCR_CATTLE_DRIVE,
|
||||
GVAR_NCR_CATTLE_TIME_MIN,
|
||||
GVAR_NCR_CATTLE_TIME_MAX,
|
||||
GVAR_CARAVAN_STATUS,
|
||||
GVAR_CARAVAN_START,
|
||||
GVAR_CARAVAN_END,
|
||||
GVAR_CARAVAN_DRIVERS,
|
||||
GVAR_CARAVAN_GUARDS,
|
||||
GVAR_CARAVAN_CARTS,
|
||||
GVAR_CARAVAN_ENCOUNTERS,
|
||||
GVAR_CARAVAN_BRAHMIN,
|
||||
GVAR_CARAVAN_MASTERS,
|
||||
GVAR_CARAVAN_DRIVERS_TOTAL,
|
||||
GVAR_CARAVAN_GUARDS_TOTAL,
|
||||
GVAR_CARAVAN_CARTS_TOTAL,
|
||||
GVAR_CARAVAN_BRAHMIN_TOTAL,
|
||||
GVAR_CARAVAN_MASTERS_TOTAL,
|
||||
GVAR_CARAVAN_ENCOUNTERS_TOTAL,
|
||||
GVAR_NEW_RENO_MYRON,
|
||||
GVAR_NEW_RENO_WRIGHT_FLAGS,
|
||||
GVAR_NEW_RENO_WRIGHT_MYSTERY,
|
||||
GVAR_DEN_SLAVER_WARNINGS,
|
||||
GVAR_V13_V15_DALIA_STATE,
|
||||
GVAR_PARTY_CHILDKILLER,
|
||||
GVAR_MODOC_STAGE_TIMER,
|
||||
GVAR_MODOC_STAGE_STATE,
|
||||
GVAR_REDDING_WHORE_CUT,
|
||||
GVAR_V15_SEED_STATUS,
|
||||
GVAR_TOWN_REP_VAULT_15,
|
||||
GVAR_ADDICT_TRAGIC,
|
||||
GVAR_ADDICT_JET,
|
||||
GVAR_MODOC_GENERIC_FLAG_1,
|
||||
GVAR_DEN_CEASAR_STATUS,
|
||||
GVAR_MODOC_BRAHMIN_ESCAPED,
|
||||
GVAR_BH_CHAD,
|
||||
GVAR_BH_FTM,
|
||||
GVAR_BH_MINE,
|
||||
GVAR_BH_JAIL,
|
||||
GVAR_BH_CONSPIRACY,
|
||||
GVAR_BH_MISSING,
|
||||
GVAR_BH_MIGHTY_MAN,
|
||||
GVAR_BH_MINING,
|
||||
GVAR_TOWN_REP_GHOST_FARM,
|
||||
GVAR_ENEMY_BROKEN_HILLS,
|
||||
GVAR_SLAG_CNT,
|
||||
GVAR_NEW_RENO_SALVATORE_RESPECT,
|
||||
GVAR_NEW_RENO_TRACK_LLOYD,
|
||||
GVAR_NEW_RENO_GUARD_ASSIGNMENT,
|
||||
GVAR_NEW_RENO_FLAG_1,
|
||||
GVAR_NEW_RENO_SALVATORE,
|
||||
GVAR_NEW_RENO_TRIBUTE,
|
||||
GVAR_NEW_RENO_SALVATORE_PISTOL,
|
||||
GVAR_NEW_RENO_ESCAPE,
|
||||
GVAR_GRAVES_UNEARTHED,
|
||||
GVAR_MOORE_STATE,
|
||||
GVAR_MOORE_ACCEPT_DELIVERY,
|
||||
GVAR_MOORE_REFUSE_DELIVERY,
|
||||
GVAR_SPECIAL_ENCOUNTER_FLAGS,
|
||||
GVAR_BH_BOSS,
|
||||
GVAR_BH_HENCH_COUNT,
|
||||
GVAR_BH_MALE_NAMES_USED,
|
||||
GVAR_BH_FEMALE_NAMES_USED,
|
||||
GVAR_BH_HENCH_KILLED,
|
||||
GVAR_BH_CHECKED,
|
||||
GVAR_BH_CARAVAN,
|
||||
GVAR_BH_RANK_KILLED,
|
||||
GVAR_REDDING_EXCAVATOR_CHIP,
|
||||
GVAR_REDDING_JET_LEVEL,
|
||||
GVAR_MAYOR_REDDING_STATUS,
|
||||
GVAR_REDDING_MARGE_STATUS,
|
||||
GVAR_REDDING_DAN_STATUS,
|
||||
GVAR_REDDING_JOHNSON_STATUS,
|
||||
GVAR_CATTLE_DRIVE_CARAVAN,
|
||||
GVAR_MEDICINE_CARAVAN,
|
||||
GVAR_JET_CARAVAN,
|
||||
GVAR_GOLD_CARAVAN,
|
||||
GVAR_REDDING_CARAVAN_STATUS,
|
||||
GVAR_NEW_RENO_SAD,
|
||||
GVAR_NEW_RENO_WRIGHT_STILL,
|
||||
GVAR_NEW_RENO_FLAG_2,
|
||||
GVAR_NEW_RENO_WRIGHT_STILL_MISSION,
|
||||
GVAR_NEW_RENO_JULES_KITTY,
|
||||
GVAR_NEW_RENO_STOLEN_CAR,
|
||||
GVAR_NEW_RENO_JULES_ELDRIDGE,
|
||||
GVAR_GRUTHAR_DSTATUS,
|
||||
GVAR_WHIRLY,
|
||||
GVAR_MYSTERIOUS_STRANGER,
|
||||
GVAR_MYSTERIOUS_STRANGER_LEVEL,
|
||||
GVAR_NEW_RENO_DELIVERY,
|
||||
GVAR_NEW_RENO_EXTORTION_BROS,
|
||||
GVAR_NEW_RENO_ASSASSINATION,
|
||||
GVAR_NEW_RENO_LIL_JESUS_REFERS,
|
||||
GVAR_SEX_COUNTER,
|
||||
GVAR_RND_SALES_NAME,
|
||||
GVAR_RND_SALES_ENCOUNTER,
|
||||
GVAR_SAN_FRAN_FLAGS,
|
||||
GVAR_SAN_FRAN_SUB,
|
||||
GVAR_SAN_FRAN_TANKER,
|
||||
GVAR_SAN_FRAN_SHIHACKED,
|
||||
GVAR_SAN_FRAN_BADGER,
|
||||
GVAR_SAN_FRAN_ELRON,
|
||||
GVAR_SAN_FRAN_SPLEEN,
|
||||
GVAR_KNOW_DOC_HOLIDAY,
|
||||
GVAR_DUMAR_STATUS,
|
||||
GVAR_NEW_RENO_JET_SOURCE,
|
||||
GVAR_DEN_BECKY_JOB,
|
||||
GVAR_HOLY_GRENADE,
|
||||
GVAR_RAIDERS_FLAGS,
|
||||
GVAR_DEN_FRED_STATUS,
|
||||
GVAR_DEN_DEREK_STATUS,
|
||||
GVAR_DEN_ROBBY_STATUS,
|
||||
GVAR_RAIDERS_COUNT,
|
||||
GVAR_DEN_HEATHER_STATUS,
|
||||
GVAR_SUPER_CAR,
|
||||
GVAR_BAR_BRAWL,
|
||||
GVAR_WADE_STATUS,
|
||||
GVAR_STANWELL_STATUS,
|
||||
GVAR_SAVINELLI_STATUS,
|
||||
GVAR_IMPLANTS_KNOWN,
|
||||
GVAR_FROG_MORTON,
|
||||
GVAR_REDDING_MORTON_BROTHERS,
|
||||
GVAR_REDDING_SHERIFF,
|
||||
GVAR_MODOC_ENDINGS,
|
||||
GVAR_WANAMINGO_OCCUPADO,
|
||||
GVAR_QUEST_RAT_GOD,
|
||||
GVAR_QUEST_RESCUE_TORR,
|
||||
GVAR_VAULT_JET_SOURCE,
|
||||
GVAR_QUEST_SUPER_REPAIR_KIT,
|
||||
GVAR_QUEST_PLASMA_TRANSFORMER,
|
||||
GVAR_GECKO_MELTDOWN,
|
||||
GVAR_QUEST_REPAIR_POWER_PLANT,
|
||||
GVAR_QUEST_OPTIMIZE_POWER_PLANT,
|
||||
GVAR_PARTY_NO_FOLLOW,
|
||||
GVAR_RND_KAGA_STATE,
|
||||
GVAR_VAULT_CITY_VENT,
|
||||
GVAR_VAULT_PIP,
|
||||
GVAR_MODOC_GENERIC_FLAG_2,
|
||||
GVAR_SLAUGHTER_SLAG_TIME,
|
||||
GVAR_PIPBOY_TOUR_GUIDE,
|
||||
GVAR_PIPBOY_CREDITS,
|
||||
GVAR_NCR_GRANT_HOSTILE,
|
||||
GVAR_NCR_WFIELD_NOTIFY,
|
||||
GVAR_ENDGAME_MOVIE_ARROYO,
|
||||
GVAR_ENDGAME_MOVIE_MODOC,
|
||||
GVAR_ENDGAME_MOVIE_DEN,
|
||||
GVAR_ENDGAME_MOVIE_VAULT_CITY,
|
||||
GVAR_ENDGAME_MOVIE_RENO,
|
||||
GVAR_ENDGAME_MOVIE_RENO_ADD1,
|
||||
GVAR_ENDGAME_MOVIE_RENO_ADD2,
|
||||
GVAR_ENDGAME_MOVIE_RENO_ADD3,
|
||||
GVAR_ENDGAME_MOVIE_RENO_ADD4,
|
||||
GVAR_ENDGAME_MOVIE_GECKO,
|
||||
GVAR_ENDGAME_MOVIE_REDDING,
|
||||
GVAR_ENDGAME_MOVIE_BROKEN_HILLS,
|
||||
GVAR_ENDGAME_MOVIE_NCR,
|
||||
GVAR_ENDGAME_MOVIE_VAULT_15,
|
||||
GVAR_ENDGAME_MOVIE_VAULT_13,
|
||||
GVAR_ENDGAME_MOVIE_SAN_FRAN_SHI,
|
||||
GVAR_ENDGAME_MOVIE_SAN_FRAN_ELRON,
|
||||
GVAR_ENDGAME_MOVIE_SAN_FRAN_PUNKS,
|
||||
GVAR_SAN_FRAN_STRUGGLE,
|
||||
GVAR_SAN_FRAN_ELRON_WHIRLY,
|
||||
GVAR_DR_TROY_STATUS,
|
||||
GVAR_V13_STATUS_FLAGS,
|
||||
GVAR_GECKO_TIMER_MELTDOWN,
|
||||
GVAR_ENCLAVE_POWER_PLANT,
|
||||
GVAR_ENCLAVE_GRANITE_JOINED,
|
||||
GVAR_ENCLAVE_ALARM,
|
||||
GVAR_ENCLAVE_TIMER,
|
||||
GVAR_ENCLAVE_REACTOR,
|
||||
GVAR_VAULT_LYNETTE_STATUS,
|
||||
GVAR_DOC_JOHNSON_STATUS,
|
||||
GVAR_NCR_GEN_FLAGS,
|
||||
GVAR_CAR_BLOWER,
|
||||
GVAR_ENCLAVE_COMPUTER,
|
||||
GVAR_ENCLAVE_MARTIN,
|
||||
GVAR_ENCLAVE_ELDER,
|
||||
GVAR_JAIL_BREAK,
|
||||
GVAR_SAN_FRAN_ARMOR,
|
||||
GVAR_DEN_FLAG_1,
|
||||
GVAR_DEN_FLAG_2,
|
||||
GVAR_DEN_FLAG_3,
|
||||
GVAR_SAN_FRAN_SPLEEN_TIME,
|
||||
GVAR_PLAYER_WAS_MARRIED,
|
||||
GVAR_DEN_SMITTY_DELIVER,
|
||||
GVAR_SMITTY_DELIVER_TIME,
|
||||
GVAR_DEN_VIC_KNOWN,
|
||||
GVAR_CAR_UPGRADE_FUEL_CELL_REGULATOR,
|
||||
GVAR_DEN_GANGWAR,
|
||||
GVAR_NEW_RENO_CAR_UPGRADE,
|
||||
GVAR_NEW_RENO_SUPER_CAR,
|
||||
GVAR_DEN_SEE_VIC,
|
||||
GVAR_STILL_START,
|
||||
GVAR_QUEST_JOSHUA,
|
||||
GVAR_ARDIN_FREEDOM,
|
||||
GVAR_TOTAL_WANAMINGOS,
|
||||
GVAR_SAN_FRAN_DAVE,
|
||||
GVAR_VC_MET_ED,
|
||||
GVAR_FRED_MONEY,
|
||||
GVAR_CAN_ASK_ARDIN_ABOUT_SMILEY,
|
||||
GVAR_VAULT_USED_TEACHING_SYSTEM,
|
||||
GVAR_DEN_GANG_1_COUNT,
|
||||
GVAR_DEN_GANG_2_COUNT,
|
||||
GVAR_DEN_GANG_D_DAY,
|
||||
GVAR_DEN_METZGER_GANG_KILL_TIMER,
|
||||
GVAR_DEN_GANG_TRAP,
|
||||
GVAR_DEN_GANG_DOOR,
|
||||
GVAR_V15_CRISSY_QUEST,
|
||||
GVAR_V15_KILL_DARION,
|
||||
GVAR_V15_NCR_DEAL,
|
||||
GVAR_V15_NCR_SPY,
|
||||
GVAR_SAN_FRAN_EG_NOTIFY,
|
||||
GVAR_SAN_FRAN_EG_A_OBJ,
|
||||
GVAR_ELRON_GUARDS,
|
||||
GVAR_ARROYO_RETURN_GECK,
|
||||
GVAR_NCR_BRAHMN_QST,
|
||||
GVAR_NCR_DRPAPR_QST,
|
||||
GVAR_NCR_ELMBISHOP_QST,
|
||||
GVAR_NCR_LYNETTE_HOLO_QST,
|
||||
GVAR_NCR_ENLONE_LETTER_QST,
|
||||
GVAR_NCR_KILL_ELRON_QST,
|
||||
GVAR_V13_COMP_QST,
|
||||
GVAR_V13_GORIS_QST,
|
||||
GVAR_GIMP_FLAG,
|
||||
GVAR_GECKO_ASSIGNED,
|
||||
GVAR_MODOC_SHITTY_DEATH,
|
||||
GVAR_ENEMY_REDDING,
|
||||
GVAR_VAL_TOOLS,
|
||||
GVAR_FALLOUT_2,
|
||||
GVAR_NEW_RENO_FLAG_3,
|
||||
GVAR_MR_BISHOP_SAFE,
|
||||
GVAR_VAULT_BOOZE_SMUGGLING,
|
||||
GVAR_ENCLAVE_COUNTDOWN,
|
||||
GVAR_ENCLAVE_FRANK_DEAD,
|
||||
GVAR_NCR_BRAHMIN_QST,
|
||||
GVAR_NEW_RENO_KITTY_MAGAZINES,
|
||||
GVAR_NCR_FREE_SLAVES_QST,
|
||||
GVAR_NEW_RENO_STUART_DEAL,
|
||||
GVAR_NEW_RENO_FIGHT_LEVEL,
|
||||
GVAR_ENEMY_VAULT_COURTYARD,
|
||||
GVAR_NEW_RENO_ROUND_NUMBER,
|
||||
GVAR_NEW_RENO_ROUND_TIME,
|
||||
GVAR_NEW_RENO_DUDE_SCORE,
|
||||
GVAR_NEW_RENO_BOXER_SCORE,
|
||||
GVAR_NEW_RENO_FIGHT_STATUS,
|
||||
GVAR_NAVARRO_BASE_ALERT,
|
||||
GVAR_NAVARRO_FOB,
|
||||
GVAR_NAVARRO_K9,
|
||||
GVAR_NAVARRO_POWER_CENTER,
|
||||
GVAR_NAVARRO_VERTIBIRDS,
|
||||
GVAR_STANWELL_PAYOUT,
|
||||
GVAR_WADE_PAYOUT,
|
||||
GVAR_SAVINE_PAYOUT,
|
||||
GVAR_SAN_FRAN_SHI_WHIRLY,
|
||||
GVAR_SIERRA_GNN_HOLODISK,
|
||||
GVAR_SIERRA_MISSION_HOLODISK,
|
||||
GVAR_ELRON_HOLODISK,
|
||||
GVAR_NEW_RENO_KILL_DADDY_WEAPON,
|
||||
GVAR_READ_FRANCIS_NOTE,
|
||||
GVAR_ENEMY_CONSPIRATORS,
|
||||
GVAR_MARCUS_DEAD,
|
||||
GVAR_RAIDER_SECRET_ENTRANCE_KNOWN,
|
||||
GVAR_COMING_FROM_INSIDE_RAIDERS,
|
||||
GVAR_VAULT_STARK_RECON,
|
||||
GVAR_NEW_RENO_MRS_BISHOP_COMBINATION,
|
||||
GVAR_TALKED_TO_ELDER,
|
||||
GVAR_SAN_FRAN_FUEL_TANK_QST,
|
||||
GVAR_SAN_FRAN_NAV_TANK_QST,
|
||||
GVAR_SAN_FRAN_FOB_TANK_QST,
|
||||
GVAR_SAN_FRAN_ELRON_GAS_QST,
|
||||
GVAR_SAN_FRAN_BADGER_GFRIEND_QST,
|
||||
GVAR_SAN_FRAN_LOPAN_KDRAGON_QST,
|
||||
GVAR_SAN_FRAN_DRAGON_KLOPAN_QST,
|
||||
GVAR_SAN_FRAN_ARMOR_QST,
|
||||
GVAR_FINISHED_STARK_RECON,
|
||||
GVAR_VAULT_CITY_DESIGNER_NOTES,
|
||||
GVAR_BH_POWER,
|
||||
GVAR_NEW_RENO_SUSPECT_JJJ,
|
||||
GVAR_NEW_RENO_SUSPECT_JULES,
|
||||
GVAR_NEW_RENO_SUSPECT_LIL_JESUS,
|
||||
GVAR_NEW_RENO_SUSPECT_RENESCO,
|
||||
GVAR_NEW_RENO_WESTIN_SNUFF_PIP,
|
||||
GVAR_NEW_RENO_CARLSON_SNUFF_PIP,
|
||||
GVAR_NEW_RENO_ELDRIDGE_PISTOL_QUEST,
|
||||
GVAR_DEN_CAR_PART_PIP,
|
||||
GVAR_DEN_ANNA_LOCKET_PIP,
|
||||
GVAR_NEW_RENO_POISON_STILL_TIME,
|
||||
GVAR_SAN_FRAN_WONG_EAT_TIME,
|
||||
GVAR_NAVARRO_XARN,
|
||||
GVAR_SAN_FRAN_KILL_OZ9_QST,
|
||||
GVAR_NEW_RENO_ETHYL_MEETING_TIME,
|
||||
GVAR_SAN_FRAN_VERTI_STEAL_SHI_QST,
|
||||
GVAR_SAN_FRAN_VERTI_STEAL_ELE_QST,
|
||||
GVAR_SAN_FRAN_KILL_EMP_QST,
|
||||
GVAR_SAN_FRAN_VERTI_SHI_QST,
|
||||
GVAR_SAN_FRAN_VERTI_ELE_QST,
|
||||
GVAR_BROKEN_HILLS_CARAVAN_POOCH_SCREW,
|
||||
GVAR_CHAD_DEAD,
|
||||
GVAR_SAN_FRAN_JASHUA_STATUS,
|
||||
GVAR_SAN_FRAN_BOS_QUEST,
|
||||
GVAR_NCR_GUARDS_CHECK_OBJ,
|
||||
GVAR_ENEMY_BANK_GUARDS,
|
||||
GVAR_ENCLAVE_TURRET_GUARD,
|
||||
GVAR_ENCLAVE_TURRET_DETENTION,
|
||||
GVAR_ENCLAVE_TURRET_SCIENCE,
|
||||
GVAR_ENCLAVE_TURRET_PRESIDENT,
|
||||
GVAR_ENCLAVE_TURRET_MAIN,
|
||||
GVAR_HOLODISK_ENCLAVE_SECURITY,
|
||||
GVAR_HOLODISK_ENCLAVE_STATE,
|
||||
GVAR_HOLODISK_ENCLAVE_WORD,
|
||||
GVAR_HOLODISK_ENCLAVE_CHEMICAL,
|
||||
GVAR_HOLODISK_ENCLAVE_ATOMIC,
|
||||
GVAR_ENCLAVE_TURRET_HELP_PLAYER,
|
||||
GVAR_NEW_RENO_GUARD_MESSAGE_TIMER,
|
||||
GVAR_MORTON_GANG,
|
||||
GVAR_GECKO_WORKING_ON_PLANT,
|
||||
GVAR_VIGNETTE_SEQUENCE,
|
||||
GVAR_PLANT_SCHEDULED_FOR_CHANGE,
|
||||
GVAR_DROP_PLAYER_BY_VAULT_8,
|
||||
GVAR_ENCLAVE_COM_LINE,
|
||||
GVAR_LEFT_CAR_AT_RAIDERS,
|
||||
GVAR_RAIDERS_CAR_ELEVATION,
|
||||
GVAR_SEXPERT,
|
||||
GVAR_GIGALO,
|
||||
GVAR_DUDE_VIRGIN,
|
||||
GVAR_MADE_MAN_SALVATORE,
|
||||
GVAR_MADE_MAN_BISHOP,
|
||||
GVAR_MADE_MAN_MORDINO,
|
||||
GVAR_MADE_MAN_WRIGHT,
|
||||
GVAR_NCR_SPY_HOLO_DOWNLOAD,
|
||||
GVAR_NCR_HISTORY_HOLO_DOWNLOAD,
|
||||
GVAR_NCR_WESTIN_HOLO_DOWNLOAD,
|
||||
GVAR_TYPHON_QUEST_STATUS,
|
||||
GVAR_8_BALL_VAULT_TERMINAL,
|
||||
GVAR_RAIDERS_DEAD,
|
||||
GVAR_KLAMATH_GENERATOR,
|
||||
GVAR_ENTERED_GUARDIAN,
|
||||
GVAR_BATH_HOUSE_REJECT,
|
||||
GVAR_SKYNET,
|
||||
GVAR_SPECIAL_ENCOUNTER_BRIDGE,
|
||||
GVAR_SPECIAL_ENCOUNTER_HOLY2,
|
||||
GVAR_SPECIAL_ENCOUNTER_TOXIC,
|
||||
GVAR_SPECIAL_ENCOUNTER_PARIAH,
|
||||
GVAR_SPECIAL_ENCOUNTER_BRAHMIN,
|
||||
GVAR_SPECIAL_ENCOUNTER_WHALE,
|
||||
GVAR_SPECIAL_ENCOUNTER_HEAD,
|
||||
GVAR_SPECIAL_ENCOUNTER_SHUTTLE,
|
||||
GVAR_SPECIAL_ENCOUNTER_GUARDIAN,
|
||||
GVAR_SPECIAL_ENCOUNTER_HOLY1,
|
||||
GVAR_SPECIAL_ENCOUNTER_WOODSMAN,
|
||||
GVAR_GECKO_FIND_WOODY,
|
||||
GVAR_SPECIAL_ENCOUNTER_CAFE,
|
||||
GVAR_GECKO_DESCENDANT_KNOWN,
|
||||
GVAR_FIND_VIC,
|
||||
GVAR_SPECIAL_ENCOUNTER_UNWASHED,
|
||||
GVAR_KLAMATH_SCORPIONS_KILLED,
|
||||
GVAR_KLAMATH_SCORPIONS_TOTAL,
|
||||
GVAR_ENCLAVE_ENEMY_GUARD,
|
||||
GVAR_ENCLAVE_ENEMY_PRESIDENT,
|
||||
GVAR_ENCLAVE_ENEMY_TRAPS,
|
||||
GVAR_ENCLAVE_ENEMY_REACTOR,
|
||||
GVAR_ENCLAVE_ENEMY_DETENTION,
|
||||
GVAR_TOWN_REP_NAVARRO,
|
||||
GVAR_GAVE_GECK_EXP,
|
||||
GVAR_DUDE_START_SEQ_1,
|
||||
GVAR_MODOC_GHOST_SEED_PIP,
|
||||
GVAR_PARTY_MEMBERS_HIDDEN,
|
||||
GVAR_CAR_PLACED_TILE,
|
||||
GVAR_RESERVED_VAR1,
|
||||
GVAR_RESERVED_VAR2,
|
||||
GVAR_RESERVED_VAR3,
|
||||
GVAR_RESERVED_VAR4,
|
||||
GVAR_RESERVED_VAR5,
|
||||
GVAR_RESERVED_VAR6,
|
||||
GVAR_RESERVED_VAR7,
|
||||
GVAR_RESERVED_VAR8,
|
||||
GVAR_RESERVED_VAR9,
|
||||
GVAR_RESERVED_VAR10,
|
||||
GVAR_RESERVED_VAR11,
|
||||
GVAR_RESERVED_VAR12,
|
||||
GVAR_RESERVED_VAR13,
|
||||
GVAR_RESERVED_VAR14,
|
||||
GVAR_RESERVED_VAR15,
|
||||
GVAR_RESERVED_VAR16,
|
||||
GVAR_RESERVED_VAR17,
|
||||
GVAR_RESERVED_VAR18,
|
||||
GVAR_RESERVED_VAR19,
|
||||
GVAR_RESERVED_VAR20,
|
||||
GVAR_RESERVED_VAR21,
|
||||
GVAR_RESERVED_VAR22,
|
||||
GVAR_RESERVED_VAR23,
|
||||
GVAR_RESERVED_VAR24,
|
||||
GVAR_RESERVED_VAR25,
|
||||
GVAR_RESERVED_VAR26,
|
||||
GVAR_RESERVED_VAR27,
|
||||
GVAR_RESERVED_VAR28,
|
||||
GVAR_RESERVED_VAR29,
|
||||
GVAR_RESERVED_VAR30,
|
||||
GVAR_RESERVED_VAR31,
|
||||
GVAR_RESERVED_VAR32,
|
||||
GVAR_RESERVED_VAR33,
|
||||
GVAR_RESERVED_VAR34,
|
||||
GVAR_RESERVED_VAR35,
|
||||
GVAR_RESERVED_VAR36,
|
||||
GVAR_RESERVED_VAR37,
|
||||
GVAR_RESERVED_VAR38,
|
||||
GVAR_RESERVED_VAR39,
|
||||
GVAR_RESERVED_VAR40,
|
||||
GVAR_RESERVED_VAR41,
|
||||
GVAR_RESERVED_VAR42,
|
||||
GVAR_RESERVED_VAR43,
|
||||
GVAR_RESERVED_VAR44,
|
||||
GVAR_RESERVED_VAR45,
|
||||
GVAR_RESERVED_VAR46,
|
||||
GVAR_RESERVED_VAR47,
|
||||
GVAR_RESERVED_VAR48,
|
||||
GVAR_RESERVED_VAR49,
|
||||
GVAR_RESERVED_VAR50,
|
||||
GVAR_RESERVED_VAR51,
|
||||
GVAR_RESERVED_VAR52,
|
||||
GVAR_RESERVED_VAR53,
|
||||
GVAR_RESERVED_VAR54,
|
||||
GVAR_RESERVED_VAR55,
|
||||
GVAR_RESERVED_VAR56,
|
||||
GVAR_RESERVED_VAR57,
|
||||
GVAR_RESERVED_VAR58,
|
||||
GVAR_RESERVED_VAR59,
|
||||
GVAR_MODOC_JONNY_PIP,
|
||||
GVAR_NEW_RENO_FLAG_4,
|
||||
GVAR_PATCH_INVAIDITATOR,
|
||||
} GameGlobalVar;
|
||||
|
||||
#endif /* GAME_VARS_H */
|
|
@ -0,0 +1,183 @@
|
|||
#include "geometry.h"
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// 0x51DEF4
|
||||
RectListNode* _rectList = NULL;
|
||||
|
||||
// 0x4C6900
|
||||
void _GNW_rect_exit()
|
||||
{
|
||||
while (_rectList != NULL) {
|
||||
RectListNode* next = _rectList->next;
|
||||
internal_free(_rectList);
|
||||
_rectList = next;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C6924
|
||||
void _rect_clip_list(RectListNode** rectListNodePtr, Rect* rect)
|
||||
{
|
||||
Rect v1;
|
||||
rectCopy(&v1, rect);
|
||||
|
||||
// NOTE: Original code is slightly different.
|
||||
while (*rectListNodePtr != NULL) {
|
||||
RectListNode* rectListNode = *rectListNodePtr;
|
||||
if (v1.right >= rectListNode->rect.left
|
||||
&& v1.bottom >= rectListNode->rect.top
|
||||
&& v1.left <= rectListNode->rect.right
|
||||
&& v1.top <= rectListNode->rect.bottom) {
|
||||
Rect v2;
|
||||
rectCopy(&v2, &(rectListNode->rect));
|
||||
|
||||
*rectListNodePtr = rectListNode->next;
|
||||
|
||||
rectListNode->next = _rectList;
|
||||
_rectList = rectListNode;
|
||||
|
||||
if (v2.top < v1.top) {
|
||||
RectListNode* newRectListNode = _rect_malloc();
|
||||
if (newRectListNode == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
rectCopy(&(newRectListNode->rect), &v2);
|
||||
newRectListNode->rect.bottom = v1.top - 1;
|
||||
newRectListNode->next = *rectListNodePtr;
|
||||
|
||||
*rectListNodePtr = newRectListNode;
|
||||
rectListNodePtr = &(newRectListNode->next);
|
||||
|
||||
v2.top = v1.top;
|
||||
}
|
||||
|
||||
if (v2.bottom > v1.bottom) {
|
||||
RectListNode* newRectListNode = _rect_malloc();
|
||||
if (newRectListNode == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
rectCopy(&(newRectListNode->rect), &v2);
|
||||
newRectListNode->rect.top = v1.bottom + 1;
|
||||
newRectListNode->next = *rectListNodePtr;
|
||||
|
||||
*rectListNodePtr = newRectListNode;
|
||||
rectListNodePtr = &(newRectListNode->next);
|
||||
|
||||
v2.bottom = v1.bottom;
|
||||
}
|
||||
|
||||
if (v2.left < v1.left) {
|
||||
RectListNode* newRectListNode = _rect_malloc();
|
||||
if (newRectListNode == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
rectCopy(&(newRectListNode->rect), &v2);
|
||||
newRectListNode->rect.right = v1.left - 1;
|
||||
newRectListNode->next = *rectListNodePtr;
|
||||
|
||||
*rectListNodePtr = newRectListNode;
|
||||
rectListNodePtr = &(newRectListNode->next);
|
||||
}
|
||||
|
||||
if (v2.right > v1.right) {
|
||||
RectListNode* newRectListNode = _rect_malloc();
|
||||
if (newRectListNode == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
rectCopy(&(newRectListNode->rect), &v2);
|
||||
newRectListNode->rect.left = v1.right + 1;
|
||||
newRectListNode->next = *rectListNodePtr;
|
||||
|
||||
*rectListNodePtr = newRectListNode;
|
||||
rectListNodePtr = &(newRectListNode->next);
|
||||
}
|
||||
} else {
|
||||
rectListNodePtr = &(rectListNode->next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C6BB8
|
||||
RectListNode* _rect_malloc()
|
||||
{
|
||||
if (_rectList == NULL) {
|
||||
for (int index = 0; index < 10; index++) {
|
||||
RectListNode* rectListNode = internal_malloc(sizeof(*rectListNode));
|
||||
if (rectListNode == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
_rect_free(rectListNode);
|
||||
}
|
||||
}
|
||||
|
||||
if (_rectList == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RectListNode* rectListNode = _rectList;
|
||||
_rectList = _rectList->next;
|
||||
|
||||
return rectListNode;
|
||||
}
|
||||
|
||||
// 0x4C6C04
|
||||
void _rect_free(RectListNode* rectListNode)
|
||||
{
|
||||
rectListNode->next = _rectList;
|
||||
_rectList = rectListNode;
|
||||
}
|
||||
|
||||
// Calculates a union of two source rectangles and places it into result
|
||||
// rectangle.
|
||||
//
|
||||
// 0x4C6C18
|
||||
void rectUnion(const Rect* s1, const Rect* s2, Rect* r)
|
||||
{
|
||||
r->left = min(s1->left, s2->left);
|
||||
r->top = min(s1->top, s2->top);
|
||||
r->right = max(s1->right, s2->right);
|
||||
r->bottom = max(s1->bottom, s2->bottom);
|
||||
}
|
||||
|
||||
// Calculates intersection of two source rectangles and places it into third
|
||||
// rectangle and returns 0. If two source rectangles do not have intersection
|
||||
// it returns -1 and resulting rectangle is a copy of s1.
|
||||
//
|
||||
// 0x4C6C68
|
||||
int rectIntersection(const Rect* s1, const Rect* s2, Rect* r)
|
||||
{
|
||||
r->left = s1->left;
|
||||
r->top = s1->top;
|
||||
r->right = s1->right;
|
||||
r->bottom = s1->bottom;
|
||||
|
||||
if (s1->left <= s2->right && s2->left <= s1->right && s2->bottom >= s1->top && s2->top <= s1->bottom) {
|
||||
if (s2->left > s1->left) {
|
||||
r->left = s2->left;
|
||||
}
|
||||
|
||||
if (s2->right < s1->right) {
|
||||
r->right = s2->right;
|
||||
}
|
||||
|
||||
if (s2->top > s1->top) {
|
||||
r->top = s2->top;
|
||||
}
|
||||
|
||||
if (s2->bottom < s1->bottom) {
|
||||
r->bottom = s2->bottom;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue