From c4356466796c697dfd298010b9bed261f9ed8c6a Mon Sep 17 00:00:00 2001 From: KholdFuzion Date: Mon, 17 Aug 2026 13:48:42 -0400 Subject: [PATCH] james bond will return. --- Makefile | 11 +- assets/obseg/Makefile.setup | 2 +- docs/SetupGuide.md | 5 +- include/Makefile.targets | 7 +- include/ultra64.h | 5 - ld/game.bss.ld.inc | 6 +- ld/game.data.ld.inc | 2 + ld/game.rodata.ld.inc | 6 +- ld/game.text.ld.inc | 3 + .../generate_prop_model_c.cpython-312.pyc | Bin 0 -> 102699 bytes src/game/bg.c | 99 +- src/game/bg_portal_table.c | 7 + src/game/bondview.c | 10625 +-------------- src/game/bondview2.c | 10757 ++++++++++++++++ src/game/bondview_internal.h | 217 + src/game/chraction.c | 35 +- src/game/chraction.h | 2 +- src/game/gun.c | 5915 +-------- src/game/gun_rodata.c | 10 + src/game/gunfire.c | 6465 ++++++++++ src/game/initpathtablelinks.c | 2 +- src/game/line_tri_intersect.c | 2 +- .../__pycache__/diff_settings.cpython-312.pyc | Bin 464 -> 0 bytes tools/asm-processor/LICENSE | 24 - tools/asm-processor/README.md | 139 - tools/asm-processor/add-test.sh | 7 - tools/asm-processor/asm_processor.py | 1652 --- tools/asm-processor/build.py | 145 - tools/asm-processor/compile-test.sh | 41 - tools/asm-processor/dist-workspace.toml | 13 - tools/asm-processor/include-stdin.c | 2 - tools/asm-processor/mypy.ini | 3 - tools/asm-processor/prelude.inc | 55 - tools/asm-processor/run-tests.sh | 23 - tools/asm-processor/rust/Cargo.lock | 236 - tools/asm-processor/rust/Cargo.toml | 24 - tools/asm-processor/rust/src/main.rs | 518 - tools/asm-processor/rust/src/postprocess.rs | 1312 -- tools/asm-processor/rust/src/preprocess.rs | 961 -- tools/asm-processor/tests/ascii.c | 19 - tools/asm-processor/tests/ascii.objdump | 29 - tools/asm-processor/tests/comments.c | 6 - tools/asm-processor/tests/comments.objdump | 21 - tools/asm-processor/tests/custom-prelude.c | 17 - .../tests/custom-prelude.objdump | 21 - tools/asm-processor/tests/custom-prelude.s | 14 - tools/asm-processor/tests/euc_jp_wavedash.c | 3 - .../tests/euc_jp_wavedash.objdump | 26 - tools/asm-processor/tests/force.c | 17 - tools/asm-processor/tests/force.objdump | 47 - .../tests/include_file.asmproc.d | 12 - tools/asm-processor/tests/include_file.c | 8 - .../asm-processor/tests/include_file.objdump | 27 - tools/asm-processor/tests/include_file_1.s | 7 - tools/asm-processor/tests/include_file_2.s | 7 - tools/asm-processor/tests/include_file_3.s | 7 - tools/asm-processor/tests/include_file_4.s | 1 - tools/asm-processor/tests/kpic-o1.c | 93 - tools/asm-processor/tests/kpic-o1.objdump | 46 - tools/asm-processor/tests/kpic-o2.c | 92 - tools/asm-processor/tests/kpic-o2.objdump | 46 - tools/asm-processor/tests/label-sameline.c | 7 - .../tests/label-sameline.objdump | 25 - tools/asm-processor/tests/large.c | 164 - tools/asm-processor/tests/large.objdump | 58 - tools/asm-processor/tests/late_rodata_align.c | 80 - .../tests/late_rodata_align.objdump | 51 - .../asm-processor/tests/late_rodata_doubles.c | 83 - .../tests/late_rodata_doubles.objdump | 55 - .../tests/late_rodata_doubles_mips1.c | 86 - .../tests/late_rodata_doubles_mips1.objdump | 52 - tools/asm-processor/tests/late_rodata_jtbl.c | 153 - .../tests/late_rodata_jtbl.objdump | 110 - .../tests/late_rodata_jtbl_mips1.c | 155 - .../tests/late_rodata_jtbl_mips1.objdump | 110 - .../tests/late_rodata_misaligned_doubles.c | 77 - .../late_rodata_misaligned_doubles.objdump | 56 - .../tests/line-continuation-separate-file.s | 4 - .../tests/line-continuation.asmproc.d | 3 - tools/asm-processor/tests/line-continuation.c | 22 - .../tests/line-continuation.objdump | 30 - tools/asm-processor/tests/o0.c | 28 - tools/asm-processor/tests/o0.objdump | 44 - tools/asm-processor/tests/o2.c | 26 - tools/asm-processor/tests/o2.objdump | 40 - tools/asm-processor/tests/pascal.objdump | 137 - tools/asm-processor/tests/pascal.p | 95 - tools/asm-processor/tests/static-global.c | 35 - .../asm-processor/tests/static-global.objdump | 60 - tools/asm-processor/tests/static.c | 32 - tools/asm-processor/tests/static.objdump | 58 - tools/asm-processor/tests/test1.c | 71 - tools/asm-processor/tests/test1.objdump | 54 - tools/asm-processor/tests/test2.c | 69 - tools/asm-processor/tests/test2.objdump | 76 - tools/asm-processor/tests/test3.c | 70 - tools/asm-processor/tests/test3.objdump | 64 - tools/ge-stats.py | 12 +- tools/include-stdin.c | 2 + tools/report/main.c | 9 +- 100 files changed, 17579 insertions(+), 24688 deletions(-) create mode 100644 scripts/__pycache__/generate_prop_model_c.cpython-312.pyc create mode 100644 src/game/bg_portal_table.c create mode 100644 src/game/bondview2.c create mode 100644 src/game/bondview_internal.h create mode 100644 src/game/gun_rodata.c create mode 100644 src/game/gunfire.c delete mode 100644 tools/__pycache__/diff_settings.cpython-312.pyc delete mode 100644 tools/asm-processor/LICENSE delete mode 100644 tools/asm-processor/README.md delete mode 100755 tools/asm-processor/add-test.sh delete mode 100644 tools/asm-processor/asm_processor.py delete mode 100644 tools/asm-processor/build.py delete mode 100755 tools/asm-processor/compile-test.sh delete mode 100644 tools/asm-processor/dist-workspace.toml delete mode 100644 tools/asm-processor/include-stdin.c delete mode 100644 tools/asm-processor/mypy.ini delete mode 100644 tools/asm-processor/prelude.inc delete mode 100755 tools/asm-processor/run-tests.sh delete mode 100644 tools/asm-processor/rust/Cargo.lock delete mode 100644 tools/asm-processor/rust/Cargo.toml delete mode 100644 tools/asm-processor/rust/src/main.rs delete mode 100644 tools/asm-processor/rust/src/postprocess.rs delete mode 100644 tools/asm-processor/rust/src/preprocess.rs delete mode 100644 tools/asm-processor/tests/ascii.c delete mode 100644 tools/asm-processor/tests/ascii.objdump delete mode 100644 tools/asm-processor/tests/comments.c delete mode 100644 tools/asm-processor/tests/comments.objdump delete mode 100644 tools/asm-processor/tests/custom-prelude.c delete mode 100644 tools/asm-processor/tests/custom-prelude.objdump delete mode 100644 tools/asm-processor/tests/custom-prelude.s delete mode 100644 tools/asm-processor/tests/euc_jp_wavedash.c delete mode 100644 tools/asm-processor/tests/euc_jp_wavedash.objdump delete mode 100644 tools/asm-processor/tests/force.c delete mode 100644 tools/asm-processor/tests/force.objdump delete mode 100644 tools/asm-processor/tests/include_file.asmproc.d delete mode 100644 tools/asm-processor/tests/include_file.c delete mode 100644 tools/asm-processor/tests/include_file.objdump delete mode 100644 tools/asm-processor/tests/include_file_1.s delete mode 100644 tools/asm-processor/tests/include_file_2.s delete mode 100644 tools/asm-processor/tests/include_file_3.s delete mode 100644 tools/asm-processor/tests/include_file_4.s delete mode 100644 tools/asm-processor/tests/kpic-o1.c delete mode 100644 tools/asm-processor/tests/kpic-o1.objdump delete mode 100644 tools/asm-processor/tests/kpic-o2.c delete mode 100644 tools/asm-processor/tests/kpic-o2.objdump delete mode 100644 tools/asm-processor/tests/label-sameline.c delete mode 100644 tools/asm-processor/tests/label-sameline.objdump delete mode 100644 tools/asm-processor/tests/large.c delete mode 100644 tools/asm-processor/tests/large.objdump delete mode 100644 tools/asm-processor/tests/late_rodata_align.c delete mode 100644 tools/asm-processor/tests/late_rodata_align.objdump delete mode 100644 tools/asm-processor/tests/late_rodata_doubles.c delete mode 100644 tools/asm-processor/tests/late_rodata_doubles.objdump delete mode 100644 tools/asm-processor/tests/late_rodata_doubles_mips1.c delete mode 100644 tools/asm-processor/tests/late_rodata_doubles_mips1.objdump delete mode 100644 tools/asm-processor/tests/late_rodata_jtbl.c delete mode 100644 tools/asm-processor/tests/late_rodata_jtbl.objdump delete mode 100644 tools/asm-processor/tests/late_rodata_jtbl_mips1.c delete mode 100644 tools/asm-processor/tests/late_rodata_jtbl_mips1.objdump delete mode 100644 tools/asm-processor/tests/late_rodata_misaligned_doubles.c delete mode 100644 tools/asm-processor/tests/late_rodata_misaligned_doubles.objdump delete mode 100644 tools/asm-processor/tests/line-continuation-separate-file.s delete mode 100644 tools/asm-processor/tests/line-continuation.asmproc.d delete mode 100644 tools/asm-processor/tests/line-continuation.c delete mode 100644 tools/asm-processor/tests/line-continuation.objdump delete mode 100644 tools/asm-processor/tests/o0.c delete mode 100644 tools/asm-processor/tests/o0.objdump delete mode 100644 tools/asm-processor/tests/o2.c delete mode 100644 tools/asm-processor/tests/o2.objdump delete mode 100644 tools/asm-processor/tests/pascal.objdump delete mode 100644 tools/asm-processor/tests/pascal.p delete mode 100644 tools/asm-processor/tests/static-global.c delete mode 100644 tools/asm-processor/tests/static-global.objdump delete mode 100644 tools/asm-processor/tests/static.c delete mode 100644 tools/asm-processor/tests/static.objdump delete mode 100644 tools/asm-processor/tests/test1.c delete mode 100644 tools/asm-processor/tests/test1.objdump delete mode 100644 tools/asm-processor/tests/test2.c delete mode 100644 tools/asm-processor/tests/test2.objdump delete mode 100644 tools/asm-processor/tests/test3.c delete mode 100644 tools/asm-processor/tests/test3.objdump create mode 100644 tools/include-stdin.c diff --git a/Makefile b/Makefile index 79ecac2f..f6865e16 100644 --- a/Makefile +++ b/Makefile @@ -216,8 +216,6 @@ ifneq (,$(shell which armips 2>/dev/null)) else ARMIPS := $(TOOLS_DIR)/armips endif -ASM_PROCESSOR_DIR := tools/asm-processor -ASM_PREPROC := python3 $(ASM_PROCESSOR_DIR)/asm_processor.py OBJCOPY := $(TOOLCHAIN)objcopy @@ -288,11 +286,8 @@ $(BUILD_DIR)/$(OBSEGMENT): $(OBSEG_RZ) $(IMAGE_OBJS) #Build C files in src/ # convert AI_PRINT commands from readable to byte-array $(BUILD_DIR)/src/%.o: src/%.c - @if grep -q 'GLOBAL_ASM(' $<; then \ - $(ASM_PREPROC) $(OPTIMIZATION) $< | $(CC) -c $(CFLAGS) $(ASM_PROCESSOR_DIR)/include-stdin.c -o $@ $(OPTIMIZATION); \ - $(ASM_PREPROC) $(OPTIMIZATION) $< --post-process $@ --assembler "$(AS) $(ASFLAGS)" --asm-prelude $(ASM_PROCESSOR_DIR)/prelude.inc; \ - elif [ "$$(basename $<)" = "chraidata.c" ]; then \ - $(ConvertAIPRINT) $< | $(CC) -c $(CFLAGS) $(ASM_PROCESSOR_DIR)/include-stdin.c -o $@ $(OPTIMIZATION); \ + @if [ "$$(basename $<)" = "chraidata.c" ]; then \ + $(ConvertAIPRINT) $< | $(CC) -c $(CFLAGS) tools/include-stdin.c -o $@ $(OPTIMIZATION); \ else \ $(CC) -c $(CFLAGS) -o $@ $(OPTIMIZATION) $<; \ fi @@ -317,7 +312,7 @@ $(BUILD_DIR)/assets/obseg/%.o: assets/obseg/%.s $(OBSEG_RZ) #Build C files in assets/ $(BUILD_DIR)/assets/%.o: assets/%.c ifeq ($(filter-out %setup%,$<),) - $(ConvertAIPRINT) $< | $(CC) -c $(CFLAGS) $(ASM_PROCESSOR_DIR)/include-stdin.c -o $@ $(OPTIMIZATION) + $(ConvertAIPRINT) $< | $(CC) -c $(CFLAGS) tools/include-stdin.c -o $@ $(OPTIMIZATION) else $(CC) -c $(CFLAGS) -o $@ $(OPTIMIZATION) $< endif diff --git a/assets/obseg/Makefile.setup b/assets/obseg/Makefile.setup index 7f559538..06a5f064 100644 --- a/assets/obseg/Makefile.setup +++ b/assets/obseg/Makefile.setup @@ -29,7 +29,7 @@ $(BUILD_DIR)/$(OBSEG_DIR)/setup/%.o: $(OBSEG_DIR)/setup/$(COUNTRYCODE)/%.c $(CC) -c $(CFLAGS) -o $@ -O2 $< $(BUILD_DIR)/$(OBSEG_DIR)/setup/%.o: $(OBSEG_DIR)/setup/%.c - $(ConvertAIPRINT) $< | $(CC) -c $(CFLAGS) tools/asm-processor/include-stdin.c -o $@ $(OPTIMIZATION) + $(ConvertAIPRINT) $< | $(CC) -c $(CFLAGS) tools/include-stdin.c -o $@ $(OPTIMIZATION) # Generate all file targets SETUP_O_FILES := $(foreach name,$(SETUP_NAMES),$(BUILD_DIR)/$(OBSEG_DIR)/setup/$(name).o) diff --git a/docs/SetupGuide.md b/docs/SetupGuide.md index d7bc5af7..1688aa53 100644 --- a/docs/SetupGuide.md +++ b/docs/SetupGuide.md @@ -202,9 +202,8 @@ The c compiler can be found in `tools/irix/root/usr/bin/cc`. This splits the com ### Assembly Preprocessor -There is a (much forked) preprocessor used by many N64 projects, found in `tools/asm-processor/asm_processor.py`. This searches for a line -beginning with `GLOBAL_ASM(` and a subsequent line beginning with `)` and treats everything in between as assembly. This is bundled with any -c code in the file and sent to the compiler. +`GLOBAL_ASM` is retired in this repository, so no asm preprocessor step is used during normal builds. +Source `.c` files are compiled directly by the IRIX compiler. ### Code build process diff --git a/include/Makefile.targets b/include/Makefile.targets index 2a8ce7c9..9157617a 100644 --- a/include/Makefile.targets +++ b/include/Makefile.targets @@ -50,12 +50,7 @@ $(BUILD_DIR)/$(OBSEGMENT): $(OBSEG_RZ) $(IMAGE_OBJS) #Build C files in src/ $(BUILD_DIR)/src/%.o: src/%.c - @if grep -q 'GLOBAL_ASM(' $<; then \ - $(ASM_PREPROC) $(OPTIMIZATION) $< | $(CC) -c $(CFLAGS) tools/asm-processor/include-stdin.c -o $@ $(OPTIMIZATION); \ - $(ASM_PREPROC) $(OPTIMIZATION) $< --post-process $@ --assembler "$(AS) $(ASFLAGS)" --asm-prelude tools/asm-processor/prelude.s; \ - else \ - $(CC) -c $(CFLAGS) -o $@ $(OPTIMIZATION) $<; \ - fi + $(CC) -c $(CFLAGS) -o $@ $(OPTIMIZATION) $< #Build RamRom diff --git a/include/ultra64.h b/include/ultra64.h index a88461c8..8c834384 100644 --- a/include/ultra64.h +++ b/include/ultra64.h @@ -18,8 +18,3 @@ #include #endif - -//temporary catchall fix since not all files in master include bondgame -#ifdef __INTELLISENSE__ -#define GLOBAL_ASM(...) -#endif diff --git a/ld/game.bss.ld.inc b/ld/game.bss.ld.inc index 459f26c8..42b2b5f7 100644 --- a/ld/game.bss.ld.inc +++ b/ld/game.bss.ld.inc @@ -70,12 +70,15 @@ build/OUTCODE/src/game/math_floor.o (.bss); build/OUTCODE/src/game/math_ceil.o (.bss); build/OUTCODE/src/game/gun.o (.bss); + build/OUTCODE/src/game/gun_rodata.o (.bss); + build/OUTCODE/src/game/gunfire.o (.bss); build/OUTCODE/src/game/bondwalk2.o (.bss); build/OUTCODE/src/game/objecthandler.o (.bss); build/OUTCODE/src/game/model.o (.bss); build/OUTCODE/src/game/objecthandler_2.o (.bss); build/OUTCODE/src/game/othermodemicrocode.o (.bss); build/OUTCODE/src/game/bondview.o (.bss); + build/OUTCODE/src/game/bondview2.o (.bss); build/OUTCODE/src/game/bondinv.o (.bss); build/OUTCODE/src/game/bondhead.o (.bss); build/OUTCODE/src/game/padhalllv.o (.bss); @@ -103,6 +106,7 @@ build/OUTCODE/src/game/stan.o (.bss); build/OUTCODE/src/game/stanintersection.o (.bss); build/OUTCODE/src/game/bg.o (.bss); + build/OUTCODE/src/game/bg_portal_table.o (.bss); build/OUTCODE/src/game/bgapply.o (.bss); build/OUTCODE/src/game/bgfog.o (.bss); build/OUTCODE/src/game/lightfixture.o (.bss); @@ -132,4 +136,4 @@ build/OUTCODE/src/game/music_0D2720.o (.bss); #ifndef VERSION_EU build/OUTCODE/src/game/spectrum.o (.bss); -#endif \ No newline at end of file +#endif diff --git a/ld/game.data.ld.inc b/ld/game.data.ld.inc index 327b371b..811be6c5 100644 --- a/ld/game.data.ld.inc +++ b/ld/game.data.ld.inc @@ -70,12 +70,14 @@ build/OUTCODE/src/game/math_floor.o (.data); build/OUTCODE/src/game/math_ceil.o (.data); build/OUTCODE/src/game/gun.o (.data); + build/OUTCODE/src/game/gun_rodata.o (.data); build/OUTCODE/src/game/bondwalk2.o (.data); build/OUTCODE/src/game/objecthandler.o (.data); build/OUTCODE/src/game/model.o (.data); build/OUTCODE/src/game/objecthandler_2.o (.data); build/OUTCODE/src/game/othermodemicrocode.o (.data); build/OUTCODE/src/game/bondview.o (.data); + build/OUTCODE/src/game/bondview2.o (.data); build/OUTCODE/src/game/bondinv.o (.data); build/OUTCODE/src/game/bondhead.o (.data); build/OUTCODE/src/game/padhalllv.o (.data); diff --git a/ld/game.rodata.ld.inc b/ld/game.rodata.ld.inc index c23cbd5e..2c43979e 100644 --- a/ld/game.rodata.ld.inc +++ b/ld/game.rodata.ld.inc @@ -70,12 +70,16 @@ build/OUTCODE/src/game/math_floor.o (.rodata); build/OUTCODE/src/game/math_ceil.o (.rodata); build/OUTCODE/src/game/gun.o (.rodata); + build/OUTCODE/src/game/gun_rodata.o (.rodata); + build/OUTCODE/src/game/gunfire.o (.rodata); + build/OUTCODE/src/game/gunfire.o (.data); build/OUTCODE/src/game/bondwalk2.o (.rodata); build/OUTCODE/src/game/objecthandler.o (.rodata); build/OUTCODE/src/game/model.o (.rodata); build/OUTCODE/src/game/objecthandler_2.o (.rodata); build/OUTCODE/src/game/othermodemicrocode.o (.rodata); build/OUTCODE/src/game/bondview.o (.rodata); + build/OUTCODE/src/game/bondview2.o (.rodata); build/OUTCODE/src/game/bondinv.o (.rodata); build/OUTCODE/src/game/bondhead.o (.rodata); build/OUTCODE/src/game/padhalllv.o (.rodata); @@ -132,4 +136,4 @@ build/OUTCODE/src/game/music_0D2720.o (.rodata); #ifndef VERSION_EU build/OUTCODE/src/game/spectrum.o (.rodata); -#endif \ No newline at end of file +#endif diff --git a/ld/game.text.ld.inc b/ld/game.text.ld.inc index 24ec692d..dab58ca7 100644 --- a/ld/game.text.ld.inc +++ b/ld/game.text.ld.inc @@ -70,12 +70,15 @@ build/OUTCODE/src/game/math_floor.o (.text); build/OUTCODE/src/game/math_ceil.o (.text); build/OUTCODE/src/game/gun.o (.text); + build/OUTCODE/src/game/gun_rodata.o (.text); + build/OUTCODE/src/game/gunfire.o (.text); build/OUTCODE/src/game/bondwalk2.o (.text); build/OUTCODE/src/game/objecthandler.o (.text); build/OUTCODE/src/game/model.o (.text); build/OUTCODE/src/game/objecthandler_2.o (.text); build/OUTCODE/src/game/othermodemicrocode.o (.text); build/OUTCODE/src/game/bondview.o (.text); + build/OUTCODE/src/game/bondview2.o (.text); build/OUTCODE/src/game/bondinv.o (.text); build/OUTCODE/src/game/bondhead.o (.text); build/OUTCODE/src/game/padhalllv.o (.text); diff --git a/scripts/__pycache__/generate_prop_model_c.cpython-312.pyc b/scripts/__pycache__/generate_prop_model_c.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..55ec2665a55d7b64f8c5cf73a96c58b7c9893fc2 GIT binary patch literal 102699 zcmeFa30z!PdM8>{R6$V``@X7JBvA+Yt7;y^;34wI0w1985)NLmz zJ4za*lQC}FG3w65D0b2~={Jp&$!nZdon=y})KPVfUPej!C9TX%f~`(E@tgPS`G4mw zb#HMCkZgDIUb-aCJ@=gNd}sf@?|kPw=l*eGqRoKcwbn13{lyzb!(Y>j{7aNPkDE*e z!>b0)&}-m~oN3tDYh+JTuZcZldSmd688)A{^jeGrV;+t@AJ-dq-r8$DAKx2)-qve7 zpU|7Y;w;1V^NGEQ=aYJq@E+Tn%*FMlaMs?`AxatlB_n6!65!goM7T*@GTam{6>b`r z4mX3#gqy`>!?kibaC5mlxcOWG+(NDh?kdg!x0ow|TgsKeUCph58^^7MTh2MT3T_=& z$*t$AxD8zO8`l45>`mipUNZEibG2|YxH`C*Ts_<@ZX?`mZWG)bZZq6mZi_3AYjEWc znz^knnR^Rdi6+Ay1GnuZ1GoJhv=#l{5g&%$LMe6!Vs|czEs|n)A@-R?v8x!~M#MGA zalH<%8D%KuT3q=kgUuC}i=0rBR+OZKJI3vHm2!LVw-@nkc7a>WvT_~3w3gxTbj5Lp@V5_tT}VfDwsYNxFXwt(tJu4l zJB)WHcLb%XaINExo+~#Pc&o|as*u~jXc#k%nViS_ccXD^&7Hr#Kre}5ZLT+k6z*jT#f-iI?7oNRRhi{n@!4d_b7k9-?P=`z^`L) z(CzX#s;^d8Z*_EE8S)IA0g8T}?;mrN4-Gm-E}d6GcRH$_+C;l{ZFTgxu6i!9^S$hld>(Mu$c`F5c}J8gY2exa2nKM|s?yQ68}UZpSFAquVjakDhm&>USe6 zj^kZ!H&uIMHTzZBdXW5d|9RJ1w_|v;pX(bvb=EcD=|e*g_nmR|b1uHziSmtHcJUrJ zWd=N+QAbzf!Eh=1Jr4fTh-c`$3$1XdLTJTehi2K7kmWfsH&fD=I5Ormh2p8f28R3H?vQ10$TiFj0g2^N3fxCl zI3aWU;R6RA8Oa;Fx3#gQwd)a0=a6MjSI6PbM==bhqqDm1k(s=vmIIG0a@fX4v9fp5 zqd3{SITUlCqvcUNy~i|lcRnI=8!|UFbsT$?AOY3XJhGEFZqMQN-ECd1kBIPwV!QV? zwsahQlq5sdKT0NVd|P`@YuACc_WdDqM`z6@=57Y~(YBuEz3i=l+}i3;0xNcR+riEQ zt)cjq1D#!M2OGPNhs;#BP(sUr=8gjg+Pd31+MU)%sX+cHjhu9HGRVm!CyShHa&q7d zNc0U}gMq3^jq>;zIIkK!)N<^1Rt+VEaYn%)7zJ>UafIXghGwPPk@#xuKnZquFO54QL> z9|)8lywg8l+UYOod<>}1wn4^CJBPvz!tX?Wd?OsUSaH4ueyRL!l)nwH6$G=JoIP+p z)9ym)_VP4)Sa&U1x=S^i`2B!fN6D(yYL6odAdg-Xa*-)pc`l^A3vN&vS z8{2Q|bV{5!sJ8Hj0KXo8Zkq1b4O3-Pmv2@2^Q)HVo_3bSaOz_7@elz?Q$sa2iUN>-YZ<^2x*74?Mk#jm&*@$sAJBEkAy8DM6 z`VEBVIaowksj$##;U6|zZER^Jd8vRoPBJZD0&XIw+4&v-%! z=Z7ww?}tgLm>39Oq2#{4{*jSUPd~{V?!G?Om=ccF-pjWSGOKZ?qJwq%@KZG~XK!pc;?2h1SW|Jf-UOE&13rN@mkrGo&xR@q^n5c)1wrNlEl(I>4%x+* zK5-BxkfhTm3Ob?03y|eUJo0P82v!ox3zk!t*FeX@ zy~?fOOs*J?$cx!!9*pHISnXQ4SXV3;=ZeMp*oswZ92d{tt$4TLJ)TRzs@2BX0b$}2 z5t6_qA;iul11^QZCIVL~Vv?k^iAbA<_hi+3I^I)M?-_VcRlR58Jx%qVh4*yTdp6!P zRPQ->&s4qV;yp|Co`?5r)q6hPb5!pIc+XY67veon^8QVpcIoIVM($DMgHfTf^eYq*PWZZZ-O%c+BWr8%h<|-fR|#tNr#+g1DmZ zW0Jk~yvx(ieDOo)v2g4Iy&f=&UCvyE1BiK^;MtG8$pq7I zn&K3^>`jrUJa#z^VB!>i%vGb?WHc~5@+dTn8TbxBIOE01@*?~p%Lt~lJCw}323?r7 z11?Ugo4o!HS>2L~A!KiA>~8IAY-#Cg?d}fQX<6PUEz5bTq0<~PyIsSB{1@=T6M7cx zrlLb{A@Ol=siBb}Pha17-l7JslH*PxiTfEi*A2mpRX+2L_+X9$kHlbRHXgR%s$!q{ zp0yyDlgC2E$Af}$3e64XmV9~D)G43&XGDGv`8O*e$e3vLXZW6lsJcRY#Shi%D>9$NCzk zRHEg*qnwmH;?K$G?xP>#2jS?aQ7)&6zkvt;vv4$vtR%=tgj%Akc5X6q$ zBqc(WN=Tlld8Hwko*9I%?0#D5d|K(nNs6jNPyHDqF*EmzTyKM9!IQbSTbG!2<1W>vpf%6Q(qVvkH9)XD!4id0GUEgwZBgJeV8ek7kKCc7*c8s^hFe z#pHN{;VjiT;wQw)t45(=6 zMDB=}>$w7W%M-%KJ|TSE6T(}c5I+71;caU8cN5-`TG1Pa7A3`5#80=s<_dc1?N)k2&$y`{}B9MBM&mo6O!qcST3&~jp$7$tH zlAo5bJc$|n^W^lCL+q3vAcrHT6pquvzf67~IYb5dpMrxmCUpA}<8UT3CLW48?Si73 z?;knsVroZGe0YV@5QF5gt4_R6QbA2X(nvOp^!~%Afm;gM9DAG-cSr0ihl!e?szyPY_OlGIk2#N$Fmnx zZWcjn2=`YZiGf&W=fCQ`>Ajy_KA&AaT{N2-$lm6&2gT5-=jOBPefEc`X}(zK6zn;Z z#dj0(A7tiDZVzOZe`K&G7EBl)6t14)-X6L&G?Nu5+%jQ%m|i$#{JEXMvZ}8a%$M!B zdGKM`>WPEFl#EvsZzkSPDVt9zn>u+fr7oC~HCcQ!;b!bYD)4+i%aE2mAp}y(J~G(j zbA62u(uyABmrk|3-FB;O`f?zD(}S$SN$#zo*M_FEW{Pj;1+wZNWEV|(-Wq#tY`dxyTOhMe2WBxIRY>jab%E?n-%pKC zPx3V{WEc`tzj*NFgZJ%@dAnmO{hobw(4IDN>g5A3?_S77$rl`k>_T5c&}zSLEtt0! zOg?+h>O|wkC*HS~&s)pySu60CTliMuYl*>}0`|zvB_?j1U9C`uGa`2#9oLAKK?6+X(V`Hdg3+m2VuiFX7msw`vJ-<`@>JcC=++D zNdTi7$I#+p#xYR9CQXtL>a(*7GYqHo&@g1bXt=fPLnc{X%TwcHTNQGN6@0{8pRRlw zcBSAW;{9~^H0(^lM@0PT@M+kcf-l}fx@)oJje=Q-5iCNi5GPoL_;;-e3$h6|$m8M2Bb zs+u3j+~~6fb4sTAUrU~@pU>U^K9HI}$<3#h_+o=udH1uN^I6V!%V+Ap(ePfw?72IQ z?~ev5+5=e~Aa^+h_jA_G=d62o?@Z4(j=y(&F5yo92g!lT&Opu~U!q>>rum)ifr^em zRwt6{VAsTF=ikq+n9r_wcgsx6H`?B7n|}?U++cbU)*Qjy z)xn(7VBT7C@jrJpNOy|OXI{uMl&^86Kypr5j- zcUay*6#dv5g~nIJ@2sNn2uH|iAm`5+3@4DvODmX|v$0_q+2=OiNY{@!tB`6L7Gz#o z@p#RG8S9sFj2YvN`Y>_fV&rLy+^->L%M)NX3l{9NSl*1`Vr7znRZuJ!OOqe@I6<-u zdi&CsDRzr~oWQhOkgntOR#OV@qlnibUXZ4Zy5vb0n_wMOR#`^FjnA76H+}~)xe;w~ zO6-YOY+h@4P2{r;!lLOVBKCTHOMCYbzi{8mKDoWU@j^Urys`0RBH<(vNBk}u(MBzZ z(~
  • &rH|#r0Fa%(e?|aAw1p)fqqD+DS4j3{z-ppX5|WSbBAw0>zb$Sv+T8NJ4sV z?1#ayMbSApnB;5eV;eZ}u&)5U9_2ZntQSHSrT`DcN%A(6`!&mcnk;qrd%PXaFBtb5 zjBN3L5{pwz6r&yodzlT^|6qL8h>pobH4MKRbHyks{)~*IJ7Yqos%rjSDgibh2c_KI zl$pbEoe|TIx6NXO)71IF7pv&Od+8@Xyx` z9~okblOAT|fJmff-cNDNr#PneeLJPi0rlpWnXu^_P}EF5(a z{}l?rd`8oVyA#B3q-J8vLU&0gs#iI)K@RIdLNK_l(GpZXsrT{S&p` zUlX!DU`}W!kny78*AM%xc@K+Mznyn0?|yO3d~r>nxb7oETKsY2yuHx3e=-A_xmO#0 zt|6F`gEoD&?PlAn2X7vnS{uly@U<@34JnzE34!F&2f0O)7hli$$Pkx$+&Iw~EM5C{ z!>tBpGqQ0ubv9;pv%jW!?ogm~&%}XXcIi}qAbaiff!UUC?t6dV-OAm;)y}tjZ}raD z=U4BTv<355-_Ng^&##$j4CHTo=&ZZ%+&b^vI=L@cP<6kccD|r?X5an#ee?DE?(Fl| z9sPE}u@93e--T={_dhKNZ+eQwl z*hCf4R`RVT#|bBt(8u>*kySiNp)|H?=sV4iUb@i7Gwu{h5yMWom5@{^zzjb4!hrGhYn)#0I$b5c0W zl9-B0p(_&aloleybe36&P;m-MV=k&Tj`X;}9lRA9eeEPcS{eko?e)|@6 zc=ddG^$hUr@Y{E&@kfKNoKLTuem0Qa;I}uZ@l?&HS53bVNZ;nSZ&Qay!@qVueeHBY zAidsiuUF?AtzH}F(>KnX3#2#s?M-U@(aNbV4_XvkEZfBG6>%k^mOPdHl)GquoEI>L zE!aR!)sW~*`h}H2%R@p{gcP!zxdQkY4ZOl5qLoCeI@0WE=$4$*sB%^SuTj;k0A8bt z(dS0tl~dGOY4#&zX@3Q+r`ea_Y;V{=TNB31JDKFp1o5uX7P3#-LnKa=za8bZTOhx~ zp3n)?<8Zi&YL=o8`L*N_!xV`v=}8!Mb=vq}gFj>)<%doWjr3hrd}E4lJY+pf%L6j* zvcY(uC_5pHPYbl>IC;Y+aX;`_OwOKxW@GZhrY z;r&#ogXDxYFt6fOy_L!T4g&P{E+zV_BL3@$Ed3V18Cl9IeE=OuJqe4`gMplls<)Yo zx6cN08uUUOQyFjP-pZZcJ=1l2e;{YegFFSt41fDvAaCnRLV_i0?w4$wFWLC@Gqav= zj=ev2XN|x6@VC|lHXR9+9DT5+dM4u=x$ou9?w;#l;=~xp-NeQBS!hY4|pcUR^x# zQWwQWPCqvD!jsM_PC7f=IP1gy*eMquGG9GEG(v9w)sT6N`Nx=locYJ$2fuDb|BKUw zY;5^O^W*mrI$j!Wt#&Fb_H3o;@za17r-$=FLD^K#+sAJmpNS0=Y<`fT-Gs^5xO50@ zr(|qW!>l~yL(=3eU>zmyifD$r4FzPw{eQu;GXD1eFRq32bJjQFXju05qQ@3914R|% zD6iQhu>zY-Ucq3jx`2L|Pi>>{4IAi~ zl7fta7+C++#bEUsu&~~!qH%B#hnd{lL~L6e<G2xxM+6&3CcKL5^Z*e7YU?!agP8PlRL+dRs5h}&6MZuv0Gy^Yi8@-s|*zE z(g`Wj!W8XN?E%l0zE=<^-1#6U%n`e99{|@378HG$Y^C{Y)tkSxpkwowHYu6C4@wsK zTYdwRGpZ%acO)Fx&eYX#tN@>e(JA<1o*JKq5i0n!_C@B%dXqG+m4Uq$jg+dNLcJ{t?~vjhprlk1oXK%}Y$A~8%80t5%o*XJKhdBP5!C~c z60bq!C?A#1qH0-*czD85LC>K97Z{WJCt}?KtX=Goii6JF5}2lBIK0LZL3GnWBjRWV zj&>&6!88_JiH^K1i%sc?Fj^5?s|K5*H_}H)iE)OhLI)d)%@Ed54=C~aXrx+JbkgdN z9Vu3~m57GgpT#>a(V1iM__l6aF_EALdlPCTQemjQS-gWbFL3w@CxSFch_TZzQU+jw z5|TzB=@O4Xi)u*5ay4i!j}CE2QqcrU=0=!OYl5(!v9? zO<-&8M|q%5p*+gnC7UfB@+E7|Vr?};bAZa~A$@1uw19Fv-(H9w&#`gI7 zSU1VwRv8G3c9{k!2}2306jzM8tM2Dl&F5FWdv(_Q&G`4@ zaR9pcgYAJ0oq_yAerrw;$@A9F=dFMD%#7z7WABa4t+`Y8L1mz-BaqkWOMZ~OYRdd} z{H^%uO*756w+FJf`0NjgozrDsbKZ8&9GM+>??j-u$!{$RmX+Tx+dN;k`9E9dGX604 zgWNm2{fCc#>tJ9@Z=md1zqL46SbV>*dcLsw>p8P!-*mq3#Gy^@gOh=p?m%G=_VFHM zhK=^hZWjhJH~VaA(Xi+C!9dPdU*dw*&~7|w^!Gh~_u%sr^^!(-*X)6N>23bOGd}Br z$uMkeHK7~#n%Ye0ond2}X|m^jVf}nzy?kOIi zSI%cu`q%H8E4Y`{?jO0}OMtGlL&~oGd4eFzmg%b54fnG4QFaNzu2X*3;N7mlNwa9z z;;-C3J9;mt-9J2n(#9IHYJ)|UK}U6PRaMa06fCL7X$^Ao*97y*f`t|2DXjP~KZyk1 zBt3zbHn5n$I|UCdSf5s$k_CfzBw_4n@o1OBGBz&ejTi_A=J7pCN(Qn#P}3mF1Gt{z z^bmH%D;>4f;>8#juwMrHqGw_38o9cA|&b@Pt8ukW4h`R4KWkKc*) zAL{y+El}SbaP)i_XQAG-==G+eUUxtgT$%bo?za^vd^L-Z6~Jp287qL-8um-$2#by= z8v_yQ_2uC;3kYCU^lj)9>8BC?C2?AgqbC+Xy32;A#->?H$fI4epwKUcW?mUH?@ARCt8%G*r;?Orf6osh6rpK0WC zwyO2`q@&jh2^O!uUtB+5T>tfBv)ng_-XFS?Ijf`Fysgbnc5n5|4P^|=1qt(1epsJIhw2F7q&(p6P zQkuBZ7T4)plx3>4e3e^-&gRxMhf5twTikxSD_c^tg%`D0^06sxL5qOxu*aDA06UVa zulQ;eUtP%Jrm{jVWII}HvbPfMMRMVv(PS@=Hrb)05W8J6ZuxbZ?_U(>J9OX`4>GmO zqs%QU3QM<`n{!T6C$nafXoEoo8n6n#lc zqrP6j)Yp&}E{<)6S@rg4nfXIEv(-|jeYI>Hk-8{0Qsz=jB&2N~{w@u|06F*IgkqUN zLyh#T8{-Uxw?HFDj{u7Pi6^wZe zdsOTaoQrwgURVLTczL+Xo0`s$T^%9b$QIt!T!q#Utt@HG%al95e`M%<--UkOLtC1n zl@HsqOoK@yHVN1$l?AnYv=LuG4pXEtkRMbY&sk$Iij8gbh!RG4h;->WC$_@kV+VqNhFa)3RfhVP$rG?MO9?OUDi9%@Wi@U(o&gJLv)dN z@uvVC-w;i_pfRaqZ~K=tI%|*;qchErwO+M&z`1F)O1AO#R-8EgFwRUXL$lt>FcE0j zxcLZ3)rZQW(k;!lxOlqv+-6M5Wli))VEFHiSpg-|P*mv<*-|-}Wva_^uyEQfaD9nD zL;E$WSbcac^;I}U)K=0+5G%m1p}utTb_HoP3zQYKt47}hW6yZ3tP}eGD>{DhMDAv` z-17XD_nn+iGiTXSrdGX_VXFn%k=8ZkwYrNLIWbwRglDpxR-F2<@6k`pw%#h({Zcw< zrM)*T;b1$0lFh4{pE)YTH{cN$H}#HkrVGOcE64}URQTw?Q<#KMDQRsKUKc6lmOYUR zB?=cyt-oD}Xfa86H5aipNNcNF>Edd_CR*Uqpk@oFkX_xgk@6@z{D8Z!=!7yYt@t$f z`E)qAGZ8(2RhIZ13)#hMyChv+qSyd3tInYm@wAiK2P()zWM!)>#-^E$g_d1V@!g<2 zn&E_`TflHV1@EN9HVGjGR3N}j=TfOY@`>gDg7@g$+^s%}@DG&!F945oVL1luBgxk| zWZX`K1)(oK*w8fB|C>b<9`R`Kbi=*ujdySu_`5oLPQh)hcT#_Im%N)Zz3*PmX51+% zZsnA%XnB{VHE7Cec(5oWSWu2lA2l{{Nv9G-X1LoY1G(EiOt%qnx9Jgg+EQf1y%YWa zqaf~F%nHcXlagMopu9Zk{gIOD71UQlriGQXkcLpNU_F^DbUDu^fEh(UxBHC-3U9Ky;s;t+fcIc7MI%8>R^IUL!D#42(HcCv$YTpyk6 z5PjqPT1r?BN8%;pjNz3v5Yx>WVx@>tg>zoyoN7LIYfY&hF@Ff~i+eb4tRsgSM&C2oWsQ9(4 zd3ksZYkt@M4jo3pPacs*jFlTXxGp4498-L;M>)0~r3_?Toh4#XyYJAP#&0C%w1G1Z zn%EUE30{1T3C6v2>yridJ|%D#Fnc zh}vG3@ii@@qyhBA`dJ8WGwrH^>*G*x@k-U=FskrhY z8C<+~kf}gd)9YGtoN#X2`19l+A!n4F3*=lRhbPBPj)$B}S##fx+k zRV-a2`H7~G-$HQo?YPK8 z@9T-32QhBJ&NB?yRg+8=1KG7OQ&gEQih44HsrD;GO|38CK}PuAzqH#4fsA@z{KH-Q z?_9jQt8=nUG>)7ezL&Snf8?kyIk;o*oyNO64o+r>R+rPy-pg(9clY>`AR=UB`K-Z& zyvaj>grceKGsS_@I{6C3$A(0lN;d}cE2a<4q}@I;pIW|?L!xMpA$Pw~>j2@n@+v@{aTf(;^=FBv~(30|!O)sA$VG9XqWr@Rk%D!ej`u^z;|Hv|oOm{!Qu^$bGRPa6h zu^$abRPbqao@Pvwh##!pG`!Ahft(`BHjq>JY~0(&q!ga+&x?;pj92w>7H=%l#>sLG zOQ9pDfR89gO(dy^BrnR1^3Y46I%?vz;u>olGg-mGDviuS z==i(tSzHy#Rrs4^pXwB8e<|8XrEB{kz0&q2JN)hxkGzL1QdOjoQR{yq$S{p2gK%sK zGosAMa}&igQcSB8{{JDThk&FDUz;i5@5%WGau|(eh_yI%Zg}PY7ztKj`AWAkx{Dbt zeVAJqX;L0ozc-NErf*K(_`%k|hW0>yM-+4N+7H$Rs@em29a?kprrX;B*_(ZKHQl@` z(#^Z2b+}jdeshWvU6c?osc`(csHR?FnH>$}wfpuz#6|as z!G!$D{=2wDyufk4V8eXD27mQ4a~lE$UA}`vaGatowpz_bR)D!%hzeoJm8a|j&YZga zY#^^eB1$mO)*hh8{bV@4?a^GCl!}%nsq3+*j>8;M?}ljC1K2sm&IfMc#4$v9JzxpX z1W-Tn)&Zh=t|V`Yv%q6 z;I(UtQqUlY=@rgBSm5r-lktoVTz#2Z^q0AMPd?SSU3!mC6W+%5*+~)*2(NbDv_*x z1yLaj6Z1mG%WhhBOQM}9*b!Nae#Zuhl=8`)&l4dcdWkEi(=&b62dP;Tm%dc+7-u6^ z`5J>65U-}vUORHL!`J#CCF?<2-emn-4X-s!xdLgGs<-L>TSI}gYMl^8>7O~1dOMfy zc@E>yNp+hw6OIIdyot>sBwr{4^nuno^T|jW|J_nEAzympdjK|J+`* zP>8xM6d6)-e97W{JksI~tza+^vu0$4Rty>ijf$jvF=oJY8ef_?Sp>qe0;Wo*LS@1u z3qvvu z_*VP3Q|j&}@AF&t{Ri9`eW$mc8&umdehZ!0<=2 zu#d(;t7c5l<*2hlz@L-L(@_3$Y1!vB^>Tn(@$MkPD4Mv zv8pW%y8jvXb%T;xBlCbxLc$D5(5x%Xscu|`bQ#C)0Jn~#HK8A~;?Q^52s-t+h-FTOG?nUXtP z{R3y54m#aQUmCy%W*s%gUI=Ulu^UYN?Cp5bs9kv`Tdp`rWea7KylJjH#N>`uC7 z$LJ-`g-f2WK15k5i@Ncx4*HO=^idnfl{5ILkVLViFBIdN4Eh*vIej=8mpY6NUq%)R zi1?9T+{&bsjoHwK;zfplFSzhOk7g6EvKEC_w%>ajfsbb445fhHJ7YsJ!>*CAY9N#* zR;`Z~{!;DOw~0h@uNFW_>_R*J+m8Cn+xkIKa)%dFk#Yt_&Znf4ENlCob z`|{2O_E7}FN9QwNqZuzM>v317cn93%nqO+3Hh(StcKlb{@8;FwQ#`)54`U6x+KrP9 zQ++et{<4Po+^zoZqrN1@Jc3CX6Bl1T`$n^<8hE|^Zc@dARGDxe38Yr~npE!~|Gk0K zYF`uX7tMA~r%iXw6wR&jcOALk_56I-^MR~>-=3g7gAwjM_v~d4vvMYzZl0Mco6lV1 z+YJE|Un zYKs_1s#quw^8)dD+LFj`zjaezm^pkcng1Dh#c#pUf&v%ALKQPfVZThy6gjuZp_LN5 z^_AUt#s40?{s}pML=LSJ_}?Yx_sRJ)a{hpvKP2Z*$)P=Yw%@{&o`xs-AZn7>qJ>Dg zxN_+v-yU*W$oahN^uy!+ClH923?G`T7UxteuK2JxXL{IUj(bdR3mLJN@~Jv}(!f$a zUH6zC3n^Ah@pL*t70;v-RPjd{)fU?VXRNVQ5fC094H`==&l?x^8H+8|Qv(YIJZ59q zW6u1T-WGNn6D>BvgU3t;R5CzOlziP%~u`R0e{&7YumJ^gO1=LZuBsz>f#v z$73Of3WkJKFeGFJv%}wvGe8#GY|CSMEEE)oPz@1E}K_H`c=1$)1}S? z7x8;Xdgp&e#R^qlcG`%W&s8i>B{Q8oE!~VBLq=$NN)Z`1i&q5wZ~?+Mo#S5Z@~~P$ z?-p?mdB~C$ZbY{rMWbNRyH}jE$l}0~Wx}24LhS2?H^IJznC&RkjUh9HMcnR$e{xRr z9Urh?{FUOXux{fO$aTjJM*O3&t1-t7SB&_cZN&k6Bi@0}itlOdt004?wiYnL3m1t0 zuuGnpHITcCa}AEC;=}7MeDysX#MId1u`GG{crtsQC@+8ZxyqC4oR#bb){q$6*A9&a zbz&%1ydpYe9>w=@Lh&x_2H@+t9v6;ofU{n}2W=QL#2K(NArp^a*bfh!30auQFcu*% z5t0P44D5?;{80*t8RBr&8BXfB_+uDO_$C5AdA4Xd5=z1+g}FYKn!ZfPKL^;~CVumu zfCLMVl(g$@57M&y*%g7bb=UU?)NtiIx4b;1C?wZ>2?exm;78Jd;_qDzL)thHC0tGuK zT0_|d!Bu5%z3|!#(>1SuPW+@xVAaM+^TTyDGi5Vb)2k-qr%Jz^^dY``)9`~ByLAKt6on4;ljUL2_JjLZ)DSyTpWb8^_F;?CKp}6NbJd!(!TE zlIYp&zk_osl^!4rRgDKqpSb<&*OUkL^Xs2r^vC;##m`0MS)YkMgll? z6~1b}QXg}IJdruOToR;Bq&!r6srqS?x8@FL^+)D6Ia$b@vJ0&_0?yq*Eck--`&4{@Z>t-1gAu; z>E7RZptYx?9R!x8SV5X4&@C19>wc(z%P>z%U*0iDi^wnH@S+}dB2XR@%5cu9i7x>U9HU>T`edQYcn)}T)J>!kuBL8 zNsNZ?qTIXTgv_*7P((>w&3BV!gCU5zZxGcGwKZlI|jCjr{JkV++ zr~5P329nFC8|IViukU@BmgmQvC293wKjf{OPpiAW|6xMb{e;5#gu;6XtEOJKzqVn1 zZNt5_+wk?#hsmke_hOM@OY)tYtP4P)WQe!yoT>??rN6r7=9({+`{KTvlJ;u+&3G*1 z^4rXC_nW)S*g#0_Hv25!Nk~!gBH!MLBlGrxU}^c=+iq=}zWCLh2KnBOn3w62c( z{c=ldO&q@;UBVxL6G~Ol35r&ZOfG^VJT8r8CRx+rAlGNs<1TJtE~Qt(VH$Lt299AGFLc<8N*uy#O9)L zM{MCe6CqiK@n#5Seyxzk_(Umo4AThKo5`&aZ1}j)S|NeCcIGBBH;K6!%uQi#Dswa8 zmcN+}PV=N`okAK{@w!<|jUFkMdS@N{mE?ER=U>-Lp;hp2VE%5YJ*!o1mnDT2bJa@Q zWeY}c4#H!F9Hrj5T#YwR$l^B87~^BOT5ldcBU{J9@>y7{kjK?CO=h2+~HI3-_& zuuk%=7D^enjJ4xx<~rc+ltR|9khRP$W-f)4znO~BziUydwZdZfa+b=; z+!E$iFn1kuOW~Hknag_a8P;=Kl$KHG1eZUK8SY&r#gv9;ffQ3I#S|}!ShPqUJ2d=;bWNtSskd%9+jj7FLEKRucoKp6OLmSgVSf zZji!CRbeu9R<(k+T56eU6_u!w!qk+bR;a>g*bEAh#qAbqSPRuMcLQ7}V)uYWDNJ400$|-FY~-q0s#KvsqMmkPlQhzeW1a9HV(|@QU4ZRo{%pYJGhdnt zwg>*hEYvu51pcGUUpRIQ>B^Q!cO0<2Qo3j1KOy-~a?c4HS(_HHHr*uETBKWj1jRt6!%DTXgyFeJY{7<@cn8aS8GAjM$= z5Is4liaQ+l6Eh@S;*$a71pmUtWE|_Etj`TVXCp{?U3rO*I(+iFn+>#C+R6H z=O5y(O5CKKm7;^WoyS=4x3i|rT?HQW&?ObvIG z`$?e(Ij8u^WN? zbK2RLcj3#gR98B#)HrF&VhCI3dz#v?Z!y4+V*mUCeHUTG(@%G4RWVHRUOs(PPK3fO zQNxaYHz8;H`Hpf|)#<8AN6Be-OK0cM1y}dj$UwQX#3>@!4RE*PRR6#^$`GH5!@=;Y zwE2(C3CGZ&Qmi32%nI1;Tw*$9qhTv-5(YfV){1oA5T8DBtlueZzqB_VY-RQYd-}Rt zdwN=riS`6tu0hxf;42zi@eS31;Y*xrLuc29)2D{2&WHdSr3CGIY<0B5rHjI;zGAdw zXdu_}h-i0(4{|hYDG}`oG-#g4ZhffOO>_#7mJq=s>)0U7So zuo}`bCR!%bC${>o;o9QG)>cYMVMxW)HiD?OF$$(}#6gLJtp*ZoQF2qesNiIUj)D0b zeO(nBSZ9U?J^XW21;U0QEUE$RuB#rtf53yUba>q3)O-Q7_uv`#}6ODm%QZ2<~G$!TVu$k z#I)foCT+inwMro$H5;=fkp8ru$N!w$A}9&GFkrKsV0ptBC; zM~3uucC~gNZS3r9Z5dBK?e6Y8>~{5_&+!%I@{diGj*pGbkIj|%P!1+V-LY{SwM+YG z$AxkyzZ*mE(SJh`$1^Bl>j5Rs~s zKYEXfLT8D^I@b2^L;Xa--Q^z}E5)$-a2VSXpdrxRStEy*Kl&zcJi1TLZxOa)IOB-~ zBQ@87ax_uxv2nX9to+gc0@%pFGS-fk@;!Y$2l}Y{oI?g|myhR10m0C4^7Vwop@nF1dHRQj2~SI3^MS^LorK7Q zJ8Ywab?TGQ%Kr@W?qXUY=&l#B|HllE0A!WI{ud}1Ay$6^aC|Lw1HCPjEs!-9Y z0T)p;HC*G7)-G5FILAw=rO~1t;3_zMQYsEk;_u>{|j*Old+q~$9R(Q7)>)af~29*Mz;u*Kl(=kAr=3)<%Jh8QO7eJ zUN0_hsZa(1h*SBv+3Bd*@Q4m+h{TQPSQ9=1ey;q{M--T&lZq}jD1Y=9lmQuTkEc-u z)sq~}5~2t;52Wdbupq)7{We9cq7Ukdn7_Qh|C79PTN9^gk&Ky~Qfq zJuu{Uqpi@j&3)}1?R^+atz8Ein_DX#<5e%bP zT$@GTj^aDWc@w!fkA?SF_+bh?PtHq-VkU$9MS8siClpWIj3lD&P&_dh(Hk>x-W`JD z37KKL>B4Rvaa_0b^n|SR#g9I41G@zk%X*t+YNot9R?K?$-Ie>%E&a7G6egNg>~g=&lz^oGh`eI znJ&XBa=ZqAwfL*UUwz1Q74KvCyNa+e{9Q%(82+vzZVZ2y5qG&Z6nkp)if0HSg;)m@ zHcl^6EAdnV%lS)J-PPiw23CKNIhrUuet;$e$rzzH80s*O`8-M(GM*0^hjq`K#tfn{ zV^C2hwuG#Bm8?4v#(X?|bpq{u-gTbtKEp09Y;{Zno{$MCVVvVW2k!ukK+$6C6+Lum zm^r|VTthM3Rp#^XWDHKRpv9Ml$0!!QVSdbg4CRNo^qKrbTg1IIw8;4oT;F{T<{%IX za}3F;6HPClnJk-6EV{n?qgbgxJ*B>uqF)BL>1H zj~t$6uqI7peBpD!nD{4!j`0pg;P1a8GQ#FC4)xMaBx8(fErYX}@ zV<35r&-|U#!pT!pCHVY&YPl~q;w^m@!A)HZq&t1q@36O~X=5P00&f|PskEuC>9jyb zr7!+FnZ<+yZ<&=o+efjnSvH?-A<0l#|Mh{{ir*N$yRLO&>*Sfc>1+R_?#|Ue-r=*t zzSf>OnKv~ypIeP%np0cnbE|y&f|+Gg-BYcwk!_ydIAfZr$7kS7vzuni=St>|%1kK6J~1s$s7IFjZ&#Uv>I|(Q%_DG3gm3?C5mI9 zc&dwyh+uNT91_S$PQi^%Vcvk*~rn4taq`tCw zf}cF}b62Knr&GVOd77U&^eb0pYv)pbbMqX3=g{w5p>f+a)iQ0GuAMHMJ~fjzW1eZ8 zIW^NWn>O1tTR+QV{ASE`-7(F1?$q8nb*BfP_3)>6`|aHiQ)wQVr<$htDQ>!Cx@)=x zvTXyG^|4_HTv&Y|a#DDa-|46UD_k{mspZ~=3{^w8m z2VDMBgZ{zO{^T=$>ltMZYcc2v^ATqkhC^DBntG)aOm?9)4+T=z!mLA@ zVKsr|)tFq`L1xdHOe5HUz07C)4tqN^WeV6!eMahX@zd~`B~vw1rI;GVDL1<2@bsRU z`q|i7_lz)CJICQuLlIpGB3L|?j;_2oHGpPno!&fCGSf4&d$we@3kJr4PlUNVei)Ep|^&ix1j)O8)v#_S}}lk&u*Ekzhl1BJvUB6KDpa(?S9e<1yk!+ zf-RVpGtoV{cRr&Glrt^E7Z*$|n>s%2p6Woa#m&Xcc<0cfyZu%=QX!IL)?UHXwbSP5 z?y2#aRDW`v-&z+LjSo{zyQlLMDki6vhmA2{F9{DK^;;Jx91STEQu}sjN)0K$(I`-l zxkF%t{0z<~%rwnhoEboiHqO?~_WP5c@mrr!3aW>HWw~ibY~yqth*#=N%;LH(B~Y+w zmpaviX*XRwpRx{vnfO^Sz2MayH+M{>gDlofUz}b$H5^E zEm~f#r7hYwsc{+uDQiHJw9_?OLqrQtC92gtX$8ONnvR*;>#uB@+cH<75{vr$y&@kt z?LT$Kf99aoTjA9)qS4dW@KO zdZf6?jfbmDB&jcJ14(OSY4ze%i730W-c$N(2}t5n=E=*fWiEk7xu;#=qXRRCL4Lbu zTjwyloBh`2Pd(Q~eX@JbGdGAnao=(IyAS)19QPjgHBMyehquc?Sfq({JsBqCMpqBbYCLXOq9FYd*QlZ|!1gYPLvam%_43GBjs$ zmGcN$SfNR0ab;-Kl`RFf(qNwy3NFl>;*^hLeM^9-@0s*lj2(>p zEq2xvYRQpq)qx?LQdRcPqs8;*p8ohyF$mul$ zg!HpGkrS6Vk@|%fz^x`~e3yK7X6+obrCe{u37hK&zMGgfu|1IJ_{flINyD^Bz)Ild z%|G8gnenCLxK!jj_EcC#CuL1=lg)tgnI0r&l7FiBwLNUP@-Qu9(sZ+YlABL0@x=l* zovpKQr2vEzYswdsUrwHkyJvL-tqH!1FI#;vn5+;zdtTW&d1T7-`g6!&p%hs!tTEU# zAlq!ZdBUGi>^B#SJ2Q4@i`>uXelQ+y4 zODAub5BuwSAJpb>o<5Aw~CW zk)7?FpF=F|8Abf~KK*drK1-By=aR(TcvVa2V&_=Nm1 z5}mCP61h}Hff9uz$(MBF#VB=7W92)okDq^5KYW=wi?-}Lo*=Da<&6WB!KZ7haIJ6r zOO(21FdA&a{VO*8vbiZPM?Y?vIy0MnmVV0Ny@+`plw>Y`hIP<5& zt>u=GQ=mn#Cj+%;m#UtKd!Lj#;!s9$G>lUPTvG{i#R@-gH%{BI9rgOoI94 zC^!rC(x8Wm)Mbj2c2$(LjuoUWmfHw4-hy_jMLT5(8B%HUqU2Zt2x_rXJj-AZq8>pd zQPQjq=X9e!YTK>}Lq)-(YW*k>Yr{BHEu-)!scxYtsmsHuqd=(JEEa8c3vHGOxe>BY zk&hS8xcRQ3Vlg& zm?e=vb{dA_@*-nU4>=v^P2^8WM;18|KNh#)&D3y9-}vfEM#M;JloqKDV~PT?{HUo3 z<9KrVg1e#*FOonU5!J>k#vTk>_+pHJl(TyAwPdb@IGvNx;=88zX1_Q&a6RyFm7azu40L+z9FzbYC zFzdyKF&9P|(OV_1wN1!obDmCmRSI;{t5V2kE}dbh6zCMqnl}|WgxytrEb44i%@eFY ziXfM-!k+_w#rP}1Un%~|@V6SW`WpPLeX7|4v3AAs`YyDsp1fYCAFekWxJY?DQ&=OE z3G8IPuvSM(JOxZ-adhHXWRr(cj^}DJ% zDK)wAjVR?8Wo6@yKh)0+`0nY)EK>(jPBz|n`~<1PwIC@uMXw$RFEE3Cddud~~+fHi`d|_Y?^QTg%)Lp;R%BgBGwO}&UPL0&2 zpI$A2=*|sp7p)uh>%cv;L|h}qc{g~gyz8TseVst3^D2cZ=F-`-rZ?5v2K^E@M=47S z<;UcKR!zP2Yqgt|t~v^?JuJ2+O6*=1TN|ZT%|bQTMw&rZmVKJCM5|GaD#iX4rKnY< zIG{>r~xW8>|(rqy)E0@q8>QCk05Hnul<>!ZYGcHK=|I{wPLF4EWAEu3s84JC_(Sr#|x$ z6K$3aP$jBH+dVq&qV3hbpo9zt`z7*aiu^firp)a zPu2;~F!)C1(s^2sCY5gc=#IThD*haW^6RF%tV-7+G)r?YmTS1yOdMQV8@FC-QN^^V zVs=MqkFINU=JbkY21cV8bT0Mk3LvA@iyNZek!F={i*aWZh_Qbo^DXv<9rJCR<{SUr zC1%?TpY?3h9TkFVRO}JwAID6?;EHkB0key*~X__4&UQ3L1OkAJL=i zG%wa+txNRjwa>awx$8^Nvd=FO_XUcRD5(ByT}F(HF&u8yH&-wQeiU3H;YK&w>=&h(|2edb&RW^Ke~H$7 z>oaf7b)Gt~R`wJ2ixQ5kgTrj9)Wk9wM-}_x3aGRe{}fRO6$UN-TM@Be(cs_DeU(uu zQAe5=g$n%AH5ra{e*aND5~6BKe_1Y((SX!%uOOFc1&(sLy`o%xC7er?vUi1B8~B;b zBd0-Myra$~3Wj&lhri0oPki>*R*>RHF%RrF?hEUTk$l+}E+bSJ}`+=_xI?|3e2G3wtVT|49cM3tJ(!Z!Fsu>z0Mk)-Q72 zQ){uX6_!YgEs{&i7>4a+r>OtUiT^}c%kMx|cAxolr7 zO;@P(7_C`heVYLv=C!}2E@PCjPAS6Lr2o9a6e1m?RqVeNI+lE68|WC@*Pn>t%c9XS zeOl!`An1>d-wuxs??JTG|4HM~+sQugnJ$0fKKvzUf`-FH#9 zE}`ozUDp!vLmfn`BIh;zcxF*IV%Lv--Qev;3|$-&@zdbdix1<~i3Q%CDC7Efk>8ex z%<#(n9>#1X>bP}@xb0Emejn*}>ckO0ue{dH{Q<+>!=CE_`-~2(Xvx=gmhPg6_(@iN zU1wV&BJirj?T!-nhi_(v`}D@&!0t%D=a-c!FhZYT{}-d@4$TSvm22%1{rm~;Tkwmc zyi@2DN|qhHe_$D!zVD6PPtZE;PtrO|%-BD< zc7WRGQ`-6NLTmgf^#j`Rzo^^sS_hvMt!1te&G<7lbW}d(509;Dol9V(ew<$s#=BvR zQOfr&>hvk|8MOHmjO~fE8!lm;_zi&xb2Ljc@BUARr+~Wz79%6qj=edi-hdpkq-eS(k7Obn#z_ z2VK*bY`?8)zatXoeuewuchAqm8a>$IDf9yJ zJ8H-%qvKaqtB_}-V0%}1mZKG5NR1EWUxo79Q8%nwsQg@lTnq1sk@6_{{dRcwU0M;O za{tw{SEl`t1b&;aj1xZOi4zqk@a2}x-V;&E)^+U!YO0ZKqChswk`uG0c%Z3^z69L` zPW^w0b>jYF1@OyD+)pNzWZjs7RKiZf;*?|-vpd(-T}P2iPDYU_BG$UPRQJEB#>I0{ z@H|w(^o7^Vi{zWZ`VD*DHAjy%rk`C~cf-|b48ok3?hqvu49%ydS7dF?rgCqFN& z)|-_YozW@bdEpdvMvi4y-E+e8ppkzioPzu0IwMxrAM1=1ebT>gozZhoB2j_k{x$JW ze*RjYBzgV`_g(l!ol(EgFO*{h7faG-xg>p-FCmHj-$Fk|@dt{`kt*@$m5ghZPRX-h zro>!A_(Zc@URh%1GUV?@VEjXm=pB$DgaKiI%OEKw&*0^_O1*Ow+~2%p5V#gYIv4Ry#*EL!v{?8Rb z4g#|B+G)6dzk+?Iu4_XK{tVoISP8sv7LW@oC<(3O*s4sjidXN0ez=01K9Z?>R2zfk z*KsGGgtAT)-uQX5`i2$j%5GS}4G5#)Ip+kcaE`{0cUTzK8yTE(+ADlo7UyjpOU$Sp z*Uml7jJh@~oq`>fPP`6tjjUv!#p%{zF4{@fVNO1^I?Tx@REN2}tR(+dPowJh+`sb4 zQ}pMjYNv})^(4D4#v44O8}mdguad!V|Dbg1i}yVD__R?tKaLx{yd#2zPYO$Ff^xD9 zQW)ZKe@23LG%VE#qcRpqZn)*cJHUPa+K4bf!uySQv*FsP3RkQQ%l#waBB{=ML5)ke zAXDBb*e-Z43KvxvmDAgtUBSq!FkTe+r7;RcxPvX`f7!2uebL1OiDQ_U*A45c_6hR-1ia40yp9V?bix{3Hy> z!gf|>RS}snU&t9bZCsgIp{R`MkSn7*M%D--T-F$WyBGh zzj_0h={fo%nBN4Sc|Y!lx$!1wrY9ed(EPV=fE)B|@e#~__XaTYC%q4IgU&mD!Ld=fq%zccnPJ^emga#sghCEaLGFNb)ly?bCa ze?!Nk<%7MKarp$beLNLE_h5EY@pIH;j-i6C!+BucRNOj5#jUSR#hwSVn~J>`P(jyo zJg}PoMtQMvh>Df3O~s#kFuSRsr|^#91wD!6fz^~yDpn6svHG>CuzN7Wu1mn%A5ht# zCpM508uw2R$Oqlo^rZRv)IeS?F^u|e|2NQzlG#Xo7YG9VY5reWNdk@F$V$@MLg3wb zSTzG{O6zMU(vW&QIPb1${vJ7Wciz*JtQ(Aru);Nd*Dwn{fnY`Y{N07S)INeqs4KWT zzJ43t&Eq>Z%JW92xI6A%wSyHg_uC-vTd+I?>5N9>-P@GLb>q55h35+ad&phmU4!QD zFy5V?&?vrp`>qjI)b89xIN&y0p}*jvc&5*D=ewGO8o}K=o)Wm{#dnRz+CaH`8=!^8 z+c@)qJCX4&-PKI|VW7XAlZ8LWywUqAtXLuier-$>itl`Dg74fL7flMrMZ;h>ZvEa# zC^grYoJetJkrOa)vEI_gZ-wT-h0A%^YCe? zjjuavPPzNd<9G=ilep*12W^^`ADG#n&~_?l_CNV8YvyjNS!~*i%X7SrPS*tvmhlQ` z*3|CLORz~#jP0&hPk%9OXlwXI7K9Gc_KyJ@ubaOZTj+_g{cnJc*T-LsO?F~zUjjB> z&q{w`ErgvE8(M1ve7sKoVtnDRfv*wp@tXXL@yTBU-yGoMHP#p7Lp$Ops#z%S_W&QS zTfZ2e@-^`N3&6+E0$z+S;x+L70`T$L?(7TeH}a(T+^fuKo;Brb&{MDXtbgl;m{smC z0lr0h)~Ew3pY+@jXey$&y(f>>dtZnt8c$_I4;SOV`U+{$Y7Rdi`_2o~qUG-s)#sZp zADieoRrR`M16tth73I&r!Lx64v(@~yzN=zANZwsrH%Br)nK>t_?1?#&GdfIONH>aes4vPodip&hUymWf|ecC zYZ>rIvILGxwG4U}o+}t;?vZfWaSP z@B;`8(dp9*<8#Z9GHq;eL4)pObp=ythWLZ=@suUeOSlnr>1qxs1BL0XBH-~|^v-?0A!ayS-~7OfV!e|&=Oi=CYY(R!63v9NG# zRHtRo&#zXeV}LM#JEW*dmv-e$jz z74$X+4=`4=o`+d7-HVI|2{Qq1dMHN_HRYqXh>V`qYN^j2aAIC|#igWv+`G}~b`Ml6 zTwK8yyF0pjE_Z(=%w)l{kf57=7bPLuhr@dZ)nyO^mA6?AL3mE~EjEJGkF>Ch%S(OQ z@kOY9zk5s)fCbxu6s#Qs2d0f&&jY?MveT2(3(W1+ytO>Tx*>??H2VZ0LJ^>Sae6`D z*2sQ=31N+1z&arSN9_O*h5)?7>bAzBgO9}rA4}MuVOkRehEmKV8$2>EkL&q*Kc)mZ zhr}ct^Jo3OUfVaSnO@d?B@AJo zB0ve{t2=WKWc}i*n~6tau(A9HEXKPi4bj+5LMsb>nX734v7lHG6rD~jDZ9L zDFz`B7(%G@^rCPWLh1b_pl6X~LlH!VAXGZ$v=e$-YX(|@AZ=6bXC%=>RUYFtHh`>e++F4&;!m*FU*1`csHJ-QHU)9lCqH) zs1S*SmJPgPu~8VegmE-4x99X?7Tum5h$>-Y4o8);u^1(RBKMDjA8s}t9}kEhmFoU! z9PHfm9f<+*+`R6gt(HvyENmj8iooL21jTuL<1b;8@x=i)wrWQ;TGox;{{ai0g5b1h zbqmw;;I2&1G8iSNVmYd3r&p;gv8fnKYqNQp)#+)jY&u3(`g0ud_s)%uYo`|H4(56! z77G@BP-59kM0kMu{;5&T;)+KI{2q|{EC6S-F^!bg81?_I#^*%r5VCJAPHUJPH8@rC zj0{XJ3=@VBH5QM0kT)n1($l5TC^iQ%lv51H^jH2YJPvs%Mb1MRBK)ztNgK@%bizNBSgfMg8H zp~I?-q4_qDa+|pgv_anlzcmaEP;=9KcZG2}`i9Zd3roXE8jjI$lv(FXhgLbuz?LbbDNZW(Lr zJn)QS_IKF1Qa&s!&tn0n$F(}158fvg67LZsZ!8^5-S`ZV{vhs1_Wwb0!&{oKjP&-k zb=CC^VupW%kqV6LZ))i2Zsem6b{&2N@KEk65+8#ch{pPNXXclLA5Z#0Z&=Vk+5O+p z-oPV&25I&s{VIq#prRb;_HlsyYvhXz@KeSPfL_i15~A2=NPc9);@sRc>dYg&OdvH; zL&xc`>|bGm@ZO%b?tzhu{dFx(2rJeVpJB#9sJuULGAKYZM9=YS`VN5*9Zw2|!6DAN z5M1a9s9As@SU`uRbNYd%$SC~2;2#Me2*I_JN-S6l_$L7?LbaGz(*H-m!F~nkyV+j2 zeI#Q4XN;+b7#*x^2%rJs$M5X_0)ZiY(mgZb9RrSx7gWzJLZ7ayEvUvb zWdihn5&X?P!H)VGIA^w{+HU??COA&LX^pf@KFZrxZU@+NIyv>VU+b_mzZV-XG*rJp zE=Rl^^i*)?p%`G3OL4fJxr9Y7)p2ZAi>RW>t7B9$mw3tN2W_247z~jpGq>Dwo_A{; zv?;wI86y|Q7w2y2SM%V)*Dd1#RRd;OhkXeZ7o2Rl+c)1ALRSoUP<2Pmy?KC5 z2Q~m@sM%8ejD<;|fDOgRBD^cdyJEZxzyMt<9S{oeox=+Svfe8c;315z0SMPY2;3qN z3L+pt5nyqTiPpM0fY!Pz0OlUl_oWWeK|6iTx_=i=@aR;Kl&|}wbMH@pyYk{6jB`on z+%+v%3jZsJtbnZnFhe*_nR@FQ8{4{DP}l>ZgDP4*P%y8w!yb>XV7QS6vJNsXL>YG% zO$J31QRxogr!uIr@Pf?-gEW6ViT>wUs#tHS^4e{q)Nyu$HRhvhTweRHpHmrDL$@3MuSnV-M{DxZh zuGXAl)M9s2Z0T-s;#jjIYPw z6AXqixQ@XH1~)Jm#b6ABaSSvV;K>A6Fu$17?@~=_^&_|nIig#eA6uLoS%5_|)`)=X z7~H|&E(W(DaEWJNoMf-!^Gys`43G)z0tSm1EMcI-K#u|Tee5j^zKy{jL*NRSA6v`p#>go(0N=L*9SUAsC$M}3_u#yixH z9DEVsex!?rBUFQTMfrgJqS+5I-;XdDLW0gg;7W$oGhDMA!8OYfP{ln{MjjRW0fPTe z5V$1M^OKaHF4^J|E&z|*8l79#xuW0f9Y%!%in7pprfJ~k8qXjN!gSGfC?=Q-3vz_e!7CG+NsPobXd;DP-Y z$VM4o&=J0tMT@I0(c&8X8C>G|X-yFgi)mQGOX^Ekx?CZYjm4CYLF~#1W*UG@6fFVf zCBVF7aEWfg{Vlk^WpIV!qRZ=N=m)TUycLnOO@?C*?dI=bx*YLA3iMN`9A&$Nb zMJzB+8ez2)t}w5rjE{8A?g~cS^rdDF8-a%;-+U<4UxZ|ynxn!Cr9`dTE%|?fr3xIM zg0&`>6k5srs2+POnL7twfWq*J$^p$)?#2KV@b4Aw2p@=7Sdiv_P8$|NW4m#M@(cMR zxPIc2jIHUlBlDw6u26m(fR7HwP60gCyFyWRk#(?GqHZnksstb46ad4lIo7P}e4$x`n%Iiu5dqcgeaOp2NZwrMBJ%Hb z?8(9bLM;8m&Tn)QrP?9R@jm1`#0AGam?9ivmFGod_D7MHD?d)M$cgf-LtNpGr!YWR zRLs3DXEH;?3C_59B93+@CJ}MmFJh85weQV5ocaEoJtp_LKpB|55$cqyOhcSJbwj)t zDu1Wyt*XtmozO(H>chA{iL>ZGUVF6m@%p26+hu!U6KT`#6l$Lqm0BA=X?xseo8ijZ z>_zPxT_iq_ljT3HIlra)N!;ggq+^7uyJ4>xC9-sqQNhV7ow8(eDhE%pWT!0Ee1Vf? z0+05>l^6qDy*tc;vUC+lJq#qwqh@CAsyPCVy#mi`Oex~YwxVT zwZ3`vi9GvhS-DO8ne~WZF(q7a|+J_xQ!v|1*aRSskinRT7;M;z-ASPosTFphP?a{f<1j4{` zZ-s0GY+Q6o!rqa+B_lC~)&R@0wa%)wUM5jBPb9Vb0RXfYoxdAh%0-vjqfcY12H~M( zrPc=PX`9e?$`(VS>YhmIF%CTNg-F%M(c}Vr)Br5m02REm1$ZO2lbjN(7S7jkDieH{IL`j`bq($y>RWL`^s( zlipWZ9|c%ie;j7MYt@jbDu<-n{l?Vqki%u5PZ9M%c3(zP zPFv@<8p!EZ(yAd^mgsH~%?e3ceWFt-O;-aU)AxDXCc1T)1X(&;V3C{!~DJ$A&aK6@}17NIycXlv(53A63h6<(~qVtLpG7E^s~xOD{XmOn(fk`p8Jb) zWav6+A0Z>-L^HXond3BbWPX8+FOo$a(XYTd=(4a;1OpIW_633_Q7c~b!Zy6LiMsI8 zExI5A$ZpXUgv1L(4vMbgrAst~mm$#zUT%oS5%Pv;1|jhRk+Y&Xyo`wE@iH%3!b|*3 z(O(G!VXSCB5X%e<^RV)XB;NZ(qDmc-vP1odhqDuKCAk)ies9$bR?yNBmhq#^Q3~0CO@8iG;7QF zEcesgtu=eW1(M%K;`=u`oC%p52y(XileK@gX1d^r$+a}vV~R<12^U$qHL)Ra)-~cOoq;7<0rgk;AIL$3$xV@vfZCW=E?4By;PLbf{u8-|rU*N7U5LUNyU1u6Lm+hvPa_P_vN!nR1vVyGLg?wH=#kq#vbG_WTUUKdl z8P)ENvfL<3ZmsN$u9)V{jk_7Axs21+agtuisj7goJ0KGq(mhX;&9}_j(n)@;O}o{( zRZA}PlYwibf0zu9kQ*~(WR}d%lZ9Jkeub>8LF(JW2CQfUFIbJDW_)T9_2Q)&BnmDU zL<4w->u^Rz-|IdsAmM?j{_^2G+3@1bKTBjuo3orO$5~WMWQ;ih#ule6 zX0w=+C4yAQ;x|V*S;|}8&aXFoIE$-^BGsJBDGHp5gw30rg1H~+!BuDH$BQ2wGhWz_ zju*$^`flic5|n&DO%SO9#z4^NL>3+Hrk@K&f&)9TpY{&GbTs<*np39QQ>Y$D?@J$q z-4ENGv@0?<0-;i5N>i6TG!@vs(dm@M?#fbt4J55~TeaIZ$h8fUtHY%AI=Mbdm@$WJ z+zVn3aL6*8aY^sRJ&ZF~a&ZOxP-x5Hiki0cKUw>Hja(SwTCSPuO`?r@U$RU~ghdQ% z<*Y?xO|$k{8_C&j!t^*~z5Xz&kK-Q2St~hpt?eesuG>l=OqWB}?Tn0hP;tLv^BNbK zv(fm{Cr?q#nHH5b=uwgt@Ko562-D(_LGSA>=+}6=myq&a#lwpCY97`Qb&ZX+C)5My zKvf&vk*7EniMxt)PLWPBfpZgNa)t~-yILa|h9`>Kd%m~T4n?hxiVU;g`VkJ{f#GXfxVRcapTOFJ#!t!XpW&4`J%V zH99~p4(?vmau>B^Vww!hkePYHEI4F~zC37^`m=`CLM^AR-zp~AIMnmpbJzMAE-uH? z_;K5#HtPhJS7XY6D*1Y^{PVN~S;nkTW!5p9$`)iB+fr=>ZH;ZKwu83E$c2lf_Y%2u zg)oB-*;OCqC*)2DaK|)j4?806javh|O&7VQi{#QEX}pR;&s=xNMtnIOVP$U4q3ks{zVXbjjg+l7rDlZ`;*1%5&KOfv) z`b%d}Tb+>)2$3X>!P#_u`Y^Q$JL{m;W%IWLMex?D6MOM>wvD zSGR1Z{#nmvlKHl^lw_83F=xqz%b>~Cwr^k9sqNm(x5%vhB&&jptt10iH`;u;XP8&b zGuAM|)H-D6{G->*v({w7oOj6Te9_Qh9qRp5TbiFte?ComN4Vx2WOR%)jg#@)gfTi~ z>%Md+tVir2Oba_<8HYQF_U*FWjv=mNh+G>X?KjAcal&XEGOaHM+6I!--kW|n{oee; zd6I|SUvm9MkF&9#T)Mo|czJW!at;JJ=Ny-Co(zxs4Jqafv(da@?IcW{Lv~<1;7fas zQ#WkYk?dwre9L}X@fQ{3;t1D4OWXb%mX<{4*u!!T7xxmmJhXdxlDj-fre?{dIWo6M zm?eko=ArVs<*}TL%e4%AJosqPy29n32=61`0_p=1z#J)(+kCLSrsI+(w0q_28XQCm(6Pk&2KiWyoqM*ZnHk>Jxn^wsjF=l zp#QY#w;F%a_Ica(6xVnedRWo`efb<=<{h#HU$Qql+?p2bU%N5+bj)d!F2wIM^?}v;%rgu6iotx7w2Pcf#@yx8!SNcyxDoo*Rbg%T02PCG0X`ZaHKt zz8XI`dLN~9fiM>xvP-@MuhA~}`sX!M(0~pp(kJXyeS+{&ytUC5^SH~duE&m{ z%&_i~?U#NSroCjG<*wtx1Q}k1iQyVQcRbaEYX!V z_3YyXdu|iSp~Eiez48~esQb2GC(MXLcH?l#eml^VN?49veQR|y+#u+ z&ZSN!nm%d|ixVhN+vT6nlYz^m>B!sxdIQU%cc$s?ReiYd^$e%3u%(jhYFj5^+8i=J z{TyGS2quXxvWFGT=Y-1Cs%{U zm6S@-O1Pxbjqbge1kgfb6DgcRMcEkgM4oPu18jDcGbs}mQFSDESuxgC4A3T=giChxZzQQwfIk4H^=NPsj@6N)(fBXKkm0hSX*uNwws^nKGkiN*rs4wsQhW^*gZ2c}G}>tDJa&zN%i- zgqL+8UFT{Rwc}HVs1w&iJ4D?Gi5H0M5%uAvUDS`4e$i#TToDZ-1xUO=Af#3_g^+lG$Z39!RpVJ>y@`=(7W>U8ooGK8`3g&9$|Qby!QALj zsGW-BUBxL*amswxy>*diKifkxdmV}kd^g>-BTqBmu?cswDxAp~=IgNjm~oaQRzRhn zt|gFgmQ$1*s&9>@!jfyfNHVG%ifV5?n;RU8Y?v3B!?=V3*bGpXn;M+n`pK~9ELv-^ zCG3gn3~U4_%e@`_Awut1^`ERgUfW8vmv@uQ9*3eA2u)1(n2%1tekPCc5v{SD1=;B&8Ffz-^1Sh<)W%%np$ z0@-|lT%6&WXEy6da;de0OFmDM>bUrNvUCg9pIZ9Jr5UbeW)oK3VWX8}>PSjG zm)L-ByL<{=hWWO6o|Lu`rrjZfJq*vHc7}P~yhu)W5vJQA>jCm$@-2BNF(+6??XgAv zGr$6CoUPOV%`>`ZG z*V1QK7Fp|dl&AL+Pkk_F9Uzq*-04m(vva$joVq~b`|bzt#WSX0f5KMG(-z3A+99j) zMWYV2z`%^jSg=uo#eX_>VQlgb{_du{s;tcZ||F^6K@+y8kLb&_1d#g+a}Q~w9i z)JfL)t&E?jKUZ&e+Uo~N=2eGc2s>Ss2~~C2Jb>XktHzmHNQ&yWN=ac0Noj?eKV7#~ zMap_kF!WVh3dq?u(tec;O>ph7v^~wW&yY6QgIpvTOAf_NuRu_Z{%KtD=FJb%%^FJ$ zmsw#?tF+bG<7!bjYG4+Z$e5G3#6qjknrf|koK6zYz`Tvg_)z-36h3YumxdhbYj)JeOU(;sEm+#J&niBx*t%w~>LZ!`4#fZ*_i$?gztdj+!L%1p zUEq+>61jep+|(0h*&(~-8>^}I5?{C*U&_UU;<6QOk8g#cF0p7gv5ZT^Q(>9*#5T}U zm+>yj#})cWy9P(m0Y@W!$`L3{)+)lBbI8v7%0+c1D{T8V9M~V>cdhEJ>(<3% zmX0z&9VD4&;ndbSP<}|qk%d{Rp;^xz#)=Bh9H$1&ie%T?G_de0=NhiSf<37pB11ET znRUqKytI+DGKcJp_tAV%<*Bh|e4>7=wsqP|+DKaa7qX81yW#W{$d`?B0UWOy*-a|u zl8Ws~a6GW=xgZ|T@r5`e)8N!bWC0vQQpDoPxy{RV#i^H{2#Lq_v(_uPKFnNm$cB9s z(OG$1syPQYcUNs8xUqX>d&ak^>*fBDjo4$4f5cjIyy_tA<>I{F8JV!z$wjL1*vBz< zei^*!;~wenRX?o8wZAcYLfsoU>aj|STDhz?lG#q$kDRJGShtn#o$^F`VKYf<`9jvZ ze;VuWS+zhC`7}CiGuIxS35R`Dai;RkAucj|L-NZYL0;MS#y7LyoreYf=q#IZBlM{< z+H~8lOowTYG-adC3Cd}!>B6@=V2UP9f&Mu%`GWv+>yN^$B91BHB1$%bX$o_TU77cy zG%?ATZwibZ+8^au*!K%LRq=+DPuFHw;u_JhdBtZx7ifjj+_%~`noV`TNI7NJemL{~ z%#Y^mDW%WhqtCEh(0yVOp)@gSlNc1|2W#J5bE*?Y-NN%=dG`PNgUYJ@8pd76}FK4Up!t$$QyPbvq3qH;Hd&di)miCOta zp-}j!TqyjZq_(P^lIH*3DQkC1+B|vIJ*u=PojD=3q^f(Tq}!A9^$O~r>1(C@O)@>V zQ_}w5o!q{il0HwSugTt?osu3;(${3t#hsFiUo+|Dos!EZOd9*(?0s0$&38l=SkKr7 zNPRz7Gq6)S@H8>SEH+=|m?Ar@^~2%;=x!dAO^<5rNtG`YF*nL`N90-Cr7b<_oa9=j zc50?5N^+`#V=C>5RkkrM@%-!JEOJB^TPL=}q-l^le|6`~Ri4aYjw!W+@^F(&Jo~yR z^BmCPGi{A<28*kvHBC$Y`Y53nahJT{i^xK2vrR)9E^@V(9A%eyDn~fxv_0{RP01xz zzKY6c*tBTOE7xr!2yUg&Q5m_1kc2 z9{TtMvknj1b=afMZiMW~Vm5@%aJebxI}11v*1cN=D>bm5A04xq``ty$l=bGH&N@|5 zo67spz3vAHVq!hEPJCfCvi z$HbUg6K*@jGUnp%u0KuA!1F$j8m(&Bd;&!-`P^oJGd6QKHlK^lx2%2Iy$#28u51@_ zgLK&o*1WDylF2DjIZX;?p2W^NK{u#-m}pV%#N|94fCc^`GOPsv`@r-UsWaO*Kgj$r z|NZ>OV(avla4U7I?(=j4Tc~L*+d_L62VM8O%vp9-&PEd)4&Dsgk)MK3TXq#{4*uss zA+PUVo#C#|kl6(?2%i@$k(`@P6s%JjP2%%+l=*(ZaDsGZcj6W|af_@Ni1s$QZ6rDC zPZW0mcr$lL>5mu+aCP_61b2xZhP?DqjatTqdGl&~Y{ z%?VFqxIaQzWXUi{t)Ap8f1$WV%UiaiEb{|~N?+Waz0J+uCdRu!*(|>$S|_T10_ zrXdAdhiYOkGMS{6+at@J49@A8dR#Q{qzSdP*{VJtCk5?as5(ww9}dNx-V5?@FT3JJ#qtGLXT`#q*kbE?yS4*>Uie0A1ot0isF)sDe_EjO+u1rrX{Bwx>O zmaF@hMYM0*zbX<0#_WodIC0YEm_wWjeCiZl7v5_kA=yOTLd3Wc8W_1Nj^V^Hf7A^D ze8~n;aar(TR$$y)vW*~^Qt+R{9Q@?#34HPu2p}*YkSX4&c&oy6(H;t)qa^(L*>r#) zZC0oQ`vZc1byJzu(3~u$pSd5ffr18Q@bCGb!{?l61Yrgq4*zt*HR17Zjswgp7AXCcF|d(G8jOO2}k4 zWXj7SHO$N3t5XfdEnuNlKc!_F7~awagI};yQ>dfV9%Yt}TH|HBW)*mwQ`8zR2cikK z&U_Y2!Nv)-LrV=mxm3rQ#-a8!T{3?YIMkY@OXf9tgILgdq)YB^+y-OOBBU$oSaUVh z7^6#d#6S%uLmP@N`5~J#)Yzdb_C@w&sOdtW;E;tvG~Wl7+zuJ(qvn5I5yzOC`+H=O z>WK9gqzY{b!>i+LfCZz?Pk;e)R`meI8$3ZvBVaj++TB145C<$L#X@JqVvvK@Q+^Iq z-V@;W*cIQdaLS|hpr>nltL>exx4Jg7?6NfYbUavQ3fl=zaw=i&xXTp5&{{>wb+_Ym@`CPP9)_tPC(ZyaI1HuYNt|d$=J=Q}qO=nD zG$gg0$j=hVSxQ&ljx^7yOvjHi%eag(_&_ARg2*e0r1I5dlL*MV;COEDDPuQPyK!nb zbZ1E?u?0k4NF;^SB+fX9f%k{TsOiA;5g5;T0JeEFf;quD4p10-=%*2V6yQJT%zzuh z!#|B!6Q~LLDA?nE226_!kA;(Hq?(YALSG3d1Gumgz=Z>x{16-%{5t&eI44>c>A^f4 z|MSKL=+WdH{b>|>G{{VUMsKOX8I984{eWKXfzd>GIU@##FoDy8^&q2oM(KI)yJ{jm zkYIAX98MGl8-r)Se&OMtMx}`YCqojWWG3qHJ8(hhj#`%*17~86zBl?CgqIkDjM8cV zdb4?oZF!vD?2`ZL1+wI4*|Krf6+e(SP#`Fc#;~uX56V8$PFlq%qV*)wPD6E zW6&)jo8-so7^4jM8tczjW2h!>RkSKXOHts62x?+HU|d8?a2m=IhVkp+MzJQ|7!GL@ zei&eYnp+RnCwXZ*miGwl;lAezt|#TXcBrcqPg>vA!{tW7I|{cGrDDhj-Gik1pgeaT zXf_4jr+H$1*Ozg|7)FO@kx>CImP*0Jk{oi8>n@#`u9_3jmHYa1&7AVl@3}L2UHP&+ zz3062Ci~TEBCVUGL-m?`e7%Arl{9dAO>Ki6$Gdf?_^%yAk8P9v)mA&KFOGazbv0ZxVMkAbU1pT7cPa-m?M4UR1CeuF+wB@V=Z?g}* zRUdeJAU{Z(^FzO0&m>$ZexrHk{?O|%R|xJi7DON`XoU9AZw5U-9QtYUGiK?I+apR#OD9$MoXg7yQsW^#<)GR8#zd9xdSQ?||DiAHGsw z9s0$VAqJH4gLwTQP6I^pOCiqSczG0J&Es4}vEp}^E+_^&iz{GZcMwd`f+UOHPFM{X z6s!o3yb-=#=y{{B_wXeH41BG}`q39dTXl&s7E0iCi%mK6f-#(GnQ7~B#<-al4_4pR zR~LgI>+7+1Vol<=i}<@0;fjE#NL|ibk2GYpc>Kjs3(DXohPsB~jhRu0AIt=}0MUUZ z$WSo(HO@{ip=%UZAUf>Oxr8}}j9$2-Q&@0rvWQ8*vN!lw0N*a7%X9il1}p@s)go6Q z_&J%>xx`c2xg~=%KVQSH<+IBRt`Hq~KLC?~?6TGn(?7Mi!mLbzCzF-MWpK|hre!pX z3tC7XG&+tMv+u%$%MhHO52nh-wFagKOen6f)8OVty9##5!C?jO7y}D}bYo8AbK21b z@O)9(sHF~Z+>UU1aoT;g0E)_kGNTjV>VVNLk7EHQmgm4#&H|uE``d=#PVnBMg<&p& z0V{TsKo+{LnWk=H*io4K8G?IrC^FtdjR|T*9RN1hcy@sCxnSMw^wJXC1Zi1zk<~4O zt!n|p{Kp?WU<@&pOg;4jLn(np06i=Rfd3746H4n6_8I~yYEP1HZ-PggN~UXCr^5oz zYxSdOgO1UFO?&huvBo|?F2x=L!ZRh;*tCt=Me()}1h_7TW(@OGKUGt*KrtX8l$UL=d2R<}Fw?&)$9=9)fj3LD59|!I| zFVq82(_p#|txxJ)5?ZAri?c4_iXp0!@rbI%mytn^*5?|qf}wJjml*aRVaY=(nI>d1 zxZW`+LTYMinEvH?G(O0{y&)7N7OPmRsbmb&e!g1ZRzlP0Dj9W#O9H|Qbm+9M@H%!9 zJfJM-!LtLn0&&T}==KP_rExAam8sL>vyQzEVt@?;>~~WusVpiFF7f2t;uzQz)obU$ zKIq~K)c$)A&zgWxHVW%k40gc5Vjl=G3pMBpn%0fLl^q6j>?I6lG3cY%so1mq7@@)7 z8;I&3V}PdaT*1()MzB={@l13D&d(ywK-xxJ!S1Hu3R+%3pB^r0)9SdEZ_!dc3kF2T zM#mwRmH|9AjjQ9?KSsQW4ht`)1^pK0H;ME}(flXKICKSJc%haPso_Hjw5t)6HdiRL z+~rZ;o~tW_a=>k1ktRfAp>Ts00_G(3qfqg3AFAnvrDeT;1WoT!xN&*`T{3#BTONbr zLcgSO$=x9EOtYg#T*2b$vK}x}%Gk?Tj^D!ot-QK|#=#t( z;>%#E$sxYtiw(7Ol5ise9yGm_kZnof5-Nx!7Iy8;LcmN?ORc9#as`+J+mN6gr^Lk33lxcmu?)Tl%Wi%%m*2c~*O7nOi)&EG;~ErFT(ra_Ar~w(lDt+D z!G95}G^y<}{F+FX3fG@Oq2n{nHy^@L(E={MU_%aNRApP__QS^KMgs6r;kMN-{c*^voFq+ru{-0 zWtuXJ?aEWYnXoL268SjsaN_$@rqEvnKn&0rodpJ7T5Z$zs8+D8laPw1|Grz}gsOp|UfzQj6ow_qc1mEZhr67}H6psT`O(Q~xkcLDbUbwc``X`g5q z_XV$uMlo_sw1AgI(HbTg6B#hUbCaS-*bPBf`$)*Uv(PiG#vlm4NvF5?jSrzha<% z;8vOOw_h>>MI0Pkk*4`IGfTVmCRiDasC3BS<5>Tm?k{DDPFWOhLk=vJ?Z{I97EY^3 z)4tN-K=yAGXZqDaKS`_;^%n&F+Zx$GnCRb0mHnlG|1Q2E3m$$dj2I9E{xq^d1rPSp z!2TMk{j3D;9fH7t5UC@O-iJvqMg}^fOD={7J_!$mdzWMc#&a0UN7Mn`-QDUuSMbP) zW^sIEgj!5@1?a#4{ACmWEZf=e_EV5AhlbOKaX z@U;kfn2yE8WER%YdDHB!P~IWSNPpYaCYOXd@qs%w28LO-38C6B=)j;0g9{i8U~mb8 z2_T22~ z(w_^mVR%!--;+7R75AXemEDu<2L*+SoZ`THxAp_@4o*8|^LL3!n=AZXw%P)pf8*QI zGOLEatFE!}DfVdEKzO?cX*2ifU3|jkMgA`1lzExID=4zM-&R)JCTJW`6BxW9-4BM; zaIcCst$Oa$GR&7e_mDEdbAPT*xRuF2NCZ;3sTEB9P1y3ClE}?y^YF7!z;rM8S%g4% zLFf|ndj1!<1U)W6-@Z6R7-ND#0xp{k&+)P!D-ebLN+b~~_5~0;4}iyg`lzBWLWH3R z9_oI9k9-QLFlt`_f%^sA{VIA;DvbT50K;di5pn>?ND)?>8} +#include "bg.h" + +/* EU needs this separate object to preserve the BSS layout. */ +#ifdef VERSION_EU +struct unk_portalstruct table_for_portals[PORTMAX]; +#endif diff --git a/src/game/bondview.c b/src/game/bondview.c index c2502fc6..acfea50e 100644 --- a/src/game/bondview.c +++ b/src/game/bondview.c @@ -156,6 +156,8 @@ #define FLOAT_TEN_A 10.0f #define FLOAT_TEN_B 10.00f +#include "bondview_internal.h" + // bss coord3d g_CamFrustumTopNormal; @@ -172,158 +174,6 @@ f32 flt_CODE_bss_80079984; // unused f32 flt_CODE_bss_80079988; // unused f32 flt_CODE_bss_8007998C; // unused -vec3d g_ForceBondMoveOffset; - -//CODE.bss:8007999C -s32 g_SurroundBondWithExplosionsTicks; -//CODE.bss:800799A0 -s32 g_PlayerTickExplodeCreatePosition; -//CODE.bss:800799A4 -s32 dword_CODE_bss_800799A4; // unused - -//CODE.bss:800799A8 -struct coord3d g_TankModelPositionOffset; - -//CODE.bss:800799B4 -s32 g_TankEngineSfxVolume; - -/** - * Address 0x800799B8. - * State 0: begin. - * State 1: Finished sitting down/turning, queue audio. - * State 2: complete -*/ -s32 g_EnterTankAudioState; - -/** - * Address 0x800799BC. -*/ -f32 g_TankEnteringSitHeight; - -/** - * Address 0x800799C0. -*/ -f32 g_TankEnteringSitHeightRemain; - -/** - * Address 0x800799C4. -*/ -f32 g_TankEnterBondHorizAngleDeg; - -/** - * Address 0x800799C8. -*/ -f32 g_TankEnterBondVertAngleDeg; - -//CODE.bss:800799CC -f32 flt_CODE_bss_800799CC; // unused/padding - -//CODE.bss:800799D0 -struct coord3d g_EnterTankCoord; - -//CODE.bss:800799DC -f32 flt_CODE_bss_800799DC; // unused/padding - -//CODE.bss:800799E0 -ITEM_IDS starting_weapon[2]; - -//CODE.bss:800799E8 -struct coord3d flt_CODE_bss_800799E8; - -//CODE.bss:800799F4 -struct PropRecord* dword_CODE_bss_800799F4; - -//CODE.bss:800799F8 -PadRecord * g_CameraLookAtBondPad; -//CODE.bss:800799FC -CutsceneRecord *gBondViewCutscene; -//CODE.bss:80079A00 -f32 flt_CODE_bss_80079A00; -//CODE.bss:80079A04 -f32 flt_CODE_bss_80079A04; -//CODE.bss:80079A08 -f32 flt_CODE_bss_80079A08; -//CODE.bss:80079A0C -f32 flt_CODE_bss_80079A0C; -//CODE.bss:80079A10 -f32 flt_CODE_bss_80079A10; -//CODE.bss:80079A14 -s32 dword_CODE_bss_80079A14; -//CODE.bss:80079A18 -enum CAMERAMODE dword_CODE_bss_80079A18; -//CODE.bss:80079A1C -s32 dword_CODE_bss_80079A1C; -//CODE.bss:80079A20 -s32 mission_timer; - -#if defined(VERSION_JP) || defined(VERSION_EU) -//CODE.bss:80079A24 -f32 watch_time_0; -#else -//CODE.bss:80079A24 -s32 watch_time_0; -#endif - -/** - * Address 80079A28 - * EU .bss 80068508 -*/ -char stringbuffer_lowerleft[0x5][BONDVIEW_HUD_MSG_BOTTOM_BUFFER_LENGTH]; -char dword_CODE_bss_80079c21[0x04]; - -#if defined(BUGFIX_R1) -//CODE.bss:80079Cd8 -s32 dword_CODE_bss_jp80079Cd8[0x05]; -s32 dword_CODE_bss_jp80079CEC[0x05]; -#endif - -/** - * Address 80079C28 - * EU .bss 80068738 -*/ -PadRecord *g_Startpad[0x10]; - -//CODE.bss:80079C68 -s32 startpadcount; -//CODE.bss:80079C6C -s32 dword_CODE_bss_80079C6C; - -#if defined LEFTOVERDEBUG -//CODE.bss:80079C70 -/***/ -char stringbuffer_top[0x2][BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH]; -u16 dword_CODE_bss_80079d9E; -#endif - -//CODE.bss:80079DA0 -/** - * EU .bss 80078780 -*/ -StandTilePoint *dword_CODE_bss_80079DA0; -//CODE.bss:80079DA4 -StandTilePoint *dword_CODE_bss_80079DA4; - -//CODE.bss:80079DA8 -s32 dword_CODE_bss_80079DA8[BSS_80079DA8_LENGTH]; - -#ifndef VERSION_EU -//CODE.bss:80079DC8 -char dword_CODE_bss_80079DC8[0x3C]; -#else -char dword_CODE_bss_80079DC8[0x2][BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH]; -char dword_CODE_bss_80079EF6[0x3C]; -#endif - -//CODE.bss:80079E04 -f32 g_MpSwirlRotateSpeed; -//CODE.bss:80079E08 -f32 g_MpSwirlAngleDegrees; -//CODE.bss:80079E0C -f32 g_MpSwirlForwardSpeed; -//CODE.bss:80079E10 -f32 g_MpSwirlDistance; - - // data //D:80036420 s32 D_80036420 = 0; @@ -934,29 +784,6 @@ void transform3DCoordinatesWithAngleAndValue(coord3d *in, coord3d *out, f32 angl out->f[0] = (g_CurrentPlayer->c_screenleft + g_CurrentPlayer->c_halfwidth) - (in->f[0] * var2); } -GLOBAL_ASM( -.late_rodata -.late_rodata_alignment 8 -glabel D_80054FB8 -.word 0 -glabel D_80054FBC -.word 0 -glabel a8s -.word 0x25387300 -glabel aX4_0f -.word 0x78202534 -.word 0x2e306600 -glabel aY4_0f -.word 0x79202534 -.word 0x2e306600 -glabel aZ4_0f -.word 0x7a202534 -.word 0x2e306600 -glabel aS3d -.word 0x25732025 -.word 0x33640000 -) - void currentPlayerSetMatrix10C4(Mtx *matrix) { g_CurrentPlayer->field_10C4 = matrix; } @@ -1815,10451 +1642,3 @@ void bondviewSetCurrentPlayerPosition(coord3d *pos, coord3d *pos2, coord3d *offs g_CurrentPlayer->pos3.f[1] = stanGetPositionYValue(g_CurrentPlayer->cameratile, g_CurrentPlayer->pos.f[0], g_CurrentPlayer->pos.f[2]); } } - -#define ALIGN64_V3(val) (((val) | 0x3f) ^ 0x3f) - -void solo_char_load(void) -{ - f32 yaw; - ChrRecord *self; - struct texpool pool; - ModelFileHeader *bodyheader; - ModelFileHeader *headheader; - ModelFileHeader *pitemheader; - u8 *weaponbuf0; - u8 *weaponbuf1; - s32 cursor; - s32 size0; - s32 size1; - s32 helddst; - WeaponObjRecord weapon; - struct player **pp; - s32 prop; - ITEM_IDS item; - s32 body; - s32 head; - struct ItemModelFileRecord *unusedpitem; - Model *model; - - yaw = bondviewGetPlayerYawRadians(); - if (g_CurrentPlayer->prop->chr == NULL) - { - weaponbuf0 = getPlayerWeaponBufferForHand(GUNRIGHT); - weaponbuf1 = getPlayerWeaponBufferForHand(GUNLEFT); - cursor = 0; - size0 = getSizeBufferWeaponInHand(GUNRIGHT); - size1 = getSizeBufferWeaponInHand(GUNLEFT); - weapon = dummy_08_pp7_obj[0]; - item = get_item_in_hand_or_watch_menu(GUNRIGHT); - body = BODY_Formal_Wear; - head = HEAD_Male_Brosnan_Default; - model = NULL; - bodyheader = NULL; - - bondviewDeregisterPlayerRoom(g_CurrentPlayer); - - if (getPlayerCount() == 1) - { - helddst = fileGetBondForCurrentFolder(); - switch (g_CurrentPlayer->bondtype) - { - case CUFF_BLUE: - break; - - case CUFF_BOILER: - body = BODY_Special_Operations_Uniform; - break; - - case CUFF_JUNGLE: - body = BODY_Jungle_Fatigues; - break; - - case CUFF_SNOW: - body = BODY_Parka; - break; - - case CUFF_BROSNAN: - body = BODY_Brosnan_Tuxedo; - break; - - case CUFF_CONNERY: - body = BODY_Brosnan_Tuxedo; - break; - - case CUFF_DALTON: - body = BODY_Brosnan_Tuxedo; - break; - - case CUFF_MOORE: - body = BODY_Brosnan_Tuxedo; - break; - - case CUFF_FOLDER: - switch (helddst) - { - case BOND_BROSNAN: - body = BODY_Brosnan_Tuxedo; - break; - - case BOND_CONNERY: - body = BODY_Brosnan_Tuxedo; - break; - - case BOND_DALTON: - body = BODY_Brosnan_Tuxedo; - break; - - case BOND_MOORE: - body = BODY_Brosnan_Tuxedo; - break; - } - - break; - } - - switch (helddst) - { - case BOND_BROSNAN: - switch (g_CurrentPlayer->bondtype) - { - case CUFF_BLUE: - break; - - case CUFF_BOILER: - head = HEAD_Male_Brosnan_Boiler; - break; - - case CUFF_JUNGLE: - head = HEAD_Male_Brosnan_Jungle; - break; - - case CUFF_BROSNAN: - head = HEAD_Male_Brosnan_Tuxedo; - break; - - case CUFF_CONNERY: - head = HEAD_Male_Brosnan_Tuxedo; - break; - - case CUFF_DALTON: - head = HEAD_Male_Brosnan_Tuxedo; - break; - - case CUFF_MOORE: - head = HEAD_Male_Brosnan_Tuxedo; - break; - - case CUFF_FOLDER: - head = HEAD_Male_Brosnan_Tuxedo; - break; - } - - break; - - case BOND_CONNERY: - head = HEAD_Male_Brosnan_Tuxedo; - break; - - case BOND_DALTON: - head = HEAD_Male_Brosnan_Tuxedo; - break; - - case BOND_MOORE: - head = HEAD_Male_Brosnan_Tuxedo; - break; - } - } - else - { - head = get_player_mp_char_head(get_cur_playernum()); - body = get_player_mp_char_body(get_cur_playernum()); - } - - if (g_CameraMode == CAMERAMODE_SWIRL) - { - item = starting_weapon[GUNRIGHT]; - } - - if (getPlayerCount() == 1) - { - remove_item_in_hand(GUNLEFT); - remove_item_in_hand(GUNRIGHT); - texInitPool(&pool, weaponbuf1, size1); - bodyheader = get_ptr_itemheader_in_hand(GUNRIGHT); - *bodyheader = *c_item_entries[body].header; - load_object_fill_header(bodyheader, (u8 *)c_item_entries[body].filename, weaponbuf0, size0, &pool); - cursor = get_pc_buffer_remaining_value((u8 *)c_item_entries[body].filename); - - do - { - cursor = ALIGN64_V3(cursor + 0x3f); - headheader = (ModelFileHeader *)(weaponbuf0 + cursor); - cursor = ALIGN64_V3(cursor + sizeof(ModelFileHeader) + 0x3f); - *headheader = *c_item_entries[head].header; - - if(1); - - load_object_fill_header(headheader, (u8 *)c_item_entries[head].filename, weaponbuf0 + cursor, size0 - cursor, &pool); - cursor = ALIGN64_V3(get_pc_buffer_remaining_value((u8 *)c_item_entries[head].filename) + cursor + 0x3f); - model = (Model *)(weaponbuf0 + cursor); - cursor = ALIGN64_V3(cursor + 0xfb); - modelCalculateRwDataLen(bodyheader); - modelCalculateRwDataLen(headheader); - - { - u32 *animdata; - s32 nrec; - animdata = (u32 *)(weaponbuf0 + cursor); - nrec = (bodyheader->numRecords + headheader->numRecords) + 0xa; - cursor = ALIGN64_V3(cursor + (nrec << 2) + 0x3f); - animInit(model, bodyheader, animdata); - model->rwdatalen = nrec; - } - - } while (FALSE); - } - else - { - bodyheader = c_item_entries[body].header; - - if (bodyheader->RootNode == NULL) - { - fileLoad(bodyheader, c_item_entries[body].filename); - } -#ifndef VERSION_US - if (c_item_entries[body].hasHead) - { - head = -1; - headheader = NULL; - } - else -#endif - { - headheader = c_item_entries[head].header; - - if (headheader->RootNode == NULL) - { - fileLoad(headheader, c_item_entries[head].filename); - } - } - } - - g_CurrentPlayer->bodyModel = makeonebody(body, head, bodyheader, headheader, 0, model); - modelSetScale(g_CurrentPlayer->bodyModel, g_CurrentPlayer->bodyModel->scale * 0.97f); - init_GUARDdata_with_set_values(g_CurrentPlayer->prop, g_CurrentPlayer->bodyModel, &g_CurrentPlayer->prop->pos, yaw, g_CurrentPlayer->prop->stan, NULL); - pp = &g_CurrentPlayer; - (*pp)->prop->type = PROP_TYPE_VIEWER; - self = (*pp)->prop->chr; - self->chrflags |= CHRFLAG_INIT; - setsuboffset((*pp)->bodyModel, &(*pp)->prop->pos); - setsubroty(g_CurrentPlayer->bodyModel, yaw); -#ifndef VERSION_US - self->headnum = head; - self->bodynum = body; -#endif - prop = getPropForHeldItem(item); - - if (prop >= 0) - { - if (getPlayerCount() == 1) - { - helddst = cursor; - helddst = ((s32)weaponbuf0) + helddst; - cursor = ALIGN64_V3(cursor + 0xc7); - pitemheader = get_ptr_itemheader_in_hand(GUNLEFT); - *pitemheader = *PitemZ_entries[prop].header; - load_object_fill_header(pitemheader, (u8 *)PitemZ_entries[prop].filename, weaponbuf0 + cursor, size0 - cursor, &pool); - get_pc_buffer_remaining_value((u8 *)PitemZ_entries[prop].filename); - modelCalculateRwDataLen(pitemheader); - } - else - { - helddst = 0; - pitemheader = NULL; - } - - something_with_generating_object(self, prop, item, 0, (WeaponObjRecord *)helddst, (ItemModelFileRecord *)pitemheader); - } - - chrlvIdleAnimationRelated7F023A94(self, 0.0f); - } - else - { - self = g_CurrentPlayer->prop->chr; - - if (self->model->anim != NULL) - { - return; - } - - self->chrflags |= CHRFLAG_INIT; - chrlvIdleAnimationRelated7F023A94(self, 0.0f); - setsuboffset(g_CurrentPlayer->bodyModel, &g_CurrentPlayer->prop->pos); - setsubroty(g_CurrentPlayer->bodyModel, yaw); - } -} - - -/** - * Address 0x7F07A4A0. - */ -void bondviewRemovePlayerBody(void) -{ - if ((g_CurrentPlayer->prop->chr) && (getPlayerCount() == 1)) - { - chrpropCleanupForRemoval(g_CurrentPlayer->prop); - g_CurrentPlayer->prop->chr = NULL; - g_CurrentPlayer->bodyModel = 0; - g_bondviewForceDisarm = 1; - bondviewUpdatePlayerRoom(g_CurrentPlayer); - } -} - - -u32 bondviewGetCameraMode(void) { - return g_CameraMode; -} - - -s32 pickDeathCameraAngles(PropRecord *prop1, coord3d *pos, PropRecord *prop2, coord3d *collision_pos, StandTile *tile, f32 camera_dist) -{ - s32 found; - s32 outertries; - f32 camclearance; - f32 spD0; - f32 angle; - StandTile *spC8; - coord3d spBC; - coord3d spB0; - f32 angleRange; - f32 frac; - f32 floorY; - s32 lineok; - s32 angletries; - - dword_CODE_bss_800799F4 = prop1; - - found = 0; - outertries = 0; - angleRange = M_TAU_F; - - while ((outertries <= 0x80) && (!found)) - { - camclearance = g_CurrentPlayer->field_488.collision_radius; - spD0 = 1500.0f + camclearance; - - angle = ((f32) randomGetNext()) * 2.3283064e-10f; - angle = angle * angleRange; - - angletries = 0; - - while ((angletries < 0x10) && (!found)) - { - angleRange = M_TAU_F; - - angle += 0.39269909f; - - if (angleRange <= angle) - { - angle -= angleRange; - } - - spBC.x = sinf(angle); - spBC.y = 0.0f; - spBC.z = cosf(angle); - - spB0.x = (((f32 *) (&spBC))[0] * spD0) + pos->x; - spB0.y = pos->y; - spB0.z = (((f32 *) (&spBC))[2] * spD0) + pos->z; - - stanResetHits(); - - spC8 = tile; - - sub_GAME_7F03D058(prop2, 0); - - lineok = stanTestLineUnobstructed(&spC8, collision_pos->x, collision_pos->z, spB0.x, spB0.z, 0x13, 0.0f, 1.0f, 0.0f, 1.0f); - - sub_GAME_7F03D058(prop2, 1); - - if (!lineok) - { - chrlvStanPointPointIntersection(collision_pos, &spBC, &spB0); - - { - f32 dx = spB0.x - collision_pos->x; - f32 dz = spB0.z - collision_pos->z; - - spD0 = sqrtf((dx * dx) + (dz * dz)); - } - } - - spD0 -= camclearance; - - if (camera_dist <= spD0) - { - frac = 1.0f; - - while ((0.0f < frac) && (!found)) - { - f32 sp90; - f32 candidateDist; - - sp90 = spD0 - camera_dist; - - candidateDist = ((f32) randomGetNext()) * 2.3283064e-10f; - candidateDist *= sp90; - candidateDist *= frac; - candidateDist += camera_dist; - - flt_CODE_bss_800799E8.x = (spBC.x * candidateDist) + pos->x; - flt_CODE_bss_800799E8.y = pos->y; - flt_CODE_bss_800799E8.z = (spBC.z * candidateDist) + pos->z; - - spC8 = tile; - - sub_GAME_7F03D058(prop2, 0); - - lineok = stanTestLineUnobstructed(&spC8, collision_pos->x, collision_pos->z, flt_CODE_bss_800799E8.x, flt_CODE_bss_800799E8.z, 0x13, 0.0f, 1.0f, 0.0f, 1.0f); - - sub_GAME_7F03D058(prop2, 1); - - if (lineok) - { - lineok = stanTestVolume(&spC8, flt_CODE_bss_800799E8.x, flt_CODE_bss_800799E8.z, camclearance, 0x1f, 0.0f, 1.0f); - - if (lineok < 0) - { - floorY = stanGetPositionYValue(spC8, flt_CODE_bss_800799E8.x, flt_CODE_bss_800799E8.z); - - flt_CODE_bss_800799E8.y = (floorY + camclearance) + ((((f32) randomGetNext()) * 2.3283064e-10f) * (185.0f - camclearance)); - - candidateDist = flt_CODE_bss_800799E8.y - pos->y; - - if (((-1000.0f) < candidateDist) && (candidateDist < 1000.0f)) - { - found = 1; - } - } - } - - frac -= 0.25f; - - if (pos); - } - } - - angletries++; - } - - angleRange = M_TAU_F; - - outertries++; - } - - return found; -} - - -// Address 0x7F07A9B8 NTSC. -void bondviewSetCameraMode(s32 arg0) -{ - s32 padding; - s32 padding2; - - g_CameraMode = arg0; - g_CameraAfterCinema = 0; - - if (g_CameraMode == CAMERAMODE_INTRO) - { - if ((ptr_random06cam_entry != NULL) && (get_recording_ramrom_flag() == 0) && (get_is_ramrom_flag() == 0)) - { - camera_transition_timer = 0.0f; - currentPlayerSetFadeColour(0, 0, 0, 1.0f); - currentPlayerSetFadeFrac(60.0f, 0.0f); - fogLoadLevelEnvironment(bossGetStageNum(), 1); - g_CurrentPlayer->cameratile = NULL; - } - else - { - bondviewSetCameraMode(CAMERAMODE_SWIRL); - } - } - else if (g_CameraMode == CAMERAMODE_FADESWIRL) - { - currentPlayerSetFadeColour(0, 0, 0, 0.0f); - currentPlayerSetFadeFrac(60.0f, 1.0f); - } - else if (g_CameraMode == CAMERAMODE_MP) - { - g_MpSwirlRotateSpeed = 0.0f; - g_MpSwirlAngleDegrees = -90.0f; - g_MpSwirlForwardSpeed = 0.0f; - g_MpSwirlDistance = 80.0f; - fogLoadLevelEnvironment(bossGetStageNum(), 0); - } - else if (g_CameraMode == CAMERAMODE_SWIRL) - { - struct ModelAnimation *sp38; - f32 sp78; - f32 ftemp_3; - f32 ftemp_1; - struct ChrRecord *temp_v1; - - camera_fade_active = 0; - currentPlayerSetFadeColour(0, 0, 0, 1.0f); - currentPlayerSetFadeFrac(60.0f, 0.0f); - fogLoadLevelEnvironment(bossGetStageNum(), 0); - - if ((g_IntroSwirl != 0) && (get_recording_ramrom_flag() == 0) && (get_is_ramrom_flag() == 0)) - { - camera_transition_timer = 0.0f; - intro_camera_index = CAMERAMODE_INTRO; - currentPlayerStartChrFade(0.0f, 1.0f); - solo_char_load(); - - // HACK: ptr_animation_table->data regalloc is backwards - sp38 = (struct ModelAnimation *)((s32)stage_intro_anim_table[g_IntroAnimationIndex].anonymous_0 + (s32)&ptr_animation_table->data); - sp78 = stage_intro_anim_table[g_IntroAnimationIndex].anonymous_2; - ftemp_1 = stage_intro_anim_table[g_IntroAnimationIndex].anonymous_1; - ftemp_3 = stage_intro_anim_table[g_IntroAnimationIndex].anonymous_3; - - modelSetAnimation( - g_CurrentPlayer->bodyModel, - sp38, - 0, - ftemp_1, - ftemp_3, - 0.0f); - - if (sp78 > 0.0f) - { - modelSetAnimEndFrame(g_CurrentPlayer->bodyModel, sp78); - } - - temp_v1 = g_CurrentPlayer->prop->chr; - temp_v1->actiontype = ACT_BONDINTRO; - temp_v1->sleep = 0; - g_CurrentPlayer->cameratile = NULL; - } - else - { - bondviewSetCameraMode(CAMERAMODE_FP); - } - } - else if (g_CameraMode == CAMERAMODE_FP) - { - if (bossGetStageNum() == LEVELID_CUBA) - { - currentPlayerSetFadeColour(0, 0, 0, 1.0f); - currentPlayerSetFadeFrac(0.0f, 1.0f); - } - else if (camera_fade_active != 0) - { - currentPlayerSetFadeColour(0, 0, 0, 1.0f); - currentPlayerSetFadeFrac(60.0f, 0.0f); - } - - if (getPlayerCount() >= 2) - { - fogLoadLevelEnvironment(bossGetStageNum(), 0); - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) - { - currentPlayerEquipWeaponWrapper(GUNLEFT, starting_weapon[GUNLEFT]); - currentPlayerEquipWeaponWrapper(GUNRIGHT, starting_weapon[GUNRIGHT]); - } - - stop_time_flag = 0; - } - else if (g_CameraMode == CAMERAMODE_DEATH_CAM_SP) - { - f32 var_f0; - PropRecord *sp64; - struct coord3d sp58; - StandTile *var_v1; - struct coord3d sp48; - PropRecord *var_a2; - struct ChrRecord *temp_v1_2; - - camera_transition_timer = 0.0f; - intro_camera_index = CAMERAMODE_INTRO; - currentPlayerSetFadeColour(0, 0, 0, 1.0f); - currentPlayerSetFadeFrac(60.0f, 0.0f); - - if (g_ExplodeTankOnDeathFlag && (g_PlayerTankProp != NULL)) - { - // removed - } - else - { - // This branch restarts Bond's death animation for his death replay - g_PlayerIsInTank = 0; - - // struct copy - g_CurrentPlayer->field_488 = g_CurrentPlayer->previous_collision_info; - - g_CurrentPlayer->vv_theta = g_CurrentPlayer->thetadie; - g_CurrentPlayer->vv_verta = g_CurrentPlayer->vertadie; - g_CurrentPlayer->prop->pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; - g_CurrentPlayer->prop->pos.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; - g_CurrentPlayer->prop->pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; - g_CurrentPlayer->prop->stan = g_CurrentPlayer->field_488.current_tile_ptr; - - bondviewApplyVertaTheta(); - bondviewMoveAnimationTick(0, 0, 0); - bondviewUpdatePlayerCollisionPositionFields(); - currentPlayerStartChrFade(0.0f, 1.0f); - solo_char_load(); - - modelSetAnimation( - g_CurrentPlayer->bodyModel, - objecthandlerGetModelAnim((Model *) &g_CurrentPlayer->model), - objecthandlerGetModelGunhand(&g_CurrentPlayer->model), - 0.0f, - 0.5f, - 0.0f); - - temp_v1_2 = g_CurrentPlayer->prop->chr; - temp_v1_2->actiontype = ACT_BONDDIE; - temp_v1_2->sleep = 0; - temp_v1_2->chrflags |= CHRFLAG_INIT; - - setsuboffset(g_CurrentPlayer->bodyModel, &g_CurrentPlayer->prop->pos); - var_f0 = bondviewGetPlayerYawRadians(); - setsubroty(g_CurrentPlayer->bodyModel, var_f0); - } - - if (g_ExplodeTankOnDeathFlag && (g_PlayerTankProp != NULL)) - { - sp64 = g_PlayerTankProp; - var_f0 = 500.0f; // distance to place the camera - sp58.f[0] = g_PlayerTankProp->pos.f[0]; - sp58.f[1] = g_PlayerTankProp->pos.f[1]; - sp58.f[2] = g_PlayerTankProp->pos.f[2]; - var_a2 = g_PlayerTankProp; - sp48.f[0] = g_PlayerTankProp->pos.f[0]; - sp48.f[1] = g_PlayerTankProp->pos.f[1]; - sp48.f[2] = g_PlayerTankProp->pos.f[2]; - var_v1 = g_PlayerTankProp->stan; - } - else - { - var_f0 = 200.0f; // distance to place the camera - sp64 = g_CurrentPlayer->prop; - sp58.f[0] = g_CurrentPlayer->field_3C4; - sp58.f[1] = g_CurrentPlayer->field_3C8; - sp58.f[2] = g_CurrentPlayer->field_3CC; - var_a2 = g_CurrentPlayer->prop; - sp48.f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; - sp48.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; - sp48.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; - var_v1 = g_CurrentPlayer->field_488.current_tile_ptr; - } - - if (pickDeathCameraAngles(sp64, &sp58, var_a2, &sp48, var_v1, var_f0) != 0) - { - if (camera_mode == 0) - { -#ifdef DEBUG - osSyncPrintf("mute\n"); -#endif - - musicTrack1Play(M_INTROSWOOSH); - sndSetScalerApplyVolumeAllSfxSlot(0.5f); - } - - if ((g_ExplodeTankOnDeathFlag != 0) && (g_PlayerTankProp != NULL)) - { - explosionCreate(g_PlayerTankProp, &g_PlayerTankProp->pos, g_PlayerTankProp->stan, 0xD, 0, get_cur_playernum(), g_PlayerTankProp->rooms, 0); - } - } - else - { - // pickDeathCameraAngles has returned 0. This happens when no possible angles were found - // to place the camera at the requested distance or when the three death replays are finished. - bossRunTitleStage(); - } - } - else if (g_CameraMode == CAMERAMODE_DEATH_CAM_MP) - { - currentPlayerSetFadeColour(0, 0, 0, 0.0f); - currentPlayerSetFadeFrac(60.0f, 1.0f); - } - else if (g_CameraMode == CAMERAMODE_POSEND) - { - solo_char_load(); - g_CurrentPlayer->cameratile = NULL; - } - else if (g_CameraMode == CAMERAMODE_FP_NOINPUT) - { - bondviewRemovePlayerBody(); - g_CameraMode = CAMERAMODE_FP; - } - else if (g_CameraMode == CAMERAMODE_FADE_TO_TITLE) - { - s32 var_s0; - - for (var_s0 = 0; var_s0 < getPlayerCount(); var_s0++) - { - set_cur_player(var_s0); - currentPlayerSetFadeColour(0, 0, 0, 0.0f); - currentPlayerSetFadeFrac(60.0f, 1.0f); - } - - set_cur_player(0); - } -} - - -void bondviewAdvanceCameraMode(void) -{ - enum CAMERAMODE mode = g_CameraMode; - - g_CameraMode = CAMERAMODE_NONE; - g_CameraAfterCinema = CAMERAMODE_NONE; - - if (mode == CAMERAMODE_INTRO) - { - bondviewSetCameraMode(CAMERAMODE_FADESWIRL); - } - else if (mode == CAMERAMODE_FADESWIRL) - { - bondviewResetIntroCameraMessageDialogs(); - bondviewSetCameraMode(CAMERAMODE_SWIRL); - } - else if (mode != CAMERAMODE_MP) - { - if (mode == CAMERAMODE_SWIRL) - { - bondviewRemovePlayerBody(); - currentPlayerStartChrFade(0.0f, 1.0f); // What's the point of this call? - bondviewSetCameraMode(CAMERAMODE_FP); - } - else if (mode != CAMERAMODE_FP) - { - if (mode == CAMERAMODE_DEATH_CAM_SP) - { - bondviewSetCameraMode(CAMERAMODE_DEATH_CAM_MP); - } - else if (mode == CAMERAMODE_DEATH_CAM_MP) - { - camera_mode++; - - if (camera_mode < CAMERAMODE_SWIRL) - { - bondviewSetCameraMode(CAMERAMODE_DEATH_CAM_SP); - } - } - } - } -} - - -/** - * Smoothly interpolate the camera between the points on the intro swirl path. - */ -void bondviewCalcIntroSwirlCamera(s32 index, f32 time, coord3d *pos, coord3d *lookat) -{ - struct SetupIntroSwirl *base; - struct SetupIntroSwirl *loopbase; - f32 pointbuf[10]; - struct SetupIntroSwirl *swirl; - f32 frac; - f32 *dst; - - base = g_IntroSwirl; - swirl = base; - swirl += index; - frac = 0.0f; - - if (swirl->duration.fval > 0.0f) - { - frac = time / swirl->duration.fval; - } - - { - struct SetupIntroSwirl *entry; - union { - struct SetupIntroSwirl *swirl; - struct player *player; - } target; - s32 i; - - loopbase = base + (u32) index; - - for (i = -1; i < 3; i++) - { - entry = loopbase; - loopbase = base + (u32) index; - target.swirl = entry + i; - dst = &pointbuf[i * 3]; - - if (i < 0) - { - if (target.swirl < base) - { - entry = base; - } - else - { - entry = target.swirl; - } - } - else - { - while (entry < target.swirl) - { - if (entry[1].bitflags & 1) - { - break; - } - - entry++; - } - } - - if (entry->bitflags & 2) - { - target.player = g_CurrentPlayer; - dst[3] = (entry->offsetfromBond[2].fval * target.player->field_488.theta_transform.f[0]) - + (entry->offsetfromBond[0].fval * target.player->field_488.theta_transform.f[2]); - dst[4] = entry->offsetfromBond[1].fval; - dst[5] = (entry->offsetfromBond[2].fval * target.player->field_488.theta_transform.f[2]) - - (entry->offsetfromBond[0].fval * target.player->field_488.theta_transform.f[0]); - } - else - { - dst[3] = entry->offsetfromBond[0].fval; - dst[4] = entry->offsetfromBond[1].fval; - dst[5] = entry->offsetfromBond[2].fval; - } - } - } - - { - f32 scale; - - base = swirl; - scale = base->scale.fval; - base = (void *)(index << 5); - - coord3dCubicSplineInterp((coord3d *) &pointbuf[0], (coord3d *) &pointbuf[3], (coord3d *) &pointbuf[6], (coord3d *) &pointbuf[9], frac, scale, pos); - - pos->x += g_CurrentPlayer->field_3C4; - pos->y += g_CurrentPlayer->field_3C8; - pos->z += g_CurrentPlayer->field_3CC; - - lookat->x = g_CurrentPlayer->field_3C4; - lookat->y = g_CurrentPlayer->field_3C8; - lookat->z = g_CurrentPlayer->field_3CC; - - swirl = (void *)(((u32) g_IntroSwirl) + (u32) base); - - if (!(swirl->bitflags & 4)) - { - if (!(swirl[1].bitflags & 4)) - { - scale = 1.0f; - } - else - { - scale = 1.0f - frac; - } - } - else if (swirl[1].bitflags & 4) - { - scale = 0.0f; - } - else - { - scale = frac; - } - - lookat->x += (g_CurrentPlayer->field_488.applied_view.x * 40.0f) * scale; - lookat->y += (g_CurrentPlayer->field_488.applied_view.y * 40.0f) * scale; - lookat->z += (g_CurrentPlayer->field_488.applied_view.z * 40.0f) * scale; - } -} - - -/** - * US address 7F07B56C. - * JP address 7F07BB8C. - * EU address 7F07B604. -*/ -void bondviewFrozenCameraTick(u16 buttons, u16 oldbuttons, struct coord3d *pos, struct coord3d *pos2, struct coord3d *offset, StandTile **stan, struct coord3d *arg6) -{ - s32 i; - f32 sp38; - s32 i2; - f32 sp30 = 0.0f; - s32 padding2; - f32 zero = 0.0f; - void *p; - struct PadRecord *setupPad; - - if ((g_CameraMode == CAMERAMODE_INTRO) || (g_CameraMode == CAMERAMODE_FADESWIRL)) - { - if (g_CameraMode == CAMERAMODE_INTRO) - { - if ((camera_transition_timer < 120.0f) && ((camera_transition_timer + g_GlobalTimerDelta) >= 120.0f)) - { -#if defined(VERSION_US) - setFontTables(ptrFontZurichBoldChars, ptrFontZurichBold); - hudmsgBottomShow(ptr_random06cam_entry->lang1c.lang_ptr); -#else - hudmsgBottomShow(ptr_random06cam_entry->lang1c.lang_ptr, ptrFontZurichBoldChars, ptrFontZurichBold); -#endif - } - - if (ptr_random06cam_entry->lang20.lang_ptr != NULL) - { - if ((camera_transition_timer < 300.0f) && ((camera_transition_timer + g_GlobalTimerDelta) >= 300.0f)) - { -#if defined(VERSION_US) - hudmsgBottomShow(ptr_random06cam_entry->lang20.lang_ptr); -#else - hudmsgBottomShow(ptr_random06cam_entry->lang20.lang_ptr, ptrFontZurichBoldChars, ptrFontZurichBold); -#endif - } - - if (camera_transition_timer > 480.0f) - { - g_CameraAfterCinema = CAMERAMODE_INTRO; - } - } - else if (camera_transition_timer > 300.0f) - { - g_CameraAfterCinema = CAMERAMODE_INTRO; - } - - camera_transition_timer += g_GlobalTimerDelta; - - if ((lvlGetControlsLockedFlag() == 0) - && (buttons & ~oldbuttons & (CONT_A | B_BUTTON | Z_TRIG | START_BUTTON | CONT_R | CONT_L))) - { - g_CameraAfterCinema = CAMERAMODE_INTRO; - } - } - else if (g_CurrentPlayer->colourfadetimemax60 < 0.0f) - { - g_CameraAfterCinema = CAMERAMODE_INTRO; - } - - pos->f[0] = ptr_random06cam_entry->unk04.fval; - pos->f[1] = ptr_random06cam_entry->unk08.fval; - pos->f[2] = ptr_random06cam_entry->unk0C.fval; - - pos2->f[0] = pos->f[0] + (cosf(ptr_random06cam_entry->unk14.fval) * sinf(ptr_random06cam_entry->unk10.fval)); - pos2->f[1] = pos->f[1] + sinf(ptr_random06cam_entry->unk14.fval); - pos2->f[2] = pos->f[2] - (cosf(ptr_random06cam_entry->unk14.fval) * cosf(ptr_random06cam_entry->unk10.fval)); - - p = &g_CurrentSetup.pads[ptr_random06cam_entry->unk18]; - setupPad = p; - *stan = setupPad->stan; - - arg6->f[0] = setupPad->pos.f[0]; - arg6->f[1] = setupPad->pos.f[1]; - arg6->f[2] = setupPad->pos.f[2]; - } - else if (g_CameraMode == CAMERAMODE_MP) - { - /** - * CAMERAMODE_MP: Perfect Dark method playerTickMpSwirl - */ - if (get_player_position_in_shuffled(get_cur_playernum()) == 0) - { - for (i2=0; i2 110.0f) - { - g_MpSwirlRotateSpeed -= 0.1f; - } - - g_MpSwirlAngleDegrees += g_MpSwirlRotateSpeed; - } -#if defined(VERSION_EU) - if (g_MpSwirlAngleDegrees >= 179.5f) -#else - else -#endif - { - g_MpSwirlAngleDegrees = 180.0f; - } - - if (g_MpSwirlAngleDegrees > 80.0f) - { - if (g_MpSwirlDistance > 60.0f) - { - g_MpSwirlForwardSpeed -= 0.1f; - } - else - { - g_MpSwirlForwardSpeed += 0.015f; - } - - g_MpSwirlDistance += g_MpSwirlForwardSpeed; - - if (g_MpSwirlDistance < 1.0f) - { - g_MpSwirlDistance = 1.0f; - } - } - } - } - - sp38 = ((g_MpSwirlAngleDegrees - g_CurrentPlayer->vv_theta) * M_PI_F) / 180.0f; - - pos->f[0] = g_CurrentPlayer->field_488.pos.f[0] + (sinf(sp38) * g_MpSwirlDistance); - pos->f[1] = g_CurrentPlayer->field_488.pos.f[1] + (g_MpSwirlDistance * 0.08f); - pos->f[2] = g_CurrentPlayer->field_488.pos.f[2] + (cosf(sp38) * g_MpSwirlDistance); - - pos2->f[0] = g_CurrentPlayer->field_488.pos.f[0]; - pos2->f[1] = g_CurrentPlayer->field_488.pos.f[1]; - pos2->f[2] = g_CurrentPlayer->field_488.pos.f[2]; - - *stan = g_CurrentPlayer->prop->stan; - - arg6->f[0] = g_CurrentPlayer->field_488.pos.f[0]; - arg6->f[1] = g_CurrentPlayer->field_488.pos.f[1] + (g_MpSwirlDistance * 0.08f); - arg6->f[2] = g_CurrentPlayer->field_488.pos.f[2]; - -#if defined(VERSION_EU) - if (((get_player_position_in_shuffled(get_cur_playernum()) + 1) == getPlayerCount()) && (g_MpSwirlDistance < 5.0f)) - { - g_CameraAfterCinema = CAMERAMODE_INTRO; - } -#else - if (g_MpSwirlDistance < 5.0f) - { - g_CameraAfterCinema = CAMERAMODE_INTRO; - } -#endif - } - else if (g_CameraMode == CAMERAMODE_SWIRL) - { - camera_transition_timer += g_GlobalTimerDelta; - - while (g_IntroSwirl[intro_camera_index].unk18.fval <= camera_transition_timer) - { - if (!(g_IntroSwirl[intro_camera_index + 3].unk04 & 1)) - { - camera_transition_timer -= g_IntroSwirl[intro_camera_index].unk18.fval; - intro_camera_index++; - } - else - { - camera_transition_timer = g_IntroSwirl[intro_camera_index].unk18.fval; - g_CameraAfterCinema = CAMERAMODE_INTRO; - break; - } - } - - sp30 += (g_IntroSwirl[intro_camera_index].unk18.fval - camera_transition_timer); - - for (i = intro_camera_index + 1; !(g_IntroSwirl[i+2].unk04 & 1); i++) - { - sp30 += g_IntroSwirl[i].unk18.fval; - } - - // Fade player body from opaque to transparent just before the player takes control. - if ((sp30 < 30.0f) && ((sp30 + g_GlobalTimerDelta) >= 30.0f)) - { - currentPlayerStartChrFade(30.0f, 0.0f); - } - - if (camera_fade_active != 0) - { - if (currentPlayerIsFadeComplete() != 0) - { - g_CameraAfterCinema = CAMERAMODE_INTRO; - } - } - - if ((sp30 > 60.0f) && (camera_fade_active == 0)) - { - if ((lvlGetControlsLockedFlag() == 0) - && (buttons & ~oldbuttons & (A_BUTTON | B_BUTTON | Z_TRIG | START_BUTTON | L_TRIG | R_TRIG))) - { - camera_fade_active = 1; - currentPlayerSetFadeColour(0, 0, 0, g_CurrentPlayer->colourscreenfrac); - - if (currentPlayerIsFadeComplete() != 0) - { - currentPlayerSetFadeFrac(60.0f, 1.0f); - } - else - { - currentPlayerSetFadeFrac(g_CurrentPlayer->colourfadetime60, 1.0f); - } - } - } - - bondviewCalcIntroSwirlCamera(intro_camera_index, camera_transition_timer, pos, pos2); - - if (g_IntroSwirl[intro_camera_index].unk1C >= 0) - { - p = &g_CurrentSetup.pads[g_IntroSwirl[intro_camera_index].unk1C]; - setupPad = p; - *stan = setupPad->stan; - - arg6->f[0] = setupPad->pos.f[0]; - arg6->f[1] = setupPad->pos.f[1]; - arg6->f[2] = setupPad->pos.f[2]; - } - else - { - *stan = g_CurrentPlayer->field_488.current_tile_ptr; - arg6->f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; - arg6->f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; - arg6->f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; - } - } - else if ((g_CameraMode == CAMERAMODE_DEATH_CAM_SP) || (g_CameraMode == CAMERAMODE_DEATH_CAM_MP)) - { - if (g_CameraMode == CAMERAMODE_DEATH_CAM_SP) - { - camera_transition_timer += g_GlobalTimerDelta; - - if (g_CurrentPlayer->bodyModel != NULL) - { - if (modelGetAnimFrame((Model *) g_CurrentPlayer->bodyModel) - >= modelGetAnimEndFrame((Model *) g_CurrentPlayer->bodyModel)) - { - g_CameraAfterCinema = CAMERAMODE_INTRO; - } - } - else if (camera_transition_timer >= 180.0f) - { - g_CameraAfterCinema = CAMERAMODE_INTRO; - } - - if ((buttons & ~oldbuttons & (CONT_A | B_BUTTON | Z_TRIG | START_BUTTON)) - && (g_CurrentPlayer->bonddead) - && (g_CurrentPlayer->redbloodfinished) - && (g_CurrentPlayer->deathanimfinished)) - { - g_CameraAfterCinema = CAMERAMODE_INTRO; - camera_mode = CAMERAMODE_FADESWIRL; - } - } - else if (g_CameraMode == CAMERAMODE_DEATH_CAM_MP) - { - camera_transition_timer += g_GlobalTimerDelta; - - if (g_CurrentPlayer->colourfadetimemax60 < 0.0f) - { - g_CameraAfterCinema = CAMERAMODE_INTRO; - } - - if ((buttons & ~oldbuttons & (CONT_A | B_BUTTON | Z_TRIG | START_BUTTON)) - && (g_CurrentPlayer->bonddead) - && (g_CurrentPlayer->redbloodfinished) - && (g_CurrentPlayer->deathanimfinished)) - { - camera_mode = CAMERAMODE_FADESWIRL; - } - } - - pos->f[0] = flt_CODE_bss_800799E8.f[0]; - pos->f[1] = flt_CODE_bss_800799E8.f[1]; - pos->f[2] = flt_CODE_bss_800799E8.f[2]; - - if (dword_CODE_bss_800799F4 == g_CurrentPlayer->prop) - { - pos2->f[0] = g_CurrentPlayer->field_3C4; - pos2->f[1] = g_CurrentPlayer->field_3C8; - pos2->f[2] = g_CurrentPlayer->field_3CC; - } - else - { - pos2->f[0] = dword_CODE_bss_800799F4->pos.f[0]; - pos2->f[1] = dword_CODE_bss_800799F4->pos.f[1]; - pos2->f[2] = dword_CODE_bss_800799F4->pos.f[2]; - } - - *stan = g_CurrentPlayer->field_488.current_tile_ptr; - - arg6->f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; - arg6->f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; - arg6->f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; - } - else if (g_CameraMode == CAMERAMODE_POSEND) - { - if (g_CameraLookAtBondPad != NULL) - { - pos->f[0] = g_CameraLookAtBondPad->pos.f[0]; - pos->f[1] = g_CameraLookAtBondPad->pos.f[1]; - pos->f[2] = g_CameraLookAtBondPad->pos.f[2]; - - pos2->f[0] = g_CurrentPlayer->field_3C4; - pos2->f[1] = g_CurrentPlayer->field_3C8; - pos2->f[2] = g_CurrentPlayer->field_3CC; - - *stan = g_CameraLookAtBondPad->stan; - - arg6->f[0] = g_CameraLookAtBondPad->pos.f[0]; - arg6->f[1] = g_CameraLookAtBondPad->pos.f[1]; - arg6->f[2] = g_CameraLookAtBondPad->pos.f[2]; - - return; - } - - if (gBondViewCutscene != NULL) - { - if (isNotBoundPad(gBondViewCutscene->pad)) - { - p = &g_CurrentSetup.pads[gBondViewCutscene->pad]; - } - else - { - p = &g_CurrentSetup.boundpads[getBoundPadNum(gBondViewCutscene->pad)]; - } - - pos->f[0] = gBondViewCutscene->pos.f[0]; - pos->f[1] = gBondViewCutscene->pos.f[1]; - pos->f[2] = gBondViewCutscene->pos.f[2]; - - setupPad = p; - *stan = setupPad->stan; - - arg6->f[0] = setupPad->pos.f[0]; - arg6->f[1] = setupPad->pos.f[1]; - arg6->f[2] = setupPad->pos.f[2]; - - if (dword_CODE_bss_80079A18 == CAMERAMODE_INTRO) - { - pos2->f[0] = g_CurrentPlayer->field_3C4; - pos2->f[1] = g_CurrentPlayer->field_3C8; - pos2->f[2] = g_CurrentPlayer->field_3CC; - } - else - { - pos2->f[0] = pos->f[0] + (cosf(gBondViewCutscene->verta) * sinf(gBondViewCutscene->theta)); - pos2->f[1] = pos->f[1] + sinf(gBondViewCutscene->verta); - pos2->f[2] = pos->f[2] - (cosf(gBondViewCutscene->verta) * cosf(gBondViewCutscene->theta)); - } - - return; - } - - if (isNotBoundPad(dword_CODE_bss_80079A14)) - { - setupPad = &g_CurrentSetup.pads[dword_CODE_bss_80079A14]; - } - else - { - setupPad = (struct PadRecord*)&g_CurrentSetup.boundpads[getBoundPadNum(dword_CODE_bss_80079A14)]; - } - - *stan = setupPad->stan; - - arg6->f[0] = setupPad->pos.f[0]; - arg6->f[1] = setupPad->pos.f[1]; - arg6->f[2] = setupPad->pos.f[2]; - - pos2->f[0] = setupPad->pos.f[0] + cosf(flt_CODE_bss_80079A00) * 0.0f; - pos2->f[1] = setupPad->pos.f[1] + flt_CODE_bss_80079A10; - pos2->f[2] = setupPad->pos.f[2] + sinf(flt_CODE_bss_80079A00) * 0.0f; - - pos->f[0] = setupPad->pos.f[0] + (sinf(flt_CODE_bss_80079A00) * flt_CODE_bss_80079A08) + cosf(flt_CODE_bss_80079A00) * 0.0f; - pos->f[1] = setupPad->pos.f[1] + flt_CODE_bss_80079A10 + flt_CODE_bss_80079A0C; - pos->f[2] = setupPad->pos.f[2] + (cosf(flt_CODE_bss_80079A00) * flt_CODE_bss_80079A08) + sinf(flt_CODE_bss_80079A00) * 0.0f; - - flt_CODE_bss_80079A00 += flt_CODE_bss_80079A04 * g_GlobalTimerDelta; - - while (flt_CODE_bss_80079A00 >= M_TAU_F) - { - flt_CODE_bss_80079A00 -= M_TAU_F; - } - - while (flt_CODE_bss_80079A00 < 0.0f) - { - flt_CODE_bss_80079A00 += M_TAU_F; - } - } -} - - -//begin bondmove.c per pd - -void sub_GAME_7F07C540(s32 arg0) -{ - g_CurrentPlayer->field_42c = arg0; -} - - -void currentPlayerSetLookAheadSetting(bool enabled) -{ - g_CurrentPlayer->automovecentreenabled = enabled; -} - - -/** - * Unreferenced - */ -bool currentPlayerGetLookAheadSetting(void) -{ - return g_CurrentPlayer->automovecentreenabled; -} - - -void currentPlayerSetYAutoAimEnabled(bool enabled) -{ - g_CurrentPlayer->autoyaimenabled = enabled; -} - - -/** - * Address 0x7F07C580. - */ -bool currentPlayerGetYAutoAimEnabled(void) -{ - if (getPlayerCount() == 1) - { - return g_CurrentPlayer->autoyaimenabled; - } - - return (bool) g_playerPerm->autoaim; -} - - -bool currentPlayerGetYAutoAimEnabledRedirect(void) -{ - return currentPlayerGetYAutoAimEnabled(); -} - - -bool currentPlayerGetIsAiming(void) -{ - return g_CurrentPlayer->insightaimmode; -} - - -/** - * Updates autoyaimtime60 by g_ClockTimer. - * Will update player->autoaimy if new autoyaimtime60 < 0 or autoaim_target != g_CurrentPlayer->autoaim_target_y. - * - * Address 0x7F07C5F0. - */ -void bondviewUpdateYAutoAimTime(struct PropRecord *autoaim_target, f32 auto_aim_y) -{ - if (g_CurrentPlayer->autoyaimtime60 >= 0) - { - g_CurrentPlayer->autoyaimtime60 = g_CurrentPlayer->autoyaimtime60 - g_ClockTimer; - } - - if (autoaim_target != g_CurrentPlayer->autoaim_target_y) - { - if (g_CurrentPlayer->autoyaimtime60 < 0) - { - g_CurrentPlayer->autoyaimtime60 = BONDVIEW_AUTOAIM_TIME; - g_CurrentPlayer->autoaim_target_y = autoaim_target; - } - else - { - return; - } - } - - g_CurrentPlayer->autoaimy = auto_aim_y; -} - - -void currentPlayerSetXAutoAimEnabled(bool enabled) -{ - g_CurrentPlayer->autoxaimenabled = enabled; - - return; -} - - -/** - * Address 0x7F07C668. - */ -bool currentPlayerGetXAutoAimEnabled(void) -{ - if (getPlayerCount() == 1) - { - return g_CurrentPlayer->autoxaimenabled; - } - - return (bool) g_playerPerm->autoaim; -} - - -bool currentPlayerGetXAutoAimEnabledRedirect(void) -{ - return currentPlayerGetXAutoAimEnabled(); -} - - -/** - * Updates autoxaimtime60 by g_ClockTimer. - * Will update player->autoaimx if new autoxaimtime60 < 0 or autoaim_target_x != g_CurrentPlayer->autoaim_target_x. - * - * Address 0x7F07C6C8. - */ -void bondviewUpdateXAutoAimTime(struct PropRecord *autoaim_target, f32 auto_aim_x) -{ - if (g_CurrentPlayer->autoxaimtime60 >= 0) - { - g_CurrentPlayer->autoxaimtime60 = g_CurrentPlayer->autoxaimtime60 - g_ClockTimer; - } - - if (autoaim_target != g_CurrentPlayer->autoaim_target_x) - { - if (g_CurrentPlayer->autoxaimtime60 < 0) - { - g_CurrentPlayer->autoxaimtime60 = BONDVIEW_AUTOAIM_TIME; - g_CurrentPlayer->autoaim_target_x = autoaim_target; - } - else - { - return; - } - } - - g_CurrentPlayer->autoaimx = auto_aim_x; - -} - - -void change_player_pos_to_target(struct collision434 *col, coord3d *pos, StandTile *stan) -{ - f32 store_x; - f32 store_x2; - f32 store_z; - f32 store_y; - col->collision_position.x = pos->x; - store_x = col->collision_position.x; - col->collision_position.y = pos->y; - store_y = col->collision_position.y; - col->collision_position.z = pos->z; - store_z = col->collision_position.z; - store_x2 = pos->x; - col->current_tile_ptr = stan; - col->current_tile_ptr_for_portals = stan; - col->applied_view.y = 0.0f; - col->applied_view.z = 0.0f; - col->applied_view2.x = 0.0f; - col->applied_view2.z = store_x2 * 0.0f; - col->theta_transform.x = 0.0f; - col->theta_transform.y = 0.0f; - col->pos.x = store_x; - col->pos3.x = store_x; - col->applied_view.x = 1.0f; - col->applied_view2.y = 1.0f; - col->theta_transform.z = 1.0f; - col->pos.y = store_y; - col->pos3.y = store_y; - col->pos.z = store_z; - col->pos3.z = store_z; - col->collision_radius = 30; -} - - -/** - * US address 7F07C7B4. -*/ -void bondviewTankModelRotationRelated(void) { - struct ObjectRecord *obj; - struct coord3d *sp68; - struct coord3d *sp64; - Mtxf sp24; - ModelNode **temp_v0; - - if (g_PlayerTankProp != NULL) - { - obj = g_PlayerTankProp->obj; - - /// TODO: Fix Model struct Data type. - temp_v0 = obj->model->obj->Switches; - sp68 = (struct coord3d *)temp_v0[2]->Data; - sp64 = (struct coord3d *)temp_v0[1]->Data; - matrix_4x4_set_rotation_around_y(M_TAU_F - g_TankTurretOrientationAngleRad, &sp24); - g_TankModelPositionOffset.f[0] = sp68->f[0]; - g_TankModelPositionOffset.f[1] = sp68->f[1]; - g_TankModelPositionOffset.f[2] = sp68->f[2]; - mtx4RotateVecInPlace(&sp24, g_TankModelPositionOffset.f); - g_TankModelPositionOffset.f[0] += sp64->f[0]; - g_TankModelPositionOffset.f[1] += sp64->f[1]; - g_TankModelPositionOffset.f[2] += sp64->f[2]; - } -} - - -/** - * Address 0x7F07C888. -*/ -void bondviewGetTankCollisionBounds(struct rect4f *tank_collision_bounds, struct coord3d *collision_position, f32 tank_orientation_angle) -{ - ObjectRecord *sp4C; - f32 sp48; - f32 sp44; - f32 sp40; - f32 sp3C; - f32 sp38; - f32 sp34; - struct ModelRoData_BoundingBoxRecord *bbox; - - #ifdef DEBUG - assert(bondonprop2); // canonically g_PlayerTankProp is bondonprop2 - presumably because it was also motorbike code -#endif - - sp4C = g_PlayerTankProp->obj; - - bbox = chrobjGetBboxFromObjectRecord(sp4C); - - sp44 = bbox->Bounds.xmin - g_TankModelPositionOffset.f[0]; - sp40 = bbox->Bounds.xmax - g_TankModelPositionOffset.f[0]; - - sp3C = bbox->Bounds.zmin - g_TankModelPositionOffset.f[2]; - sp38 = bbox->Bounds.zmax - g_TankModelPositionOffset.f[2]; - - sp34 = sp4C->model->scale * cosf(tank_orientation_angle); - sp48 = sp4C->model->scale * sinf(tank_orientation_angle); - - tank_collision_bounds->points[0].f[0] = collision_position->f[0] + (-sp3C * sp48) + (sp44 * sp34); - tank_collision_bounds->points[0].f[1] = collision_position->f[2] + (sp3C * sp34) + (sp44 * sp48); - - tank_collision_bounds->points[1].f[0] = collision_position->f[0] + (-sp3C * sp48) + (sp40 * sp34); - tank_collision_bounds->points[1].f[1] = collision_position->f[2] + (sp3C * sp34) + (sp40 * sp48); - - tank_collision_bounds->points[2].f[0] = collision_position->f[0] + (-sp38 * sp48) + (sp40 * sp34); - tank_collision_bounds->points[2].f[1] = collision_position->f[2] + (sp38 * sp34) + (sp40 * sp48); - - tank_collision_bounds->points[3].f[0] = collision_position->f[0] + (-sp38 * sp48) + (sp44 * sp34); - tank_collision_bounds->points[3].f[1] = collision_position->f[2] + (sp38 * sp34) + (sp44 * sp48); -} - - -/** - * Address 0x7F07CA2C. -*/ -s32 bondviewTestLineUnobstructed(StandTile **pTile, f32 p_x, f32 p_z, f32 dest_x, f32 dest_z, s32 cdtypes, struct coord3d *coord_p, struct coord3d *coord_dest) -{ - s32 temp_v0; - - temp_v0 = stanTestLineUnobstructed(pTile, p_x, p_z, dest_x, dest_z, cdtypes, 0.0f, 1.0f, 0.0f, 1.0f); - if ((temp_v0 == 0) && (coord_p != NULL)) - { - coord_p->f[0] = p_x; - coord_p->f[1] = 0.0f; - coord_p->f[2] = p_z; - coord_dest->f[0] = dest_x; - coord_dest->f[1] = 0.0f; - coord_dest->f[2] = dest_z; - } - - return temp_v0; -} - - -/** - * Address 0x7F07CAC8. -*/ -s32 bondviewTankCollisionStatus(struct coord3d *collision_position, StandTile *arg1, f32 tank_orientation_angle, struct coord3d *arg3, struct coord3d *arg4) -{ - StandTile *spBC; - s32 stack_padding; - struct rect4f tank_collision_bounds; - s32 sp94; - f32 temp_f0; - - Model *sp8C; - - ModelNode **switches; - struct coord3d *temp_a1; - struct coord3d *temp_a2; - struct coord3d sp74; - Mtxf sp34; - struct coord3d *temp_v1; - - spBC = arg1; - sp94 = 0; - - bondviewGetTankCollisionBounds(&tank_collision_bounds, collision_position, tank_orientation_angle); - - if (g_PlayerTankProp != NULL) - { - sub_GAME_7F03D058(g_PlayerTankProp, 0); - } - - if ((bondviewTestLineUnobstructed(&spBC, collision_position->f[0], collision_position->f[2], tank_collision_bounds.points[0].f[0], tank_collision_bounds.points[0].f[1], CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PATHBLOCKER | CDTYPE_OBJSIMMUNETOEXPLOSIONS, arg3, arg4) != 0) - && (bondviewTestLineUnobstructed(&spBC, tank_collision_bounds.points[0].f[0], tank_collision_bounds.points[0].f[1], tank_collision_bounds.points[1].f[0], tank_collision_bounds.points[1].f[1], CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PATHBLOCKER | CDTYPE_OBJSIMMUNETOEXPLOSIONS, arg3, arg4) != 0) - && (bondviewTestLineUnobstructed(&spBC, tank_collision_bounds.points[1].f[0], tank_collision_bounds.points[1].f[1], tank_collision_bounds.points[2].f[0], tank_collision_bounds.points[2].f[1], CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PATHBLOCKER | CDTYPE_OBJSIMMUNETOEXPLOSIONS, arg3, arg4) != 0) - && (bondviewTestLineUnobstructed(&spBC, tank_collision_bounds.points[2].f[0], tank_collision_bounds.points[2].f[1], tank_collision_bounds.points[3].f[0], tank_collision_bounds.points[3].f[1], CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PATHBLOCKER | CDTYPE_OBJSIMMUNETOEXPLOSIONS, arg3, arg4) != 0) - && (bondviewTestLineUnobstructed(&spBC, tank_collision_bounds.points[3].f[0], tank_collision_bounds.points[3].f[1], tank_collision_bounds.points[0].f[0], tank_collision_bounds.points[0].f[1], CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PATHBLOCKER | CDTYPE_OBJSIMMUNETOEXPLOSIONS, arg3, arg4) != 0)) - { - sp94 = 1; - - if (g_PlayerTankProp != NULL) - { - ObjectRecord *obj = g_PlayerTankProp->obj; - sp8C = obj->model; - switches = sp8C->obj->Switches; - - temp_v1 = switches[3]->Data; - temp_a1 = switches[4]->Data; - temp_a2 = switches[2]->Data; - - sp74.f[0] = temp_a1->f[0] + temp_v1->f[0] - temp_a2->f[0]; - sp74.f[1] = 0.0f; - sp74.f[2] = temp_a1->f[2] + temp_v1->f[2] - temp_a2->f[2]; - - temp_f0 = tank_orientation_angle + g_TankTurretOrientationAngleRad; - - if (temp_f0 >= M_TAU_F) - { - temp_f0 -= M_TAU_F; - } - - if (temp_f0 < 0.0f) - { - temp_f0 += M_TAU_F; - } - - matrix_4x4_set_rotation_around_y(M_TAU_F - temp_f0, &sp34); - mtx4RotateVecInPlace(&sp34, (f32*)&sp74); - - sp74.f[0] *= sp8C->scale; - sp74.f[2] *= sp8C->scale; - - sp74.f[0] += collision_position->f[0]; - sp74.f[2] += collision_position->f[2]; - - spBC = arg1; - - if (bondviewTestLineUnobstructed(&spBC, collision_position->f[0], collision_position->f[2], sp74.f[0], sp74.f[2], CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PATHBLOCKER | CDTYPE_OBJSIMMUNETOEXPLOSIONS, arg3, arg4) == 0) - { - sp94 = 0; - } - - } - } - - if (g_PlayerTankProp != NULL) - { - sub_GAME_7F03D058(g_PlayerTankProp, 1); - } - - return sp94; -} - - - - -/** - * Address 0x7F07CDA8. -*/ -s32 bondviewCallTankCollisionStatus(struct coord3d *collision_position, StandTile *arg1, f32 tank_orientation_angle) -{ - return bondviewTankCollisionStatus(collision_position, arg1, tank_orientation_angle, NULL, NULL); -} - - - - - -/** - * Address 0x7F07CDD4. -*/ -s32 sub_GAME_7F07CDD4(struct coord3d *arg0, f32 arg1, StandTile **arg2) -{ - StandTile *sp3C; - s32 unused_padding[2]; - - sp3C = g_CurrentPlayer->field_488.current_tile_ptr; - - if (( - stanTestLineUnobstructed( - &sp3C, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2], - arg0->f[0], - arg0->f[2], - 0, - 0.0f, - 1.0f, - 0.0f, - 1.0f) != 0) - && (bondviewCallTankCollisionStatus(arg0, sp3C, arg1) != 0)) - { - *arg2 = sp3C; - return 1; - } - - return 0; -} - - - - - -bool isBondInTank(void) -{ - return g_PlayerIsInTank; -} - - - - - - -struct PropRecord *get_ptr_for_players_tank(void) -{ - if (g_PlayerIsInTank == 1) - { - return g_PlayerTankProp; - } - - return 0; -} - - - - - -/** - * Sets paraameter position based on global variables g_TankOrientationAngle, g_TankTurretOrientationAngleRad, g_TankTurretVerticalAngle. - * - * Address 0x7F07CEB0. - */ -void bondviewSet3dCoord7F07CEB0(coord3d *arg0) -{ - f32 f; - - f = g_TankOrientationAngle + g_TankTurretOrientationAngleRad; - - if (f >= M_TAU_F) - { - f = f - M_TAU_F; - } - - if (f < 0.0f) - { - f = f + M_TAU_F; - } - - arg0->f[0] = -sinf(f) * cosf(g_TankTurretVerticalAngle); - arg0->f[1] = sinf(g_TankTurretVerticalAngle); - arg0->f[2] = cosf(f) * cosf(g_TankTurretVerticalAngle); -} - - - - - - -/** - * Unreferenced. - * - * Returns global variable g_TankTurretVerticalAngle, which is in radians. - * - * Address 0x7F07CF80. - */ -f32 bondviewGet8003646CRad(void) -{ - return g_TankTurretVerticalAngle; -} - - - -/** - * Address 0x7F07CF8C. -*/ -s32 bondviewTryMoveToStan(struct coord3d *arg0, StandTile **stan) -{ - s32 sp94; - StandTile *sp90; - s32 cdtypes; - f32 height; - f32 always_30; - f32 collision_radius; - s32 sp7C; - struct TankRecord *tank; - s32 stack_padding[11]; - struct StandTileLocusCallbackRecord sp3C; - - sp94 = 0; - - if ((g_PlayerIsInTank == 1) && (g_EnterTankAudioState != TANK_RUN_STATE_NOT_RUNNING)) - { - sp94 = sub_GAME_7F07CDD4(arg0, g_TankOrientationAngle, stan); - } - else - { - sp90 = g_CurrentPlayer->field_488.current_tile_ptr; - - if (obj_collision_flag) - { - cdtypes = CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PLAYERS | CDTYPE_CHRS | CDTYPE_PATHBLOCKER; - } - else - { - cdtypes = 0; - } - - bondviewGetCollisionRadius(g_CurrentPlayer->prop, &collision_radius, &height, &always_30); - - if (g_WorldTankProp != NULL) - { - sub_GAME_7F03D058(g_WorldTankProp, 0); - } - - sub_GAME_7F03D058(g_CurrentPlayer->prop, 0); - sp7C = stanTileDistanceRelated(&sp90, arg0->f[0], arg0->f[2], collision_radius, &sp3C); - - if (stanGetLocusField0(&sp3C) != 0) - { - g_CurrentPlayer->autocrouchpos = CROUCH_SQUAT; - } - - if ((stanTestLineUnobstructed( - &sp90, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2], - arg0->f[0], - arg0->f[2], - cdtypes, - height, - always_30, - 0.0f, - 1.0f) != 0) - && stanTestVolume(&sp90, arg0->f[0], arg0->f[2], collision_radius, cdtypes, height, always_30) < 0) - { - if (g_CurrentPlayer->ducking_height_offset == FULL_CROUCH_OFFSET || sp7C < 0) - { - if (stanGetLocusCount(&sp3C) == 0 && stanTestLocusEdgeAboveY(&sp90, arg0->f[0], arg0->f[2], collision_radius, g_CurrentPlayer->field_488.collision_position.f[1] + 175.0f) >= 0) - { - goto block_20; - } - else - { - *stan = sp90; - sp94 = 1; - } - } - else - { - goto block_20; - } - } - else - { -block_20: - /* I'm sorry, this is the only way I could make it match. */ - if (g_PlayerTankProp == NULL - && (stanSavedColl_posData != NULL) - && (stanSavedColl_posData->type == PROP_TYPE_OBJ)) - { - tank = (struct TankRecord *)stanSavedColl_posData->obj; - if (tank->type == PROPDEF_TANK) - { - g_WorldTankProp = stanSavedColl_posData; - } - } - } - - sub_GAME_7F03D058(g_CurrentPlayer->prop, 1); - - if (g_WorldTankProp != NULL) - { - sub_GAME_7F03D058(g_WorldTankProp, 1); - } - } - - return sp94; -} - - - -/** - * Calculates collision with current player. - * - * @param next_pos: 3d coordinate to attempt to move to. - * @param collision_pt0: Out parameter. Will set {x,0,z} position of first point (from line edge) if Bond is in collision, otherwise {0}. - * @param collision_pt1: Out parameter. Will set {x,0,z} position of second point (from line edge) if Bond is in collision, otherwise ... Bond's look angle? - * - * @return 1 if able to update stan and collision position, zero otherwise. - * - * Address 0x7F07D234. - */ -s32 bondviewTrySimpleMovePlayerCollision(coord3d *next_pos, coord3d *collision_pt0, coord3d *collision_pt1) -{ - struct StandTile *stan; - - // resets stan global collision variables - stanResetHits(); - - if (bondviewTryMoveToStan(next_pos, &stan) != 0) - { - g_CurrentPlayer->field_488.current_tile_ptr = stan; - g_CurrentPlayer->field_488.collision_position.f[0] = next_pos->f[0]; - g_CurrentPlayer->field_488.collision_position.f[2] = next_pos->f[2]; - - return 1; - } - - getCollisionEdge_maybe(collision_pt0, collision_pt1); - - return 0; -} - - -/** - * This is a fallback method used when bondviewTrySimpleMovePlayerCollision fails. - * Instead of moving to the full coordinate specified by `next_pos`, it will - * scale the position using `calculateRayToSegmentIntersectionNormalized` and try to move to that position. - * - * @param next_pos: 3d coordinate to attempt to move to. - * @param collision1_pt0: Prior collision point 0. - * @param collision1_pt1: Prior collision point 1. - * @param collision2_pt0: Out parameter. Will set {x,0,z} position of first point (from line edge) if Bond is in collision, otherwise {0}. - * @param collision2_pt1: Out parameter. Will set {x,0,z} position of second point (from line edge) if Bond is in collision, otherwise ... Bond's look angle? - * - * @return 1 if able to update stan and collision position, zero if still unable to move by failing on the same collision edge, -1 otherwise (still unable to move). - * - * US address 7F07D2B4. - * Perfect Dark, see bondwalk.c bwalk0f0c47d0, bondbike.c bbike0f0d36d4. -*/ -s32 bondviewTryFractionMovePlayerCollision( - struct coord3d *next_pos, - struct coord3d *collision1_pt0, - struct coord3d *collision1_pt1, - struct coord3d *collision2_pt0, - struct coord3d *collision2_pt1) -{ - StandTile *stan; - f32 height; - f32 always_30; - struct coord3d try_next_pos; - struct coord3d delta_pos; - struct coord3d sp50; - struct coord2d sp48; - struct coord2d sp40; - struct coord2d sp38; - f32 temp_f0; - f32 collision_radius; - - bondviewGetCollisionRadius(g_CurrentPlayer->prop, &collision_radius, &height, &always_30); - - delta_pos.f[0] = next_pos->f[0] - g_CurrentPlayer->field_488.collision_position.f[0]; - delta_pos.f[2] = next_pos->f[2] - g_CurrentPlayer->field_488.collision_position.f[2]; - - sp50.f[0] = collision_radius; - sp50.f[1] = g_CurrentPlayer->field_488.collision_position.f[0]; - sp50.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; - - sp48.f[0] = collision1_pt0->f[0]; - sp48.f[1] = collision1_pt0->f[2]; - - sp40.f[0] = collision1_pt1->f[0]; - sp40.f[1] = collision1_pt1->f[2]; - - sp38.f[0] = delta_pos.f[0]; - sp38.f[1] = delta_pos.f[2]; - - temp_f0 = calculateRayToSegmentIntersectionNormalized(&sp50, &sp48, &sp40, &sp38); - - try_next_pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0] + (delta_pos.f[0] * temp_f0 * 0.25f); - try_next_pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2] + (delta_pos.f[2] * temp_f0 * 0.25f); - - if (bondviewTryMoveToStan(&try_next_pos, &stan) != 0) - { - g_CurrentPlayer->field_488.current_tile_ptr = stan; - g_CurrentPlayer->field_488.collision_position.f[0] = try_next_pos.f[0]; - g_CurrentPlayer->field_488.collision_position.f[2] = try_next_pos.f[2]; - - return 1; - } - - getCollisionEdge_maybe(collision2_pt0, collision2_pt1); - - if (collision2_pt0->f[0] != collision1_pt0->f[0] - || collision2_pt0->f[1] != collision1_pt0->f[1] - || collision2_pt0->f[2] != collision1_pt0->f[2] - || collision2_pt1->f[0] != collision1_pt1->f[0] - || collision2_pt1->f[1] != collision1_pt1->f[1] - || collision2_pt1->f[2] != collision1_pt1->f[2]) - { - return 0; - } - - return -1; -} - - - - -/** - * This is a fallback method used when bondviewTrySimpleMovePlayerCollision fails. - * Instead of moving to the full coordinate specified by `next_pos`, it will - * attempt to move along the collision edge. - * - * @param prior_next_pos: Prior 3d coordinate that Bond failed to move to. - * @param collision1_pt0: Prior collision point 0. - * @param collision1_pt1: Prior collision point 1. - * - * @return -1 if either x or z coordinates are the same for the collision points, 1 if able to update stan and collision position, zero otherwise. - * - * US address 7F07D4C0. - */ -s32 bondviewTryEdgeMovePlayerCollision(struct coord3d *prior_next_pos, struct coord3d *collision_pt0, struct coord3d *collision_pt1) -{ - struct coord3d delta_pos; - f32 tempf; - struct coord3d norm_collision_edge; - struct coord3d try_next_pos; - StandTile *stan; - - delta_pos.f[0] = prior_next_pos->f[0] - g_CurrentPlayer->field_488.collision_position.f[0]; - delta_pos.f[2] = prior_next_pos->f[2] - g_CurrentPlayer->field_488.collision_position.f[2]; - - if (collision_pt0->f[0] != collision_pt1->f[0] || collision_pt0->f[2] != collision_pt1->f[2]) - { - norm_collision_edge.f[0] = collision_pt1->f[0] - collision_pt0->f[0]; - norm_collision_edge.f[2] = collision_pt1->f[2] - collision_pt0->f[2]; - - tempf = (norm_collision_edge.f[0] * norm_collision_edge.f[0]) + (norm_collision_edge.f[2] * norm_collision_edge.f[2]); - tempf = 1.0f / sqrtf(tempf); - norm_collision_edge.f[0] *= tempf; - norm_collision_edge.f[2] *= tempf; - - /** - * Normalizing gives you the direction vector of the wall, so the dot product in the assignment to - * tempf gives you the distance moved along the direction of the wall. - * Then try_next_pos is simply the point of the collision with the wall, plus the - * length moved along the wall times the direction vector of the wall. - **/ - tempf = (delta_pos.f[0] * norm_collision_edge.f[0]) + (delta_pos.f[2] * norm_collision_edge.f[2]); - try_next_pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0] + (tempf * norm_collision_edge.f[0]); - try_next_pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2] + (tempf * norm_collision_edge.f[2]); - - if (bondviewTryMoveToStan(&try_next_pos, &stan)) - { - g_CurrentPlayer->field_488.current_tile_ptr = stan; - g_CurrentPlayer->field_488.collision_position.f[0] = try_next_pos.f[0]; - g_CurrentPlayer->field_488.collision_position.f[2] = try_next_pos.f[2]; - - return 1; - } - - return 0; - } - - return -1; -} - - - -/** - * This is a fallback method used when bondviewTrySimpleMovePlayerCollision fails. - * If Bond previously failed to move because of a collision, this will check - * if Bond is near the end point of the collision edge. If within the collision - * radius of Bond to the edge endpoint, then allow movement. - * - * @param prior_next_pos: Prior 3d coordinate that Bond failed to move to. - * @param collision1_pt0: Prior collision point 0. - * @param collision1_pt1: Prior collision point 1. - * - * @return 1 if able to update stan and collision position, zero otherwise. - * - * US address 7F07D61C. - * - * Perfect Dark bwalk0f0c4a5c. -*/ -s32 bondviewTryEndHopPlayerCollision(struct coord3d *prior_next_pos, struct coord3d *collision_pt0, struct coord3d *collision_pt1) -{ - struct coord3d delta_pos; - struct coord3d sp50; - struct coord3d try_next_pos; - f32 height; - f32 always_30; - f32 tempf; - StandTile *stan; - f32 collision_radius; - - bondviewGetCollisionRadius(g_CurrentPlayer->prop, &collision_radius, &height, &always_30); - - delta_pos.f[0] = prior_next_pos->f[0] - g_CurrentPlayer->field_488.collision_position.f[0]; - delta_pos.f[2] = prior_next_pos->f[2] - g_CurrentPlayer->field_488.collision_position.f[2]; - - sp50.f[0] = collision_pt0->f[0] - prior_next_pos->f[0]; - sp50.f[2] = collision_pt0->f[2] - prior_next_pos->f[2]; - - if (((sp50.f[0] * sp50.f[0]) + (sp50.f[2] * sp50.f[2])) <= (collision_radius * collision_radius)) - { - if (collision_pt0->f[0] != g_CurrentPlayer->field_488.collision_position.f[0] || collision_pt0->f[2] != g_CurrentPlayer->field_488.collision_position.f[2]) - { - sp50.f[0] = -(collision_pt0->f[2] - g_CurrentPlayer->field_488.collision_position.f[2]); - sp50.f[2] = collision_pt0->f[0] - g_CurrentPlayer->field_488.collision_position.f[0]; - - tempf = (sp50.f[0] * sp50.f[0]) + (sp50.f[2] * sp50.f[2]); - tempf = 1.0f / sqrtf(tempf); - sp50.f[0] *= tempf; - sp50.f[2] *= tempf; - - tempf = (delta_pos.f[0] * sp50.f[0]) + (delta_pos.f[2] * sp50.f[2]); - sp50.f[0] *= tempf; - sp50.f[2] *= tempf; - try_next_pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0] + (sp50.f[0]); - try_next_pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2] + (sp50.f[2]); - - if (bondviewTryMoveToStan(&try_next_pos, &stan)) - { - g_CurrentPlayer->field_488.current_tile_ptr = stan; - g_CurrentPlayer->field_488.collision_position.f[0] = try_next_pos.f[0]; - g_CurrentPlayer->field_488.collision_position.f[2] = try_next_pos.f[2]; - - return 1; - } - } - } - else - { - sp50.f[0] = collision_pt1->f[0] - prior_next_pos->f[0]; - sp50.f[2] = collision_pt1->f[2] - prior_next_pos->f[2]; - - if (((sp50.f[0] * sp50.f[0]) + (sp50.f[2] * sp50.f[2])) <= (collision_radius * collision_radius)) - { - if (collision_pt1->f[0] != g_CurrentPlayer->field_488.collision_position.f[0] || collision_pt1->f[2] != g_CurrentPlayer->field_488.collision_position.f[2]) - { - sp50.f[0] = -(collision_pt1->f[2] - g_CurrentPlayer->field_488.collision_position.f[2]); - sp50.f[2] = collision_pt1->f[0] - g_CurrentPlayer->field_488.collision_position.f[0]; - - tempf = (sp50.f[0] * sp50.f[0]) + (sp50.f[2] * sp50.f[2]); - tempf = 1.0f / sqrtf(tempf); - sp50.f[0] *= tempf; - sp50.f[2] *= tempf; - - tempf = (delta_pos.f[0] * sp50.f[0]) + (delta_pos.f[2] * sp50.f[2]); - sp50.f[0] *= tempf; - sp50.f[2] *= tempf; - try_next_pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0] + (sp50.f[0]); - try_next_pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2] + (sp50.f[2]); - - if (bondviewTryMoveToStan(&try_next_pos, &stan)) - { - g_CurrentPlayer->field_488.current_tile_ptr = stan; - g_CurrentPlayer->field_488.collision_position.f[0] = try_next_pos.f[0]; - g_CurrentPlayer->field_488.collision_position.f[2] = try_next_pos.f[2]; - - return 1; - } - } - } - } - - return 0; -} - - -/** - * Unreferenced. - * - * Bitwise convert 32bit int to float. - * - * Address 0x7F07D954. - */ -f32 bondviewBitconvertIntToFloat(s32 arg0) -{ - return *(f32*)&arg0; -} - - - - -struct dummy_struct { - s32 unk00; - s32 unk04; -}; - -/** - * Sets Bond bondprevpos, attempts to move by `offset`. - * - * @param offset: Attempt to move Bond by {x,0,z} amount. - * @param allow_scoot: If movement causes collision, when set will allow Bond to scoot along the collision edge and to bump around corner edges. Otherwise, any collision will stop movement. - * - * US address 7F07D960. - * JP address 7F07DA34 (maybe). - */ -void bondviewCalcUpdatePlayerCollision(struct coord3d *offset, s32 allow_scoot) -{ - struct coord3d next_pos; // spb4 - struct coord3d collision1_pt0; // spa8 - struct coord3d collision1_pt1; // sp9c - struct rect4f *polygon; // sp98 - s32 edges; // sp94 - struct TankRecord *tank_objrecord; // no stack - struct ObjectRecord *obj; - f32 *farr5; - f32 *farr6; - f32 temp_f2; // sp80 - struct coord3d collision2_pt0; // sp74 - struct coord3d collision2_pt1; // sp68 - StandTile *stan; // no stack - struct coord3d collision3_pt0; // sp58 - struct coord3d collision3_pt1; // sp4c - s32 tile_count; // sp48 - s32 i; // sp44 - s32 temp_a3; // no stack - s32 phi_a0_3; // sp3c - s32 temp_v0_7; // no stack - - - g_CurrentPlayer->bondprevpos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; - g_CurrentPlayer->bondprevpos.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; - g_CurrentPlayer->bondprevpos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; - - next_pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0] + offset->f[0]; - next_pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2] + offset->f[2]; - - g_BondCanEnterTank = 0; - - g_CurrentPlayer->autocrouchpos = CROUCH_STAND; - - if (g_WorldTankProp != NULL) - { - chraiGetCollisionBoundsWithoutY(g_WorldTankProp, &polygon, &edges); - - if ((g_PlayerIsInTank == 1) - || (chrpropTestPointInPolygon(&g_CurrentPlayer->field_488.collision_position, polygon, edges) != 0) - || ((chrobjTestPointPolygonCollision(&g_CurrentPlayer->field_488.collision_position, g_CurrentPlayer->field_488.collision_radius, polygon, edges) != 0))) - { - - obj = g_WorldTankProp->obj; - tank_objrecord = (struct TankRecord *)g_WorldTankProp->obj; - - /// TODO: replace with ModelNode structs - farr5 = (f32*)obj->model->obj->Switches[5]->Data; - farr6 = (f32*)obj->model->obj->Switches[6]->Data; - g_PlayerTankProp = g_WorldTankProp; - - temp_f2 = (farr5[4] - farr5[3]) * obj->model->scale; - - if (g_PlayerIsInTank == 1 - || (chrpropTestPointInPolygon(&g_CurrentPlayer->field_488.collision_position, &tank_objrecord->rect, (s32)tank_objrecord->collision) != 0)) - { - temp_f2 += (farr6[4] - farr6[3]) * obj->model->scale; - g_BondCanEnterTank = 1; - } - - if ((g_PlayerIsInTank == 0) && (g_PlayerTankYOffset < temp_f2)) - { - g_PlayerTankYOffset += (20.0f * g_GlobalTimerDelta); - if ((temp_f2 < g_PlayerTankYOffset)) - { - //empty; - } - else - { - return; - } - - g_PlayerTankYOffset = temp_f2; - } - else - { - g_PlayerTankYOffset = temp_f2; - } - - if (g_PlayerIsInTank == 1) - { - if (g_EnterTankAudioState == TANK_RUN_STATE_NOT_RUNNING) - { - g_PlayerTankYOffset += -37.0f * (1.0f - g_TankEnteringSitHeightRemain); - } - else - { - g_PlayerTankYOffset += -37.0f; - } - } - } - else - { - if (g_PlayerTankProp != NULL) - { - g_WorldTankProp = NULL; - g_PlayerTankProp = NULL; - g_PlayerTankYOffset = 0.0f; - } - } - } - - // This `if` block looks like Perfect Dark bbike0f0d3c60 - if (bondviewTrySimpleMovePlayerCollision(&next_pos, &collision1_pt0, &collision1_pt1) == 0) - { - // return values are: - // 1 if able to update stan and collision position - // zero if still unable to move by failing on the same collision edge - // -1 otherwise (still unable to move). - temp_v0_7 = bondviewTryFractionMovePlayerCollision(&next_pos, &collision1_pt0, &collision1_pt1, &collision2_pt0, &collision2_pt1); - - if ((temp_v0_7 > 0) || (temp_v0_7 < 0)) - { - if ((allow_scoot != 0) - && (bondviewTryEdgeMovePlayerCollision(&next_pos, &collision1_pt0, &collision1_pt1) <= 0) - && (bondviewTryEndHopPlayerCollision(&next_pos, &collision1_pt0, &collision1_pt1) == 0)) - { - // empty - } - } - else if (temp_v0_7 == 0) - { - bondviewTryFractionMovePlayerCollision(&next_pos, &collision2_pt0, &collision2_pt1, &collision3_pt0, &collision3_pt1); - - if ((allow_scoot != 0) - && (bondviewTryEdgeMovePlayerCollision(&next_pos, &collision2_pt0, &collision2_pt1) <= 0) - && (bondviewTryEdgeMovePlayerCollision(&next_pos, &collision1_pt0, &collision1_pt1) <= 0) - && (bondviewTryEndHopPlayerCollision(&next_pos, &collision2_pt0, &collision2_pt1) == 0)) - { - bondviewTryEndHopPlayerCollision(&next_pos, &collision1_pt0, &collision1_pt1); - } - } - } - - /** - * This block seems to be some error checking code, this will only occur when Bond - * goes out of bounds. - */ - if (stanTestPointWithinTileBoundsMaybe( - g_CurrentPlayer->field_488.current_tile_ptr, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2]) == 0) - { - if(1); - - stan = g_CurrentPlayer->field_488.current_tile_ptr; - - for (tile_count=0; tile_count<5; tile_count++) - { - /// TODO: fix the horrible casts below. - - for (i=0, phi_a0_3 = 0; i<((stan->tail.half >> 0xC) & 0xF); i++) - { - // maybe: if (( stan->points[i+1].link >> 4) != 0) - if (( ((struct StandTilePoint*)stan) [i+1].link >> 4) != 0) - { - if(1); - phi_a0_3++; - } - } - - temp_a3 = randomGetNext() % (u32)phi_a0_3; - - for (i=0, phi_a0_3 = 0; i<(((s16) stan->tail.half >> 0xC) & 0xF); i++) - { - // maybe: if (( stan->points[i+1].link >> 4) != 0) - if (( ((struct StandTilePoint*)stan) [i+1].link >> 4) != 0) - { - if (phi_a0_3 == temp_a3) - { - // note: no `>> 4` - // maybe: stan = &(standTileStart)[stan->points[i+1].link]; - stan = (struct StandTile*)&((struct dummy_struct*)standTileStart)[( ((struct StandTilePoint*)stan)[i+1].link)]; - break; - } - - phi_a0_3++; - } - } - - if(1); - - if (stanTestPointWithinTileBoundsMaybe( - stan, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2])) - { - g_CurrentPlayer->field_488.current_tile_ptr = stan; - break; - } - } - } - - bondviewUpdatePlayerRoom(g_CurrentPlayer); - - if (g_CurrentPlayer->field_488.current_tile_ptr != NULL) - { - objectivestatusCheckRoomEntered(g_CurrentPlayer->field_488.current_tile_ptr->room); - } -} - - -/** - * Address: 7F07DE64 - */ -void bondviewDeregisterPlayerRoom(struct player *player) -{ - chrpropDeregisterRoom(player->prop, player->registeredroom); - player->registeredroom = -1; -} - - -/** - * Address 0x7F07DE9C. - */ -void bondviewUpdatePlayerRoom(struct player *player) -{ - bondviewDeregisterPlayerRoom(player); - - if (player->prop->chr) - { - chrDetectRooms(player->prop->chr); - return; - } - - if (player->field_488.current_tile_ptr) - { - player->registeredroom = (s16) player->field_488.current_tile_ptr->room; - - chrpropRegisterRoom(player->prop, player->registeredroom); - } -} - - -/** - * Address: 7F07DEFC - */ -void bondviewInitPauseTransition(void) -{ - g_CurrentPlayer->pause_starting_angle = g_CurrentPlayer->vv_verta; - g_CurrentPlayer->pause_transition_time = 0.0f; - g_CurrentPlayer->pause_state = 0; -} - - -/** - * Set the pause tilt's start and end pitch. Also calculates how long the transition should take. - * The greater the angular distance between the player's camera pitch and the pause pitch of -40 degrees, - * the longer it takes to pause. - * - * @param topause: When set, pause_target_verta will be -40.0f, otherwise g_CurrentPlayer->vv_verta. - * @return: How long the tilt should take. - * - * Address 0x7F07DF28. - */ -f32 bondviewSetupPauseTransition(bool topause) -{ - f32 anglediff; - f32 duration; - - if (topause) - { - g_CurrentPlayer->pause_saved_verta = g_CurrentPlayer->vv_verta; - g_CurrentPlayer->pause_target_verta = -40.0f; - } - else - { - g_CurrentPlayer->pause_saved_verta = g_CurrentPlayer->pause_starting_angle; - g_CurrentPlayer->pause_target_verta = g_CurrentPlayer->vv_verta; - } - - anglediff = g_CurrentPlayer->pause_saved_verta - g_CurrentPlayer->pause_target_verta; - - if (anglediff < 0.0f) - { - anglediff = -anglediff; - } - - /** - * If the delta between pause_saved_verta and pause_target_verta is large, - * the time penalty per degree above 60 is cut in half. - */ - if (anglediff >= 60.0f) - { - duration = (((anglediff - 60.0f) * 60.0f * 0.5f) / 60.0f) + 60.0f; - } - else if (anglediff <= 0.0f) - { - duration = 0.0f; - } - else - { - // this is a different `60` than the other values above! - duration = (anglediff * 60.f) / 60.f; - } - - return duration; -} - - -void bondviewStartPauseTransition(f32 duration) { - g_CurrentPlayer->pause_transition_time = 0.0f; - g_CurrentPlayer->pause_transition_duration = duration; - g_CurrentPlayer->pause_state = 1; -} - - -void bondviewStartUnpauseTransition(f32 duration) { - g_CurrentPlayer->pause_transition_time = 0.0f; - g_CurrentPlayer->pause_transition_duration = duration; - g_CurrentPlayer->pause_state = 2; -} - - -bool bondViewIsPauseTransitioning(void) { - return (g_CurrentPlayer->pause_state != 0 && g_CurrentPlayer->pause_state != 3); -} - - -/** - * Transition camera pitch from playing to watch menu (-40.0f degrees). - * Then when the game is unpaused, transition the camera pitch back to its pitch before pausing began. - */ -void bondviewUpdatePauseTransition(void) { - f32 prevverta; - f32 frac; - f32 weight; - - prevverta = g_CurrentPlayer->vv_verta; - - // Entering pause. - if (g_CurrentPlayer->pause_state == 1) { - g_CurrentPlayer->pause_transition_time += g_GlobalTimerDelta * watch_transition_time; - - if (g_CurrentPlayer->pause_transition_time < g_CurrentPlayer->pause_transition_duration) { - // Cosine ease-in-out - frac = g_CurrentPlayer->pause_transition_time / g_CurrentPlayer->pause_transition_duration; - weight = (1.0f - cosf((frac * M_TAU_F) * 0.5f)) * 0.5f; - - g_CurrentPlayer->vv_verta = g_CurrentPlayer->pause_saved_verta - + ((g_CurrentPlayer->pause_target_verta - g_CurrentPlayer->pause_saved_verta) * weight); - } else { - g_CurrentPlayer->vv_verta = g_CurrentPlayer->pause_target_verta; - // Set pause state to paused. - g_CurrentPlayer->pause_state = 3; - } - // Leaving pause. - } else if (g_CurrentPlayer->pause_state == 2) { - g_CurrentPlayer->pause_transition_time += g_GlobalTimerDelta * watch_transition_time; - - if (g_CurrentPlayer->pause_transition_time < g_CurrentPlayer->pause_transition_duration) { - // Cosine ease-in-out - frac = g_CurrentPlayer->pause_transition_time / g_CurrentPlayer->pause_transition_duration; - weight = (1.0f - cosf((frac * M_TAU_F) * 0.5f)) * 0.5f; - - g_CurrentPlayer->vv_verta = g_CurrentPlayer->pause_target_verta - + ((g_CurrentPlayer->pause_saved_verta - g_CurrentPlayer->pause_target_verta) * weight); - } else { - g_CurrentPlayer->vv_verta = g_CurrentPlayer->pause_saved_verta; - // Set pause state to unpaused. - g_CurrentPlayer->pause_state = 0; - } - } - - // Wrap vv_verta into [-180, 180) - if (g_CurrentPlayer->vv_verta < -180.0f) { - g_CurrentPlayer->vv_verta += 360.0f; - } else if (g_CurrentPlayer->vv_verta >= 180.0f) { - g_CurrentPlayer->vv_verta -= 360.0f; - } - - /** - * Calculate shortest angular velocity from previous frame, - * scale it by g_GlobalTimerDelta, - * clamp it to [-0.7, 0.7] so the pitch change is never too fast. - */ - if (g_ClockTimer > 0) { - g_CurrentPlayer->speedverta = g_CurrentPlayer->vv_verta - prevverta; - - if (g_CurrentPlayer->speedverta < 0.0f) { - g_CurrentPlayer->speedverta += 360.0f; - } - - if (g_CurrentPlayer->speedverta > 180.0f) { - g_CurrentPlayer->speedverta -= 360.0f; - } - - g_CurrentPlayer->speedverta /= g_GlobalTimerDelta + g_GlobalTimerDelta; - - if (g_CurrentPlayer->speedverta < -0.7f) { - g_CurrentPlayer->speedverta = -0.7f; - } else if (g_CurrentPlayer->speedverta > 0.7f) { - g_CurrentPlayer->speedverta = 0.7f; - } - } -} - - -f32 bondViewGetPauseTransitionFrac(void) { - - // Entering pause - if (g_CurrentPlayer->pause_state == 1) { - return g_CurrentPlayer->pause_transition_time / g_CurrentPlayer->pause_transition_duration; - } - // Leaving pause - if (g_CurrentPlayer->pause_state == 2) { - return 1.0f - (g_CurrentPlayer->pause_transition_time / g_CurrentPlayer->pause_transition_duration); - } - // Fully paused - if (g_CurrentPlayer->pause_state == 3) { - return 1.0f; - } - // Unpaused - return 0.0f; -} - -void trigger_watch_zoom(f32 final,f32 time) -{ - g_CurrentPlayer->zoomintime = 0.00000000; - g_CurrentPlayer->zoomintimemax = time; - g_CurrentPlayer->zoominfovyold = g_CurrentPlayer->zoominfovy; - g_CurrentPlayer->zoominfovynew = final; -} - - -f32 bondviewGetWatchZoomFovy(void) { - - if (g_CurrentPlayer->zoomintime < g_CurrentPlayer->zoomintimemax) - { - return g_CurrentPlayer->zoominfovynew; - } - - return g_CurrentPlayer->zoominfovy; -} - -/** - * Triggers watch zoom if new value. - * - * @param zoominfovy: watch zoom fovy. - * - * Address 0x7F07E46C. - */ -void bondviewTriggerWatchZoom(f32 zoominfovy) -{ - if (bondviewGetWatchZoomFovy() != zoominfovy) - { - if (zoominfovy < g_CurrentPlayer->zoominfovy) - { - trigger_watch_zoom(zoominfovy, ((g_CurrentPlayer->zoominfovy - zoominfovy) * 15.0f) / 30.0f); - - return; - } - - trigger_watch_zoom(zoominfovy, ((zoominfovy - g_CurrentPlayer->zoominfovy) * 15.0f) / 30.0f); - } -} - - -/** - * Trigger watch zoom with default angle. - * - * Address 0x7F07E504. - */ -void bondviewTriggerWatchZoomDefault(void) -{ - bondviewTriggerWatchZoom(60.0f); -} - - -/** - * Address 0x7F07E52C. - */ -void bondviewZoomToWatchOnOpen(void) -{ - f32 f; - -#if defined(VERSION_EU) - f = ((6.09999990463f - g_CurrentPlayer->zoominfovy) * 45.0f) / -53.9000015259f; -#else - f = ((5.9f - g_CurrentPlayer->zoominfovy) * 45.0f) / -54.1f; -#endif - - if (f < 0.0f) - { - f = -f; - } - -#if defined(VERSION_EU) - trigger_watch_zoom(6.09999990463f, f); -#else - trigger_watch_zoom(5.9f, f); -#endif - -} - - - -/** - * Address 0x7F07E594. - */ -void bondviewZoomFromWatchOnExit(void) -{ - f32 f; - -#if defined(VERSION_EU) - f = ((60.0f - g_CurrentPlayer->zoominfovy) * 45.0f) / -53.9000015259f; -#else - f = ((60.0f - g_CurrentPlayer->zoominfovy) * 45.0f) / -54.1f; -#endif - - if (f < 0.0f) - { - f = -f; - } - - trigger_watch_zoom(60.0f, f); -} - - - -s32 check_watch_page_transistion_running(void) -{ - return (g_CurrentPlayer->zoomintime < g_CurrentPlayer->zoomintimemax); -} - - -/** - * Address 0x7F07E62C. - */ -void bondviewUpdateWatchZoomIn(void) -{ - if (g_CurrentPlayer->zoomintime < g_CurrentPlayer->zoomintimemax) - { - if ((g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x5) || (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xc)) - { -#if defined(BUGFIX_R1) - g_CurrentPlayer->zoomintime = g_CurrentPlayer->zoomintime + (f32) jpD_800484D0; -#else - g_CurrentPlayer->zoomintime = g_CurrentPlayer->zoomintime + (f32) speedgraphframes; -#endif - } - else - { -#if defined(BUGFIX_R1) - g_CurrentPlayer->zoomintime = g_CurrentPlayer->zoomintime + (jpD_800484D0 * watch_transition_time); -#else - g_CurrentPlayer->zoomintime = g_CurrentPlayer->zoomintime + (speedgraphframes * watch_transition_time); -#endif - } - - if (g_CurrentPlayer->zoomintimemax < g_CurrentPlayer->zoomintime) - { - g_CurrentPlayer->zoomintime = g_CurrentPlayer->zoomintimemax; - } - - g_CurrentPlayer->zoominfovy = - g_CurrentPlayer->zoominfovyold + - ( - (g_CurrentPlayer->zoomintime * - (g_CurrentPlayer->zoominfovynew - g_CurrentPlayer->zoominfovyold) - ) - / g_CurrentPlayer->zoomintimemax - ); - } - else - { - g_CurrentPlayer->zoomintime = g_CurrentPlayer->zoomintimemax; - g_CurrentPlayer->zoominfovy = g_CurrentPlayer->zoominfovynew; - } - - set_cur_player_fovy(g_CurrentPlayer->zoominfovy); - viSetFovY(g_CurrentPlayer->zoominfovy); -} - - - - -/** - * Address 0x7F07E740. - */ -f32 bondviewWatchAnimationRelated(void) -{ - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x4) - { - return ((45.0f - g_CurrentPlayer->zoomintimemax) + g_CurrentPlayer->zoomintime) / 45.0f; - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x6) - { - return (g_CurrentPlayer->zoomintimemax - g_CurrentPlayer->zoomintime) / 45.0f; - } - - if ((g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x5) || (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xc)) - { - return 1.0f; - } - - return 0.0f; -} - - - - - -void sub_GAME_7F07E7CC(void) { - ModelFileHeader *itemheader; - - itemheader = get_ptr_itemheader_in_hand(1); - modelCalculateRwDataLen(itemheader); -#ifndef VERSION_EU - if (0x32 < itemheader->numRecords) { - return_null(); - } -#endif - animInit((Model *)((u8 *)g_CurrentPlayer + 0x230), itemheader, (u32 *)((u8 *)g_CurrentPlayer + 0x2ec)); - modelSetScale((Model *)((u8 *)g_CurrentPlayer + 0x230), c_item_entries[41].scale * 0.10000001f); - modelSetAnimation((Model *)((u8 *)g_CurrentPlayer + 0x230), (ModelAnimation *)&ptr_animation_table->data[(s32)&ANIM_DATA_bond_watch], 0, 0.0f, 0.5f * watch_transition_time, 0.0f); - *(s32 *)((u8 *)g_CurrentPlayer + 0x220) = 0; -} - - - - - -/** - * Address 0x7F07E8B0. - */ -void bondviewSetPauseWatchRelated(f32 arg0) -{ - if (g_CurrentPlayer->step_in_view_watch_animation == 0) - { - g_CurrentPlayer->pause_watch_related_scaled = 20.0f / arg0; - } - else - { - g_CurrentPlayer->pause_watch_related_scaled = (20.0f - g_CurrentPlayer->pause_watch_related_adjust) / arg0; - } - - g_CurrentPlayer->step_in_view_watch_animation = 1; - g_CurrentPlayer->pause_watch_related = arg0; -} - - - - -/** - * Address 0x7F07E910. - */ -void bondviewSetPauseWatchRelatedAlt(f32 arg0) -{ - if (g_CurrentPlayer->step_in_view_watch_animation == 3) - { - g_CurrentPlayer->pause_watch_related_scaled = 20.0f / arg0; - } - else - { - g_CurrentPlayer->pause_watch_related_scaled = g_CurrentPlayer->pause_watch_related_adjust / arg0; - } - - g_CurrentPlayer->step_in_view_watch_animation = 2; - g_CurrentPlayer->pause_watch_related = arg0; -} - - - - - -/** - * Address 0x7F07E964. - */ -void bondviewStepWatchAnimation(void) -{ - if ((g_CurrentPlayer->step_in_view_watch_animation != 0) && (g_CurrentPlayer->step_in_view_watch_animation != 3)) - { - if (g_CurrentPlayer->step_in_view_watch_animation == 1) - { - g_CurrentPlayer->pause_animation_counter += g_GlobalTimerDelta * watch_transition_time * g_CurrentPlayer->pause_watch_related_scaled; - - if (g_CurrentPlayer->pause_animation_counter > 20.0f) - { - g_CurrentPlayer->pause_animation_counter = 20.0f; - g_CurrentPlayer->step_in_view_watch_animation = 3; - } - } - else if (g_CurrentPlayer->step_in_view_watch_animation == 2) - { - g_CurrentPlayer->pause_animation_counter -= g_GlobalTimerDelta * watch_transition_time * g_CurrentPlayer->pause_watch_related_scaled; - - if (g_CurrentPlayer->pause_animation_counter < 0.0f) - { - g_CurrentPlayer->pause_animation_counter = 0.0f; - g_CurrentPlayer->step_in_view_watch_animation = 0; - } - } - - modelSetAnimFrame2((void*)&g_CurrentPlayer->something_with_watch_object_instance, g_CurrentPlayer->pause_animation_counter, 0.0f); - } -} - - - - - - -/** - * Address 0x7F07EA78. - */ -f32 bondviewGetPauseAnimationPercent(void) -{ - if ((g_CurrentPlayer->step_in_view_watch_animation == 1) || (g_CurrentPlayer->step_in_view_watch_animation == 2)) - { - return g_CurrentPlayer->pause_animation_counter / 20.0f; - } - - if (g_CurrentPlayer->step_in_view_watch_animation == 3) - { - return 1.0f; - } - - return 0.0f; -} - - - - -void set_BONDdata_outside_watch_menu_flag(s32 arg0) { - g_CurrentPlayer->outside_watch_menu = arg0; -} - -s32 get_BONDdata_outside_watch_menu_flag(void) { - return g_CurrentPlayer->outside_watch_menu; -} - - - - - -void bondviewPlayerStopAudioForPause(void) -{ - struct hand *hand; - s32 i; - ObjectRecord *obj; - PropRecord *prop; - - deactivate_alarm_sound_effect(); - check_deactivate_gas_sound(); - - for (i = 0; i < 2; i++) - { - hand = &g_CurrentPlayer->hands[i]; - - if (hand->audioHandle && sndGetPlayingState(hand->audioHandle) != AL_STOPPED) { - sndDeactivate(hand->audioHandle); - } - } - - for (i = 0; i < 2; i++) - { - if (g_TankSfxState[i] && sndGetPlayingState(g_TankSfxState[i]) != AL_STOPPED) { - sndDeactivate(g_TankSfxState[i]); - } - } - - for (prop = chrpropGetActiveTail(); prop; prop = prop->prev) - { - if (prop->type != PROP_TYPE_DOOR && prop->type == PROP_TYPE_OBJ) - { - obj = prop->obj; - - if (obj->type == PROPDEF_VEHICHLE) - { - VehichleRecord *vehicle = (VehichleRecord *)prop->obj; - if (vehicle->Sound && sndGetPlayingState(vehicle->Sound) != AL_STOPPED) { - sndDeactivate(vehicle->Sound); - } - } - else if (obj->type == PROPDEF_AIRCRAFT) - { - AircraftRecord *aircraft = (AircraftRecord *)prop->obj; - if (aircraft->Sound && sndGetPlayingState(aircraft->Sound) != AL_STOPPED) { - sndDeactivate(aircraft->Sound); - } - } - - if(1); - } - } -} - - - - - -/** - * US address 7F07EC54. - * JP address 7F07F260. - * EU address 7F07ECF4. -*/ -void bondviewWatchAnimationTick(void) -{ -#if defined(VERSION_EU) - #define WATCH_VAR_LOWER 14 - #define WATCH_VAR_UPPER 29 -#else - #define WATCH_VAR_LOWER 17 - #define WATCH_VAR_UPPER 35 -#endif - - s32 sp3c; - s32 sp38; - s32 sp34; - f32 sp30; - f32 sp2c; - f32 sp28; - f32 sp24; - f32 sp20; - - if (g_CurrentPlayer->watch_animation_state) - { - sp34 = getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_TRIGGER || getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_WATCHLASER; - sp3c = sp34; - -#if defined (VERSION_US) - sp38 = WATCH_VAR_LOWER; - - if (sp34) - { - sp38 = WATCH_VAR_UPPER; - } -#else - sp38 = (sp34) ? WATCH_VAR_UPPER : WATCH_VAR_LOWER; -#endif - - g_CurrentPlayer->timer_1C4 += g_ClockTimer; - g_CurrentPlayer->watch_pause_time += 1; - g_CurrentPlayer->pausing_flag = FALSE; - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x1) - { - g_CurrentPlayer->pausing_flag = FALSE; - - if (g_CurrentPlayer->watch_pause_time == 1) - { - draw_item_in_hand(GUNLEFT, ITEM_SUIT_LF_HAND); - } - else if (g_CurrentPlayer->watch_pause_time == 2) - { - if (sp34) - { - draw_item_in_hand(GUNRIGHT, ITEM_UNARMED); - } - } - else - { - if ( - (get_item_in_hand_or_watch_menu(1) == ITEM_SUIT_LF_HAND) - && (Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED) - && ( - (sp34 == 0) - || ( - (get_item_in_hand_or_watch_menu(0) == ITEM_UNARMED) - && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED))) - && (g_CurrentPlayer->timer_1C4 >= sp38)) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x2; - g_CurrentPlayer->watch_pause_time = 1; - g_CurrentPlayer->timer_1C4 = 0; - } - } - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x2) - { - g_CurrentPlayer->pausing_flag = FALSE; - - if (g_CurrentPlayer->watch_pause_time == 1) - { - gunSetSightVisible(GUNAMMOREASON_DAMAGE, FALSE); - gunSetGunAmmoVisible(GUNSIGHTREASON_NOCONTROL, FALSE); - hudmsgsSetOff(PLAYERFLAG_LOCKCONTROLS); - bondviewSetUpperTextDisplayFlag(PLAYERFLAG_LOCKCONTROLS); - countdownTimerSetVisible(4, 0); - - if ((g_CurrentPlayer->pause_state == 0) || (g_CurrentPlayer->pause_state == 2) || (g_CurrentPlayer->pause_state == 3)) - { - sp20 = bondviewSetupPauseTransition(TRUE); - - if (sp20 < 30.0f) - { - sp20 = 30.0f; - } - - bondviewStartPauseTransition(sp20); - } - } - - if ((g_CurrentPlayer->pause_transition_duration - g_CurrentPlayer->pause_transition_time) < 30.0f) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x3; - g_CurrentPlayer->watch_pause_time = 1; - g_CurrentPlayer->timer_1C4 = 0; - - sub_GAME_7F07E7CC(); - } - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x3) - { - if (g_CurrentPlayer->watch_pause_time == 1) - { - sp30 = 40.0f; - - if ((g_CurrentPlayer->step_in_view_watch_animation != 0) && (g_CurrentPlayer->step_in_view_watch_animation != 3)) - { - sp30 = ((20.0f - g_CurrentPlayer->pause_watch_related_adjust) * 40.0f) / 20.0f; - } - - if ((g_CurrentPlayer->pause_state == 0) || (g_CurrentPlayer->pause_state == 2) || (g_CurrentPlayer->pause_state == 3)) - { - sp2c = bondviewSetupPauseTransition(TRUE); - sp20 = sp30 - 10.0f; - - if (sp2c < sp20) - { - sp2c = sp20; - } - - bondviewStartPauseTransition(sp2c); - - sp20 = sp2c + 10.0f; - - if (sp30 < sp20) - { - sp30 = sp20; - } - } - - bondviewSetPauseWatchRelated(sp30); - } - - if ( - ((g_CurrentPlayer->step_in_view_watch_animation != 0) && (g_CurrentPlayer->step_in_view_watch_animation != 3)) - || - bondViewIsPauseTransitioning() - ) - { - g_CurrentPlayer->pausing_flag = TRUE; - } - else - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x4; - g_CurrentPlayer->watch_pause_time = 1; - g_CurrentPlayer->timer_1C4 = 0; - } - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x4) - { - if ((g_CurrentPlayer->watch_pause_time == 1) && (g_CurrentPlayer->field_21C != 0)) - { - sndPlaySfx(g_musicSfxBufferPtr, WATCH_ON_SFX, NULL); - g_CurrentPlayer->field_21C = 0; - } - - bondviewZoomToWatchOnOpen(); - - if (check_watch_page_transistion_running() != 0) - { - g_CurrentPlayer->pausing_flag = TRUE; - } - else - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x5; - g_CurrentPlayer->watch_pause_time = 1; - g_CurrentPlayer->timer_1C4 = 0; - g_CurrentPlayer->field_21C = 1; - } - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x5) - { - if (g_CurrentPlayer->watch_pause_time == 1) - { - sub_GAME_7F0C1310(); - } - - g_CurrentPlayer->pausing_flag = TRUE; - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xc) - { - g_CurrentPlayer->pausing_flag = TRUE; - - if (g_CurrentPlayer->watch_pause_time >= 3) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x6; - g_CurrentPlayer->watch_pause_time = 1; - g_CurrentPlayer->timer_1C4 = 0; - sndPlaySfx(g_musicSfxBufferPtr, WATCH_OFF_SFX, NULL); - } - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x6) - { - if (g_CurrentPlayer->watch_pause_time == 1) - { - bondviewZoomFromWatchOnExit(); - if (sp34) - { - draw_item_in_hand(GUNRIGHT, ITEM_UNARMED); - } - else - { - sub_GAME_7F05DAE4(0); - } - } - if (check_watch_page_transistion_running()) - { - g_CurrentPlayer->pausing_flag = TRUE; - } - else - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x7; - g_CurrentPlayer->watch_pause_time = 1; - g_CurrentPlayer->timer_1C4 = 0; - g_CurrentPlayer->field_21C = 1; - } - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x7) - { - if (g_CurrentPlayer->watch_pause_time == 1) - { - sp28 = 40.0f; - sp24 = bondviewSetupPauseTransition(FALSE); - - if ((g_CurrentPlayer->step_in_view_watch_animation != 0) && (g_CurrentPlayer->step_in_view_watch_animation != 3)) - { - sp28 = (g_CurrentPlayer->pause_watch_related_adjust * 40.0f) / 20.0f; - } - - sp20 = sp28 + 20.0f; - - if (sp24 < sp20) - { - sp24 = sp20; - } - - bondviewStartUnpauseTransition(sp24); - bondviewSetPauseWatchRelatedAlt(sp28); - } - - if ((g_CurrentPlayer->step_in_view_watch_animation != 0) && (g_CurrentPlayer->step_in_view_watch_animation != 3)) - { - g_CurrentPlayer->pausing_flag = TRUE; - } - else - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x8; - g_CurrentPlayer->watch_pause_time = 1; - g_CurrentPlayer->timer_1C4 = 0; - } - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x8) - { - g_CurrentPlayer->pausing_flag = FALSE; - - if (g_CurrentPlayer->watch_pause_time == 1) - { - - if ((get_item_in_hand_or_watch_menu(GUNLEFT) != getCurrentPlayerWeaponId(GUNLEFT)) && (Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED)) - { - draw_item_in_hand(GUNLEFT, getCurrentPlayerWeaponId(GUNLEFT)); - } - - if (sp3c) - { - if ((get_item_in_hand_or_watch_menu(GUNRIGHT) != getCurrentPlayerWeaponId(GUNRIGHT)) && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED)) - { - draw_item_in_hand(GUNRIGHT, getCurrentPlayerWeaponId(GUNRIGHT)); - } - } - } - else if (!bondViewIsPauseTransitioning()) - { - if ( - (get_item_in_hand_or_watch_menu(GUNLEFT) == getCurrentPlayerWeaponId(GUNLEFT)) - && (Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED) - && ( - (sp3c == 0) - || (((get_item_in_hand_or_watch_menu(GUNRIGHT) == getCurrentPlayerWeaponId(GUNRIGHT))) && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED)))) - { - sub_GAME_7F05DAE4(1); - - if (sp3c) - { - sub_GAME_7F05DAE4(0); - } - - gunSetSightVisible(GUNAMMOREASON_DAMAGE, TRUE); - gunSetGunAmmoVisible(GUNSIGHTREASON_NOCONTROL, TRUE); - hudmsgsSetOn(1); - bondviewClearUpperTextDisplayFlag(1); - countdownTimerSetVisible(4, 1); - - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x0; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - } - } - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x9) - { - g_CurrentPlayer->pausing_flag = FALSE; - - if ( - (getCurrentPlayerWeaponId(GUNLEFT) != get_item_in_hand_or_watch_menu(GUNLEFT)) - && (Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED) - && ( - (sp3c == 0) - || (((getCurrentPlayerWeaponId(GUNRIGHT) != get_item_in_hand_or_watch_menu(GUNRIGHT))) && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED)))) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x8; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - } - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xa) - { - g_CurrentPlayer->pausing_flag = FALSE; - - if (g_CurrentPlayer->watch_pause_time == 1) - { - bondviewStartUnpauseTransition(bondviewSetupPauseTransition(FALSE)); - } - - if ( - (getCurrentPlayerWeaponId(GUNLEFT) != get_item_in_hand_or_watch_menu(GUNLEFT)) - && (Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED) - && ( - (sp3c == 0) - || (((getCurrentPlayerWeaponId(GUNRIGHT) != get_item_in_hand_or_watch_menu(GUNRIGHT))) && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED)))) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x8; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - } - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xb) - { - g_CurrentPlayer->pausing_flag = FALSE; - - if ( - (getCurrentPlayerWeaponId(GUNLEFT) == get_item_in_hand_or_watch_menu(GUNLEFT)) - && (Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED) - && ( - (sp3c == 0) - || ( - ( (getCurrentPlayerWeaponId(GUNRIGHT) == get_item_in_hand_or_watch_menu(GUNRIGHT))) - && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED)))) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x1; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - } - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xd) - { - g_CurrentPlayer->pausing_flag = FALSE; - - if (Gun_hand_without_item(GUNLEFT) - && Gun_hand_without_item(GUNRIGHT)) - { - if ((g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_LOWER) - && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_SWAP) - && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_HOLD) - && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_RAISE)) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x1; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - } - } - } - - bondviewUpdatePauseTransition(); - bondviewStepWatchAnimation(); - bondviewUpdateWatchZoomIn(); - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x5) - { - lvlSetControlsLockedFlag(TRUE); - sub_GAME_7F0A6A80(); - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xc) - { - lvlSetControlsLockedFlag(TRUE); - } - else - { - lvlSetControlsLockedFlag(FALSE); - } - -#undef WATCH_VAR_LOWER -#undef WATCH_VAR_UPPER -} - - -void set_open_close_solo_watch_menu_to1(void) -{ - g_CurrentPlayer->open_close_solo_watch_menu = TRUE; -} - - -/** - * US address 7F07F874. - * EU address 7F07F918. -*/ -void trigger_solo_watch_menu(s32 arg0) -{ - struct WatchVertex *ptr_a; - Gfx *ptr_b; - struct WatchVertex *next; - struct WatchVertex *ptr_copy; - s32 i; - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) - { - if (arg0 == 0) - { - watch_transition_time *= 1.1f; - if (watch_transition_time > 1.7f) - { - watch_transition_time = 1.7f; - } - - if ((Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED) - && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED) - && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_LOWER) - && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_SWAP) - && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_HOLD) - && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_RAISE)) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x1; - } - else - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0xd; - } - - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - - bondviewInitPauseTransition(); - bondviewTriggerWatchZoomDefault(); - - hudMakeDamageSegments(&g_CurrentPlayer->armor_display_values, 23*2, 1, currentPlayerGetArmor()); - buildGaugeBarDL(&g_CurrentPlayer->watch_body_armor_bar_gdl, OS_K0_TO_PHYSICAL(&g_CurrentPlayer->armor_display_values), 0x2E); - - hudMakeDamageSegments(&g_CurrentPlayer->health_display_values, 23*2, -1, currentPlayerGetHealth()); - buildGaugeBarDL(&g_CurrentPlayer->watch_health_bar_gdl, OS_K0_TO_PHYSICAL(&g_CurrentPlayer->health_display_values), 0x2E); - - sub_GAME_7F0A69A8(); - - /** - * This section is for rendering the selected screen rectangles. - */ - ptr_b = g_CurrentPlayer->buffer_for_watch_greenbackdrop_DL; // Gfx - ptr_a = &g_CurrentPlayer->buffer_for_watch_greenbackdrop_vertices->vtx[0]; // struct WatchRectangle - - for (i=0; - i<(WATCH_NUMBER_SCREENS * WATCH_SCREEN_SELECT_RECTANGLE_HSTEP); - i+=WATCH_SCREEN_SELECT_RECTANGLE_HSTEP) - { - // Note: colors are set here but overwritten in watch.c set_page_rectangle_colors - ptr_copy = ptr_a; - ptr_a = setup_watch_rectangles(ptr_a, i, 0, 0x64, 0x14, -0x12B, 0x136); - ptr_b = sub_GAME_7F0A3B40(ptr_b, OS_K0_TO_PHYSICAL(ptr_copy)); - } - - gSPEndDisplayList(ptr_b); - /** - * End watch screen select rectangles. - */ - - /** - * This section is related to rendering static on the watch menu. - * Static is defined by a horizontal bar in the middle of the screen. - */ - ptr_a = &g_CurrentPlayer->buffer_for_watch_static_vertices->vtx[0]; // struct WatchRectangle - ptr_b = g_CurrentPlayer->buffer_for_watch_static_DL; // Gfx - - ptr_copy = &g_CurrentPlayer->buffer_for_watch_static_vertices->vtx[0]; - next = setup_watch_rectangles(ptr_a, 0, 0, 0x398, 0x14, -0x1CC, 0); - ptr_b = sub_GAME_7F0A3B40(ptr_b, OS_K0_TO_PHYSICAL(ptr_copy)); - - gSPEndDisplayList(ptr_b); - /** - * End watch static section. - */ - } - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x1) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x9; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x2) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0xa; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x3) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x7; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x4) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x6; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x5) - { - deleteCurrentSelectedFolder(); - sub_GAME_7F0C1340(); - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0xc; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - g_CurrentPlayer->open_close_solo_watch_menu = FALSE; - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xc) - { - // removed - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x6) - { - if (arg0 == 0) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x4; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - sub_GAME_7F0A69A8(); - } - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x7) - { - if (arg0 == 0) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x3; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - sub_GAME_7F0A69A8(); - } - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x8) - { - if (arg0 == 0) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0xb; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - sub_GAME_7F0A69A8(); - } - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x9) - { - if (arg0 == 0) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x1; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - } - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xa) - { - if (arg0 == 0) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x1; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - } - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xb) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x8; - g_CurrentPlayer->watch_pause_time = 0; - g_CurrentPlayer->timer_1C4 = 0; - } - else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xd) - { - g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x0; - } -} - -/** - * US address 7F07FCC4. - * Perfect Dark bwalkUpdateSpeedSideways. -*/ -void bondviewUpdateSpeedSideways(s32 arg0) { - if (arg0 == -1) { - g_CurrentPlayer->speedstrafe = (g_CurrentPlayer->speedstrafe - g_GlobalTimerDelta); - if (g_CurrentPlayer->speedstrafe < -1.0f) { - g_CurrentPlayer->speedstrafe = -1.0f; - } - } - else { - if (arg0 == 1) { - g_CurrentPlayer->speedstrafe = (g_CurrentPlayer->speedstrafe + g_GlobalTimerDelta); - if (1.0f < g_CurrentPlayer->speedstrafe) { - g_CurrentPlayer->speedstrafe = 1.0f; - } - } else { - if (0.0f < g_CurrentPlayer->speedstrafe) { - g_CurrentPlayer->speedstrafe = (g_CurrentPlayer->speedstrafe - g_GlobalTimerDelta); - if (g_CurrentPlayer->speedstrafe < 0.0f) { - g_CurrentPlayer->speedstrafe = 0.0f; - } - } else { - g_CurrentPlayer->speedstrafe = (g_CurrentPlayer->speedstrafe + g_GlobalTimerDelta); - if (0.0f < g_CurrentPlayer->speedstrafe) { - g_CurrentPlayer->speedstrafe = 0.0f; - } - } - } - } - g_CurrentPlayer->speedsideways = g_CurrentPlayer->speedstrafe; -} - -/** - * US address 7F07FE1C. - * Perfect Dark bwalkUpdateSpeedForwards. -*/ -void bondviewUpdateSpeedForwards(s32 arg0) { - if (arg0 == 1) { - g_CurrentPlayer->speedgo = (g_CurrentPlayer->speedgo + g_GlobalTimerDelta); - if (1.0f < g_CurrentPlayer->speedgo) { - g_CurrentPlayer->speedgo = 1.0f; - } - } else { - if (arg0 == -1) { - g_CurrentPlayer->speedgo = (g_CurrentPlayer->speedgo - g_GlobalTimerDelta); - if (g_CurrentPlayer->speedgo < -1.0f) { - g_CurrentPlayer->speedgo = -1.0f; - } - } else { - if (0.0f < g_CurrentPlayer->speedgo) { - g_CurrentPlayer->speedgo = (g_CurrentPlayer->speedgo - g_GlobalTimerDelta); - if (g_CurrentPlayer->speedgo < 0.0f) { - g_CurrentPlayer->speedgo = 0.0f; - } - } else { - g_CurrentPlayer->speedgo = (g_CurrentPlayer->speedgo + g_GlobalTimerDelta); - if (0.0f < g_CurrentPlayer->speedgo) { - g_CurrentPlayer->speedgo = 0.0f; - } - } - } - } - g_CurrentPlayer->speedforwards = g_CurrentPlayer->speedgo; -} - -/** - * US address 7F07FF74. - * Duplicate of sub_GAME_7F080228. -*/ -f32 sub_GAME_7F07FF74(f32 value) { - if (value > 0) { - return (viGetFovY() * value * -0.7f) / FOV_Y_F; - } - - if (value < 0) { - return (viGetFovY() * -value * 0.7f) / FOV_Y_F; - } - - return 0; -} - - -/** - * Address 0x7F080010. - */ -void bondviewCurrentPlayerUpdateSpeedVerta(f32 value) -{ - f32 mult = viGetFovY() / FOV_Y_F; - f32 limit = sub_GAME_7F07FF74(value); - - if (value > 0.0f) - { - if (g_CurrentPlayer->speedverta > 0.0f) - { - g_CurrentPlayer->speedverta -= (0.05f * g_GlobalTimerDelta * mult); - } - else - { - g_CurrentPlayer->speedverta -= (0.0125f * g_GlobalTimerDelta * mult); - } - - if (g_CurrentPlayer->speedverta < limit) - { - g_CurrentPlayer->speedverta = limit; - } - } - else if (value < 0.0f) - { - if (g_CurrentPlayer->speedverta < 0.0f) - { - g_CurrentPlayer->speedverta += (0.05f * g_GlobalTimerDelta * mult); - } - else - { - g_CurrentPlayer->speedverta += (0.0125f * g_GlobalTimerDelta * mult); - } - - if (g_CurrentPlayer->speedverta > limit) - { - g_CurrentPlayer->speedverta = limit; - } - } - else - { - if (g_CurrentPlayer->speedverta > limit) - { - g_CurrentPlayer->speedverta -= (0.05f * g_GlobalTimerDelta * mult); - - if (g_CurrentPlayer->speedverta < limit) - { - g_CurrentPlayer->speedverta = limit; - } - } - else - { - g_CurrentPlayer->speedverta += (0.05f * g_GlobalTimerDelta * mult); - - if (g_CurrentPlayer->speedverta > limit) - { - g_CurrentPlayer->speedverta = limit; - } - } - } -} - - - -/** - * US address 7F080228. - * Duplicate of sub_GAME_7F07FF74. -*/ -f32 sub_GAME_7F080228(f32 arg0) { - if (0.0f < arg0) { - return (viGetFovY() * arg0 * -0.7f) / FOV_Y_F; - } else if (arg0 < 0.0f) { - return (viGetFovY() * -arg0 * 0.7f) / FOV_Y_F; - } else { - return 0.0f; - } -} - -/** - * Address 0x7F0802C4. - */ -void bondviewCurrentPlayerUpdateSpeedTheta(f32 value) -{ - f32 mult = viGetFovY() / FOV_Y_F; - f32 limit = sub_GAME_7F080228(value); - - if (value > 0.0f) - { - if (g_CurrentPlayer->speedtheta > 0.0f) - { - g_CurrentPlayer->speedtheta -= (0.05f * g_GlobalTimerDelta * mult); - } - else - { - g_CurrentPlayer->speedtheta -= (0.0125f * g_GlobalTimerDelta * mult); - } - - if (g_CurrentPlayer->speedtheta < limit) - { - g_CurrentPlayer->speedtheta = limit; - } - } - else if (value < 0.0f) - { - if (g_CurrentPlayer->speedtheta < 0) - { - g_CurrentPlayer->speedtheta += (0.05f * g_GlobalTimerDelta * mult); - } - else - { - g_CurrentPlayer->speedtheta += (0.0125f * g_GlobalTimerDelta * mult); - } - - if (limit < g_CurrentPlayer->speedtheta) - { - g_CurrentPlayer->speedtheta = limit; - } - } - else - { - if (limit < g_CurrentPlayer->speedtheta) - { - g_CurrentPlayer->speedtheta -= (0.05f * g_GlobalTimerDelta * mult); - - if (g_CurrentPlayer->speedtheta < limit) - { - g_CurrentPlayer->speedtheta = limit; - } - } - else - { - g_CurrentPlayer->speedtheta += (0.05f * g_GlobalTimerDelta * mult); - - if (limit < g_CurrentPlayer->speedtheta) - { - g_CurrentPlayer->speedtheta = limit; - } - } - } -} - - -Gfx *currentPlayerDrawFade(Gfx *gdl) -{ - f32 frac = g_CurrentPlayer->colourscreenfrac; - s32 r = g_CurrentPlayer->colourscreenred; - s32 g = g_CurrentPlayer->colourscreengreen; - s32 b = g_CurrentPlayer->colourscreenblue; - if ((cameraFrameCounter1 != 0) || (cameraFrameCounter2 != 0)) { - frac = 1.0f; - b = 0; - g = 0; - r = 0; - } - if (frac > 0) { - gDPPipeSync(gdl++); - gDPSetCycleType(gdl++, G_CYC_1CYCLE); - gDPSetColorDither(gdl++, G_CD_DISABLE); - gDPSetTexturePersp(gdl++, G_TP_NONE); - gDPSetAlphaCompare(gdl++, G_AC_NONE); - gDPSetTextureLOD(gdl++, G_TL_TILE); - gDPSetTextureFilter(gdl++, G_TF_BILERP); - gDPSetTextureConvert(gdl++, G_TC_FILT); - gDPSetTextureLUT(gdl++, G_TT_NONE); - gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_CLD_SURF2); - gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); - gDPSetPrimColor(gdl++, 0, 0, r, g, b, (s32)(frac * 255.0f)); - gDPFillRectangle(gdl++, viGetViewLeft(), viGetViewTop(), (viGetViewLeft() + viGetViewWidth()), (viGetViewTop() + viGetViewHeight())); - gDPPipeSync(gdl++); - gDPSetColorDither(gdl++, G_CD_BAYER); - gDPSetTexturePersp(gdl++, G_TP_PERSP); - gDPSetTextureLOD(gdl++, G_TL_LOD); - } - - return gdl; -} - -void currentPlayerSetFadeColour(s32 r, s32 g, s32 b, f32 frac) { - g_CurrentPlayer->colourscreenred = r; - g_CurrentPlayer->colourscreengreen = g; - g_CurrentPlayer->colourscreenblue = b; - g_CurrentPlayer->colourscreenfrac = frac; -} - -void currentPlayerAdjustFade(f32 maxfadetime, s32 r, s32 g, s32 b, f32 frac) -{ - g_CurrentPlayer->colourfadetime60 = 0; - g_CurrentPlayer->colourfadetimemax60 = maxfadetime; - g_CurrentPlayer->colourfaderedold = g_CurrentPlayer->colourscreenred; - g_CurrentPlayer->colourfaderednew = r; - g_CurrentPlayer->colourfadegreenold = g_CurrentPlayer->colourscreengreen; - g_CurrentPlayer->colourfadegreennew = g; - g_CurrentPlayer->colourfadeblueold = g_CurrentPlayer->colourscreenblue; - g_CurrentPlayer->colourfadebluenew = b; - g_CurrentPlayer->colourfadefracold = g_CurrentPlayer->colourscreenfrac; - g_CurrentPlayer->colourfadefracnew = frac; -} - -void currentPlayerSetFadeFrac(f32 maxfadetime, f32 frac) -{ - currentPlayerAdjustFade(maxfadetime, g_CurrentPlayer->colourscreenred, g_CurrentPlayer->colourscreengreen, g_CurrentPlayer->colourscreenblue, frac); -} - -bool currentPlayerIsFadeComplete(void) -{ - return g_CurrentPlayer->colourfadetimemax60 < 0; -} - -void currentPlayerUpdateColourScreenProperties(void) -{ - if (g_CurrentPlayer->colourfadetimemax60 >= 0) - { - g_CurrentPlayer->colourfadetime60 += g_GlobalTimerDelta; - - if (g_CurrentPlayer->colourfadetime60 < g_CurrentPlayer->colourfadetimemax60) - { - f32 mult = g_CurrentPlayer->colourfadetime60 / g_CurrentPlayer->colourfadetimemax60; - g_CurrentPlayer->colourscreenfrac = g_CurrentPlayer->colourfadefracold + (g_CurrentPlayer->colourfadefracnew - g_CurrentPlayer->colourfadefracold) * mult; - g_CurrentPlayer->colourscreenred = g_CurrentPlayer->colourfaderedold + (s32)((g_CurrentPlayer->colourfaderednew - g_CurrentPlayer->colourfaderedold) * mult); - g_CurrentPlayer->colourscreengreen = g_CurrentPlayer->colourfadegreenold + (s32)((g_CurrentPlayer->colourfadegreennew - g_CurrentPlayer->colourfadegreenold) * mult); - g_CurrentPlayer->colourscreenblue = g_CurrentPlayer->colourfadeblueold + (s32)((g_CurrentPlayer->colourfadebluenew - g_CurrentPlayer->colourfadeblueold) * mult); - return; - } - - g_CurrentPlayer->colourscreenfrac = g_CurrentPlayer->colourfadefracnew; - g_CurrentPlayer->colourscreenred = g_CurrentPlayer->colourfaderednew; - g_CurrentPlayer->colourscreengreen = g_CurrentPlayer->colourfadegreennew; - g_CurrentPlayer->colourscreenblue = g_CurrentPlayer->colourfadebluenew; - g_CurrentPlayer->colourfadetimemax60 = -1; - } -} - -void currentPlayerStartChrFade(f32 duration60, f32 targetfrac) -{ - ChrRecord *chr = g_CurrentPlayer->prop->chr; - - if (chr) - { - g_CurrentPlayer->bondfadetime60 = 0; - g_CurrentPlayer->bondfadetimemax60 = duration60; - g_CurrentPlayer->bondfadefracold = chr->fadealpha / 255.0f; - g_CurrentPlayer->bondfadefracnew = targetfrac; - } -} - -void currentPlayerTickChrFade(void) -{ - if (g_CurrentPlayer->bondfadetimemax60 >= 0) - { - ChrRecord *chr = g_CurrentPlayer->prop->chr; - f32 frac; - - g_CurrentPlayer->bondfadetime60 += g_GlobalTimerDelta; - - if (g_CurrentPlayer->bondfadetime60 < g_CurrentPlayer->bondfadetimemax60) - { - frac = g_CurrentPlayer->bondfadefracold + (g_CurrentPlayer->bondfadefracnew - g_CurrentPlayer->bondfadefracold) * g_CurrentPlayer->bondfadetime60 / g_CurrentPlayer->bondfadetimemax60; - } - else - { - frac = g_CurrentPlayer->bondfadefracnew; - g_CurrentPlayer->bondfadetimemax60 = -1; - } - - if (chr) - { - chr->fadealpha = (s8)(frac * 255); - } - } -} - -/** - * Will apply a move animation update. The pass through call to bheadUpdate is - * what allows Bond to move. This will also trigger the death animation once - * Bond dies. This chooses a random death animation from g_bondviewBondDeathAnimations. - * Address 0x7F080B34. -*/ -void bondviewMoveAnimationTick(f32 speed, f32 speedforwards, f32 speedsideways) -{ - f32 percent_speed; - Mtxf sp8C; - Mtxf sp4C; - - percent_speed = 0.0f; - - if (g_CurrentPlayer->bonddead == 0) - { - bheadAdjustAnimation(speed); - - if (speed != 0.0f) - { - percent_speed = speedforwards / speed; - } - else if (speedforwards == 0.0f) - { - // - } - } - else - { - if (g_CurrentPlayer->startnewbonddie) - { - // HACK: ptr_animation_table dereference addition is backwards. - // this should be: - // ptr_animation_table->data[g_bondviewBondDeathAnimations[((u32) randomGetNext() % (u32) g_bondviewBondDeathAnimationsCount)]] - bheadStartDeathAnimation((struct ModelAnimation *) ((s32)g_bondviewBondDeathAnimations[((u32) randomGetNext() % (u32) g_bondviewBondDeathAnimationsCount)] + (s32)&ptr_animation_table->data[0]), randomGetNext() & 1, 0.0f, 1.0f); - g_CurrentPlayer->startnewbonddie = FALSE; - } - - bheadSetSpeed(0.5f); - speedsideways = 0.0f; - } - - bheadUpdate(percent_speed, speedsideways); - - matrix_4x4_set_rotation_around_x((360.0f - g_CurrentPlayer->vv_verta360) * DegToRad1Fact(1), &sp8C); - matrix_4x4_set_basis_and_position_target(&sp4C, 0.0f, 0.0f, 0.0f, -g_CurrentPlayer->headlook.f[0], -g_CurrentPlayer->headlook.f[1], -g_CurrentPlayer->headlook.f[2], g_CurrentPlayer->headup.f[0], g_CurrentPlayer->headup.f[1], g_CurrentPlayer->headup.f[2]); - matrix_4x4_multiply_in_place(&sp4C, &sp8C); - matrix_4x4_set_rotation_around_y((360.0f - g_CurrentPlayer->vv_theta) * DegToRad1Fact(1), &sp4C); - matrix_4x4_multiply_in_place(&sp4C, &sp8C); - - g_CurrentPlayer->field_488.applied_view.f[0] = sp8C.m[2][0]; - g_CurrentPlayer->field_488.applied_view.f[1] = sp8C.m[2][1]; - g_CurrentPlayer->field_488.applied_view.f[2] = sp8C.m[2][2]; - - g_CurrentPlayer->field_488.applied_view2.f[0] = sp8C.m[1][0]; - g_CurrentPlayer->field_488.applied_view2.f[1] = sp8C.m[1][1]; - g_CurrentPlayer->field_488.applied_view2.f[2] = sp8C.m[1][2]; - -} - - -/** - * Address 0x7F080D60. - */ -f32 bondviewYPositionRelated(StandTile *arg0, f32 arg1, f32 arg2) -{ - f32 ret; - - if (g_PlayerTankProp != NULL) - { - ObjectRecord * obj = ((PropRecord *)g_PlayerTankProp)->obj; - PropRecord *p = obj->prop; - - ret = stanGetPositionYValue(p->stan, p->pos.x, p->pos.z); - - ret += g_PlayerTankYOffset; - } - else - { - if (g_CurrentPlayer->field_2A6C) - { - ret = stanGetPositionYValue(g_CurrentPlayer->field_2A70, arg1, arg2); - } - else - { - ret = stanGetPositionYValue(arg0, arg1, arg2); - } - } - - return ret; -} - - - -/** - * US Address 0x7F080DF8. - * EU Address 0x7F080E9C. - */ -void bondviewUpdatePlayerY(s32 use_stanHeight, f32 stanHeight_offset) -{ - s32 i; // sp6c - f32 unused; - f32 sp64; - StandTile *stan; //sp60 - f32 collision_radius; //sp5c - f32 height; //sp58 - f32 always_30; //sp54 - f32 temp_f0; // no stack - f32 new_field_70; // sp4c - f32 new_field_7c; //sp48 - f32 ftemp2; - f32 sp40; - - if (1); - - if (g_PlayerIsInTank == 1) - { - g_CurrentPlayer->stanHeight = bondviewYPositionRelated( - g_CurrentPlayer->field_488.current_tile_ptr, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2]); - - g_CurrentPlayer->field_6C = g_CurrentPlayer->field_70 / (1.0f - TANK_UNKD0_SCALE); - - for (i=0; ifield_6C = (g_CurrentPlayer->field_6C * TANK_UNKD0_SCALE) + g_CurrentPlayer->stanHeight; - } - - g_CurrentPlayer->field_70 = g_CurrentPlayer->field_6C * (1.0f - TANK_UNKD0_SCALE); - } - else - { - if (use_stanHeight != 0) - { - g_CurrentPlayer->stanHeight = g_CurrentPlayer->stanHeight + stanHeight_offset; - - temp_f0 = bondviewYPositionRelated( - g_CurrentPlayer->field_488.current_tile_ptr, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2]); - - if (g_CurrentPlayer->stanHeight < temp_f0) - { - g_CurrentPlayer->stanHeight = temp_f0; - } - } - else - { - stan = g_CurrentPlayer->field_488.current_tile_ptr; - - bondviewGetCollisionRadius(g_CurrentPlayer->prop, &collision_radius, &height, &always_30); - - sp64 = bondviewYPositionRelated( - g_CurrentPlayer->field_488.current_tile_ptr, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2]); - - // Another error checking block, it seems this condition is almost never triggered in the game. - if (stanTestLocusEdgeAboveY( - &stan, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2], - collision_radius, - bondviewGetPlayerDuckingHeightRelated(g_CurrentPlayer) + sp64) >= 0) - { - if (sp64 < g_CurrentPlayer->stanHeight) - { - sp64 = g_CurrentPlayer->stanHeight; - } - } - - g_CurrentPlayer->stanHeight = sp64; - } - - if ((g_CurrentPlayer->field_2A6C != 0) && (g_CurrentPlayer->field_70 < g_CurrentPlayer->stanHeight)) - { - g_CurrentPlayer->field_2A6C = 0; - g_CurrentPlayer->field_488.current_tile_ptr = g_CurrentPlayer->field_2A70; - g_CurrentPlayer->field_2A70 = NULL; - } - - if ((g_CurrentPlayer->field_7C >= 0.0f) || (g_CurrentPlayer->field_70 < g_CurrentPlayer->stanHeight)) - { - g_CurrentPlayer->field_6C = g_CurrentPlayer->field_70 / (1.0f - TANK_UNKD0_SCALE); - - for (i=0; ifield_6C = (g_CurrentPlayer->field_6C * TANK_UNKD0_SCALE) + g_CurrentPlayer->stanHeight; - } - - if (g_CurrentPlayer->field_70 < g_CurrentPlayer->stanHeight) - { - g_CurrentPlayer->field_70 = g_CurrentPlayer->field_6C * (1.0f - TANK_UNKD0_SCALE); - } - } - - if (g_CurrentPlayer->stanHeight < g_CurrentPlayer->field_70) - { - new_field_7c = g_CurrentPlayer->field_7C; - new_field_70 = g_CurrentPlayer->field_70; - - if ((get_debug_fast_bond_flag() != 0) && (g_ForceBondMoveOffset.f[0] == 0.0f) && (g_ForceBondMoveOffset.f[2] == 0.0f)) - { - sp40 = 1.388889f; - } - else - { - sp40 = 0.27777779f; - } - - ftemp2 = new_field_7c - (g_GlobalTimerDelta * sp40); - new_field_70 += (g_GlobalTimerDelta * (new_field_7c + ftemp2) * 0.5f); - new_field_7c = ftemp2; - - if (new_field_70 < g_CurrentPlayer->stanHeight) - { - new_field_70 = g_CurrentPlayer->stanHeight; - new_field_7c = -sqrtf((g_CurrentPlayer->field_7C * g_CurrentPlayer->field_7C) + (((2.0f * (g_CurrentPlayer->field_70 - g_CurrentPlayer->stanHeight) * 0.27777779f) / 60.0f) * 60.0f)); - - - if (g_CurrentPlayer->field_2A6C != 0) - { - g_CurrentPlayer->field_2A6C = 0; - g_CurrentPlayer->field_488.current_tile_ptr = g_CurrentPlayer->field_2A70; - g_CurrentPlayer->field_2A70 = NULL; - } - } - - g_CurrentPlayer->field_70 = new_field_70; - g_CurrentPlayer->field_7C = new_field_7c; - } - - if ((g_CurrentPlayer->field_7C < 0.0f) && (g_CurrentPlayer->field_70 <= g_CurrentPlayer->stanHeight)) - { - if (g_CurrentPlayer->field_7C < -13.333333f) - { - g_CurrentPlayer->field_8C = CLIPPING_FIELD8C_VALUE; - g_CurrentPlayer->vertical_bounce_adjust = -90.0f; - } - else if (g_CurrentPlayer->field_7C < -5.0f) - { - g_CurrentPlayer->field_8C = CLIPPING_FIELD8C_VALUE; - g_CurrentPlayer->vertical_bounce_adjust = ((-5.0f - g_CurrentPlayer->field_7C) * -90.0f) / 8.333333f; - } - - g_CurrentPlayer->field_7C = 0.0f; - } - - if (g_CurrentPlayer->field_2A6C != 0) - { - if (g_CurrentPlayer->field_70 + bondviewGetPlayerDuckingHeightRelated(g_CurrentPlayer) - < stanGetPositionYValue( - g_CurrentPlayer->field_488.current_tile_ptr, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2])) - { - g_CurrentPlayer->field_2A6C = 0; - g_CurrentPlayer->field_488.current_tile_ptr = g_CurrentPlayer->field_2A70; - g_CurrentPlayer->field_2A70 = NULL; - } - } - } - - for (i=0; ifield_8C > 0) - { - g_CurrentPlayer->field_84 = (g_CurrentPlayer->field_84 * CLIPPING_CLOCK_FACTOR) + g_CurrentPlayer->vertical_bounce_adjust; - g_CurrentPlayer->field_8C += -1; - } - else - { - if (g_CurrentPlayer->vertical_bounce_adjust < 0.0f) - { - g_CurrentPlayer->vertical_bounce_adjust -= CLIPPING_FIELD90_VALUE; - - if (0.0f <= g_CurrentPlayer->vertical_bounce_adjust) - { - g_CurrentPlayer->vertical_bounce_adjust = 0.0f; - } - } - - g_CurrentPlayer->field_84 = (g_CurrentPlayer->field_84 * CLIPPING_CLOCK_FACTOR) + g_CurrentPlayer->vertical_bounce_adjust; - } - } - - g_CurrentPlayer->field_88 = g_CurrentPlayer->field_84 * CLIPPING_FIELD88_FACTOR; -} - - - - - -/** - * Address 0x7F081478 (NTSC). - * Address 0x7F08151C (PAL). -*/ -void bondviewUpdatePlayerCollisionPositionFields(void) -{ - f32 phi_f0; - s32 i; - StandTile *sp2C; - s32 sp28; - - g_CurrentPlayer->eyeheight = (g_CurrentPlayer->headpos.f[1] * g_playerPerm->player_perspective_height) + 7.0f; - - phi_f0 = g_CurrentPlayer->eyeheight + - ((g_CurrentPlayer->field_88 + g_CurrentPlayer->ducking_height_offset) * g_playerPerm->player_perspective_height); - - if (phi_f0 < 30.0f) - { - phi_f0 = 30.0f; - } - - g_CurrentPlayer->field_488.collision_position.f[1] = g_CurrentPlayer->field_70 + phi_f0; - - if (((g_CameraMode != CAMERAMODE_DEATH_CAM_SP) && (g_CameraMode != CAMERAMODE_DEATH_CAM_MP) && (g_CameraMode != CAMERAMODE_POSEND)) - || (g_CurrentPlayer->bodyModel == 0)) - { - g_CurrentPlayer->field_488.pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; - g_CurrentPlayer->field_488.pos.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; - g_CurrentPlayer->field_488.pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; - } - - if (g_CurrentPlayer->bonddead != FALSE) - { - if (g_CurrentPlayer->field_29C0 > 0.0f) - { - g_CurrentPlayer->field_29C0 -= 0.25f; - - if (g_CurrentPlayer->field_29C0 < 0.0f) - { - g_CurrentPlayer->field_29C0 = 0.0f; - } - } - } - - if (g_CurrentPlayer->vv_verta < 0.0f) - { - g_CurrentPlayer->field_488.pos.f[1] += -(1.0f - g_CurrentPlayer->vv_cosverta) * g_CurrentPlayer->field_29C0; - } - - sp2C = g_CurrentPlayer->field_488.current_tile_ptr; - sp28 = stanlinelog_flag; - stanlinelog_flag = 0; - - walkTilesBetweenPoints_NoCallback( - &sp2C, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2], - g_CurrentPlayer->field_488.pos.f[0], - g_CurrentPlayer->field_488.pos.f[2]); - - stanlinelog_flag = sp28; - - g_CurrentPlayer->field_488.current_tile_ptr_for_portals = sp2C; - - g_CurrentPlayer->field_488.pos3.f[0] = g_CurrentPlayer->field_488.pos.f[0]; - g_CurrentPlayer->field_488.pos3.f[2] = g_CurrentPlayer->field_488.pos.f[2]; - - g_CurrentPlayer->field_488.pos3.f[1] = bondviewYPositionRelated( - g_CurrentPlayer->field_488.current_tile_ptr_for_portals, - g_CurrentPlayer->field_488.pos.f[0], - g_CurrentPlayer->field_488.pos.f[2]); - - g_CurrentPlayer->prop->stan = g_CurrentPlayer->field_488.current_tile_ptr; - - g_CurrentPlayer->prop->pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; - g_CurrentPlayer->prop->pos.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; - g_CurrentPlayer->prop->pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; - -#if defined(VERSION_EU) -#define S7F081478_FACTOR_1 0.881200015545f -#else -#define S7F081478_FACTOR_1 0.9f -#endif - for (i=0; ifield_3B8.f[0] = (S7F081478_FACTOR_1 * g_CurrentPlayer->field_3B8.f[0]) + g_CurrentPlayer->field_488.pos.f[0]; - g_CurrentPlayer->field_3B8.f[1] = (S7F081478_FACTOR_1 * g_CurrentPlayer->field_3B8.f[1]) + g_CurrentPlayer->field_488.pos.f[1]; - g_CurrentPlayer->field_3B8.f[2] = (S7F081478_FACTOR_1 * g_CurrentPlayer->field_3B8.f[2]) + g_CurrentPlayer->field_488.pos.f[2]; - } - -#if defined(VERSION_EU) -#define S7F081478_FACTOR_2 0.118799984455f -#else -#define S7F081478_FACTOR_2 0.100000024f -#endif - g_CurrentPlayer->field_3C4 = g_CurrentPlayer->field_3B8.f[0] * S7F081478_FACTOR_2; - g_CurrentPlayer->field_3C8 = g_CurrentPlayer->field_3B8.f[1] * S7F081478_FACTOR_2; - g_CurrentPlayer->field_3CC = g_CurrentPlayer->field_3B8.f[2] * S7F081478_FACTOR_2; -} - - - - - -/** - * Fixes vv_verta within -90 and +90. - * Updates vv_costheta, vv_sintheta, vv_verta360, vv_cosverta, vv_sinverta, field_488.theta_transform. - * Address 0x7F081790. - * - * Perfect Dark function bmoveUpdateVerta. -*/ -void bondviewApplyVertaTheta(void) -{ - while (g_CurrentPlayer->vv_verta < -180.0f) - { - g_CurrentPlayer->vv_verta += 360.0f; - } - - while (g_CurrentPlayer->vv_verta >= 180.0f) - { - g_CurrentPlayer->vv_verta -= 360.0f; - } - - if (g_CurrentPlayer->vv_verta > 90.0f) - { - g_CurrentPlayer->vv_verta = 90.0f; - } - else if (g_CurrentPlayer->vv_verta < -90.0f) - { - g_CurrentPlayer->vv_verta = -90.0f; - } - - g_CurrentPlayer->vv_costheta = cosf(g_CurrentPlayer->vv_theta * DegToRad1Fact(1)); - g_CurrentPlayer->vv_sintheta = sinf(g_CurrentPlayer->vv_theta * DegToRad1Fact(1)); - - g_CurrentPlayer->vv_verta360 = g_CurrentPlayer->vv_verta; - if (g_CurrentPlayer->vv_verta360 < 0.0f) - { - g_CurrentPlayer->vv_verta360 += 360.0f; - } - - g_CurrentPlayer->vv_cosverta = cosf(g_CurrentPlayer->vv_verta360 * DegToRad1Fact(1)); - g_CurrentPlayer->vv_sinverta = sinf(g_CurrentPlayer->vv_verta360 * DegToRad1Fact(1)); - - g_CurrentPlayer->field_488.theta_transform.f[0] = -g_CurrentPlayer->vv_sintheta; - g_CurrentPlayer->field_488.theta_transform.f[1] = 0; - g_CurrentPlayer->field_488.theta_transform.f[2] = g_CurrentPlayer->vv_costheta; -} - - -/** - * US address 7F081974. - * EU address 7F081A18. - * Perfect Dark method bmoveProcessInput. -*/ -void bondviewProcessInput(s8 stick_x, s8 stick_y, u16 buttons, u16 oldbuttons) -{ - struct MoveData moveData; // sp120 - - s8 player_joyGetStickX; // sp11F - s8 player_joyGetStickY; // sp11E - u16 player_joyGetButtons; // sp11C - u16 copy_prev_buttons_pressed; // sp11A - s32 adjustedStickX; - s32 tmpc2sticky; - s32 sp10C; - s32 sp108; - s32 sp104; - s32 sp100; - u16 shootButtons; // spFE - u16 aimButtons; // spFC - u16 invButtons; // spFA - // missing spF8 - TankRecord *spF4; - s32 i_0; // spF0 - TankRecord *spEC; - f32 ftemp_nostack_spE8; // unused - f32 noiseRadius; // spE4 - f32 ftemp_nostack_spE0; - f32 targetSpeed; - f32 ftemp_nostack_spD8; - f32 unadjustedTargetSpeed; - f32 ftemp_nostack_spD0; - f32 ftemp_nostack_spCC; - f32 ftemp_nostack_spC8; - f32 targetPitch; - StandTile *spC0; - f32 spBC; - f32 ftemp_nostack_spB8; - struct coord3d spAC; - struct coord3d spA0; - s32 stack_padding_sp9C; // unused - f32 ftemp_nostack_sp98; - f32 ftemp_nostack_sp94; - f32 ftemp_nostack_sp90; // unused - f32 ftemp_nostack_sp8C; - f32 ftemp_nostack_sp88; - f32 ftemp_nostack_sp84; - f32 ftemp_nostack_sp80; - s32 i_1; - f32 ftemp_nostack_sp78; - s32 canCycleWeapons; // sp74 - f32 sp70; - - - moveData.canSwivelGun = 0; - moveData.canManualAim = 0; - moveData.triggerOn = 0; - moveData.btap = 0; - moveData.canLookAhead = 0; - moveData.canTurnTank = 0; - moveData.canNaturalTurn = 0; - moveData.canNaturalPitch = 0; - moveData.digitalStepForward = 0; - moveData.digitalStepBack = 0; - moveData.digitalStepLeft = 0; - moveData.digitalStepRight = 0; - moveData.tankTurnLeftSpeed = 0; - moveData.tankTurnRightSpeed = 0; - moveData.speedVertaDown = 0; - moveData.speedVertaUp = 0; - moveData.aimTurnLeftSpeed = 0; - moveData.aimTurnRightSpeed = 0; - moveData.weaponBackOffset = 0; - moveData.weaponForwardOffset = 0; - moveData.aiming = 0; - moveData.zooming = 0; - moveData.zoomOutFovPersec = 0; - moveData.zoomInFovPersec = 0; - moveData.crouchDown = 0; - moveData.crouchUp = 0; - moveData.rLeanLeft = 0; - moveData.rLeanRight = 0; - moveData.detonating = 0; - moveData.canAutoAim = 0; - moveData.invertPitch = get_cur_player_look_vertical_inverted() == 0; - moveData.disableLookAhead = 0; - - if (stick_x < -5) { - moveData.controlStickXSafe = stick_x + 5; - } else if (stick_x > 5) { - moveData.controlStickXSafe = stick_x - 5; - } else { - moveData.controlStickXSafe = 0; - } - - if (stick_y < -5) { - moveData.controlStickYSafe = stick_y + 5; - } else if (stick_y > 5) { - moveData.controlStickYSafe = stick_y - 5; - } else { - moveData.controlStickYSafe = 0; - } - - moveData.controlStickXRaw = (s32)stick_x; - moveData.controlStickYRaw = (s32)stick_y; - - moveData.analogTurn = moveData.controlStickXSafe; - moveData.analogPitch = moveData.controlStickYSafe; - moveData.analogStrafe = moveData.controlStickXSafe; - moveData.analogWalk = moveData.controlStickYSafe; - - if (g_CurrentPlayer->bonddead == FALSE - && g_bondviewForceDisarm <= 0 - && ( - (g_CurrentPlayer->watch_animation_state != WATCH_ANIMATION_0x5 - && ((buttons & ~oldbuttons) & START_BUTTON) - ) - || - (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x5 - && g_CurrentPlayer->open_close_solo_watch_menu) - ) - && (getPlayerCount() == 1)) - { - trigger_solo_watch_menu(0); - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0 - && g_CurrentPlayer->bonddead == FALSE - && ( - getPlayerCount() == 1 - || ( - g_stopPlayFlag == 0 - && g_gameOverFlag == 0))) - { - if (cur_player_get_control_type() == CONTROLLER_CONFIG_DOMINO /* 2.3 */ - || cur_player_get_control_type() == CONTROLLER_CONFIG_GOODHEAD /* 2.4 */ - || cur_player_get_control_type() == CONTROLLER_CONFIG_GALORE /* 2.2 */ - || cur_player_get_control_type() == CONTROLLER_CONFIG_PLENTY /* 2.1 */ - ) - { - player_joyGetStickX = joyGetStickX(get_cur_playernum() + getPlayerCount()); - player_joyGetStickY = joyGetStickY(get_cur_playernum() + getPlayerCount()); - player_joyGetButtons = joyGetButtons(get_cur_playernum() + getPlayerCount() , (u32)ANY_BUTTON); - - copy_prev_buttons_pressed = g_CurrentPlayer->prev_buttons_pressed; - - if (player_joyGetStickX < -5) - { - adjustedStickX = player_joyGetStickX + 5; - } - else if (player_joyGetStickX > 5) - { - adjustedStickX = player_joyGetStickX - 5; - } - else - { - adjustedStickX = 0; - } - - if (player_joyGetStickY < -5) - { - tmpc2sticky = player_joyGetStickY + 5; - } - else if (player_joyGetStickY >= 6) - { - tmpc2sticky = player_joyGetStickY - 5; - } - else - { - tmpc2sticky = 0; - } - - /* 2.1 and 2.3 */ - if (cur_player_get_control_type() == CONTROLLER_CONFIG_PLENTY || (cur_player_get_control_type() == CONTROLLER_CONFIG_DOMINO)) - { - moveData.analogStrafe = adjustedStickX; - moveData.analogPitch = tmpc2sticky; - } - else - { - if (g_PlayerIsInTank == 1 && !g_CurrentPlayer->insightaimmode) - { - moveData.analogTurn = adjustedStickX; - } - else - { - moveData.analogStrafe = adjustedStickX; - } - - moveData.analogWalk = tmpc2sticky; - } - - /* 2.1 and 2.2 */ - if (cur_player_get_control_type() == CONTROLLER_CONFIG_PLENTY || cur_player_get_control_type() == CONTROLLER_CONFIG_GALORE) - { - sp104 = (player_joyGetButtons & Z_TRIG) != 0; - sp100 = ((player_joyGetButtons & ~copy_prev_buttons_pressed) & Z_TRIG) != 0; - sp10C = (buttons & Z_TRIG) != 0; - sp108 = ((buttons & ~oldbuttons) & Z_TRIG) != 0; - } - else - { - sp104 = (buttons & Z_TRIG) != 0; - sp100 = ((buttons & ~oldbuttons) & Z_TRIG) != 0; - sp10C = (player_joyGetButtons & Z_TRIG) != 0; - sp108 = ((player_joyGetButtons & ~copy_prev_buttons_pressed) & Z_TRIG) != 0; - } - - if (lvlGetControlsLockedFlag() == 0 && disablePlayerActionsWhenPausedOrInMpMenu()) - { - if (cur_player_get_aim_control() == 0) - { - g_CurrentPlayer->insightaimmode = sp104; - } - else if (sp100) - { - g_CurrentPlayer->insightaimmode = !g_CurrentPlayer->insightaimmode; - } - - moveData.canSwivelGun = !g_CurrentPlayer->insightaimmode; - moveData.canAutoAim = !g_CurrentPlayer->insightaimmode; - - moveData.canManualAim = g_CurrentPlayer->insightaimmode; - - moveData.btap = ( - (((buttons & ~oldbuttons) & B_BUTTON) != 0) - || - ((((player_joyGetButtons & ~copy_prev_buttons_pressed) & B_BUTTON)) != 0) - ); - - moveData.canLookAhead = !g_CurrentPlayer->insightaimmode; - moveData.canTurnTank = 1; - moveData.canNaturalTurn = !g_CurrentPlayer->insightaimmode; - moveData.canNaturalPitch = !g_CurrentPlayer->insightaimmode; - - if (g_CurrentPlayer->insightaimmode && (stick_y > 60)) - { - moveData.speedVertaDown = (f32) (stick_y - 60) / FLOAT_TEN_B; - if (moveData.speedVertaDown > 1.0f) - { - moveData.speedVertaDown = 1.0f; - } - } - else - { - //moveData.speedVertaDown = 0; - } - - if (g_CurrentPlayer->insightaimmode && (stick_y < -60)) - { - moveData.speedVertaUp = (f32) (-60 - stick_y) / FLOAT_TEN_B; - if (moveData.speedVertaUp > 1.0f) - { - moveData.speedVertaUp = 1.0f; - } - } - else - { - //moveData.speedVertaUp = 0; - } - - - if (g_CurrentPlayer->insightaimmode && (stick_x < -60)) - { - moveData.aimTurnLeftSpeed = (f32) (-60 - stick_x) / FLOAT_TEN_B; - if (moveData.aimTurnLeftSpeed > 1.0f) - { - moveData.aimTurnLeftSpeed = 1.0f; - } - } - else - { - //moveData.aimTurnLeftSpeed = 0; - } - - if (g_CurrentPlayer->insightaimmode && (stick_x > 60) ) - { - moveData.aimTurnRightSpeed = (f32) (stick_x - 60) / FLOAT_TEN_B; - if (moveData.aimTurnRightSpeed > 1.0f) - { - moveData.aimTurnRightSpeed = 1.0f; - } - } - else - { - //moveData.aimTurnRightSpeed = 0; - } - - moveData.weaponBackOffset = ( - ((buttons & A_BUTTON) != 0) - || - ((player_joyGetButtons & A_BUTTON) != 0) - ) - && (sp108); - - moveData.weaponForwardOffset = ( - ( - (((buttons & ~oldbuttons) & A_BUTTON) != 0) - || - (((player_joyGetButtons & ~copy_prev_buttons_pressed) & A_BUTTON) != 0) - )) - && (!sp10C); - - moveData.aiming = g_CurrentPlayer->insightaimmode; - moveData.zooming = g_CurrentPlayer->insightaimmode; - - if ((bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_DISABLE_CROUCH)) - && g_CurrentPlayer->insightaimmode) - { - if (tmpc2sticky < 0) - { - moveData.zoomOutFovPersec = (f32) -tmpc2sticky / 70.0f; - if (moveData.zoomOutFovPersec > 1.0f) - { - moveData.zoomOutFovPersec = 1.0f; - } - - moveData.zoomOutFovPersec *= 2.0f; - } - - if (tmpc2sticky > 0) - { - moveData.zoomInFovPersec = (f32) tmpc2sticky / 70.0f; - if (moveData.zoomInFovPersec > 1.0f) - { - moveData.zoomInFovPersec = 1.0f; - } - - moveData.zoomInFovPersec *= 2.0f; - } - } - - moveData.crouchDown = (bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_DISABLE_CROUCH) == 0) - && (g_CurrentPlayer->insightaimmode) - && (player_joyGetStickY < -30); - - moveData.crouchUp = (bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_DISABLE_CROUCH) == 0) - && (g_CurrentPlayer->insightaimmode) - && (player_joyGetStickY > 30); - - if (( - (((buttons & A_BUTTON) != 0) && (((buttons & ~oldbuttons) & B_BUTTON) != 0)) - || (((buttons & B_BUTTON) != 0) && (((buttons & ~oldbuttons) & A_BUTTON) != 0)) - || ((player_joyGetButtons & A_BUTTON) && ((player_joyGetButtons & ~copy_prev_buttons_pressed) & B_BUTTON)) - || ((player_joyGetButtons & B_BUTTON) && ((player_joyGetButtons & ~copy_prev_buttons_pressed) & A_BUTTON))) - && (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_REMOTEMINE)) - { - moveData.detonating = 1; - moveData.weaponBackOffset = 0; - moveData.weaponForwardOffset = 0; - moveData.btap = 0; - } - - if (g_PlayerIsInTank == 1 && g_CurrentPlayer->insightaimmode) - { - if (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_TANKSHELLS) - { - moveData.controlStickXRaw = 0; - - if (moveData.analogStrafe == 0) - { - moveData.analogStrafe = moveData.analogTurn; - } - } - else if (moveData.analogStrafe == 0) - { - if (moveData.aimTurnLeftSpeed > 0) - { - moveData.tankTurnLeftSpeed = moveData.aimTurnLeftSpeed; - } - - if (moveData.aimTurnRightSpeed > 0) - { - moveData.tankTurnRightSpeed = moveData.aimTurnRightSpeed; - } - } - - moveData.aimTurnLeftSpeed = 0; - moveData.aimTurnRightSpeed = 0; - } - } - - moveData.triggerOn = (sp10C) - && (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) - && ((buttons & A_BUTTON) == 0) - && ((player_joyGetButtons & A_BUTTON) == 0); - - moveData.disableLookAhead = 1; - g_CurrentPlayer->prev_buttons_pressed = player_joyGetButtons; - } - else - { - /* 1.3 and 1.4 */ - if (cur_player_get_control_type() == CONTROLLER_CONFIG_KISSY - || cur_player_get_control_type() == CONTROLLER_CONFIG_GOODNIGHT) - { - shootButtons = A_BUTTON; - aimButtons = Z_TRIG; - invButtons = L_TRIG | R_TRIG; - } - else - { - shootButtons = Z_TRIG; - aimButtons = L_TRIG | R_TRIG; - invButtons = A_BUTTON; - } - - if (lvlGetControlsLockedFlag() == 0) - { - if (disablePlayerActionsWhenPausedOrInMpMenu()) - { - if (cur_player_get_aim_control() == 0) - { - g_CurrentPlayer->insightaimmode = (buttons & aimButtons) != 0; - } - else if ((buttons & ~oldbuttons) & aimButtons) - { - g_CurrentPlayer->insightaimmode = !g_CurrentPlayer->insightaimmode; - } - - moveData.canSwivelGun = !g_CurrentPlayer->insightaimmode; - moveData.canAutoAim = !g_CurrentPlayer->insightaimmode; - moveData.btap = ((buttons & ~oldbuttons) & B_BUTTON) != 0; - moveData.canManualAim = g_CurrentPlayer->insightaimmode; - - /* 1.2 and 1.4 */ - if (cur_player_get_control_type() == CONTROLLER_CONFIG_SOLITARE - || cur_player_get_control_type() == CONTROLLER_CONFIG_GOODNIGHT) - { - if ((buttons & (L_JPAD | L_CBUTTONS)) != 0) - { - if (!g_CurrentPlayer->insightaimmode) - { - if (g_PlayerIsInTank == 1) - { - moveData.aimTurnLeftSpeed = 1.0f; - } - else - { - moveData.digitalStepLeft = 1; - } - } - else - { - moveData.tankTurnLeftSpeed = 1.0f; - } - } - - if ((buttons & (R_JPAD | R_CBUTTONS)) != 0) - { - if (!g_CurrentPlayer->insightaimmode) - { - if (g_PlayerIsInTank == 1) - { - moveData.aimTurnRightSpeed = 1.0f; - } - else - { - moveData.digitalStepRight = 1; - } - } - else - { - moveData.tankTurnRightSpeed = 1.0f; - } - } - - moveData.digitalStepForward = (!g_CurrentPlayer->insightaimmode) - && ((buttons & (U_JPAD | U_CBUTTONS)) ); - - moveData.digitalStepBack = (!g_CurrentPlayer->insightaimmode) - && ((buttons & (D_JPAD | D_CBUTTONS))); - - moveData.canNaturalPitch = !g_CurrentPlayer->insightaimmode; - - if (g_PlayerIsInTank == 1) - { - moveData.canTurnTank = !g_CurrentPlayer->insightaimmode; - } - else - { - moveData.canNaturalTurn = !g_CurrentPlayer->insightaimmode; - } - } - else - { - if ((buttons & (s32)(L_JPAD | L_CBUTTONS)) != 0) - { - moveData.tankTurnLeftSpeed = 1.0f; - } - /* optional else statement, matches with or without. */ - else - { - moveData.tankTurnLeftSpeed = 0; - } - - if ((buttons & (s32)(R_JPAD | R_CBUTTONS)) != 0) - { - moveData.tankTurnRightSpeed = 1.0f; - } - /* optional else statement, matches with or without. */ - else - { - moveData.tankTurnRightSpeed = 0; - } - - moveData.digitalStepLeft = (!g_CurrentPlayer->insightaimmode) - && ((buttons & (s32)(L_JPAD | L_CBUTTONS)) ); - - moveData.digitalStepRight = (!g_CurrentPlayer->insightaimmode) - && ((buttons & (s32)(R_JPAD | R_CBUTTONS))); - - moveData.canLookAhead = !g_CurrentPlayer->insightaimmode; - - if ((!g_CurrentPlayer->insightaimmode) && (buttons & (U_JPAD | U_CBUTTONS)) ) - { - moveData.speedVertaDown = 1.0f; - } - - if ((!g_CurrentPlayer->insightaimmode) && (buttons & (D_JPAD | D_CBUTTONS))) - { - moveData.speedVertaUp = 1.0f; - } - - moveData.canNaturalTurn = !g_CurrentPlayer->insightaimmode; - } - - if ((g_CurrentPlayer->insightaimmode) && (stick_y > 60)) - { - moveData.speedVertaDown = (f32) (stick_y - 60) / FLOAT_TEN_B; - if (moveData.speedVertaDown > 1.0f) - { - moveData.speedVertaDown = 1.0f; - } - } - else if ((g_CurrentPlayer->insightaimmode) && (stick_y < -60)) - { - moveData.speedVertaUp = (f32) (-60 - stick_y) / FLOAT_TEN_B; - if (moveData.speedVertaUp > 1.0f) - { - moveData.speedVertaUp = 1.0f; - } - } - - if ((g_CurrentPlayer->insightaimmode) && (stick_x < -60)) - { - moveData.aimTurnLeftSpeed = (f32) (-60 - stick_x) / FLOAT_TEN_B; - if (moveData.aimTurnLeftSpeed > 1.0f) - { - moveData.aimTurnLeftSpeed = 1.0f; - } - } - - if ((g_CurrentPlayer->insightaimmode) && (stick_x > 60)) - { - moveData.aimTurnRightSpeed = (f32) (stick_x - 60) / FLOAT_TEN_B; - if (moveData.aimTurnRightSpeed > 1.0f) - { - moveData.aimTurnRightSpeed = 1.0f; - } - } - - moveData.weaponBackOffset = - ((buttons & invButtons) != 0) - && - (((buttons & ~oldbuttons) & shootButtons) != 0) - ; - - moveData.weaponForwardOffset = - (((buttons & ~oldbuttons) & invButtons) != 0) - && - ((buttons & shootButtons) == 0) - ; - - moveData.aiming = g_CurrentPlayer->insightaimmode; - moveData.zooming = g_CurrentPlayer->insightaimmode; - - if ((bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_DISABLE_CROUCH)) - && g_CurrentPlayer->insightaimmode - ) - { - /* down = 0x404 */ - if ((buttons & (D_JPAD | D_CBUTTONS)) != 0) - { - moveData.zoomOutFovPersec = 1.0f; - } - - if ((buttons & (U_JPAD | U_CBUTTONS)) != 0) - { - moveData.zoomInFovPersec = 1.0f; - } - } - - moveData.crouchDown = (bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_DISABLE_CROUCH) == 0) - && (g_CurrentPlayer->insightaimmode) - && ((buttons & (D_JPAD | D_CBUTTONS))); - - moveData.crouchUp = (bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_DISABLE_CROUCH) == 0) - && (g_CurrentPlayer->insightaimmode) - && ((~buttons & (U_JPAD | U_CBUTTONS))); - - moveData.rLeanLeft = (g_CurrentPlayer->insightaimmode) - && ((buttons & (L_JPAD | L_CBUTTONS))); - - moveData.rLeanRight = (g_CurrentPlayer->insightaimmode) - && ((buttons & (R_JPAD | R_CBUTTONS))); - - if ( - ((((buttons & invButtons) != 0) && (((buttons & ~oldbuttons) & B_BUTTON) != 0)) - || ((buttons & B_BUTTON) && (((buttons & ~oldbuttons) & invButtons) != 0))) - && (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_REMOTEMINE)) - { - moveData.detonating = 1; - moveData.weaponBackOffset = 0; - moveData.weaponForwardOffset = 0; - moveData.btap = 0; - } - - if ((g_PlayerIsInTank == 1) && (g_CurrentPlayer->insightaimmode)) - { - if (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_TANKSHELLS) - { - moveData.controlStickXRaw = 0; - moveData.canTurnTank = 1; - } - else if ((moveData.tankTurnLeftSpeed == 0) && (moveData.tankTurnRightSpeed == 0)) - { - if (moveData.aimTurnLeftSpeed > 0) - { - moveData.tankTurnLeftSpeed = moveData.aimTurnLeftSpeed; - } - - if (moveData.aimTurnRightSpeed > 0) - { - moveData.tankTurnRightSpeed = moveData.aimTurnRightSpeed; - } - } - - moveData.aimTurnLeftSpeed = 0; - moveData.aimTurnRightSpeed = 0; - } - } - } - - moveData.triggerOn = ((buttons & shootButtons) != 0) - && (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) - && ((buttons & invButtons) == 0); - - /* 1.2 and 1.4 */ - if (cur_player_get_control_type() == CONTROLLER_CONFIG_SOLITARE || cur_player_get_control_type() == CONTROLLER_CONFIG_GOODNIGHT) - { - moveData.disableLookAhead = 1; - } - } - } - - g_CurrentPlayer->field_D0 = 0; - - if (moveData.btap) - { - /* If Bond is in the tank and pressed B, then exit. */ - if (g_PlayerIsInTank == 1) - { - spF4 = (struct TankRecord *)g_PlayerTankProp->obj; - spF4->unkD8 = get_ammo_count_for_weapon(ITEM_TANKSHELLS); - - add_ammo_to_weapon(ITEM_TANKSHELLS, 0); - bondinvRemoveItemByID(ITEM_TANKSHELLS); - - if (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_TANKSHELLS) - { - spF4->unkD8 += get_ammo_in_hands_magazine(GUNRIGHT); - autoadvance_on_deplete_all_ammo(); - } - - spF4->is_firing_tank = 0; - g_PlayerIsInTank = 0; - g_CurrentPlayer->speedsideways = 0; - g_CurrentPlayer->speedforwards = 0; - g_CurrentPlayer->speedtheta = 0; - - for (i_0=0; i_0<3; i_0++) - { - g_CurrentPlayer->bondshotspeed.f[i_0] = 0; - } - - g_CurrentPlayer->crouchpos = CROUCH_STAND; - } - /* If Bond is standing on the tank and pressed B, enter the tank. */ - else if (g_PlayerTankProp != NULL - && g_PlayerTankProp->type == PROP_TYPE_OBJ - && g_PlayerTankProp->obj->type == PROPDEF_TANK - && g_BondCanEnterTank) - { - spEC = (struct TankRecord *)g_PlayerTankProp->obj; - - bondinvAddInvItem(ITEM_TANKSHELLS); - add_ammo_to_weapon(ITEM_TANKSHELLS, spEC->unkD8); - spEC->unkD8 = 0; - g_TankTurretVerticalAngle = spEC->turret_vertical_angle; - g_TankTurretVerticalAngleRelated = g_TankTurretVerticalAngle / TANK_VERT_ANGLE_FACTOR; - g_TankTurretAngle = spEC->turret_orientation_angle; - g_TankTurretOrientationAngleRad = spEC->turret_orientation_angle; - g_TankTurretOrientationAngleDeg = g_TankTurretOrientationAngleRad / TANK_VERT_ANGLE_RAD_FACTOR; - tank_turret_turn_speed = 0; - g_TankOrientationAngle = spEC->tank_orientation_angle; - g_TankTurnSpeed = 0; - g_PlayerIsInTank = 1; - g_EnterTankAudioState = TANK_RUN_STATE_NOT_RUNNING; - g_CurrentPlayer->speedsideways = 0; - g_CurrentPlayer->speedforwards = 0; - g_CurrentPlayer->speedtheta = 0; - g_CurrentPlayer->crouchpos = CROUCH_HALF; - g_TankEnteringSitHeight = 0; - g_TankEnteringSitHeightRemain = 1.0f; - g_TankEnterBondHorizAngleDeg = g_CurrentPlayer->vv_theta; - g_TankEnterBondVertAngleDeg = g_CurrentPlayer->vv_verta; - g_EnterTankCoord.f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; - g_EnterTankCoord.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; - g_EnterTankCoord.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; - g_TankDamagePenaltyTicks = 0; - - bondviewTankModelRotationRelated(); - } - else - { - g_CurrentPlayer->field_D0 = 1; - } - } - - if (moveData.invertPitch == 0) - { - f32 ftemp_nostack_spE8; - - moveData.controlStickYRaw = (s32) -stick_y; - moveData.analogPitch = -moveData.analogPitch; - ftemp_nostack_spE8 = moveData.speedVertaDown; - moveData.speedVertaDown = moveData.speedVertaUp; - moveData.speedVertaUp = ftemp_nostack_spE8; - } - - if (bondviewGetIfCurrentPlayerDamageShowTime() && getPlayerCount() == 1) - { - moveData.triggerOn = 0; - } - - gunTickGameplay(moveData.triggerOn); - - if (bondviewGetVisibleToGuardsFlag() - && (get_hands_firing_status(GUNRIGHT) - || get_hands_firing_status(GUNLEFT))) - { - noiseRadius = 0; - - if (get_hands_firing_status(GUNRIGHT) && getCurrentPlayerNoise(GUNRIGHT) > noiseRadius) - { - noiseRadius = getCurrentPlayerNoise(GUNRIGHT); - } - - if (get_hands_firing_status(GUNLEFT) && noiseRadius < getCurrentPlayerNoise(GUNLEFT)) - { - noiseRadius = getCurrentPlayerNoise(GUNLEFT); - } - - chrCheckGuardsHeardSound(noiseRadius); - } - - gunSetSightVisible(GUNSIGHTREASON_NOTAIMING, moveData.aiming); - - if (moveData.zoomOutFovPersec > 0) - { - camera_sniper_zoom_out(moveData.zoomOutFovPersec); - } - - if (moveData.zoomInFovPersec > 0) - { - camera_sniper_zoom_in(moveData.zoomInFovPersec); - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) - { - ftemp_nostack_spE0 = 60.0f; - - if (moveData.zooming) - { - ftemp_nostack_spE0 = get_item_in_hand_zoom(); - - if (ftemp_nostack_spE0 <= 0) - { - ftemp_nostack_spE0 = 60.0f; - } - } - - bondviewTriggerWatchZoom(ftemp_nostack_spE0); - bondviewUpdateWatchZoomIn(); - } - - if (g_PlayerIsInTank == 1) - { - g_TankTurretTurn = 0; - - if (g_EnterTankAudioState == TANK_RUN_STATE_RUNNING) - { - if (moveData.tankTurnRightSpeed > 0) - { - g_TankTurretTurn += g_GlobalTimerDelta * moveData.tankTurnRightSpeed * DegToRad1Fact(1); - } - else if (moveData.tankTurnLeftSpeed > 0) - { - g_TankTurretTurn -= g_GlobalTimerDelta * moveData.tankTurnLeftSpeed * DegToRad1Fact(1); - } - else if (moveData.canTurnTank) - { - targetSpeed = (f32) moveData.analogStrafe / 70.0f; - - if (targetSpeed > 1.0f) - { - targetSpeed = 1.0f; - } - - if (targetSpeed < -1.0f) - { - targetSpeed = -1.0f; - } - - g_TankTurretTurn += DegToRad1Fact(1) * targetSpeed * g_GlobalTimerDelta; - } - - if (!g_CurrentPlayer->insightaimmode) - { - ftemp_nostack_spD8 = 0; - targetSpeed = 1.0f; - ftemp_nostack_spE8 = 1.0f; - - if (moveData.canLookAhead) - { - ftemp_nostack_spD8 = (f32) moveData.analogWalk / 70.0f; - } - else if (moveData.digitalStepForward) - { - ftemp_nostack_spD8 = 1.0f; - } - else if (moveData.digitalStepBack) - { - ftemp_nostack_spD8 = -1.0f; - } - - if (ftemp_nostack_spD8 > 1.0f) - { - ftemp_nostack_spD8 = 1.0f; - } - else if (ftemp_nostack_spD8 < -1.0f) - { - ftemp_nostack_spD8 = -1.0f; - } - - unadjustedTargetSpeed = ftemp_nostack_spD8 * TANK_MAX_SPEED; - targetSpeed = unadjustedTargetSpeed; - - if (g_TankDamagePenaltyTicks > 0) - { - targetSpeed = unadjustedTargetSpeed * 0.5f; - ftemp_nostack_spE8 = 4.0f; - g_TankDamagePenaltyTicks -= g_ClockTimer; - } - - if (targetSpeed != g_CurrentPlayer->speedforwards) - { - if (g_CurrentPlayer->speedforwards < targetSpeed) - { - unadjustedTargetSpeed = ((((((targetSpeed - g_CurrentPlayer->speedforwards) / 4.0f) / TANK_MAX_SPEED) + 0.5f) * ftemp_nostack_spE8 * FLOAT_TEN_A) / 60.0f); - - g_CurrentPlayer->speedforwards += (unadjustedTargetSpeed) * g_GlobalTimerDelta; - - if (targetSpeed < g_CurrentPlayer->speedforwards) - { - g_CurrentPlayer->speedforwards = targetSpeed; - } - } - else if (targetSpeed < g_CurrentPlayer->speedforwards) - { - unadjustedTargetSpeed = ((((((g_CurrentPlayer->speedforwards - targetSpeed) / 4.0f) / TANK_MAX_SPEED) + 0.5f) * ftemp_nostack_spE8 * -FLOAT_TEN_A) / 60.0f); - - g_CurrentPlayer->speedforwards += (unadjustedTargetSpeed) * g_GlobalTimerDelta; - - if (g_CurrentPlayer->speedforwards < targetSpeed) - { - g_CurrentPlayer->speedforwards = targetSpeed; - } - } - } - } - } - } - else - { - if (moveData.digitalStepLeft) - { - bondviewUpdateSpeedSideways(-1); - } - else if (moveData.digitalStepRight) - { - bondviewUpdateSpeedSideways(1); - } - else - { - bondviewUpdateSpeedSideways(0); - } - - if (moveData.canTurnTank) // ?? not sure why this tank property is used here. Is the name wrong? - { - g_CurrentPlayer->speedsideways = (f32) moveData.analogStrafe / 70.0f; - } - - if (moveData.digitalStepForward) - { - bondviewUpdateSpeedForwards(1); - g_CurrentPlayer->speedmaxtime60 += g_ClockTimer; - } - else if (moveData.digitalStepBack) - { - bondviewUpdateSpeedForwards(-1); - } - else - { - bondviewUpdateSpeedForwards(0); - } - - if (moveData.canLookAhead) - { - g_CurrentPlayer->speedforwards = (f32) moveData.analogWalk / 70.0f; - - if (moveData.analogWalk > 60) - { - g_CurrentPlayer->speedmaxtime60 += g_ClockTimer; - } - else - { - g_CurrentPlayer->speedmaxtime60 = 0; - } - } - - if (g_CurrentPlayer->speedforwards > 1.0f) - { - g_CurrentPlayer->speedforwards = 1; - } - - if (g_CurrentPlayer->speedforwards < -1.0f) - { - g_CurrentPlayer->speedforwards = -1.0f; - } - - if (g_CurrentPlayer->speedsideways > 1) - { - g_CurrentPlayer->speedsideways = 1; - } - - if (g_CurrentPlayer->speedsideways < -1) - { - g_CurrentPlayer->speedsideways = -1; - } - - g_CurrentPlayer->speedforwards *= 1.08f; - g_CurrentPlayer->speedforwards *= g_CurrentPlayer->speedboost; - - if ((moveData.canLookAhead == 0) && (moveData.digitalStepForward == 0)) - { - g_CurrentPlayer->speedmaxtime60 = 0; - } - - if (moveData.rLeanLeft) - { - currentPlayerSetSwayTarget(-1); - } - else if (moveData.rLeanRight) - { - currentPlayerSetSwayTarget(1); - } - else - { - currentPlayerSetSwayTarget(0); - } - - if (moveData.crouchDown) - { - currentPlayerAdjustCrouchPos(-2); - } - else if (moveData.crouchUp) - { - currentPlayerAdjustCrouchPos(2); - } - } - - if (g_CurrentPlayer->speedmaxtime60 >= THREE_SECOND_TICKS) - { - if (g_CurrentPlayer->speedboost < SPEED_RUN_MAX) - { - g_CurrentPlayer->speedboost += (SPEED_TICK_ADJUST * g_GlobalTimerDelta); - } - - if (g_CurrentPlayer->speedboost > SPEED_RUN_MAX) - { - g_CurrentPlayer->speedboost = SPEED_RUN_MAX; - } - } - else - { - if (g_CurrentPlayer->speedboost > SPEED_REGULAR_MAX) - { - g_CurrentPlayer->speedboost -= (SPEED_TICK_ADJUST * g_GlobalTimerDelta); - } - - if (g_CurrentPlayer->speedboost < SPEED_REGULAR_MAX) - { - g_CurrentPlayer->speedboost = SPEED_REGULAR_MAX; - } - } - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) - { - // By default the camera is pitched slightly below the horizon - targetPitch = -4.0f; - - // lookaheadcentreenabled is always true, so this block always executes. - if (g_CurrentPlayer->lookaheadcentreenabled) - { - spC0 = g_CurrentPlayer->field_488.current_tile_ptr; - spBC = 300.0f; - - // prop, f32 *collision_radius, f32 *height, f32 *always_30 - bondviewGetCollisionRadius(g_CurrentPlayer->prop, &spA0.f[0], &spA0.f[2], &spA0.f[1]); - - spAC.f[0] = g_CurrentPlayer->field_488.collision_position.f[0] + (g_CurrentPlayer->field_488.theta_transform.f[0] * 300.0f); - spAC.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; - spAC.f[2] = g_CurrentPlayer->field_488.collision_position.f[2] + (g_CurrentPlayer->field_488.theta_transform.f[2] * 300.0f); - - stanResetHits(); - - if (stanTestLineUnobstructed(&spC0, g_CurrentPlayer->field_488.collision_position.f[0], g_CurrentPlayer->field_488.collision_position.f[2], spAC.f[0], spAC.f[2], CDTYPE_CLOSEDDOORS, spA0.f[2], spA0.f[1], 0, 1.0f)) - { - spAC.f[1] = bondviewYPositionRelated(spC0, spAC.f[0], spAC.f[2]); - } - else - { - chrlvStanPointPointIntersection(&g_CurrentPlayer->field_488.collision_position, &g_CurrentPlayer->field_488.theta_transform, (struct coord3d *) &spAC); - ftemp_nostack_spD0 = spAC.f[0] - g_CurrentPlayer->field_488.collision_position.f[0]; - ftemp_nostack_spCC = spAC.f[2] - g_CurrentPlayer->field_488.collision_position.f[2]; - spBC = sqrtf((ftemp_nostack_spD0 * ftemp_nostack_spD0) + (ftemp_nostack_spCC * ftemp_nostack_spCC)); - spAC.f[1] = bondviewYPositionRelated(spC0, spAC.f[0], spAC.f[2]); - } - - if (spBC > 0) - { - ftemp_nostack_spC8 = spAC.f[1] - g_CurrentPlayer->stanHeight; - - if ((ftemp_nostack_spC8 > -300.0f) && (ftemp_nostack_spC8 < 500.0f)) - { - targetPitch = ((atan2f(ftemp_nostack_spC8, spBC) * 360.0f) / M_TAU_F) + -4.0f; - - if (targetPitch >= 180.0f) - { - targetPitch -= 360.0f; - } - - if (targetPitch > 0) - { - targetPitch *= 0.8666667f; - } - } - } - } - - if ((g_CurrentPlayer->movecentrerelease) && (moveData.analogWalk < 40) && (moveData.analogWalk > -40)) - { - g_CurrentPlayer->movecentrerelease = FALSE; - } - - - if (g_PlayerIsInTank == 0) - { - /** - * If the player is giving manual pitch inputs, stop the automatic look ahead pitch adjust. - */ - if ((moveData.speedVertaDown > 0) || (moveData.speedVertaUp > 0)) - { - g_CurrentPlayer->docentreupdown = FALSE; - g_CurrentPlayer->prevupdown = TRUE; - g_CurrentPlayer->automovecentre = FALSE; - } - else - { - if (moveData.disableLookAhead) - { - g_CurrentPlayer->automovecentre = FALSE; - } - else if (g_CurrentPlayer->automovecentreenabled) - { - if ((moveData.canLookAhead) && ((moveData.analogWalk > 60) || (moveData.analogWalk < -60))) - { - g_CurrentPlayer->automovecentre = TRUE; - } - - /** - * If the player's camera pitch is 5 degrees above the target pitch or 10 degrees below the target pitch, - * and move centre is allowed, look ahead (docentreupdown) can be activated. - */ - if ((g_CurrentPlayer->automovecentre) - && (( ((targetPitch + 5.0f) < g_CurrentPlayer->vv_verta)) || (g_CurrentPlayer->vv_verta < (targetPitch + -FLOAT_TEN_A))) - && (g_CurrentPlayer->movecentrerelease == FALSE)) - { - g_CurrentPlayer->docentreupdown = TRUE; - } - } - /** - * fastmovecentreenabled is never set to true, so this block can never execute. Cut option? - */ - else if ((g_CurrentPlayer->fastmovecentreenabled) - && (moveData.canLookAhead) - && ((moveData.analogWalk > 60) || (moveData.analogWalk < -60)) - && (( ((targetPitch + 5.0f) < g_CurrentPlayer->vv_verta)) || (g_CurrentPlayer->vv_verta < (targetPitch + -FLOAT_TEN_A))) - && (g_CurrentPlayer->movecentrerelease == FALSE)) - { - g_CurrentPlayer->docentreupdown = TRUE; - } - - g_CurrentPlayer->prevupdown = FALSE; - } - } - - /** - * If look ahead (docentreupdown) is active, adjust the player's camera pitch to the target pitch. - */ - if (g_CurrentPlayer->docentreupdown) - { - if (g_PlayerIsInTank == 0) - { - ftemp_nostack_spB8 = (g_CurrentPlayer->speedverta * g_CurrentPlayer->speedverta * 0.5f) / 0.05f; - - if ((targetPitch + ftemp_nostack_spB8) < g_CurrentPlayer->vv_verta) - { - bondviewCurrentPlayerUpdateSpeedVerta(1.0f); - } - else if (g_CurrentPlayer->vv_verta < (targetPitch - ftemp_nostack_spB8)) - { - bondviewCurrentPlayerUpdateSpeedVerta(-1.0f); - } - else - { - bondviewCurrentPlayerUpdateSpeedVerta(0); - } - - ftemp_nostack_spB8 = g_CurrentPlayer->vv_verta + (2.0f * (g_CurrentPlayer->speedverta * g_GlobalTimerDelta)); - - if ((targetPitch < g_CurrentPlayer->vv_verta) && (targetPitch < ftemp_nostack_spB8)) - { - g_CurrentPlayer->vv_verta = ftemp_nostack_spB8; - } - else if ((g_CurrentPlayer->vv_verta < targetPitch) && (ftemp_nostack_spB8 < targetPitch)) - { - g_CurrentPlayer->vv_verta = ftemp_nostack_spB8; - } - else - { - g_CurrentPlayer->vv_verta = targetPitch; - g_CurrentPlayer->speedverta = 0; - - if (g_CurrentPlayer->prevupdown == FALSE) - { - g_CurrentPlayer->docentreupdown = FALSE; - } - } - } - } - else - { - if (moveData.canNaturalPitch) - { - ftemp_nostack_sp98 = viGetFovY() / 60.0f; - ftemp_nostack_sp94 = (f32) moveData.analogPitch / 70.0f; - - if (ftemp_nostack_sp94 > 1) - { - ftemp_nostack_sp94 = 1; - } - else if (ftemp_nostack_sp94 < -1) - { - ftemp_nostack_sp94 = -1; - } - - if (ftemp_nostack_sp94 >= 0) - { - ftemp_nostack_sp94 *= ftemp_nostack_sp94; - } - else - { - ftemp_nostack_sp94 *= -ftemp_nostack_sp94; - } - - g_CurrentPlayer->speedverta = -ftemp_nostack_sp94 * ftemp_nostack_sp98; - } - else if (moveData.speedVertaDown > 0) - { - bondviewCurrentPlayerUpdateSpeedVerta(moveData.speedVertaDown); - - // Bug? This is true for every value except exactly 60. - if ((moveData.canLookAhead) && ((moveData.analogWalk > 60) || (moveData.analogWalk < 60))) - { - g_CurrentPlayer->movecentrerelease = TRUE; - } - } - else if (moveData.speedVertaUp > 0) - { - bondviewCurrentPlayerUpdateSpeedVerta(-moveData.speedVertaUp); - - if ((moveData.canLookAhead) && ((moveData.analogWalk > 60) || (moveData.analogWalk < 60))) - { - g_CurrentPlayer->movecentrerelease = TRUE; - } - } - else - { - bondviewCurrentPlayerUpdateSpeedVerta(0); - } - - g_CurrentPlayer->vv_verta += g_CurrentPlayer->speedverta * g_GlobalTimerDelta * 3.5f; - - if ((g_PlayerIsInTank == 1) && (g_EnterTankAudioState == TANK_RUN_STATE_RUNNING) && (g_CurrentPlayer->vv_verta < -20.0f)) - { - g_CurrentPlayer->vv_verta = -20.0f; - } - } - } - - if (moveData.canNaturalTurn) - { - ftemp_nostack_sp8C = viGetFovY(); - ftemp_nostack_sp84 = (f32) moveData.analogTurn / 70.0f; - - if (ftemp_nostack_sp84 > 1) - { - ftemp_nostack_sp84 = 1; - } - else if (ftemp_nostack_sp84 < -1) - { - ftemp_nostack_sp84 = -1; - } - - if (ftemp_nostack_sp84 >= 0) - { - ftemp_nostack_sp84 *= ftemp_nostack_sp84; - } - else - { - ftemp_nostack_sp84 *= -ftemp_nostack_sp84; - } - - ftemp_nostack_sp88 = (ftemp_nostack_sp8C / FOV_Y_F); - g_CurrentPlayer->speedtheta = ftemp_nostack_sp84 * ftemp_nostack_sp88; - } - else if (moveData.aimTurnLeftSpeed > 0) - { - bondviewCurrentPlayerUpdateSpeedTheta(moveData.aimTurnLeftSpeed); - } - else if (moveData.aimTurnRightSpeed > 0) - { - bondviewCurrentPlayerUpdateSpeedTheta(-moveData.aimTurnRightSpeed); - } - else - { - bondviewCurrentPlayerUpdateSpeedTheta(0); - } - - if (g_PlayerIsInTank == 1) - { - if (g_EnterTankAudioState == TANK_RUN_STATE_RUNNING) - { - ftemp_nostack_sp80 = 0; - - if (moveData.canNaturalTurn) - { - ftemp_nostack_sp80 = g_CurrentPlayer->speedtheta * 0.3f; - } - else if (moveData.aimTurnLeftSpeed > 0) - { - ftemp_nostack_sp80 = sub_GAME_7F080228(1) * 0.3f; - } - else if (moveData.aimTurnRightSpeed > 0) - { - ftemp_nostack_sp80 = sub_GAME_7F080228(-1) * 0.3f; - } - - for (i_1=0; i_1speedtheta = g_TankTurnSpeed * TANK_VERT_ANGLE_RAD_FACTOR; - } - else - { - g_CurrentPlayer->speedtheta = 0; - } - } - - if (moveData.detonating) - { - g_CurrentPlayer->hands[GUNRIGHT].weapon_action_state = GUN_ANIM_STATE_IDLE; - g_CurrentPlayer->hands[GUNRIGHT].weapon_current_animation = 0; - trigger_remote_mine_detonation(); - } - - canCycleWeapons = 1; - - if ((getPlayerCount() >= 2) && (get_scenario() == 2) && (bondinvIsAliveWithFlag())) - { - canCycleWeapons = 0; - } - - if (canCycleWeapons) - { - if (moveData.weaponBackOffset) - { - backstep_through_inventory(); - } - - if (moveData.weaponForwardOffset) - { - advance_through_inventory(); - } - } - - if (moveData.canSwivelGun) - { - g_CurrentPlayer->controldef = CONTROLLER_CONFIG_HONEY; - } - else if (moveData.canManualAim) - { - g_CurrentPlayer->controldef = CONTROLLER_CONFIG_KISSY; - } - - if (g_CurrentPlayer->controldef == CONTROLLER_CONFIG_HONEY) - { - gunSetAimType(0); - - if (moveData.canAutoAim - && currentPlayerGetXAutoAimEnabledRedirect() - && g_CurrentPlayer->autoaim_target_x - && bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_HAS_AUTO_AIM)) - { - sp70 = g_CurrentPlayer->autoaimx; - } - else - { - sp70 = g_CurrentPlayer->speedtheta * 0.3f; - } - - if (moveData.canAutoAim - && currentPlayerGetYAutoAimEnabledRedirect() - && g_CurrentPlayer->autoaim_target_y - && bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_HAS_AUTO_AIM)) - { - ftemp_nostack_sp78 = g_CurrentPlayer->autoaimy; - } - else - { - ftemp_nostack_sp78 = -g_CurrentPlayer->speedverta * 0.1f; - } - - sub_GAME_7F067F58(sp70, ftemp_nostack_sp78, MAX_AIMLOCK_SPEED_DEFAULT); - } - else if (g_CurrentPlayer->controldef == CONTROLLER_CONFIG_KISSY) - { - gunSetAimType(0); - sub_GAME_7F067FBC(((f32) moveData.controlStickXRaw * 0.65f) / 80.0f, ((f32) moveData.controlStickYRaw * 0.65f) / 80.0f); - } -} - - -/** - * Perfect Dark playerTickDamageAndHealth - * - * NTSC address 7F083FC8. - * NTSC-J address 7F0845D8. - * EU address 7F08406C. -*/ -void bondviewPlayerTickDamageAndHealth(void) -{ - // update damage showtime - if (g_CurrentPlayer->damageshowtime >= 0) - { - // 0: This is the first frame of damage - if (g_CurrentPlayer->damageshowtime == 0) - { - gunSetGunAmmoVisible(GUNAMMOREASON_DAMAGE, FALSE); - gunSetSightVisible(GUNSIGHTREASON_DAMAGE, FALSE); - hudmsgsSetOff(4); - bondviewSetUpperTextDisplayFlag(PLAYERFLAG_NOTIMER); - countdownTimerSetVisible(8, 0); - - g_CurrentPlayer->damagetype = (s32)(currentPlayerGetHealth() * 8.0f); - - if (g_CurrentPlayer->damagetype >= 8) - { - g_CurrentPlayer->damagetype = 7; - } - -// Ensure we don't read out of bounds of the g_DamageTypes array. -#if defined(VERSION_EU) || defined(VERSION_JP) - if (g_CurrentPlayer->damagetype < 0) - { - g_CurrentPlayer->damagetype = 0; - } -#endif - } - -#ifdef VERSION_US - if ( - (g_DamageTypes[g_CurrentPlayer->damagetype].field_0x8 >= g_CurrentPlayer->damageshowtime) - || (g_DamageTypes[g_CurrentPlayer->damagetype].flashEndFrame >= g_CurrentPlayer->damageshowtime)) - { - if (!g_CurrentPlayer->bonddead) - { -#else - if (!g_CurrentPlayer->bonddead - && ( - (g_DamageTypes[g_CurrentPlayer->damagetype].field_0x8 >= g_CurrentPlayer->damageshowtime) - || (g_DamageTypes[g_CurrentPlayer->damagetype].flashEndFrame >= g_CurrentPlayer->damageshowtime))) - { -#endif - if (g_CurrentPlayer->damageshowtime >= g_DamageTypes[g_CurrentPlayer->damagetype].flashStartFrame - && g_CurrentPlayer->damageshowtime <= g_DamageTypes[g_CurrentPlayer->damagetype].flashEndFrame) - { - f32 frac; -#ifdef VERSION_US - s32 flashdoneframes; - s32 totalframes; - s32 flashfullframe; -#else - f32 flashdoneframes; - f32 totalframes; - f32 flashfullframe; -#endif - - flashdoneframes = g_CurrentPlayer->damageshowtime - g_DamageTypes[g_CurrentPlayer->damagetype].flashStartFrame; - flashfullframe = g_DamageTypes[g_CurrentPlayer->damagetype].flashFullFrame; - totalframes = g_DamageTypes[g_CurrentPlayer->damagetype].flashEndFrame - g_DamageTypes[g_CurrentPlayer->damagetype].flashStartFrame; - - if (flashdoneframes < flashfullframe) - { - frac = (g_DamageTypes[g_CurrentPlayer->damagetype].maxAlpha * (f32)flashdoneframes) / (f32)flashfullframe; - } - else - { - frac = (g_DamageTypes[g_CurrentPlayer->damagetype].maxAlpha * (f32)(totalframes - flashdoneframes)) / (f32)(totalframes - flashfullframe); - } - - currentPlayerSetFadeColour( - g_DamageTypes[g_CurrentPlayer->damagetype].red, - g_DamageTypes[g_CurrentPlayer->damagetype].green, - g_DamageTypes[g_CurrentPlayer->damagetype].blue, - frac); - } -#ifdef VERSION_US - } -#endif - - if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) - { -#if defined(VERSION_US) - g_CurrentPlayer->damageshowtime += g_ClockTimer; -#else - g_CurrentPlayer->damageshowtime += g_GlobalTimerDelta; -#endif - } - else - { -#if defined(VERSION_US) - g_CurrentPlayer->damageshowtime += speedgraphframes; -#else - g_CurrentPlayer->damageshowtime += jpD_800484D0; -#endif - } - } - else /* (damage showtime is over) */ - { - g_CurrentPlayer->damageshowtime = -1; - currentPlayerSetFadeColour(0xFF, 0xFF, 0xFF, 0); - - if (!g_CurrentPlayer->bonddead) - { - gunSetGunAmmoVisible(GUNAMMOREASON_DAMAGE, TRUE); - gunSetSightVisible(GUNSIGHTREASON_DAMAGE, TRUE); - hudmsgsSetOn(4); - bondviewClearUpperTextDisplayFlag(PLAYERFLAG_NOTIMER); - countdownTimerSetVisible(8, 1); - } - } - } - - // update health showtime - if (g_CurrentPlayer->healthshowtime >= 0) - { - // 0: This is the first frame of damage - if (g_CurrentPlayer->healthshowtime == 0) - { - g_CurrentPlayer->healthdamagetype = (s32)(currentPlayerGetHealth() * 8.0f); - - if (g_CurrentPlayer->healthdamagetype >= 8) - { - g_CurrentPlayer->healthdamagetype = 7; - } - -#if defined(VERSION_EU) || defined(VERSION_JP) - if (g_CurrentPlayer->healthdamagetype < 0) - { - g_CurrentPlayer->healthdamagetype = 0; - } -#endif - } - - if (!g_CurrentPlayer->bonddead) - { - if ((g_CurrentPlayer->healthshowtime >= g_HealthDisplayDurations[g_CurrentPlayer->healthdamagetype].validStartFrame) - && (g_HealthDisplayDurations[g_CurrentPlayer->healthdamagetype].updateToRealHealthFrame >= g_CurrentPlayer->healthshowtime)) - { - g_CurrentPlayer->apparenthealth = g_CurrentPlayer->oldhealth; - g_CurrentPlayer->apparentarmour = g_CurrentPlayer->oldarmour; -#if defined(VERSION_US) - g_CurrentPlayer->healthshowtime += g_ClockTimer; -#else - g_CurrentPlayer->healthshowtime += g_GlobalTimerDelta; -#endif - } - else if ((g_CurrentPlayer->healthshowtime >= g_HealthDisplayDurations[g_CurrentPlayer->healthdamagetype].validStartFrame) - && (g_HealthDisplayDurations[g_CurrentPlayer->healthdamagetype].hideHealthFrame >= g_CurrentPlayer->healthshowtime)) - { - g_CurrentPlayer->apparenthealth = g_CurrentPlayer->bondhealth; - g_CurrentPlayer->apparentarmour = g_CurrentPlayer->bondarmour; -#if defined(VERSION_US) - g_CurrentPlayer->healthshowtime += g_ClockTimer; -#else - g_CurrentPlayer->healthshowtime += g_GlobalTimerDelta; -#endif - } - else - { - g_CurrentPlayer->healthshowtime = -1; - } - } - else - { - g_CurrentPlayer->healthshowtime = -1; - } - } -} - -/** - * If global flag g_SurroundBondWithExplosionsFlag is set then explosions - * will be randomly created around Bond. - * Perfect Dark method playerTickExplode. - * NTSC address 7F084360. - * EU address 7F0844A4. -*/ -void bondviewPlayerTickExplode(void) -{ - g_PlayerTickExplodeCreatePosition++; - - if (g_SurroundBondWithExplosionsFlag - && (g_PlayerInvincible == FALSE) - && g_SurroundBondWithExplosionsTicks < g_GlobalTimer) - { - struct coord3d pos; - - pos.f[0] = g_CurrentPlayer->prop->pos.f[0]; - pos.f[1] = g_CurrentPlayer->prop->pos.f[1]; - pos.f[2] = g_CurrentPlayer->prop->pos.f[2]; - - switch (g_PlayerTickExplodeCreatePosition % 4) - { - case 0: pos.x += 250.0f + 150.0f * RANDOMGETNEXT_F32(); break; - case 1: pos.x -= 250.0f + 150.0f * RANDOMGETNEXT_F32(); break; - case 2: pos.z += 250.0f + 150.0f * RANDOMGETNEXT_F32(); break; - case 3: pos.z -= 250.0f + 150.0f * RANDOMGETNEXT_F32(); break; - } - - pos.y += 200.0f * RANDOMGETNEXT_F32() - 100.0f; - - explosionCreate(0, &pos, g_CurrentPlayer->prop->stan, EXPLOSION_DEF_PLAYER, 0, 0, g_CurrentPlayer->prop->rooms, 0); - - g_SurroundBondWithExplosionsTicks = (randomGetNext() % (u32)PLAYER_TICKEXPLODE_FACTOR) + g_GlobalTimer + PLAYER_TICKEXPLODE_FACTOR; - } -} - - -/** - * NTSC Address 0x7F084648. - * NTSC-J address 0x7F084CF8. - * - * Met by Saint Jon The Archangel in the writhing pits of hell, the beast was - * pinned, prone on the floor. He had taken many forms throughout the ages. - * From the creator of man to the far reaches of the universe, his perpetual - * reincarnations reigned throughout space and time... until now. His form was - * weak, the opposition strong. The time for atonement had finally come. - * - * Battered, torn, exposed, the beast slacked his gaping maw. - * - * "I'm sorry, Jon" he whispered. - * - * The archangel raised his flaming blade. - * - * "You are forgiven, Garfield" - * - * And the beast exhaled his last. - * - * 10 months of off and on work to match. - * Thanks Trevor. - * - Bethany Burns - */ -void MoveBond(s8 stick_x, s8 stick_y, u16 buttons, u16 oldbuttons) -{ - struct coord3d move_offset; - f32 ftemp; - f32 stack_padding_9; - f32 sp3A0; - s32 i; - f32 maxspeed; - s32 use_stanHeight; - f32 sp390; - - move_offset = g_DefaultMoveBondOffset; - - use_stanHeight = 0; - maxspeed = 0.0f; - sp390 = 0.0f; - - #if defined(VERSION_US) || defined(VERSION_JP) - if (stick_x >= 100 || stick_x <= -100) return_null(); // __LINE__ __FILE__ (#6414 bondview.c) "joystick x has value %d!\n" - if (stick_y >= 100 || stick_y <= -100) return_null(); // __LINE__ __FILE__ (#6415 bondview.c) "joystick y has value %d!\n" - #endif - - if (g_bondviewForceDisarm > 0) - { - g_bondviewForceDisarm++; - if (g_bondviewForceDisarm >= 4) - { - g_bondviewForceDisarm = 0; - g_CurrentPlayer->lock_hand_model[GUNLEFT] = 0; - g_CurrentPlayer->lock_hand_model[GUNRIGHT] = 0; - currentPlayerUnEquipWeaponWrapper(GUNLEFT, getCurrentPlayerWeaponId(GUNLEFT)); - currentPlayerUnEquipWeaponWrapper(GUNRIGHT, getCurrentPlayerWeaponId(GUNRIGHT)); - } - } - - currentPlayerSetCameraMode(0); - bondviewPlayerTickDamageAndHealth(); - bondviewPlayerTickExplode(); - bondviewProcessInput(stick_x, stick_y, buttons, oldbuttons); - - if (lvlGetControlsLockedFlag()) - { - bondviewPlayerStopAudioForPause(); - } - - if (g_CurrentPlayer->watch_animation_state != WATCH_ANIMATION_0x0) - { - bondviewWatchAnimationTick(); - } - - /* - Apply bondshotspeed vector to speedforwards scalar and speedsideways scalar. - Crouching applies a 50% base speed reduction before applying boost. - Bond can't be boosted while in the tank. - */ - if (g_PlayerIsInTank == 0) - { - // This `if` block is Perfect Dark bwalkApplyCrouchSpeed. - if (currentPlayerGetCrouchPos() == CROUCH_SQUAT) - { - g_CurrentPlayer->speedforwards *= 0.5f; - g_CurrentPlayer->speedsideways *= 0.5f; - } - - if ((g_CurrentPlayer->bondshotspeed.f[0] != 0.0f) || (g_CurrentPlayer->bondshotspeed.f[2] != 0.0f)) - { - // boost forwards - f32 shotboost_forward; // sp38C - // boost sideways - f32 shotboost_sideways; // sp388 - f32 shotboost_norm; // sp384 - - // Assigning these two variables is done in Perfect Dark bmove0f0cba88. - shotboost_forward = - (-g_CurrentPlayer->bondshotspeed.f[0] * g_CurrentPlayer->vv_sintheta) - + (g_CurrentPlayer->bondshotspeed.f[2] * g_CurrentPlayer->vv_costheta); - shotboost_sideways = - (-g_CurrentPlayer->bondshotspeed.f[0] * g_CurrentPlayer->vv_costheta) - - (g_CurrentPlayer->bondshotspeed.f[2] * g_CurrentPlayer->vv_sintheta); - - shotboost_norm = sqrtf( - (g_CurrentPlayer->bondshotspeed.f[0] * g_CurrentPlayer->bondshotspeed.f[0]) + - (g_CurrentPlayer->bondshotspeed.f[2] * g_CurrentPlayer->bondshotspeed.f[2])); - - g_CurrentPlayer->speedforwards += shotboost_forward; - g_CurrentPlayer->speedsideways += shotboost_sideways; - - // 3: x,y,z components of bondshotspeed - for (i=0; i<3; i++) - { - if (g_CurrentPlayer->bondshotspeed.f[i] != 0.0f) - { - if (g_CurrentPlayer->bondshotspeed.f[i] > 0.0f) - { - g_CurrentPlayer->bondshotspeed.f[i] -= - ((0.06666667f * g_GlobalTimerDelta * g_CurrentPlayer->bondshotspeed.f[i]) / shotboost_norm); - - if (g_CurrentPlayer->bondshotspeed.f[i] < 0.0f) - { - g_CurrentPlayer->bondshotspeed.f[i] = 0.0f; - } - } - else if (g_CurrentPlayer->bondshotspeed.f[i] < 0.0f) - { - g_CurrentPlayer->bondshotspeed.f[i] -= - ((0.06666667f * g_GlobalTimerDelta * g_CurrentPlayer->bondshotspeed.f[i]) / shotboost_norm); - - if (g_CurrentPlayer->bondshotspeed.f[i] > 0.0f) - { - g_CurrentPlayer->bondshotspeed.f[i] = 0.0f; - } - } - } - } - } - } - - /** - * This section updates the tank turret horizontal position (turning left and right), - * as well as turning the tank left and right. - */ - if (g_PlayerIsInTank == 1) - { - f32 ftemp2; - struct coord3d check_collision_p1; - struct coord3d check_collision_p2; - f32 stack_padding_1; - s32 i_1; - f32 curTankAngleRad; - f32 tankChangeInAngle; - f32 sp354; - struct coord3d tank_collision_pt1; - struct coord3d tank_collision_pt2; - f32 tank_collision_dx; - f32 tank_collision_dz; - - tankChangeInAngle = DegToRad1Fact(g_CurrentPlayer->speedtheta * g_GlobalTimerDelta) * 3.5f; - curTankAngleRad = g_TankOrientationAngle + tankChangeInAngle; - - if (curTankAngleRad >= M_TAU_F) - { - curTankAngleRad -= M_TAU_F; - } - - if (curTankAngleRad < 0.0f) - { - curTankAngleRad += M_TAU_F; - } - - if (bondviewTankCollisionStatus( - &g_CurrentPlayer->field_488.collision_position, - g_CurrentPlayer->field_488.current_tile_ptr, - curTankAngleRad, - &check_collision_p1, - &check_collision_p2)) - { - g_TankOrientationAngle = curTankAngleRad; - } - else - { - f32 sp1E4; //x - s32 stack_padding_1; //x - f32 sp1FC; //x - f32 sp324; - f32 sp320; - f32 sp31C; - f32 sp20C; //x - f32 tank_collision_norm; //x - f32 sp210; //x - f32 sp30C; - f32 sp308; - f32 sp304; - - sp31C = -1; //sp31C: scope within this block, used throughout - sp304 = -1; //sp304: scope within this block, used throughout - - getCollisionEdge_maybe(&tank_collision_pt1, &tank_collision_pt2); - - tank_collision_dx = (tank_collision_pt2.f[0] - tank_collision_pt1.f[0]); - tank_collision_dz = (tank_collision_pt2.f[2] - tank_collision_pt1.f[2]); - - tank_collision_norm = 1.0f / sqrtf((tank_collision_dx * tank_collision_dx) + (tank_collision_dz * tank_collision_dz)); - - // sp320: scoped within this block, used throughout - // sp324: scoped within this block, used throughout - tank_collision_dx *= tank_collision_norm; - tank_collision_dz *= tank_collision_norm; - sp324 = tank_collision_dz; - sp320 = -tank_collision_dx; - - // sp210: short lived variable - sp210 = - ((g_CurrentPlayer->field_488.collision_position.f[0] - check_collision_p2.f[0]) * sp324) + - ((g_CurrentPlayer->field_488.collision_position.f[2] - check_collision_p2.f[2]) * sp320); - - if (sp210 < 0.0f) - { - sp210 = -sp210; - sp324 = -sp324; - sp320 = -sp320; - } - - // sp20C: very short lived variable - sp20C = - ((g_CurrentPlayer->field_488.collision_position.f[0] - tank_collision_pt1.f[0]) * sp324) + - ((g_CurrentPlayer->field_488.collision_position.f[2] - tank_collision_pt1.f[2]) * sp320); - - if (sp20C < sp210) - { - sp31C = sp210 - sp20C; - } - - tank_collision_dx = check_collision_p2.f[0] - check_collision_p1.f[0]; - tank_collision_dz = check_collision_p2.f[2] - check_collision_p1.f[2]; - - tank_collision_norm = 1.0f / sqrtf((tank_collision_dx * tank_collision_dx) + (tank_collision_dz * tank_collision_dz)); - - // sp308: scoped within this block, used throughout - // sp30C: scoped within this block, used throughout - tank_collision_dx *= tank_collision_norm; - tank_collision_dz *= tank_collision_norm; - sp30C = tank_collision_dz; - sp308 = -tank_collision_dx; - - // sp1F8 -> sp210: short lived variable - sp210 = - ((g_CurrentPlayer->field_488.collision_position.f[0] - check_collision_p2.f[0]) * sp30C) + - ((g_CurrentPlayer->field_488.collision_position.f[2] - check_collision_p2.f[2]) * sp308); - - if (sp210 < 0.0f) - { - sp210 = -sp210; - sp30C = -sp30C; - sp308 = -sp308; - } - - // sp1FC: very short lived variable - // sp1E4: very short lived variable - sp1FC = - ((g_CurrentPlayer->field_488.collision_position.f[0] - tank_collision_pt1.f[0]) * sp30C) + - ((g_CurrentPlayer->field_488.collision_position.f[2] - tank_collision_pt1.f[2]) * sp308); - sp1E4 = - ((g_CurrentPlayer->field_488.collision_position.f[0] - tank_collision_pt2.f[0]) * sp30C) + - ((g_CurrentPlayer->field_488.collision_position.f[2] - tank_collision_pt2.f[2]) * sp308); - - if (sp1E4 < sp1FC) - { - sp1FC = sp1E4; - } - - if (sp1FC < sp210) - { - sp304 = sp210 - sp1FC; - } - - if ((sp304 >= 0.0f) && ((sp304 < sp31C) || (sp31C < 0.0f))) - { - sp324 = sp30C; - sp320 = sp308; - sp31C = sp304; - } - - if (sp31C >= 0.0f) - { - move_offset.f[0] = sp31C * sp324 * 1.01f; - move_offset.f[2] = sp31C * sp320 * 1.01f; - - bondviewCalcUpdatePlayerCollision(&move_offset, 1); - - move_offset.f[0] = 0.0f; - move_offset.f[2] = 0.0f; - - if (bondviewTankCollisionStatus( - &g_CurrentPlayer->field_488.collision_position, - g_CurrentPlayer->field_488.current_tile_ptr, - curTankAngleRad, - &check_collision_p1, - &check_collision_p2)) - { - g_TankOrientationAngle = curTankAngleRad; - } - else - { - tankChangeInAngle = 0.0f; - } - } - else - { - tankChangeInAngle = 0.0f; - } - } - - sp354 = g_TankTurretOrientationAngleRad; - g_TankTurretAngle += g_TankTurretTurn; - if (g_TankTurretAngle >= M_TAU_F) - { - g_TankTurretAngle -= M_TAU_F; - } - - if (g_TankTurretAngle < 0.0f) - { - g_TankTurretAngle += M_TAU_F; - } - - ftemp = (DegToRad1Fact(g_CurrentPlayer->speedtheta * 3.5f) * 4.0f) + g_TankTurretAngle; - - if (ftemp < 0.0f) - { - ftemp += M_TAU_F; - } - - if (ftemp >= M_TAU_F) - { - ftemp -= M_TAU_F; - } - - if ((ftemp - g_TankTurretOrientationAngleRad) >= M_PI_F) - { - ftemp -= M_TAU_F; - } - else if ((ftemp - g_TankTurretOrientationAngleRad) < -M_PI_F) - { - ftemp += M_TAU_F; - } - - for (i_1=0; i_1= M_TAU_F) - { - g_TankTurretOrientationAngleRad -= M_TAU_F; - g_TankTurretOrientationAngleDeg = g_TankTurretOrientationAngleRad / (1.0f - TANKUPDATEROTATION_SCALE); - } - - if (g_TankTurretOrientationAngleRad < 0.0f) - { - g_TankTurretOrientationAngleRad += M_TAU_F; - g_TankTurretOrientationAngleDeg = g_TankTurretOrientationAngleRad / (1.0f - TANKUPDATEROTATION_SCALE); - } - - if (bondviewCallTankCollisionStatus( - &g_CurrentPlayer->field_488.collision_position, - g_CurrentPlayer->field_488.current_tile_ptr, - g_TankOrientationAngle) == 0) - { - g_TankTurretOrientationAngleRad = sp354; - g_TankTurretOrientationAngleDeg = g_TankTurretOrientationAngleRad / (1.0f - TANKUPDATEROTATION_SCALE); - g_TankTurretAngle = sp354; - } - - if (g_PlayerTankProp != NULL) - { - // sp 0x300 - struct TankRecord *temp_tank; - struct coord3d tank_move_offset; - Mtxf sp2B4; - f32 stack_padding_4; - - temp_tank = (struct TankRecord *)g_PlayerTankProp->obj; - - tank_move_offset.f[1] = 0.0f; - tank_move_offset.f[0] = g_TankModelPositionOffset.f[0]; - tank_move_offset.f[2] = g_TankModelPositionOffset.f[2]; - - matrix_4x4_set_rotation_around_y(tankChangeInAngle, &sp2B4); - mtx4RotateVecInPlace(&sp2B4, &tank_move_offset); - bondviewTankModelRotationRelated(); - - if (0) { } - - tank_move_offset.f[1] = 0.0f; - tank_move_offset.f[0] = g_TankModelPositionOffset.f[0] - tank_move_offset.f[0]; - tank_move_offset.f[2] = g_TankModelPositionOffset.f[2] - tank_move_offset.f[2]; - - matrix_4x4_set_rotation_around_y(M_TAU_F - g_TankOrientationAngle, &sp2B4); - matrix_scalar_multiply(temp_tank->model->scale, &sp2B4); - mtx4RotateVecInPlace(&sp2B4, &tank_move_offset); - bondviewCalcUpdatePlayerCollision(&tank_move_offset, 1); - } - - if (g_ClockTimer > 0) { - for (i=0; ivv_theta = ( - g_TankOrientationAngle + - g_TankTurretOrientationAngleRad + - ((DegToRad1Fact(g_CurrentPlayer->speedtheta * 3.5f)) * (4.0f)) + - (ftemp * 4.0f) - ) * 360.0f / M_TAU_F; - - while (g_CurrentPlayer->vv_theta < 0.0f) - { - g_CurrentPlayer->vv_theta += 360.0f; - } - while (g_CurrentPlayer->vv_theta >= 360.0f) - { - g_CurrentPlayer->vv_theta -= 360.0f; - } - } - else - { - stack_padding_9 = g_CurrentPlayer->vv_theta + (g_CurrentPlayer->speedtheta * g_GlobalTimerDelta * 3.5f); - - while (stack_padding_9 < 0.0f) - { - stack_padding_9 += 360.0f; - } - while (stack_padding_9 >= 360.0f) - { - stack_padding_9 -= 360.0f; - } - - g_CurrentPlayer->vv_theta = stack_padding_9; - } - - bondviewApplyVertaTheta(); - - // Handle crouching, and animation between standing and crouching. - // Add basic block to declare local variables at the correct stack position. - { - f32 sp2AC; - f32 stack_padding_15; - - sp2AC = 0.0f; - if (currentPlayerGetCrouchPos() == CROUCH_SQUAT) - { - sp2AC = FULL_CROUCH_OFFSET; - } - else if (currentPlayerGetCrouchPos() == CROUCH_HALF) - { - sp2AC = -60.0f; - } - else - { - // removed? - currentPlayerGetCrouchPos(); - } - - if (sp2AC != g_CurrentPlayer->ducking_height_offset) - { - chrobjApplySpeed( - &g_CurrentPlayer->ducking_height_offset, - sp2AC, - &g_CurrentPlayer->field_A4, - CHR_OBJ_ACCEL_SPEED_FACTOR, - CHR_OBJ_ACCEL_SPEED_FACTOR, - CHR_OBJ_MAXSPEED); - } - - if (sp2AC == g_CurrentPlayer->ducking_height_offset) - { - g_CurrentPlayer->field_A4 = 0.0f; - } - } - - /** - * Update forwards/backwards movement. - */ - if (g_PlayerIsInTank == 1) - { - /** - * This section handles the forward/backwards movement of the tank. - */ - - Mtxf sp268; - struct coord3d sp25C; - f32 sp258; - f32 sp254; - s32 stack_padding_14; - s32 i_3; - f32 ftemp_5; - f32 tank_engine_utilization_percent; - struct TankRecord *tank_obj; - - /** - * Check to see if Bond is just now entering the tank. - * If so, initialize the tank prop. - * This also handles spinning Bond around (if required) to face the same direction as the turret. - */ - if (g_EnterTankAudioState == TANK_RUN_STATE_NOT_RUNNING) - { - if (g_PlayerTankProp != NULL) - { - tank_obj = g_PlayerTankProp->obj; - matrix_4x4_set_rotation_around_y(M_TAU_F - g_TankOrientationAngle, &sp268); - matrix_scalar_multiply(tank_obj->model->scale, &sp268); - - sp25C.f[0] = g_TankModelPositionOffset.f[0]; - sp25C.f[1] = g_TankModelPositionOffset.f[1]; - sp25C.f[2] = g_TankModelPositionOffset.f[2]; - mtx4RotateVecInPlace(&sp268, (f32*)&sp25C); - - sp25C.f[0] += tank_obj->runtime_pos.f[0]; - sp25C.f[1] += tank_obj->runtime_pos.f[1]; - sp25C.f[2] += tank_obj->runtime_pos.f[2]; - - sp258 = ((g_TankOrientationAngle + g_TankTurretOrientationAngleRad) * 360.0f) / M_TAU_F; - sp254 = g_CurrentPlayer->vv_verta; - if (sp254 < -20.0f) - { - sp254 = -20.0f; - } - - g_TankEnteringSitHeight += g_GlobalTimerDelta / 45.0f; - if (g_TankEnteringSitHeight >= 1.0f) - { - g_TankEnteringSitHeight = 1.0f; - } - - g_TankEnteringSitHeightRemain = (cosf(g_TankEnteringSitHeight * M_TAU_F * 0.5f) + 1.0f) * 0.5f; - - g_CurrentPlayer->vv_verta = - (g_TankEnteringSitHeightRemain * g_TankEnterBondVertAngleDeg) - + ((1.0f - g_TankEnteringSitHeightRemain) * sp254); - - ftemp_5 = sp258 - g_TankEnterBondHorizAngleDeg; - if (ftemp_5 > 180.0f) - { - sp258 -= 360.0f; - } - if (ftemp_5 < -180.0f) - { - sp258 += 360.0f; - } - - g_CurrentPlayer->vv_theta = - (g_TankEnteringSitHeightRemain * g_TankEnterBondHorizAngleDeg) - + ((1.0f - g_TankEnteringSitHeightRemain) * sp258); - - if (g_CurrentPlayer->vv_theta >= 360.0f) - { - g_CurrentPlayer->vv_theta -= 360.0f; - } - - if (g_CurrentPlayer->vv_theta < 0.0f) - { - g_CurrentPlayer->vv_theta += 360.0f; - } - - move_offset.f[0] = ( - (g_TankEnteringSitHeightRemain * g_EnterTankCoord.f[0]) + - ((1.0f - g_TankEnteringSitHeightRemain) * sp25C.f[0]) - ) - - g_CurrentPlayer->field_488.collision_position.f[0]; - - move_offset.f[1] = 0.0f; - - move_offset.f[2] = ( - (g_TankEnteringSitHeightRemain * g_EnterTankCoord.f[2]) + - ((1.0f - g_TankEnteringSitHeightRemain) * sp25C.f[2]) - ) - - g_CurrentPlayer->field_488.collision_position.f[2]; - } - - if (!(g_TankEnteringSitHeight >= 1.0f)) - { - } - else - { - g_EnterTankAudioState = TANK_RUN_STATE_STARTING; - } - } - /** - * Else, Bond has already entered the tank. - */ - else - { - /** - * There's an initial "starting" step. - */ - if (g_EnterTankAudioState == TANK_RUN_STATE_STARTING) - { - g_EnterTankAudioState = TANK_RUN_STATE_RUNNING; - if ((g_TankSfxState[0] == NULL) && (lvlGetControlsLockedFlag() == 0)) - { - sndPlaySfx(g_musicSfxBufferPtr, TRUCK_START_SFX, &g_TankSfxState[0]); - } - - sndCreatePostEvent(g_TankSfxState[0], 8, 0x61A8); - g_TankEngineSfxVolume = 0x61A8; - } - /** - * Else Bond has fully entered the tank, and the engine is running. - * Update turret vertical angle. - * Update engine sound effect volume based on current tank speed. - */ - else - { - f32 tank_scaled_speedforwards; - f32 tank_scaled_speedtheta; - f32 tank_vertical_angle; - - tank_scaled_speedforwards = g_CurrentPlayer->speedforwards / TANK_MAX_SPEED; - tank_scaled_speedtheta = g_CurrentPlayer->speedtheta / 0.3f; - - if (tank_scaled_speedforwards < 0.0f) - { - tank_scaled_speedforwards = -tank_scaled_speedforwards; - } - if (tank_scaled_speedtheta < 0.0f) - { - tank_scaled_speedtheta = -tank_scaled_speedtheta; - } - - tank_engine_utilization_percent = tank_scaled_speedforwards; - if (tank_scaled_speedforwards < tank_scaled_speedtheta) - { - tank_engine_utilization_percent = tank_scaled_speedtheta; - } - - if (tank_engine_utilization_percent > 0.0f) - { - if (tank_engine_utilization_percent > 1.0f) - { - tank_engine_utilization_percent = 1.0f; - } - - if (g_TankSfxState[1] == NULL) - { - if (lvlGetControlsLockedFlag() == 0) - { - sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, TANK_SFX, &g_TankSfxState[1]); - } - } - - if (g_TankSfxState[1] != NULL) - { - s32 phi_a2; - - phi_a2 = 0x7FFF; - if (tank_engine_utilization_percent < 0.15f) - { - phi_a2 = (s32) ((tank_engine_utilization_percent * 20000.0f) / 0.15f); - } - else if (tank_engine_utilization_percent < 0.9f) - { - phi_a2 = (s32) ((((tank_engine_utilization_percent - 0.15f) * 12767.0f) / 0.75f) + 20000.0f); - } - - sndCreatePostEvent(g_TankSfxState[1], 8, phi_a2); - } - } - else - { - if (g_TankSfxState[1] != NULL) - { - if (sndGetPlayingState(g_TankSfxState[1]) != 0) - { - sndDeactivate(g_TankSfxState[1]); - } - } - } - - if (g_TankSfxState[0] == NULL) - { - if (lvlGetControlsLockedFlag() == 0) - { - sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, TRUCK_RUN_SFX, &g_TankSfxState[0]); - } - } - - if (g_TankSfxState[0] != NULL) - { - g_TankEngineSfxVolume = 0x7FFF; - if (tank_engine_utilization_percent < 0.9f) - { - g_TankEngineSfxVolume = (s32) (((tank_engine_utilization_percent * 7767.0f) / 0.9f) + 25000.0f); - } - - sndCreatePostEvent(g_TankSfxState[0], 8, g_TankEngineSfxVolume); - } - - if (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_TANKSHELLS) - { - tank_vertical_angle = g_CurrentPlayer->field_2A08; - tank_vertical_angle += 0.17453294f; /* should be DegToRad1Fact(10), but that yields 0.17453293f */ - } - else - { - tank_vertical_angle = g_TankTurretVerticalAngle; - } - - if (tank_vertical_angle > DegToRad1Fact(25)) - { - tank_vertical_angle = DegToRad1Fact(25); - } - - /* -0.087266468f should be DegToRad1Fact(-5), but that yields -0.0872664600611 */ - if (tank_vertical_angle < -0.087266468f) - { - tank_vertical_angle = -0.087266468f; - } - - for (i_3=0; i_3bondbreathing -= (0.750f * g_GlobalTimerDelta) / 2700.0f; - - if (g_CurrentPlayer->bondbreathing < 0.0f) - { - g_CurrentPlayer->bondbreathing = 0.0f; - } - - bondviewMoveAnimationTick(0.0f, 0.0f, 0.0f); - - move_offset.f[0] += g_CurrentPlayer->speedforwards * sinf(M_TAU_F - g_TankOrientationAngle) * g_GlobalTimerDelta; - move_offset.f[2] += g_CurrentPlayer->speedforwards * cosf(M_TAU_F - g_TankOrientationAngle) * g_GlobalTimerDelta; - - bondviewCalcUpdatePlayerCollision(&move_offset, 1); - - if ((g_EnterTankAudioState == TANK_RUN_STATE_RUNNING) && (g_ClockTimer > 0)) - { - f32 calc_x; - f32 calc_z; - f32 calc_speedforwards; - -#if defined(VERSION_EU) - // Divide by zero check. - if (g_GlobalTimerDelta == 0) - { - #if DEBUG - // unknown what went here. - return_null(); - #endif - } -#endif - - calc_x = (g_CurrentPlayer->field_488.collision_position.f[0] - g_CurrentPlayer->bondprevpos.f[0]) / g_GlobalTimerDelta; - calc_z = (g_CurrentPlayer->field_488.collision_position.f[2] - g_CurrentPlayer->bondprevpos.f[2]) / g_GlobalTimerDelta; - calc_speedforwards = sqrtf((calc_x * calc_x) + (calc_z * calc_z)); - - if (g_CurrentPlayer->speedforwards < 0.0f) - { - calc_speedforwards = -calc_speedforwards; - } - - g_CurrentPlayer->speedforwards = calc_speedforwards; - } - } - else // not in tank: g_PlayerIsInTank != 1 - { - f32 sp220; - f32 sp21C; - f32 dist; - f32 ftemp_col_x; - f32 ftemp_col_z; - f32 stack_padding_12; - f32 start_collision_pos_x; - f32 start_collision_pos_z; - struct StandTile *sp200; - f32 stack_padding_2; - s32 stack_padding_11; - f32 speedforwards; - f32 ftemp_11; - f32 speedsideways; - f32 speedtheta; - f32 stack_padding_25; - f32 stack_padding_5; - s32 stack_padding_6; - f32 sp164; - f32 sp2B0; - f32 stack_padding_3; - f32 stack_padding_111; - f32 ftemp_26; - f32 nd; // canonical name - f32 ftemp_7; - f32 sp240; - struct move_bond_temp_struct curLocus; - struct move_bond_collision bondCollision; - f32 shorten; // canonical name - f32 headpos_x; - f32 headpos_z; - struct StandTile *sp174; - struct StandTile *sp170; - f32 sp16C; - f32 sp168; - - if ((g_TankSfxState[0] != NULL) && (sndGetPlayingState(g_TankSfxState[0]) != 0)) - { - #if defined(VERSION_US) - g_TankEngineSfxVolume -= (g_ClockTimer * 1000); - #endif - - #if defined(VERSION_JP) || defined(VERSION_EU) - g_TankEngineSfxVolume -= (s32)(1000.0f * g_GlobalTimerDelta); - #endif - - if (g_TankEngineSfxVolume > 0) - { - sndCreatePostEvent(g_TankSfxState[0], 8, g_TankEngineSfxVolume); - } - else - { - sndDeactivate(g_TankSfxState[0]); - } - } - - if ((g_TankSfxState[1] != NULL) && (sndGetPlayingState(g_TankSfxState[1]) != 0)) - { - sndDeactivate(g_TankSfxState[1]); - } - - - ftemp_7 = (g_BondMoveAnimationSetup[1].speedMultiplier * 0.5f * g_GlobalTimerDelta); - sp3A0 = g_CurrentPlayer->speedsideways * ftemp_7; - - /* - The following is similar to a block of Perfect Dark bwalk0f0c69b8. - */ - - ftemp_26 = -g_CurrentPlayer->swaytarget * g_CurrentPlayer->field_488.theta_transform.f[2]; - ftemp_11 = g_CurrentPlayer->swaytarget * g_CurrentPlayer->field_488.theta_transform.f[0]; - - sp220 = (ftemp_26) - g_CurrentPlayer->swayoffset0; - sp21C = (ftemp_11) - g_CurrentPlayer->swayoffset2; - - dist = (sp220 * sp220) + (sp21C * sp21C); - - if (dist >= 100.0f) - { - sp220 *= 0.6f * 1.0f; - sp21C *= 0.6f * 1.0f; - } - - speedsideways = g_CurrentPlayer->speedsideways * MAX_SPEED_FACTOR; - speedforwards = g_CurrentPlayer->speedforwards; - speedtheta = g_CurrentPlayer->speedtheta * MAX_SPEED_FACTOR; - - if (speedsideways < 0.0f) - { - speedsideways = -speedsideways; - } - if (speedforwards < 0.0f) - { - speedforwards = -speedforwards; - } - if (speedtheta < 0.0f) - { - speedtheta = -speedtheta; - } - - maxspeed = speedforwards; - -#if defined(VERSION_EU) - if (maxspeed < speedsideways && 1) -#else - if (maxspeed < speedsideways) -#endif - { - maxspeed = speedsideways; - } - if (maxspeed < speedtheta) - { - maxspeed = speedtheta; - } - - if (dist >= 0.1f && maxspeed < MAX_SPEED_FACTOR) - { - maxspeed = MAX_SPEED_FACTOR; - } - - if (maxspeed >= 0.750f) - { - g_CurrentPlayer->bondbreathing += (maxspeed - 0.750f) * g_GlobalTimerDelta / 900.0f ; - } - else - { - g_CurrentPlayer->bondbreathing -= (0.750f - maxspeed) * g_GlobalTimerDelta / 2700.0f; - } - - if (g_CurrentPlayer->bondbreathing < 0.0f) - { - g_CurrentPlayer->bondbreathing = 0.0f; - } - else if (g_CurrentPlayer->bondbreathing > 1.0f) - { - g_CurrentPlayer->bondbreathing = 1.0f; - } - - // perfect dark call: bmove0f0cc654 - bondviewMoveAnimationTick(maxspeed, g_CurrentPlayer->speedforwards, sp3A0); - - headpos_x = g_CurrentPlayer->headpos.f[0]; - headpos_z = g_CurrentPlayer->headpos.f[2]; - - move_offset.f[0] += - ( - (headpos_z * g_CurrentPlayer->field_488.theta_transform.f[0]) - - (headpos_x * g_CurrentPlayer->field_488.theta_transform.f[2]) - ) * g_GlobalTimerDelta; - - move_offset.f[2] += - ( - (headpos_z * g_CurrentPlayer->field_488.theta_transform.f[2]) + - (headpos_x * g_CurrentPlayer->field_488.theta_transform.f[0]) - ) * g_GlobalTimerDelta; - - - move_offset.f[0] += sp220; - move_offset.f[2] += sp21C; - - start_collision_pos_x = g_CurrentPlayer->field_488.collision_position.f[0]; - start_collision_pos_z = g_CurrentPlayer->field_488.collision_position.f[2]; - sp200 = g_CurrentPlayer->field_488.current_tile_ptr; - - if (get_debug_fast_bond_flag()) - { - move_offset.f[0] += - ( - (g_CurrentPlayer->field_488.theta_transform.f[0] * g_CurrentPlayer->speedforwards) - - (g_CurrentPlayer->field_488.theta_transform.f[2] * g_CurrentPlayer->speedsideways) - ) * g_GlobalTimerDelta * 10.0f; - - move_offset.f[2] += - ( - (g_CurrentPlayer->field_488.theta_transform.f[2] * g_CurrentPlayer->speedforwards) + - (g_CurrentPlayer->field_488.theta_transform.f[0] * g_CurrentPlayer->speedsideways) - ) * g_GlobalTimerDelta * 10.0f; - } - - bondviewCalcUpdatePlayerCollision(&move_offset, (g_CurrentPlayer->swaytarget == 0.0f)); - - stanTileDistanceRelated( - &sp200, - start_collision_pos_x, - start_collision_pos_z, - g_CurrentPlayer->field_488.collision_radius * 1.16f, - &curLocus); - - /* almost never true */ - if (stanGetLocusCount(&curLocus) != 0) - { - use_stanHeight = 1; - } - - stanTileDistanceRelated( - &g_CurrentPlayer->field_488.current_tile_ptr, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2], - g_CurrentPlayer->field_488.collision_radius * 1.01f, - &curLocus); - - /* almost never true */ - if (stanGetLocusCount(&curLocus) != 0) - { - use_stanHeight = 1; - } - - stanTileDistanceRelated( - &g_CurrentPlayer->field_488.current_tile_ptr, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2], - g_CurrentPlayer->field_488.collision_radius, - &curLocus); - - /* almost always true */ - if (stanGetLocusCount(&curLocus) == 0) - { - stanTileDistanceRelated( - &sp200, - start_collision_pos_x, - start_collision_pos_z, - g_CurrentPlayer->field_488.collision_radius * 0.990099f, - &curLocus); - } - - /* almost never true */ - if (stanGetLocusCount(&curLocus)) - { - use_stanHeight = 1; - stanGetMoveBondCollisionTiles(&sp174, &sp170, &bondCollision); - - if (g_CurrentPlayer->stanHeight <= bondCollision.sp19C.f[1]) - { - f32 sp2A8; - f32 sp24C; - f32 sp250; - f32 sp310; - f32 sp314; - - sp168 = bondCollision.bondCollision.f[0] - bondCollision.sp190.f[0]; - sp16C = bondCollision.sp190.f[2] - bondCollision.bondCollision.f[2]; - - nd = sqrtf((sp16C * sp16C) + (sp168 * sp168)); - - sp168 = sp168 / nd; - sp16C = sp16C / nd; - - sp164 = - ((start_collision_pos_x - bondCollision.bondCollision.f[0]) * sp16C) + - ((start_collision_pos_z - bondCollision.bondCollision.f[2]) * sp168); - - sp2B0 = - (((start_collision_pos_x + move_offset.f[0]) - bondCollision.bondCollision.f[0]) * sp16C) + - (((start_collision_pos_z + move_offset.f[2]) - bondCollision.bondCollision.f[2]) * sp168); - - if ((sp164 * sp2B0) <= 0.0f) - { - shorten = 0.0f; - } - else - { - if (sp2B0 < 0.0f) - { - sp164 = -sp164; - sp2B0 = -sp2B0; - } - - if (sp164 <= sp2B0) - { - shorten = 0.0f; - } - else if (g_CurrentPlayer->field_488.collision_radius < sp2B0) - { - shorten = 0.0f; - } - else if (sp164 < g_CurrentPlayer->field_488.collision_radius) - { - shorten = 0.0f; - } - else - { - shorten = (sp164 - g_CurrentPlayer->field_488.collision_radius) / (sp164 - sp2B0); - } - } - - sp2A8 = sqrtf((move_offset.f[0] * move_offset.f[0]) + (move_offset.f[2] * move_offset.f[2])); - if (sp2A8 > 0.0f) - { - f32 sp318; - - sp318 = (1.0f - shorten) * sp2A8; - sp390 = sp318 * 0.25f; - - if (bondCollision.sp19C.f[1] <= (g_CurrentPlayer->stanHeight + sp390)) - { - sp390 = (bondCollision.sp19C.f[1] - g_CurrentPlayer->stanHeight); - sp318 -= (sp390 / 0.25f); - shorten += (sp318 / sp2A8); - } - } - - sp314 = bondCollision.sp19C.f[0] - bondCollision.bondCollision.f[0]; - sp310 = bondCollision.sp19C.f[2] - bondCollision.bondCollision.f[2]; - sp250 = bondCollision.sp1A8.f[0] - bondCollision.bondCollision.f[0]; - sp24C = bondCollision.sp1A8.f[2] - bondCollision.bondCollision.f[2]; - - if (((sp250 * sp250) + (sp24C * sp24C)) < ((sp314 * sp314) + (sp310 * sp310))) - { - sp314 = sp250; - sp310 = sp24C; - } - - move_offset.f[0] = (move_offset.f[0] * shorten) + (sp314 * (sp390 / (bondCollision.sp19C.f[1] - bondCollision.bondCollision.f[1]))); - move_offset.f[2] = (move_offset.f[2] * shorten) + (sp310 * (sp390 / (bondCollision.sp19C.f[1] - bondCollision.bondCollision.f[1]))); - - g_CurrentPlayer->field_488.collision_position.f[0] = start_collision_pos_x; - g_CurrentPlayer->field_488.collision_position.f[2] = start_collision_pos_z; - g_CurrentPlayer->field_488.current_tile_ptr = sp200; - - bondviewCalcUpdatePlayerCollision(&move_offset, (g_CurrentPlayer->swaytarget == 0.0f)); - } - } - - ftemp_col_x = g_CurrentPlayer->field_488.collision_position.f[0] - start_collision_pos_x; - ftemp_col_z = g_CurrentPlayer->field_488.collision_position.f[2] - start_collision_pos_z; - sp240 = (move_offset.f[0] * move_offset.f[0]) + (move_offset.f[2] * move_offset.f[2]); - if (sp240 != 0.0f) - { - sp240 = ((ftemp_col_x * ftemp_col_x) + (ftemp_col_z * ftemp_col_z)) / sp240; - } - sp240 = sqrtf(sp240); - g_CurrentPlayer->swayoffset0 += sp240 * sp220; - g_CurrentPlayer->swayoffset2 += sp240 * sp21C; - } - - // add basic block - { - f32 breathing; - f32 sp14C_temp; - f32 weapon_speed_verta; - - sp14C_temp = g_CurrentPlayer->speedtheta; - weapon_speed_verta = - (g_CurrentPlayer->speedverta / 0.7f) + - (g_CurrentPlayer->field_A4 / CHR_OBJ_MAXSPEED); - - /* - Following matches the end of Perfect Dark bwalk0f0c69b8 - */ - breathing = bheadGetBreathingValue(); - - if (weapon_speed_verta > 1.0f) - { - weapon_speed_verta = 1.0f; - } - else if (weapon_speed_verta < -1.0f) - { - weapon_speed_verta = -1.0f; - } - - if (g_CurrentPlayer->headanim == 1) - { - breathing *= 1.2f; - } - - // Perfect Dark call bgun0f09d8dc - gunSetBondWeaponSway(breathing, maxspeed, weapon_speed_verta, sp14C_temp); - - // Perfect Dark call bgunSetAdjustPos - gunSetOffsetRelated(DegToRad1Fact(g_CurrentPlayer->vv_verta360)); - } - - // end perfect dark `void bwalk0f0c69b8(void)` - - /** - * The following section updates the TankRecord fields, and handles prop collision detection - * with the tank. If colliding with character, play the "arrrhghhg" sound effect, or if - * colliding with prop then set tank movement penalty and create an explosion. - */ - if ((g_PlayerTankProp != NULL) && (g_PlayerIsInTank == 1) && (g_EnterTankAudioState == TANK_RUN_STATE_RUNNING)) - { - struct PropRecord *prop; - struct TankRecord *sp140_tank_as_TankRecord; - struct ObjectRecord *sp138_tank_as_ObjectRecord; - f32 ftemp_12; - struct ModelNode_BoundingBoxRecord *sp130; - Mtxf spF0; - struct coord3d spE4; - s32 stack_padding_13; - s32 i_4; - s32 stemp; - void *stack_padding_8; - struct rect4f spB4_tank_collision_bounds; - // roomids - s32 sp94[8]; - s32 stanlineret; - s16 *lookup_index; - - sp140_tank_as_TankRecord = ((struct TankRecord *)g_PlayerTankProp->obj); - sp138_tank_as_ObjectRecord = (struct ObjectRecord*)g_PlayerTankProp->obj; - sp130 = (struct ModelNode_BoundingBoxRecord *)((struct ModelNode *)sp138_tank_as_ObjectRecord->model->obj->Switches)->Child->Data; - - sp140_tank_as_TankRecord->is_firing_tank = (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_TANKSHELLS) - && get_hands_firing_status(GUNRIGHT); - - sp140_tank_as_TankRecord->turret_vertical_angle = g_TankTurretVerticalAngle; - sp140_tank_as_TankRecord->turret_orientation_angle = g_TankTurretOrientationAngleRad; - sp140_tank_as_TankRecord->tank_orientation_angle = g_TankOrientationAngle; - - matrix_4x4_set_rotation_around_y(M_TAU_F - g_TankOrientationAngle, &spF0); - matrix_scalar_multiply(sp138_tank_as_ObjectRecord->model->scale, &spF0); - - spE4.f[0] = -g_TankModelPositionOffset.f[0]; - spE4.f[1] = -g_TankModelPositionOffset.f[1]; - spE4.f[2] = -g_TankModelPositionOffset.f[2]; - - mtx4RotateVecInPlace(&spF0, &spE4); - - spE4.f[0] += g_CurrentPlayer->field_488.collision_position.f[0]; - spE4.f[2] += g_CurrentPlayer->field_488.collision_position.f[2]; - - sp138_tank_as_ObjectRecord->prop->stan = g_CurrentPlayer->field_488.current_tile_ptr; - - stanlineret = walkTilesBetweenPoints_NoCallback( - &sp138_tank_as_ObjectRecord->prop->stan, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2], - spE4.f[0], - spE4.f[2]); - #ifdef DEBUG - assert(stanlineret); // #7362 - #endif - - sp140_tank_as_TankRecord->stan_y = stanGetPositionYValue(sp138_tank_as_ObjectRecord->prop->stan, spE4.f[0], spE4.f[2]); - - for (i_4=0; i_4unkD0 = (sp140_tank_as_TankRecord->unkD0 * TANK_UNKD0_SCALE) + sp140_tank_as_TankRecord->stan_y; - } - - ftemp_12 = (sp140_tank_as_TankRecord->unkD0 * (1.0f - TANK_UNKD0_SCALE)); - spE4.f[1] = ftemp_12 - - (chrpropBBOXGetYmin(sp130) * sp138_tank_as_ObjectRecord->model->scale) - + 4.0f; - - matrix_4x4_copy(&spF0, &sp138_tank_as_ObjectRecord->mtx); - - sp138_tank_as_ObjectRecord->runtime_pos.f[0] = sp138_tank_as_ObjectRecord->prop->pos.f[0] = spE4.f[0]; - sp138_tank_as_ObjectRecord->runtime_pos.f[1] = sp138_tank_as_ObjectRecord->prop->pos.f[1] = spE4.f[1]; - sp138_tank_as_ObjectRecord->runtime_pos.f[2] = sp138_tank_as_ObjectRecord->prop->pos.f[2] = spE4.f[2]; - - setupUpdateObjectRoomPosition(sp138_tank_as_ObjectRecord); - chrobjCollisionRelated(sp138_tank_as_ObjectRecord); - bondviewGetTankCollisionBounds(&spB4_tank_collision_bounds, &g_CurrentPlayer->field_488.collision_position, g_TankOrientationAngle); - chraiGetPropRoomIds(sp138_tank_as_ObjectRecord->prop, &sp94); - - // update num_obj_position_data_entries - roomGetProps(&sp94); - - for (lookup_index=ptr_list_object_lookup_indices; *lookup_index>=0; lookup_index++) - { - prop = &g_Props[*lookup_index]; - if (prop != sp138_tank_as_ObjectRecord->prop) - { - if (prop->type == PROP_TYPE_CHR) - { - s32 sp88_collision_bound_height; - s32 sp84_collision_bound_z; - f32 sp80_collision_radius; - s32 sp7C; - struct coord3d sp70; - struct ChrRecord *sp6C; - f32 stack_padding_28; - - sp7C = 1; - sp6C = prop->chr; - chrpropGetCollisionBounds(prop, &sp80_collision_radius, &sp88_collision_bound_height, &sp84_collision_bound_z); - - if (chrpropTestPointInPolygon(&prop->pos, &spB4_tank_collision_bounds, 4)) - { - sp7C = 0; - - if (sp6C->actiontype == ACT_DIE) - { -#if defined(VERSION_US) - if ((sp6C->chrflags << 7) >= 0) -#endif -#if defined(VERSION_JP) || defined(VERSION_EU) - if ((sp6C->chrflags << 7) >= 0 && lvlGetControlsLockedFlag() == 0) -#endif - { - sp6C->chrflags |= CHRFLAG_01000000; - if ((D_80048380 % 3) < 2) - { - chrobjSndCreatePostEventDefault(sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, CRUSHED_YELL_SFX, NULL), &prop->pos); - } - if ((D_80048380 % 3) > 0) - { - chrobjSndCreatePostEventDefault(sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, TANK_CRUSH_MAN_SFX, NULL), &prop->pos); - } - } - } - } - - if (sp7C && (chrobjTestPointPolygonCollision(&prop->pos, sp80_collision_radius, &spB4_tank_collision_bounds, 4))) - { - sp7C = 0; - } - - if (sp7C == 0) - { - sp70.f[0] = sp138_tank_as_ObjectRecord->runtime_pos.f[0]; - sp70.f[1] = prop->pos.f[1]; - sp70.f[2] = sp138_tank_as_ObjectRecord->runtime_pos.f[2]; - - chrlvExplosionDamage(prop->chr, &sp70, 3.0f, 1); - } - } - else if (prop->type == PROP_TYPE_OBJ) - { - struct rect4f *polygon; - s32 edges; - - chraiGetCollisionBoundsWithoutY(prop, &polygon, &edges); - if ((edges > 0) && chrobjTestPolygonsTouchingOrOverlap2D(polygon, edges, &spB4_tank_collision_bounds, 4)) - { - // Explode destroyable props when the tank touches them - maybe_detonate_object_and_its_children(prop, 10000.0f, &prop->obj->runtime_pos, 0x20, get_cur_playernum()); - g_TankDamagePenaltyTicks = TANK_DAMAGE_PENTALTY_TICKS; - } - } - } - } - } - - bondviewUpdatePlayerY(use_stanHeight, sp390); - bondviewUpdatePlayerCollisionPositionFields(); - bondviewUpdatePlayerCollisionBounds(); - - if (get_debug_man_pos_flag() != 0) - { - f32 sp5C_out_unused; - - copy_tile_RGB_as_24bit( - g_CurrentPlayer->field_488.current_tile_ptr, - g_CurrentPlayer->field_488.collision_position.f[0], - g_CurrentPlayer->field_488.collision_position.f[2], - &sp5C_out_unused); - } -} - - -/** - * US address 7F086990. - * EU address 7F086AB0. -*/ -void bondviewFrozenMoveBond(s8 stick_x, s8 stick_y, u16 buttons, u16 oldbuttons) -{ - struct coord3d property_pos; - struct coord3d property_pos2; - struct coord3d property_offset; - struct coord3d offset; - struct StandTile *room_pointer_tile; - struct coord3d stan_walk_start; - - property_pos = g_DefaultFrozenPlayerPos; - property_pos2 = g_DefaultFrozenPlayerPos2; - property_offset = g_DefaultFrozenPlayerOffset; - offset = g_DefaultFrozenMoveOffset; - - bondviewPlayerTickDamageAndHealth(); - bondviewPlayerTickExplode(); - bondviewProcessInput(0, 0, 0, 0); - bondviewApplyVertaTheta(); - bondviewMoveAnimationTick(0, 0, 0); - - if ((g_ForceBondMoveOffset.f[0] != 0.0f) || (g_ForceBondMoveOffset.f[2] != 0.0f)) - { - offset.f[0] += g_ForceBondMoveOffset.f[0] * g_GlobalTimerDelta; - offset.f[2] += g_ForceBondMoveOffset.f[2] * g_GlobalTimerDelta; - } - - offset.f[0] += ((g_CurrentPlayer->headpos.f[2] * g_CurrentPlayer->field_488.theta_transform.f[0]) - (g_CurrentPlayer->headpos.f[0] * g_CurrentPlayer->field_488.theta_transform.f[2])) * g_GlobalTimerDelta; - offset.f[2] += ((g_CurrentPlayer->headpos.f[2] * g_CurrentPlayer->field_488.theta_transform.f[2]) + (g_CurrentPlayer->headpos.f[0] * g_CurrentPlayer->field_488.theta_transform.f[0])) * g_GlobalTimerDelta; - - bondviewCalcUpdatePlayerCollision(&offset, 1); - bondviewUpdatePlayerY(0, 0.0f); - bondviewUpdatePlayerCollisionPositionFields(); - - if ((g_CameraMode == CAMERAMODE_FP_NOINPUT) || (g_CameraMode == CAMERAMODE_FP) || (g_CameraMode == CAMERAMODE_FADE_TO_TITLE)) - { - currentPlayerSetCameraMode(0); - return; - } - - bondviewFrozenCameraTick(buttons, oldbuttons, &property_pos, &property_pos2, &property_offset, &room_pointer_tile, &stan_walk_start); - currentPlayerSetCameraMode(1); - bondviewSetCurrentPlayerPosition(&property_pos, &property_pos2, &property_offset, room_pointer_tile, &stan_walk_start); -} - - -s16 getWidth320or440(void) -{ - if (cameraBufferToggle != 0) - { - return SCREEN_WIDTH_440; - } - - return SCREEN_WIDTH_320; -} - - -s16 getHeight330or240(void) -{ - if (cameraBufferToggle != 0) - { - return SCREEN_HEIGHT_330; - } - - return SCREEN_HEIGHT; -} - -s16 bondviewGetCurrentPlayerViewportWidth(void) -{ - if (getPlayerCount() >= 3) - { - return VIEWPORT_WIDTH_4P; - } - - if (cameraBufferToggle != 0) - { - return SCREEN_WIDTH_440; - } - - if (cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) - { - return VIEWPORT_WIDTH_WIDESCREEN; - } - - if (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA) - { - return VIEWPORT_WIDTH_CINEMA; - } - - return VIEWPORT_WIDTH_FULLSCREEN; -} - -s16 get_curplayer_viewport_ulx(void) -{ - if (2 < getPlayerCount()) - { - if ((get_cur_playernum() == 1) || (get_cur_playernum() == 3)) - { - return 0xa1; - } - } - - return 0; -} - - - - -/** - * Address 0x7F086D24. - */ -s16 bondviewGetCurrentPlayerViewportHeight(void) -{ - f32 t; - - if (getPlayerCount() >= 2) - { - return VIEWPORT_HEIGHT_4P; - } - - if (cameraBufferToggle != 0) - { - if (cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) - { - return VIEWPORT_HEIGHT_WIDESCREEN; - } - else if (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA) - { - return VIEWPORT_HEIGHT_CINEMA; - } - else - { - return VIEWPORT_HEIGHT_FULLSCREEN; - } - } - - if (cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) - { - t = bondviewGetPauseAnimationPercent(); - return (s16) ((s32) (WIDESCREEN_SCALE_FACTOR * t) + VIEWPORT_OFFSET_HEIGHT_WIDESCREEN); - } - else if (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA) - { - t = bondviewGetPauseAnimationPercent(); - return (s16) ((s32) (CINEMA_SCALE_FACTOR * t) + VIEWPORT_OFFSET_HEIGHT_CINEMA); - } - else - { - return VIEWPORT_HEIGHT_DEFAULT; - } -} - - - -/** - * Address 0x7F086E38. - */ -s16 bondviewGetCurrentPlayerViewportUly(void) -{ - f32 t; - - if (getPlayerCount() == 2) - { - if (get_cur_playernum() == 0) - { -#ifdef VERSION_EU - return 0; -#else - return VIEWPORT_ULY_2P_PLAYER_1; -#endif - } - - return VIEWPORT_ULY_2P_PLAYER_2; - } - - if (getPlayerCount() >= 3) - { - if (get_cur_playernum() < 2) - { -#ifdef VERSION_EU - return 0; -#else - return VIEWPORT_ULY_4P_PLAYER_12; -#endif - } - - return VIEWPORT_ULY_4P_PLAYER_34; - } - - if (cameraBufferToggle != 0) - { - if (cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) - { - return VIEWPORT_ULY_CAM_WIDESCREEN; - } - else if (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA) - { - return VIEWPORT_ULY_CAM_CINEMA; - } - else - { - return VIEWPORT_ULY_CAM_FULLSCREEN; - } - } - - if (cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) - { - t = bondviewGetPauseAnimationPercent(); - return (s16) ((s32) (WIDESCREEN_ULY_SCALE_FACTOR * t) + VIEWPORT_ULY_WIDESCREEN_OFFSET); - } - else if (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA) - { - t = bondviewGetPauseAnimationPercent(); - return (s16) ((s32) (CINEMA_ULY_SCALE_FACTOR * t) + VIEWPORT_ULY_CINEMA_OFFSET); - } - else - { -#ifdef VERSION_EU - return 0; -#else - return VIEWPORT_ULY_DEFAULT; -#endif - } -} - -/** - * Sets/updates viewport for player. - * Refreshes autoaim setting. - * Arguments are passed into MoveBond or bondviewFrozenMoveBond. - * Checks if necessary to call bossReturnTitleStage. - * Set player->buttons_pressed to arg2. - * - * Address 0x7F086F9C (VERSION_US). - * Address 0x7F0870BC (VERSION_EU). - * Address 0x7F087668 (VERSION_JP). - */ -void bondviewMovePlayerUpdateViewport(s8 stick_x, s8 stick_y, u16 buttons) -{ -#ifdef VERSION_EU - f32 faspect; -#endif - - set_cur_player_fovy(FOV_Y_F); - - // This call doesn't do anything, the call viSetFovY(g_CurrentPlayer->fovy); in lvlRender - // will actually change the field of view. - // The call above should set g_CurrentPlayer->fovy, but it doesn't seem to affect - // the fov.... - viSetFovY(FOV_Y_F); - - if (cameraFrameCounter1 != 0) - { - if ((cameraFrameCounter1 >= 4) && (resolution != 0) && (viGetFrameBuf2() == (u8*)(cfb_16[1]))) - { - cameraBufferToggle = 1; - cameraFrameCounter1 = 0; - } - else - { - cameraFrameCounter1 += 1; - } - } - else - { - if (cameraFrameCounter2 != 0) - { - if ((cameraFrameCounter2 >= 4) && (viGetFrameBuf2() == (u8*)(cfb_16[0]))) - { - cameraBufferToggle = 0; - cameraFrameCounter2 = 0; - } - else - { - cameraFrameCounter2 += 1; - } - } - } - - if ((cameraBufferToggle != 0) && (viGetFrameBuf2() == (u8*)(cfb_16[1]))) - { - viSetFrameBuf2((u8 *) resolution); - } - -#ifdef VERSION_EU - if (get_screen_ratio() == SCREEN_RATIO_16_9) - { - faspect = ((f32) bondviewGetCurrentPlayerViewportWidth() / (f32) bondviewGetCurrentPlayerViewportHeight()) * 0.75f * WIDESCREEN_ASPECT; - } - else - { - faspect = (f32) bondviewGetCurrentPlayerViewportWidth() / (f32) bondviewGetCurrentPlayerViewportHeight(); - } - - if (cameraBufferToggle == 0) - { - faspect *= EU_CAMERA_8003642C_ASPECT; - } - - set_cur_player_aspect(faspect); - viSetAspect(faspect); - -#else - - if (get_screen_ratio() == SCREEN_RATIO_16_9) - { - set_cur_player_aspect(((f32) bondviewGetCurrentPlayerViewportWidth() / (f32) bondviewGetCurrentPlayerViewportHeight()) * 0.75f * WIDESCREEN_ASPECT); - viSetAspect(((f32) bondviewGetCurrentPlayerViewportWidth() / (f32) bondviewGetCurrentPlayerViewportHeight()) * 0.75f * WIDESCREEN_ASPECT); - } - else - { - set_cur_player_aspect((f32) bondviewGetCurrentPlayerViewportWidth() / (f32) bondviewGetCurrentPlayerViewportHeight()); - viSetAspect((f32) bondviewGetCurrentPlayerViewportWidth() / (f32) bondviewGetCurrentPlayerViewportHeight()); - } -#endif - - set_cur_player_screen_size( bondviewGetCurrentPlayerViewportWidth(), bondviewGetCurrentPlayerViewportHeight()); - set_cur_player_viewport_size( get_curplayer_viewport_ulx(), bondviewGetCurrentPlayerViewportUly()); - viSetXY(getWidth320or440(), getHeight330or240()); - viSetBuf(getWidth320or440(), getHeight330or240()); - viSetViewSize(bondviewGetCurrentPlayerViewportWidth(), bondviewGetCurrentPlayerViewportHeight()); - viSetViewPosition(get_curplayer_viewport_ulx(), bondviewGetCurrentPlayerViewportUly()); - currentPlayerUpdateColourScreenProperties(); - currentPlayerTickChrFade(); - currentPlayerSetYAutoAimEnabled(cur_player_get_autoaim()); - currentPlayerSetXAutoAimEnabled(cur_player_get_autoaim()); - currentPlayerSetLookAheadSetting(cur_player_get_lookahead()); - gunSetGunAmmoVisible(GUNAMMOREASON_OPTION, cur_player_get_ammo_onscreen_setting()); - - gunSetSightVisible( - GUNSIGHTREASON_1, - (getPlayerCount() == 1 && cur_player_get_sight_onscreen_control()) - || (getPlayerCount() >= 2 && g_playerPerm->sight) - ); - -#if defined(VERSION_EU) - if (1); -#endif - - if ((g_CameraMode == CAMERAMODE_NONE) || ((g_CameraMode == CAMERAMODE_FP) && (is_timer_active != 0)) || (g_CameraMode == CAMERAMODE_FADE_TO_TITLE)) - { - if (get_cur_playernum() == 0) - { - mission_timer += g_ClockTimer; - } - - MoveBond(stick_x, stick_y, buttons, (u16) g_CurrentPlayer->buttons_pressed); - } - else - { - bondviewFrozenMoveBond(stick_x, stick_y, buttons, (u16) g_CurrentPlayer->buttons_pressed); - } - -#if defined(BUGFIX_R1) - watch_time_0 += jpD_800484D0; -#else - // VERSION_US - watch_time_0 += speedgraphframes; -#endif - - if (stop_time_flag != 0) - { - if ((lvlGetControlsLockedFlag() == 0) && ((buttons & ~(g_CurrentPlayer->buttons_pressed) & (CONT_A | B_BUTTON | Z_TRIG | START_BUTTON | CONT_R | CONT_L)))) - { - stop_time_flag = 2; - - if (currentPlayerIsFadeComplete()) - { - if (g_CurrentPlayer->colourscreenfrac == 0.0f) - { - currentPlayerSetFadeColour(0, 0, 0, 0.0f); - currentPlayerSetFadeFrac(60.0f, 1.0f); - } - } - else - { - if (g_CurrentPlayer->colourfadefracnew == 0.0f) - { - currentPlayerSetFadeFrac(g_CurrentPlayer->colourfadetime60, 1.0f); - } - } - } - - if ((stop_time_flag == 2) && currentPlayerIsFadeComplete() && (g_CurrentPlayer->colourscreenfrac == 1.0f)) - { - bossReturnTitleStage(); - } - } - - if (g_CameraAfterCinema) - { - bondviewAdvanceCameraMode(); - } - - if (g_CurrentPlayer->bonddead) - { - if (g_CurrentPlayer->redbloodfinished == FALSE) - { - currentPlayerEquipWeaponWrapper(GUNLEFT, 0); - currentPlayerEquipWeaponWrapper(GUNRIGHT, 0); - - if (0) - { - // removed? - }; - } - - if (g_CurrentPlayer->redbloodfinished && g_CurrentPlayer->deathanimfinished && (camera_mode >= CAMERAMODE_SWIRL)) - { - bossRunTitleStage(); - } - } - - if ((g_CameraMode == CAMERAMODE_FADE_TO_TITLE) && currentPlayerIsFadeComplete()) - { - bossRunTitleStage(); - } - - g_CurrentPlayer->buttons_pressed = buttons; -} - - -/** - * Address 0x7F0875E4. - */ -void bondviewUpdateCurrentRoomPosition(s32 arg0) -{ - getRoomPositionScaledByIndex(arg0, &g_CurrentPlayer->current_model_pos); - g_CurrentPlayer->current_room_pos.f[0] = g_CurrentPlayer->current_model_pos.f[0] * get_room_data_float1(); - g_CurrentPlayer->current_room_pos.f[1] = g_CurrentPlayer->current_model_pos.f[1] * get_room_data_float1(); - g_CurrentPlayer->current_room_pos.f[2] = g_CurrentPlayer->current_model_pos.f[2] * get_room_data_float1(); - setPlayerRoomField(arg0); -} - - -void store_BONDdata_curpos_to_previous(void) { - g_CurrentPlayer->previous_model_pos.f[0] = g_CurrentPlayer->current_model_pos.f[0]; - g_CurrentPlayer->previous_model_pos.f[1] = g_CurrentPlayer->current_model_pos.f[1]; - g_CurrentPlayer->previous_model_pos.f[2] = g_CurrentPlayer->current_model_pos.f[2]; - mtx4RotateVecInPlace(camGetWorldToScreenMtxf(), &g_CurrentPlayer->previous_model_pos); -} - - -/** - * Address: 7F0876C4 - */ -void bondviewUpdateCameraMatrices(coord3d* cam_pos, coord3d* cam_look_dir, coord3d* cam_up) -{ - Mtx sp108; - LookAt *lookat; - Mtxf spC4; - coord3d clpos; - coord3d scaledpos; - f32 scale; - Mtx *temp_s0; - Mtxf *projmtx; - Mtxf sp60; - s32 j; - s32 i; - - i = bondviewGetCurrentPlayersRoom(); - bondviewUpdateCurrentRoomPosition(i); - - g_CurrentPlayer->field_5C = dynAllocateMatrix(); - g_CurrentPlayer->field_60 = dynAllocateMatrix(); - g_CurrentPlayer->field_64 = dynAllocateMatrix(); - g_CurrentPlayer->field_68 = dynAllocateMatrix(); - - lookat = dynAllocateLights(2); - - scale = D_800364CC; - - scaledpos.x = (cam_pos->x - g_CurrentPlayer->current_model_pos.x) * scale; - scaledpos.y = (cam_pos->y - g_CurrentPlayer->current_model_pos.y) * scale; - scaledpos.z = (cam_pos->z - g_CurrentPlayer->current_model_pos.z) * scale; - - clpos.f[0] = scaledpos.f[0] + cam_look_dir->f[0]; - clpos.f[1] = scaledpos.f[1] + cam_look_dir->f[1]; - clpos.f[2] = scaledpos.f[2] + cam_look_dir->f[2]; - - matrix_4x4_set_lookat(&spC4, - scaledpos.x, scaledpos.y, scaledpos.z, - cam_look_dir->x, cam_look_dir->y, cam_look_dir->z, - cam_up->x, cam_up->y, cam_up->z); - - guLookAtReflect(&sp108, lookat, - scaledpos.x, scaledpos.y, scaledpos.z, - clpos.x, clpos.y, clpos.z, - cam_up->x, cam_up->y, cam_up->z); - - matrix_4x4_set_lookat((Mtxf*) g_CurrentPlayer->field_64, - cam_pos->x, cam_pos->y, cam_pos->z, - cam_look_dir->x, cam_look_dir->y, cam_look_dir->z, - cam_up->x, cam_up->y, cam_up->z); - - matrix_4x4_set_basis_and_position((Mtxf*) g_CurrentPlayer->field_68, - cam_pos->x, cam_pos->y, cam_pos->z, - cam_look_dir->x, cam_look_dir->y, cam_look_dir->z, - cam_up->x, cam_up->y, cam_up->z); - - temp_s0 = dynAllocateMatrix(); - - projmtx = currentPlayerGetProjectionMatrixF(); - matrix_4x4_multiply(projmtx, &spC4, &sp60); - - for (i = 0; i < 4; i++) - { - for (j = 0; j < 4; j++) - { - if (sp60.m[i][j] > 32000.0f) - { - sp60.m[i][j] = 32000.0f; - } - else if (sp60.m[i][j] < -32000.0f) - { - sp60.m[i][j] = -32000.0f; - } - } - } - - guMtxF2L((f32 (*)[4]) &sp60, temp_s0); - set_BONDdata_field_10E0((s32) temp_s0); - - scale = bgGetLevelVisibilityScale(); - - matrix_scalar_multiply(scale, spC4.m[0]); - guMtxF2L((f32 (*)[4]) &spC4, (Mtx* ) g_CurrentPlayer->field_5C); - sub_GAME_7F059334((s32* ) g_CurrentPlayer->field_5C, (s32* ) g_CurrentPlayer->field_60); - - currentPlayerSetMatrix10C8((Mtx* ) g_CurrentPlayer->field_5C); - currentPlayerSetMatrix10C4((Mtx* ) g_CurrentPlayer->field_60); - currentPlayerSetMatrix10CC((Mtxf* ) g_CurrentPlayer->field_64); - currentPlayerSetViewToWorldMtxf((Mtxf* ) g_CurrentPlayer->field_68); - - sub_GAME_7F078464((s32) lookat); - bondviewUpdateFrustumPlanes(); - store_BONDdata_curpos_to_previous(); -} - - -/** - * Address: 7F087A08 - */ -Gfx *bondviewRenderDebugBondView(Gfx *gdl) -{ - coord3d cam_pos; - coord3d cam_look; - coord3d cam_up; - struct collision434 *collision; - coord3d shake; - coord3d vec; - coord3d zeropos; - f32 vec_y; - f32 horizontal_len; - struct player *player; - f32 angle; - f32 vertical_rot; - f32 ft4; - -#if defined(VERSION_EU) - if (bossGetStageNum() == LEVELID_CUBA) - { - if (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA) - { - gdl = clear_framebuffer_black(gdl); - gdl = clear_framebuffer_black(gdl); - gdl = clear_framebuffer_black(gdl); - gdl = clear_framebuffer_black(gdl); - } - else if (cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) - { - gdl = clear_framebuffer_black(gdl); - gdl = clear_framebuffer_black(gdl); - gdl = clear_framebuffer_black(gdl); - } - else - { - gdl = clear_framebuffer_black(gdl); - gdl = clear_framebuffer_black(gdl); - } - } -#endif - - if (g_CurrentPlayer->cameramode == 1) { - cam_pos.x = g_CurrentPlayer->pos.x; - cam_pos.y = g_CurrentPlayer->pos.y; - cam_pos.z = g_CurrentPlayer->pos.z; - - cam_look.x = g_CurrentPlayer->pos2.x - g_CurrentPlayer->pos.x; - cam_look.y = g_CurrentPlayer->pos2.y - g_CurrentPlayer->pos.y; - cam_look.z = g_CurrentPlayer->pos2.z - g_CurrentPlayer->pos.z; - - cam_up.x = g_CurrentPlayer->offset.x; - cam_up.y = g_CurrentPlayer->offset.y; - cam_up.z = g_CurrentPlayer->offset.z; - } else { - collision = &g_CurrentPlayer->field_488; - - shake = ZeroCoordShake; - - if (!g_CurrentPlayer->bonddead) { - explosionScreenShake( - &collision->pos, - &collision->applied_view, - &shake - ); - } else { - viShake(0.0f); - } - - cam_pos.x = collision->pos.x; - cam_pos.y = collision->pos.y; - cam_pos.z = collision->pos.z; - - cam_look.x = collision->applied_view.x; - cam_look.y = collision->applied_view.y; - cam_look.z = collision->applied_view.z; - - cam_up.x = collision->applied_view2.x; - cam_up.y = collision->applied_view2.y; - cam_up.z = collision->applied_view2.z; - } - - bondviewUpdateCameraMatrices(&cam_pos, &cam_look, &cam_up); - sub_GAME_7F068190(&zeropos, &vec); - - - vec_y = vec.y; - horizontal_len = sqrtf((vec.z * vec.z) + (vec.x * vec.x)); - vertical_rot = bondviewGetPlayerPitchRadians(); - ft4 = atan2f(vec_y, horizontal_len) + vertical_rot; - - if (ft4 >= M_PI_F) { - ft4 -= M_TAU_F; - } - g_CurrentPlayer->field_2A08 = ft4; - - angle = atan2f(-vec.x, -vec.z); - if (angle >= M_PI_F) { - angle -= M_TAU_F; - } - g_CurrentPlayer->field_2A0C = angle; - - return gdl; -} - - -void bondviewSelectCuff(Model *model, ModelFileHeader *header, s32 switchindex) -{ - s32 pad; - s32 local; - ModelNode **switches; - ModelNode **base; - ModelNode *node; - s32 offset; - s32 *rwdata; - s32 index; - s32 visible; - s32 pad2; - - local = fileGetBondForCurrentFolder(); - switches = header->Switches; - offset = switchindex << 2; - - if (1); - - // byte-indexed on purpose: offset = switchindex * 4. &switches[i] won't match. - base = (ModelNode **) (((u8 *) switches) + offset); - - if (base[0] != NULL) - { - rwdata = (s32 *) modelGetNodeRwData(model, base[0]); - *rwdata = g_CurrentPlayer->bondtype == CUFF_BOILER; - switches = header->Switches; - base = (ModelNode **) (((u8 *) switches) + offset); - } - - index = switchindex + 1; - - if (((void *) (index * 0)) != base[1]) - { - node = switches[index]; - rwdata = (s32 *) modelGetNodeRwData(model, node); - visible = g_CurrentPlayer->bondtype == CUFF_BROSNAN; - if (visible == 0) - { - visible = g_CurrentPlayer->bondtype == CUFF_DALTON; - if (visible == 0) - { - visible = g_CurrentPlayer->bondtype == CUFF_MOORE; - if (visible == 0) - { - visible = g_CurrentPlayer->bondtype == CUFF_FOLDER; - if (visible != 0) - { - visible = local != 1; - } - } - } - } - *rwdata = visible; - switches = header->Switches; - base = (ModelNode **) (((u8 *) switches) + offset); - } - - index = switchindex + 2; - - if (base[2] != NULL) - { - rwdata = (s32 *) modelGetNodeRwData(model, switches[index]); - visible = g_CurrentPlayer->bondtype == CUFF_CONNERY; - - if (visible == 0) - { - visible = g_CurrentPlayer->bondtype == CUFF_FOLDER; - if (visible != 0) - { - visible = local == 1; - } - } - - *rwdata = visible; - switches = header->Switches; - base = (ModelNode **) (((u8 *) switches) + offset); - } - - index = switchindex + 3; - - if (base[3] != NULL) - { - rwdata = (s32 *) modelGetNodeRwData(model, switches[index]); - *rwdata = g_CurrentPlayer->bondtype == CUFF_BLUE; - switches = header->Switches; - base = (ModelNode **) (((u8 *) switches) + offset); - } - - index = (switchindex + 4) ^ (((switchindex + 4) ^ 0) * 0); - - if (base[4]) - { - rwdata = (s32 *) modelGetNodeRwData(model, switches[index]); - *rwdata = g_CurrentPlayer->bondtype == CUFF_JUNGLE; - switches = header->Switches; - base = (ModelNode **) (((u8 *) switches) + offset); - } - - index = switchindex + 5; - - if (base[5] != NULL) - { - rwdata = (s32 *) modelGetNodeRwData(model, switches[index]); - *rwdata = g_CurrentPlayer->bondtype == CUFF_SNOW; - } -} - - -/** - * Address: 7F087E74 - */ -Gfx *bondviewRenderWatch(Gfx *gdl) -{ - ModelRenderData renderdata; - Mtxf watchmtx; - coord3d watchpos; - f32 t; - Mtxf *matrices; - ModelFileHeader *objheader; - f32 *nodepos; - union ModelRwData *rwdata; - Mtx *perspmtx; - u16 perspNorm; - - if (g_CurrentPlayer->watch_animation_state == 0) - { - goto end; - } - - if (g_CurrentPlayer->pausing_flag == FALSE) - { - goto end; - } - - renderdata = D_8003683C; - watchpos = ZeroCoordWatchPos; - objheader = get_ptr_itemheader_in_hand(GUNLEFT); - nodepos = (f32 *) objheader->Switches[3]; - rwdata = modelGetNodeRwData((Model *) (&g_CurrentPlayer->something_with_watch_object_instance), (ModelNode *) nodepos); - perspmtx = dynAllocateMatrix(); -#if defined(VERSION_EU) - guPerspective(perspmtx, &perspNorm, g_CurrentPlayer->zoominfovy, 1.4005603f, 10.0f, 300.0f, 1.0f); -#else - guPerspective(perspmtx, &perspNorm, g_CurrentPlayer->zoominfovy, 1.4545455f, 10.0f, 300.0f, 1.0f); -#endif - - gSPMatrix(gdl++, OS_PHYSICAL_TO_K0((u32) perspmtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); - gSPPerspNormalize(gdl++, perspNorm); - - // Keep this nested block for matching. - { - Mtxf targetmtx; - coord3d currot; - coord3d targetrot; - quatf quat1; - quatf quat2; - quatf quat3; - coord3d targetpos; - s32 total_seconds; - s32 seconds; - s32 total_minutes; - s32 minutes; - f32 framesfrac; - f32 secondsAngle; - f32 minutesAngle; - f32 hoursAngle; - s32 time; - f32 *nodepos2; - Mtxf handmtx; - Mtx *finalmtx; - - rwdata->Switch.visible = g_CurrentPlayer->outside_watch_menu; - - watchpos.x = (g_CurrentPlayer->field_488.theta_transform.x * (g_CurrentPlayer->headbodyoffset.z + (-12.0f))) + (g_CurrentPlayer->field_488.collision_position.x + (g_CurrentPlayer->headbodyoffset.x * (-g_CurrentPlayer->field_488.theta_transform.z))); - watchpos.y = g_CurrentPlayer->headbodyoffset.y + g_CurrentPlayer->field_488.collision_position.y; - watchpos.z = (g_CurrentPlayer->field_488.theta_transform.z * (g_CurrentPlayer->headbodyoffset.z + (-12.0f))) + (g_CurrentPlayer->field_488.collision_position.z + (g_CurrentPlayer->headbodyoffset.x * g_CurrentPlayer->field_488.theta_transform.x)); - - matrix_4x4_set_position_and_rotation_around_y(watchpos.f, (360.0f - g_CurrentPlayer->vv_theta) * 0.017453292f, &watchmtx); - matrix_4x4_multiply_homogeneous_in_place(camGetWorldToScreenMtxf(), &watchmtx); - matrices = dynAllocate(objheader->numMatrices << 6); - bondviewSelectCuff((Model *) (&g_CurrentPlayer->something_with_watch_object_instance), objheader, 4); - renderdata.basemtx = &watchmtx; - renderdata.mtxlist = matrices; - subcalcmatrices(&renderdata, (Model *) (&g_CurrentPlayer->something_with_watch_object_instance)); - nodepos = (f32 *) objheader->Switches[0]->Data; - time = watch_time_0; - t = g_CurrentPlayer->pause_watch_related_adjust / 20.0f; - - if (t > 1.0f) - { - t = 1.0f; - } - - targetpos.x = matrices->m[3][0] + (((g_CurrentPlayer->field_1D4 - (nodepos[0] * g_CurrentPlayer->watch_scale_destination)) - matrices->m[3][0]) * t); - targetpos.y = matrices->m[3][1] + (((g_CurrentPlayer->field_1D8 + (nodepos[2] * g_CurrentPlayer->watch_scale_destination)) - matrices->m[3][1]) * t); - targetpos.z = matrices->m[3][2] + (((g_CurrentPlayer->pause_watch_position - (nodepos[1] * g_CurrentPlayer->watch_scale_destination)) - matrices->m[3][2]) * t); - - matrix_4x4_set_basis_and_position_target(&targetmtx, 0.0f, 0.0f, 0.0f, g_CurrentPlayer->field_1E0, g_CurrentPlayer->field_1E4, g_CurrentPlayer->field_1E8, g_CurrentPlayer->field_1EC, g_CurrentPlayer->field_1F0, g_CurrentPlayer->field_1F4); - matrix_4x4_get_rotation_around_xyz(matrices, &currot); - matrix_4x4_get_rotation_around_xyz(&targetmtx, &targetrot); - quaternion_set_rotation_around_xyzf(currot.f, quat1); - quaternion_set_rotation_around_xyzf(targetrot.f, quat2); - quaternion_ensure_shortest_path(quat1, quat2); - quaternion_slerp(quat1, quat2, t, quat3); - quaternion_to_matrix(quat3, matrices->m); - matrix_4x4_set_position(&targetpos, matrices); - matrix_scalar_multiply(g_CurrentPlayer->watch_scale_destination, (f32 *) matrices); - total_seconds = time / 60; - seconds = total_seconds % 60; - total_minutes = total_seconds / 60; - minutes = total_minutes % 60; - framesfrac = ((f32) (time % 60)) / 60.0f; - secondsAngle = ((-(((f32) seconds) + framesfrac)) * M_TAU_F) / 60.0f; - minutesAngle = ((((-((f32) minutes)) * M_TAU_F) / 60.0f) * 1.0f) + (secondsAngle / 60.0f); - hoursAngle = ((((-((f32) ((total_seconds / 3600) % 12))) * M_TAU_F) / 12.0f) + (minutesAngle / 12.0f)) + (secondsAngle / 720.0f); - - while (secondsAngle < 0.0f) - { - secondsAngle += M_TAU_F; - } - - while (minutesAngle < 0.0f) - { - minutesAngle += M_TAU_F; - } - - while (hoursAngle < 0.0f) - { - hoursAngle += M_TAU_F; - } - - matrix_4x4_set_position_and_rotation_around_y((f32 *) objheader->Switches[0]->Data, hoursAngle, &matrices[1]); - matrix_4x4_multiply_in_place(matrices, &matrices[1]); - matrix_4x4_set_position_and_rotation_around_y((f32 *) objheader->Switches[1]->Data, minutesAngle, &matrices[2]); - matrix_4x4_multiply_in_place(matrices, &matrices[2]); - matrix_4x4_set_position_and_rotation_around_y((f32 *) objheader->Switches[2]->Data, secondsAngle, &matrices[3]); - matrix_4x4_multiply_in_place(matrices, &matrices[3]); - - renderdata.flags = 3; - renderdata.zbufferenabled = 0; - renderdata.gdl = gdl; - renderdata.PropType = PROP_TYPE_WEAPON; - - if ((g_CurrentPlayer->watch_animation_state == 5) || (g_CurrentPlayer->watch_animation_state == 12)) - { - renderdata.envcolour.word = 0xcd; - } - else - { - renderdata.envcolour.word = g_CurrentPlayer->tileColor.a | (((g_CurrentPlayer->tileColor.r << 24) | (g_CurrentPlayer->tileColor.g << 16)) | (g_CurrentPlayer->tileColor.b << 8)); - } - - subdraw(&renderdata, (Model *) (&g_CurrentPlayer->something_with_watch_object_instance)); - gdl = renderdata.gdl; - nodepos2 = (f32 *) objheader->Switches[2]->Data; - finalmtx = dynAllocateMatrix(); - matrix_4x4_set_identity_and_position((coord3d *) nodepos2, &handmtx); - matrix_4x4_multiply_in_place(matrices, &handmtx); - matrix_4x4_7F058C64(); - matrix_4x4_f32_to_s32(&handmtx, finalmtx); - matrix_4x4_7F058C88(); - gdl = draw_watch_current_page(gdl, finalmtx, (g_CurrentPlayer->watch_animation_state == 5) || (g_CurrentPlayer->watch_animation_state == 12)); - matrix_4x4_7F058C64(); - bondviewTransformManyPosToViewMatrix(g_CurrentPlayer->field_23C, objheader->numMatrices); - matrix_4x4_7F058C88(); - } - - end: - return gdl; -} - - -/** - * Address: 7F088618 - * - * Renders the in-game health and armor gauges. - * The watch menu gauges are handled by trigger_solo_watch_menu(). - */ -Gfx *bondviewRenderGaugeBars(Gfx *gdl) -{ - Mtx *lookatmtx; - Mtx *orthomtx; - Mtxf lookatmtxf; - - //Set up armor bars. - hudMakeDamageSegments(&g_CurrentPlayer->armor_display_values[0].items[0], 0x2e, 1, g_CurrentPlayer->apparentarmour); - buildGaugeBarDL((Gfx *)&g_CurrentPlayer->watch_body_armor_bar_gdl, OS_PHYSICAL_TO_K0(&g_CurrentPlayer->armor_display_values[0].items[0]), 0x2e); - - // Set up health bars. - hudMakeDamageSegments(&g_CurrentPlayer->health_display_values[0].items[0], 0x2e, -1, g_CurrentPlayer->apparenthealth); - buildGaugeBarDL((Gfx *)&g_CurrentPlayer->watch_health_bar_gdl, OS_PHYSICAL_TO_K0(&g_CurrentPlayer->health_display_values[0].items[0]), 0x2e); - - // Create an orthographic render state for the gauge. - lookatmtx = dynAllocateMatrix(); - orthomtx = dynAllocateMatrix(); - - guOrtho(orthomtx, -800.0f * D_800364CC, 800.0f * D_800364CC, -600.0f * D_800364CC, 600.0f * D_800364CC, -100.0f, 1000.0f, 1.0f); - - gSPMatrix(gdl++, osVirtualToPhysical(orthomtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); - - matrix_4x4_set_lookat_target( - &lookatmtxf, - 0.0f, 500.0f, 0.0f, - 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, -1.0f - ); - - matrix_4x4_f32_to_s32(&lookatmtxf, (Mtxf *)lookatmtx); - - gSPMatrix(gdl++, osVirtualToPhysical(lookatmtx), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); - - gDPPipeSync(gdl++); - gDPSetCycleType(gdl++, G_CYC_1CYCLE); - gDPSetRenderMode(gdl++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2); - gDPSetAlphaCompare(gdl++, G_AC_NONE); - gDPSetCombineMode(gdl++, G_CC_SHADE, G_CC_SHADE); - gDPSetPrimColor(gdl++, 0, 0, 0xe6, 0xe6, 0xe6, 0x00); - gSPClearGeometryMode(gdl++, G_CULL_BOTH); - - gSPDisplayList(gdl++, OS_PHYSICAL_TO_K0(&g_CurrentPlayer->watch_body_armor_bar_gdl)); - gSPDisplayList(gdl++, OS_PHYSICAL_TO_K0(&g_CurrentPlayer->watch_health_bar_gdl)); - - gSPMatrix(gdl++, osVirtualToPhysical(currentPlayerGetProjectionMatrix()), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); - - return gdl; -} - - -void mp_respawn_handler(void) -{ - coord3d start_pos = ZeroCoordSpawnPos; - f32 start_look_angle; - s32 start_stan; - s32 pad; - f32 stan_height; - s32 var_v0; - s32 var_v1; - u32 var_v0_2; - struct SetupIntroEmpty* intro_record; - - intro_record = g_CurrentSetup.intro; - - init_player_BONDdata(); - bondviewPlayerBeginLife(); - - g_CurrentPlayer->bonddead = 0; - g_CurrentPlayer->deathanimfinished = 0; - g_CurrentPlayer->redbloodfinished = 0; - g_CurrentPlayer->startnewbonddie = 1; - g_CurrentPlayer->healthdamagetype = 7; - g_CurrentPlayer->damagetype = 7; - g_CurrentPlayer->gunammooff = 0; - g_CurrentPlayer->gunsightmode = 2; - - hudmsgsSetOn(-1); - bondviewClearUpperTextDisplayFlag(-1); - - - if ((getPlayerCount() >= 2) && (startpadcount > 0)) - { - var_v1 = bondviewGetRandomSpawnPadIndex(); - } - else - { - var_v1 = 0; - } - - #ifdef DEBUG - assert(g_Startpad[var_v1]->stan); - #endif - - start_pos.x = g_Startpad[var_v1]->pos.x; - start_pos.z = g_Startpad[var_v1]->pos.z; - start_stan = g_Startpad[var_v1]->stan; - - stan_height = bondviewYPositionRelated(start_stan, start_pos.x, start_pos.z); - - start_pos.y = g_CurrentPlayer->eyeheight + stan_height; - g_CurrentPlayer->field_70 = stan_height; - - start_look_angle = randomGetNext() * 2.3283064e-10f * 6.2831855f; - - g_CurrentPlayer->vv_theta = (f32) ((start_look_angle * 360.0f) / 6.2831855f); - g_CurrentPlayer->stanHeight = stan_height; -#if defined(VERSION_EU) - g_CurrentPlayer->field_6C = (f32) (stan_height / 0.2004f); -#else - g_CurrentPlayer->field_6C = (f32) (stan_height / 0.17000002f); -#endif - - change_player_pos_to_target(&g_CurrentPlayer->field_488, &start_pos, start_stan); - - g_CurrentPlayer->field_488.theta_transform.x = -sinf(start_look_angle); - g_CurrentPlayer->field_488.theta_transform.y = 0.0f; - g_CurrentPlayer->field_488.theta_transform.z = cosf(start_look_angle); - g_CurrentPlayer->prop->pos.x = g_CurrentPlayer->bondprevpos.x = start_pos.f[0]; - g_CurrentPlayer->prop->pos.y = g_CurrentPlayer->bondprevpos.y = start_pos.f[1]; - g_CurrentPlayer->prop->pos.z = g_CurrentPlayer->bondprevpos.z = start_pos.f[2]; - g_CurrentPlayer->prop->stan = start_stan; -#if defined(VERSION_EU) - g_CurrentPlayer->field_3B8.x = (f32) (g_CurrentPlayer->field_488.pos.x / 0.118799984f); - g_CurrentPlayer->field_3B8.y = (f32) (g_CurrentPlayer->field_488.pos.y / 0.118799984f); - g_CurrentPlayer->field_3B8.z = (f32) (g_CurrentPlayer->field_488.pos.z / 0.118799984f); -#else - g_CurrentPlayer->field_3B8.x = (f32) (g_CurrentPlayer->field_488.pos.x / 0.100000024f); - g_CurrentPlayer->field_3B8.y = (f32) (g_CurrentPlayer->field_488.pos.y / 0.100000024f); - g_CurrentPlayer->field_3B8.z = (f32) (g_CurrentPlayer->field_488.pos.z / 0.100000024f); -#endif - - bondinvReinitInv(); - var_v0 = 0; - - while (var_v0 != 30) - { - g_CurrentPlayer->ammoheldarr[var_v0++] = 0; - } - - if (intro_record != NULL) - { - while (intro_record->type != 9) // INTROTYPE_END - { - switch (intro_record->type) - { - case 0: // INTROTYPE_SPAWN - intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroSpawn)); - break; - case 1: // INTROTYPE_ITEM - if (check_ramrom_flags() == ((struct SetupIntroAmmo*)intro_record)->is_demo_playback) { - if ( ((struct SetupIntroItem*)intro_record)->item_left >= 0) { - bondinvAddDoublesInvItem(((struct SetupIntroItem*)intro_record)->item_right, ((struct SetupIntroItem*)intro_record)->item_left); - } else { - bondinvAddInvItem(((struct SetupIntroItem*)intro_record)->item_right); - } - } - intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroItem)); - break; - case 2: // INTROTYPE_AMMO - if (check_ramrom_flags() == ((struct SetupIntroAmmo*)intro_record)->is_demo_playback) { - give_cur_player_ammo(((struct SetupIntroAmmo*)intro_record)->ammo_type, ((struct SetupIntroAmmo*)intro_record)->ammo_amount); - } - intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroAmmo)); - break; - case 3: // INTROTYPE_SWIRL - intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroSwirl)); - break; - case 4: // INTROTYPE_ANIM - intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroAnim)); - break; - case 5: // INTROTYPE_CUFF - intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroCuff)); - break; - case 6: // INTROTYPE_CAMERA - intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroCamera)); - break; - default: // INTROTYPE_WATCH, INTROTYPE_CREDITS - intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroEmpty)); - break; - } - #ifdef DEBUG - ossyncprintf("unknown bondstart type %d!\n", var_v0_2); - #endif - } - } - - g_CurrentPlayer->field_78 = 0.0f; - g_CurrentPlayer->field_7C = -0.0001f; - g_CurrentPlayer->field_80 = 0.0f; - currentPlayerStartChrFade(120.0f, 1.0f); -} - - -/** - * Address: 7F088CD8 - */ -Gfx *bondviewRenderCredits(Gfx *gdl) -{ - s32 frame; - s32 start; - s32 x; - s32 y; - s32 xpos1; - s32 xpos2; - s32 textheight; - s32 textwidth; - s32 i; - s32 end; - s32 x2; - s32 entrysize; - s32 align1; - s32 align2; - s16 viewheight; - char *text; - - if (bossGetStageNum() == LEVELID_CUBA && credits_state == 1 && credits_pointer != NULL) - { - xpos1 = 0xdc; - xpos2 = 0xdc; - align1 = CREDITS_ALIGN_RIGHT; - align2 = CREDITS_ALIGN_RIGHT; - camera_80036438++; - frame = camera_80036438; - gdl = microcode_constructor(gdl); - start = (frame - viGetViewHeight()) / 16; - end = (frame / 16) + 1; - - if (start < 0) - { - start = 0; - } - - for (i = 0; i < start; i++) - { - if (credits_pointer[i].TextId1 == 0 && credits_pointer[i].TextId2 == 0) - { - end = i; - start = i; - credits_state = 2; - break; - } - - if (credits_pointer[i].TextId1 != 0x5011) - { - if (credits_pointer[i].Position1 >= 0) - { - xpos1 = credits_pointer[i].Position1; - } - - if ((s16) credits_pointer[i].Alignment1 >= CREDITS_ALIGN_RIGHT) - { - align1 = (s16) credits_pointer[i].Alignment1; - } - } - - if (credits_pointer[i].TextId2 != 0x5011) - { - if (credits_pointer[i].Position2 >= 0) - { - xpos2 = credits_pointer[i].Position2; - } - - if ((s16) credits_pointer[i].Alignment2 - >= CREDITS_ALIGN_RIGHT) - { - align2 = (s16) credits_pointer[i].Alignment2; - } - } - } - - for (i = start; i < end && (credits_pointer[i].TextId1 || credits_pointer[i].TextId2); i++) - { - if ((u32) credits_pointer[i].TextId1 != 0x5011) - { - text = langGet(credits_pointer[i].TextId1); - - if (credits_pointer[i].Position1 >= 0) - { - xpos1 = credits_pointer[i].Position1; - } - - if ((s16) credits_pointer[i].Alignment1 >= CREDITS_ALIGN_RIGHT) - { - align1 = (s16) credits_pointer[i].Alignment1; - } - - viewheight = viGetViewHeight(); - y = ((viGetViewTop() + (i * 16)) - frame) + viewheight; - textheight = 0; - textwidth = 0; - - textMeasure(&textheight, &textwidth, text, ptrFontZurichBoldChars, ptrFontZurichBold, 0); - - entrysize = y + textheight; - - if (align1 == CREDITS_ALIGN_LEFT) - { - x = xpos1 - textwidth; - x2 = xpos1; - } - else if (align1 == CREDITS_ALIGN_CENTER) - { - x = xpos1 - (textwidth >> 1); - x2 = x + textwidth; - } - else - { - x = xpos1; - x2 = xpos1 + textwidth; - } - - gdl = microcode_constructor_related_to_menus(gdl, x, y - 1, x2 + 1, entrysize + 1, 0); - - gdl = textRender(gdl, &x, &y, text, ptrFontZurichBoldChars, ptrFontZurichBold, -1, viGetX(), viGetY(), 0, 0); - } - - if (credits_pointer[i].TextId2 != 0x5011) - { - text = langGet(credits_pointer[i].TextId2); - - if (credits_pointer[i].Position2 >= 0) - { - xpos2 = credits_pointer[i].Position2; - } - - if ((s16) credits_pointer[i].Alignment2 >= CREDITS_ALIGN_RIGHT) - { - align2 = (s16) credits_pointer[i].Alignment2; - } - - viewheight = viGetViewHeight(); - y = ((viGetViewTop() + (i * 16)) - frame) + viewheight; - textheight = 0; - textwidth = 0; - - textMeasure(&textheight, &textwidth, text, ptrFontZurichBoldChars, ptrFontZurichBold, 0); - - entrysize = y + textheight; - - if (align2 == CREDITS_ALIGN_LEFT) - { - x = xpos2 - textwidth; - x2 = xpos2; - } - else if (align2 == CREDITS_ALIGN_CENTER) - { - x = xpos2 - (textwidth >> 1); - x2 = x + textwidth; - } - else - { - x = xpos2; - x2 = xpos2 + textwidth; - } - - gdl = microcode_constructor_related_to_menus(gdl, x, y - 1, x2 + 1, entrysize + 1, 0); - - gdl = textRender(gdl, &x, &y, text, ptrFontZurichBoldChars, ptrFontZurichBold, -1, viGetX(), viGetY(), 0, 0); - } - } - - gdl = combiner_bayer_lod_perspective(gdl); - } - - return gdl; -} - - -Gfx *maybe_mp_interface(Gfx *gdl) -{ - s32 ulx; - s32 uly; - s32 lrx; - s32 lry; - s32 doblood; - s32 scenario; - s32 cur; - s32 count; - s32 i; - s32 total; - - if (g_CurrentPlayer->cameramode == 1) - { - bondviewIntroCameraTextTick(); - gdl = hudmsgBottomRender(gdl); - bondviewUpperTextWindowTimerTick(); - gdl = sub_GAME_7F08AAE8(gdl); - gdl = countdownTimerRender(gdl); - gdl = currentPlayerDrawFade(gdl); - return bondviewRenderCredits(gdl); - } - - gunUpdateAndFireBothHands(); - gunRenderCasings(&gdl); - gunRenderFirstPersonGunModels(&gdl); - gdl = bondviewRenderWatch(gdl); - - if (g_CurrentPlayer->mpmenuon != 0) - { - ulx = viGetViewLeft(); - uly = viGetViewTop(); - lrx = viGetViewLeft() + viGetViewWidth(); - lry = viGetViewTop() + viGetViewHeight(); - gdl = microcode_constructor(gdl); - gdl = microcode_constructor_related_to_menus(gdl, ulx, uly, lrx, lry, 160); - } - - if (bondviewGetIfCurrentPlayerHealthShowTime() && - (g_CurrentPlayer->watch_animation_state == 0)) - { - gdl = bondviewRenderGaugeBars(gdl); - } - else if (mpwatchShouldDisplayGauges()) - { - gdl = bondviewRenderGaugeBars(gdl); - if (g_CurrentPlayer->healthdisplaytime > 0) - { - g_CurrentPlayer->healthdisplaytime -= g_ClockTimer; - } - if (g_CurrentPlayer->healthdisplaytime < 0) - { - g_CurrentPlayer->healthdisplaytime = 0; - } - } - - if (getPlayerCount() == 1) - { - display_objective_status_text_on_status_change(); - } - - if (g_CurrentPlayer->bonddead != 0) - { - if (g_CurrentPlayer->deathanimfinished == 0) - { - doblood = 0; - if (g_CurrentPlayer->bonddead == 1) - { - doblood = 1; - g_CurrentPlayer->bonddead = 2; - } - if (doblood) - { - die_blood_image_routine(0); - if (getPlayerCount() == 1) - { - // This unusual comma-expression syntax is required for a byte match. - set_missionstate((musicStopSlot(-1), 0)); - musicTrack1ApplySeqpVol(sub_GAME_7F0C0BF0()); - g_musicXTrack1Fade = 0; - musicTrack2ApplySeqpVol(0); - g_musicXTrack2Fade = 0; - musicTrack1Play(27); - } - else - { - set_missionstate(6); - } - } - else - { - if (g_CurrentPlayer->redbloodfinished) - { - currentPlayerSetFadeColour(150, 0, 0, 0.7058824f); - } - else - { - if (g_ClockTimer > 0) - { - doblood = 1; - } - else - { - doblood = 2; - } - if (die_blood_image_routine(doblood)) - { - g_CurrentPlayer->redbloodfinished = TRUE; - } - gdl = gameplayBloodOverlayDL(gdl); - } - } - } - if (modelGetAnimFrame(&g_CurrentPlayer->model) >= - modelGetAnimEndFrame(&g_CurrentPlayer->model)) - { - if (g_CurrentPlayer->redbloodfinished) - { - if (!g_CurrentPlayer->deathanimfinished) - { - g_CurrentPlayer->deathanimfinished = TRUE; - currentPlayerAdjustFade(60.0f, 0, 0, 0, 1.0f); - currentPlayerStartChrFade(120.0f, 0.0f); - } - if (currentPlayerIsFadeComplete()) - { - if (getPlayerCount() == 1) - { - bondviewSetCameraMode(CAMERAMODE_DEATH_CAM_SP); - } - else - { - scenario = get_scenario(); - cur = get_cur_playernum(); - count = getPlayerCount(); - total = 0; - for (i = 0; i < count; i++) - { - total += g_playerPlayerData[i].kill_counts[cur]; - } - if ((scenario != SCENARIO_YOLT) || (total < 2)) - { - if (joyGetButtons(get_cur_playernum(), 0xB000)) - { - mp_respawn_handler(); - } - } - } - } - } - } - } - - bondviewIntroCameraTextTick(); - gdl = hudmsgBottomRender(gdl); - bondviewUpperTextWindowTimerTick(); - gdl = sub_GAME_7F08AAE8(gdl); - gunDrawSight(&gdl); - gdl = generate_ammo_total_microcode(gdl); - gdl = countdownTimerRender(gdl); - gdl = display_red_blue_on_radar(gdl); - return currentPlayerDrawFade(gdl); -} - - - - - -/** - * Address 0x7F0896C0. - */ -Gfx *write_stan_tiles_in_yellow(Gfx *gdl) -{ - if (dword_CODE_bss_80079DA0 != NULL) - { - gdl = sub_GAME_7F0B3024(gdl, dword_CODE_bss_80079DA0, 0xFF00FF80U); - } - - if (dword_CODE_bss_80079DA4 != NULL) - { - gdl = sub_GAME_7F0B3024(gdl, dword_CODE_bss_80079DA4, 0xFF00FF80U); - } - - return gdl; -} - - -void sub_GAME_7F089718(f32 arg0) -{ - f32 scalar; - struct collision434* col; - - scalar = D_800364D0 / arg0; - - col = &g_CurrentPlayer->field_488; - col->collision_position.x *= scalar; - col->collision_position.z *= scalar; - - D_800364D0 = arg0; - D_800364D4 = 1.0f / arg0; -} - - -void sub_GAME_7F08976C(f32 param_1) -{ - D_800364CC = param_1; -} - - -/** - * Address 0x7F089778. - */ -f32 bondviewGetPlayerStanHeight(struct player *player) -{ - return player->stanHeight; -} - - -/** - * Address 0x7F089780. - */ -f32 bondviewGetPlayerDuckingHeightRelated(struct player *player) -{ - return player->eyeheight + player->field_88 + player->ducking_height_offset; -} - - -PropRecord* getCurrentPlayerProp(void) { - return g_CurrentPlayer->prop; -} - - -/** - * Address 0x7F0897A8. - */ -void bondviewKillCurrentPlayer(void) -{ - if ((g_CurrentPlayer->cheatBondInvincible == 0) && (g_CurrentPlayer->bonddead == FALSE)) - { - if (g_CurrentPlayer->watch_animation_state != WATCH_ANIMATION_0x0) - { - trigger_solo_watch_menu(1); - } - - g_isBondKIA = 1; - g_CurrentPlayer->bonddead = 1; - - g_CurrentPlayer->previous_collision_info = g_CurrentPlayer->field_488; - - g_CurrentPlayer->thetadie = g_CurrentPlayer->vv_theta; - g_CurrentPlayer->vertadie = g_CurrentPlayer->vv_verta; - - if (g_PlayerTankProp != NULL) - { - g_ExplodeTankOnDeathFlag = 1; - } - - currentPlayerEquipWeaponWrapper(GUNLEFT, 0); - currentPlayerEquipWeaponWrapper(GUNRIGHT, 0); - - if ((getMissiontimer() - g_CurrentPlayer->lifestarttime60) < g_playerPerm->shortest_inning) - { - g_playerPerm->shortest_inning = getMissiontimer() - g_CurrentPlayer->lifestarttime60; - } - - g_CurrentPlayer->lifestarttime60 = getMissiontimer(); - } -} - - -/** - * Unreferenced. - * - * Address 0x7F0898E8. - */ -s32 sub_GAME_7F0898E8(void) -{ - return (s32) ((joyGetStickY(0) * 8) + 0x280) / 0xA0; -} - - -/** - * @param damage_amount: damage amount - * @param vectorx: damage source x coordinate - * @param vectorz: damage source y coordinate - * @param playerid: player index of player causing the damage - * @param arg4: boolean, does the damage apply to body armor (e.g. false when gas) - * - * Address US 7F08991C. - * Address EU 7F089A84. - * Address JP 7F089FF0. - */ -void record_damage_kills(f32 damage_amount, f32 vectorx, f32 vectorz, s32 playerid, s32 affects_armor) { - f32 damage_dealt = g_playerPerm->handicap * damage_amount; - s32 cur_player_num; - f32 angle; - s32 padding; - s32 sp2C; - s32 sp28; - - if (g_CurrentPlayer->watch_animation_state != WATCH_ANIMATION_0x0) - { - hudMakeDamageSegments(g_CurrentPlayer->armor_display_values, 0x2E, 1, currentPlayerGetArmor()); - hudMakeDamageSegments(g_CurrentPlayer->health_display_values, 0x2E, -1, currentPlayerGetHealth()); - } - - if (getPlayerCount() < 2 || (g_stopPlayFlag == 0 && g_gameOverFlag == 0)) - { - if (g_PlayerIsInTank == 1) - { - damage_dealt *= 0.25f; - } - - if (g_CurrentPlayer->bonddead == FALSE && g_CurrentPlayer->cheatBondInvincible == FALSE) - { - joyRumblePakStart(get_cur_playernum(), 0.25); - if (cur_player_get_control_type() >= 4) - { - // rumble second controller in 2.x - joyRumblePakStart(get_cur_playernum() + getPlayerCount(), 0.25); - } - } - - if (getPlayerCount() >= 2 && get_scenario() == SCENARIO_LTK) - { - // the damage dealt is always equivalent to how much health and armor the player has - // the result of this is to always kill the player regardless of how much damage he can sustain - damage_dealt = (g_CurrentPlayer->bondhealth * g_CurrentPlayer->actual_health) + (g_CurrentPlayer->bondarmour * g_CurrentPlayer->actual_armor); - } - - if (g_CurrentPlayer->cheatBondInvincible == FALSE && g_CurrentPlayer->bonddead == FALSE && g_PlayerInvincible == FALSE && - (g_CurrentPlayer->damageshowtime < 0 || (getPlayerCount() >= 2 && g_CurrentPlayer->damageshowtime == 0))) - { - if (g_CurrentPlayer->watch_animation_state != WATCH_ANIMATION_0x5 && g_CurrentPlayer->watch_animation_state != WATCH_ANIMATION_0xc) - { - g_CurrentPlayer->oldhealth = g_CurrentPlayer->bondhealth; - g_CurrentPlayer->oldarmour = g_CurrentPlayer->bondarmour; - - if (getPlayerCount() >= 2) - { - cur_player_num = get_cur_playernum(); - angle = g_playerPointers[cur_player_num]->vv_theta - (360.0f - ((atan2f(vectorx, vectorz) * 180.0f) / 3.1415927f)); - - if (angle < 0.0f) - { - angle = -angle; - } - - if (angle < 90.0f || angle > 270.0f) - { - // danger: if Bond could be damaged by toxic gas in multiplayer, playerid would be -1 - // thus causing an out of bounds access - g_playerPlayerData[playerid].damage_to_backside++; - } - } - - if (affects_armor && damage_dealt <= g_CurrentPlayer->bondarmour * g_CurrentPlayer->actual_armor) - { - g_CurrentPlayer->bondarmour = g_CurrentPlayer->bondarmour - (damage_dealt / g_CurrentPlayer->actual_armor); - } - else - { - if (affects_armor) - { - damage_dealt -= g_CurrentPlayer->bondarmour / g_CurrentPlayer->actual_armor; - g_CurrentPlayer->bondarmour = 0.0f; - g_CurrentPlayer->actual_armor = 1.0f; - } - - g_CurrentPlayer->bondhealth = g_CurrentPlayer->bondhealth - (damage_dealt / g_CurrentPlayer->actual_health); - - if (g_CurrentPlayer->bondhealth <= 0.0f) - { - if (getPlayerCount() >= 2) - { - sp2C = get_cur_playernum(); - sp28 = 0; - - if (get_scenario() == 3 && bondinvHasGoldenGun()) - { - sp28 = 1; - } - -#if defined(VERSION_EU) || defined(VERSION_JP) - drop_inventory(); -#endif - if (sp2C != playerid) - { -#if defined(VERSION_US) - drop_inventory(); -#endif - increment_num_deaths(); - } - - set_cur_player(playerid); - - if (sp2C == playerid) - { - increment_num_suicides_display_MP(); - } - else - { - increment_num_kills_display_text_in_MP(); - - if (sp28 != 0) - { - increment_num_times_killed_MwtGC(); - } - } - - set_cur_player(sp2C); - - if(1); - - g_playerPlayerData[playerid].kill_counts[sp2C]++; - } - - bondviewKillCurrentPlayer(); - } - } - -#if defined(VERSION_EU) || defined(VERSION_JP) - #define ZERO_7F08991C 0.0f -#else - #define ZERO_7F08991C 0 -#endif - if (g_CurrentPlayer->damageshowtime < ZERO_7F08991C) - { - g_CurrentPlayer->bondshotspeed.x = g_CurrentPlayer->bondshotspeed.x + 2.0f * vectorx; - g_CurrentPlayer->bondshotspeed.z = g_CurrentPlayer->bondshotspeed.z + 2.0f * vectorz; - } - - g_CurrentPlayer->damageshowtime = ZERO_7F08991C; - g_CurrentPlayer->healthshowtime = ZERO_7F08991C; - -#undef ZERO_7F08991C - -#if defined(VERSION_EU) || defined(VERSION_JP) - if (!lvlGetControlsLockedFlag()) - { - sndPlaySfx(g_musicSfxBufferPtr, BOND_GET_HIT1_SFX, 0); - } -#else - sndPlaySfx(g_musicSfxBufferPtr, BOND_GET_HIT1_SFX, 0); -#endif - } - } - } -} - - -/** - * @param damage_amount: damage amount - * @param rad: damage source angle - * @param player_id: player index of player causing the damage - * @param affects_armor: boolean, does the damage apply to body armor (e.g. false when gas) - * - * Address 0x7F089E4C. - */ -void bondviewCallRecordDamageKills(f32 damage_amount, f32 angle, s32 playerid, s32 affects_armor) -{ - record_damage_kills(damage_amount, sinf(angle), cosf(angle), playerid, affects_armor); -} - - -int bondviewGetIfCurrentPlayerDamageShowTime(void) -{ - return (g_CurrentPlayer->damageshowtime >= (s32)0); -} - - -int bondviewGetIfCurrentPlayerHealthShowTime(void) -{ - return (g_CurrentPlayer->healthshowtime > (s32)0); -} - - -f32 bondviewGetBondBreathing(void) -{ - return g_CurrentPlayer->bondbreathing; -} - - -/** - * Gets the current player's heading angle, converted from degrees to radians. - * @return Heading (Yaw) in Radians -*/ -f32 bondviewGetPlayerYawRadians(void) -{ - return DegToRad(360.0f - g_CurrentPlayer->vv_theta); -} - - -/** - * Gets the current player's vertical look angle, converted from degrees to radians. - * @return Pitch in radians. - */ -f32 bondviewGetPlayerPitchRadians(void) -{ - return DegToRad(g_CurrentPlayer->vv_verta); -} - - -s32 bond_pressed_reload_activate(void) { - return g_CurrentPlayer->field_D0; -} - - -void set_bondata_invincible_flag(u32 arg0) { - g_CurrentPlayer->cheatBondInvincible = arg0; -} - - -u8 get_bondata_invincible_flag(void) { - return g_CurrentPlayer->cheatBondInvincible; -} - - -/** - * Sets g_VisibleToGuardsFlag. - * 1 = visible, 0 = not visible. - */ -void bondviewSetVisibleToGuardsFlag(s32 param_1) -{ - g_VisibleToGuardsFlag = param_1; -} - -/** - * Gets g_VisibleToGuardsFlag. - * 1 = visible, 0 = not visible - */ -s32 bondviewGetVisibleToGuardsFlag(void) -{ - return g_VisibleToGuardsFlag; -} - -void set_obj_collision_flag(s32 flag) { - obj_collision_flag = flag; -} - -s32 get_obj_collision_flag(void) { - return obj_collision_flag; -} - - - - - - -/** - * Address 0x7F089F98. - */ -u8 bondviewGetCurrentPlayersRoom(void) -{ - if ((g_CurrentPlayer->cameramode == 1) && (g_CurrentPlayer->cameratile != 0)) - { - return g_CurrentPlayer->cameratile->room; - } - - return g_CurrentPlayer->field_488.current_tile_ptr_for_portals->room; -} - - - - -/** - * Address 0x7F089FD4. - */ -coord3d *bondviewGetCurrentPlayersPosition(void) -{ - if (g_CurrentPlayer->cameramode == 1) - { - return &g_CurrentPlayer->pos; - } - - return &g_CurrentPlayer->field_488.pos; -} - - - -coord3d * bondviewGetCurrentPlayersPosition3(void) -{ - - if (g_CurrentPlayer->cameramode == 1) - { - return &g_CurrentPlayer->pos3; - } - - return &g_CurrentPlayer->field_488.pos3; -} - -struct coord3d *getCurrentPlayerPrevPos(void) -{ - return &g_CurrentPlayer->bondprevpos; -} - - -/** - * Address 0x7F08A03C. - */ -void bondviewUpdateGuardTankFlagsRelated(PropRecord *prop, s32 flag) -{ - s32 playerIndex; - - playerIndex = getPlayerPointerIndex(prop); - - if (prop->chr != NULL) - { - chrSetMoving(prop->chr, flag); - } - - if (g_PlayerTankProp != NULL) - { - // When commented out tank shells fired from the tank detonate immediately. - sub_GAME_7F04F218(g_PlayerTankProp, flag); - } - - g_playerPointers[playerIndex]->field_AC = flag; -} - - - - - -/** - * Address 0x7F08A0B0. - */ -void bondviewGetPropHeightRelatedValues(PropRecord *arg0, struct rect4f **field_B0, s32 *arg2, f32 *height_related, f32 *collision) -{ - s32 temp_v0; - - temp_v0 = getPlayerPointerIndex(arg0); - if (g_playerPointers[temp_v0]->field_AC != 0) - { - // What is this doing and why is it 1 player only? - if (getPlayerCount() == 1 || g_playerPointers[temp_v0]->bonddead == FALSE) - { - if (g_playerPointers[temp_v0]->cameramode != 1) - { - *arg2 = 4; - *field_B0 = &g_playerPointers[temp_v0]->collision_bounds; - *collision = g_playerPointers[temp_v0]->field_70; - *height_related = *collision + bondviewGetPlayerDuckingHeightRelated(g_playerPointers[temp_v0]) + 10.0f; - - return; - } - } - } - - *arg2 = 0; -} - - - - -/** - * Address 0x7F08A19C. - */ -void bondviewUpdatePlayerCollisionBounds(void) -{ - - if (g_PlayerIsInTank == 1) - { - bondviewGetTankCollisionBounds(&g_CurrentPlayer->collision_bounds, &g_CurrentPlayer->field_488.collision_position, g_TankOrientationAngle); - - return; - } - - g_CurrentPlayer->collision_bounds.f[0] = (g_CurrentPlayer->field_488.collision_position.f[0] + g_CurrentPlayer->field_488.collision_radius); - g_CurrentPlayer->collision_bounds.f[1] = g_CurrentPlayer->field_488.collision_position.f[2]; - g_CurrentPlayer->collision_bounds.f[2] = g_CurrentPlayer->field_488.collision_position.f[0]; - g_CurrentPlayer->collision_bounds.f[3] = (g_CurrentPlayer->field_488.collision_position.f[2] + g_CurrentPlayer->field_488.collision_radius); - g_CurrentPlayer->collision_bounds.f[4] = (g_CurrentPlayer->field_488.collision_position.f[0] - g_CurrentPlayer->field_488.collision_radius); - g_CurrentPlayer->collision_bounds.f[5] = g_CurrentPlayer->field_488.collision_position.f[2]; - g_CurrentPlayer->collision_bounds.f[6] = g_CurrentPlayer->field_488.collision_position.f[0]; - g_CurrentPlayer->collision_bounds.f[7] = (g_CurrentPlayer->field_488.collision_position.f[2] - g_CurrentPlayer->field_488.collision_radius); -} - - - - - -/** - * @param arg0: prop - * @param width: out parameter, will be set to field_488.collision_radius - * @param height: out parameter, will be set to character height - 30 - * @param always_30: out parameter, will be set to 30 - * - * Address 0x7F08A274. - */ -void bondviewGetCollisionRadius(PropRecord* arg0, f32 *collision_radius, f32 *height, f32 *always_30) -{ - struct player **temp_v1; - - temp_v1 = &g_playerPointers[getPlayerPointerIndex(arg0)]; - *collision_radius = (*temp_v1)->field_488.collision_radius; - *height = (bondviewGetPlayerDuckingHeightRelated(*temp_v1) + 10.0f) - 30.0f; - *always_30 = 30.0f; -} - - - - - -/** - * Address 0x7F08A2EC. - */ -f32 currentPlayerGetHealth(void) -{ - return g_CurrentPlayer->bondhealth; -} - - -f32 currentPlayerGetArmor(void) -{ - return g_CurrentPlayer->bondarmour; -} - - - - - -/** - * Address 0x7F08A30C. - */ -void bondviewAddCurrentPlayerArmor(f32 arg0) -{ - g_playerPerm->body_armor_pickups += arg0; - g_CurrentPlayer->bondarmour = arg0; -} - - - - - -/** - * Address 0x7F08A330. - */ -void bondviewResetIntroCameraMessageDialogs(void) -{ - g_CurrentPlayer->hudmessoff = FALSE; - g_CurrentPlayer->bondmesscnt = -1; - display_statusbar = 0; - status_bar_text_buffer_index = 0; - -#ifdef BUGFIX_R0 - copy_1stfonttable = ptrFontBankGothic; - copy_2ndfonttable = ptrFontBankGothicChars; -#endif -} - - - -void hudmsgsSetOn(s32 flag) -{ - g_CurrentPlayer->hudmessoff &= ~flag; -} - - - - - -/** - * Address 0x7F08A39C. - */ -void hudmsgsSetOff(s32 flags) -{ - g_CurrentPlayer->hudmessoff |= flags; -} - - -#ifdef VERSION_US -void setFontTables(s32 arg0, s32 arg1) -{ - copy_2ndfonttable = arg0; - copy_1stfonttable = arg1; -} -#endif - - -#ifdef BUGFIX_R1 -void hudmsgBottomShow(char *string, s32 font, s32 arg2) -{ - s32 abs_index; - s32 index; - if (getPlayerCount() == 1) - { - if (display_statusbar < 5) - { - abs_index = status_bar_text_buffer_index + display_statusbar; - index = abs_index % 5; - abs_index = index; - strncpy(stringbuffer_lowerleft[abs_index], string, (BONDVIEW_HUD_MSG_BOTTOM_BUFFER_LENGTH-1)); - stringbuffer_lowerleft[abs_index][(BONDVIEW_HUD_MSG_BOTTOM_BUFFER_LENGTH-1)] = 0; - dword_CODE_bss_jp80079CEC[abs_index] = font; - dword_CODE_bss_jp80079Cd8[abs_index] = arg2; - display_statusbar++; - } - } - else - { - index = get_cur_playernum(); - strncpy(stringbuffer_lowerleft[index], string, (BONDVIEW_HUD_MSG_BOTTOM_BUFFER_LENGTH-1)); - stringbuffer_lowerleft[index][(BONDVIEW_HUD_MSG_BOTTOM_BUFFER_LENGTH-1)] = 0; - dword_CODE_bss_jp80079CEC[index] = font; - dword_CODE_bss_jp80079Cd8[index] = arg2; -#if defined(VERSION_EU) - g_CurrentPlayer->bondmesscnt = 0x64; -#elif defined(VERSION_JP) - g_CurrentPlayer->bondmesscnt = 0x78; -#endif - } -} - -#else -#ifdef DEBUG -void hudmsgBottomShow(char *mess, void *font) -#else -void hudmsgBottomShow(char *mess) -#endif -{ - s32 abs_index; - s32 index; - #ifdef DEBUG - assert(font); - assert(strlen(mess)<=MAXMESSAGELEN); - #endif - if (getPlayerCount() == 1) - { - if (display_statusbar < 5) - { - abs_index = status_bar_text_buffer_index + display_statusbar; - index = abs_index % 5; - strncpy(stringbuffer_lowerleft[index], mess, MAXMESSAGELEN); - display_statusbar++; - stringbuffer_lowerleft[index][MAXMESSAGELEN] = 0; - } - } - else - { - index = get_cur_playernum(); - strncpy(stringbuffer_lowerleft[index], mess, MAXMESSAGELEN); - stringbuffer_lowerleft[index][MAXMESSAGELEN] = 0; - g_CurrentPlayer->bondmesscnt = 0x78; - } -} - -#endif - - -#if defined(BUGFIX_R1) -void jp_hudmsgBottomShow(char *string) -{ - hudmsgBottomShow(string, ptrFontBankGothicChars, ptrFontBankGothic); -} -#endif - - -/** - * Address 0x7F08A4E4. - */ -void bondviewIntroCameraTextTick(void) -{ - if ((g_CurrentPlayer->hudmessoff == FALSE) && (g_CurrentPlayer->mpmenuon == FALSE)) - { - if (g_CurrentPlayer->bondmesscnt >= 0) - { - g_CurrentPlayer->bondmesscnt -= g_ClockTimer; - - if (getPlayerCount() == 1) - { - if (g_CurrentPlayer->bondmesscnt < 0) - { - status_bar_text_buffer_index = (s32) (status_bar_text_buffer_index + 1) % 5; - display_statusbar = display_statusbar - 1; - } - else if ((display_statusbar >= 2) && (g_CurrentPlayer->bondmesscnt >= BONDVIEW_INTRO_CAMERA_BONDMESSCNT_A)) - { - g_CurrentPlayer->bondmesscnt = BONDVIEW_INTRO_CAMERA_BONDMESSCNT_B; - } - } - } - - if ((getPlayerCount() == 1) && (g_CurrentPlayer->bondmesscnt < 0) && (display_statusbar > 0)) - { - if (display_statusbar >= 2) - { - g_CurrentPlayer->bondmesscnt = BONDVIEW_INTRO_CAMERA_BONDMESSCNT_B; - } - else - { - g_CurrentPlayer->bondmesscnt = BONDVIEW_INTRO_CAMERA_BONDMESSCNT_C; - } - } - } -} - - -/** - * Address: 7F08A5FC - */ -Gfx* hudmsgBottomRender(Gfx* arg0) -{ - s32 var_v1; - s32 view_left; - s32 view_vert; - s32 view_horiz; - s32 view_top; - s32 view_top_offset; - s32 view_left_offset; - - if ((g_CurrentPlayer->hudmessoff == FALSE) && (g_CurrentPlayer->bondmesscnt >= 0) && (g_CurrentPlayer->mpmenuon == FALSE)) - { - var_v1 = 0; - if (getPlayerCount() == 1) - { - if ((u8) *stringbuffer_lowerleft[status_bar_text_buffer_index] != 0) - { - var_v1 = 1; - } - } - else if (g_CurrentPlayer->bondmesscnt >= 0) - { - status_bar_text_buffer_index = get_cur_playernum(); - var_v1 = 1; - } - - if (var_v1 != 0) - { - arg0 = microcode_constructor(arg0); - view_left_offset = 0; - view_top_offset = 0; - textMeasure(&view_top_offset, &view_left_offset ,(u8* ) stringbuffer_lowerleft[status_bar_text_buffer_index], BONDVIEW_2ND_FONTTABLE(status_bar_text_buffer_index), BONDVIEW_1ST_FONTTABLE(status_bar_text_buffer_index), 0); - - if (getPlayerCount() < 3) - { - view_left = viGetViewLeft() + 0x1E; - } - else if (get_cur_playernum() & 1) - { - view_left = viGetViewLeft() + 0xA; - } - else - { - view_left = viGetViewLeft() + 0x1E; - } - - view_horiz = view_left + view_left_offset; - - if (getPlayerCount() < 3) - { - if ((get_ammo_type_for_weapon(getCurrentPlayerWeaponId(GUNLEFT)) == 0) && (is_clock_drawn_onscreen() == 0)) - { - view_top = (viGetViewTop() + viGetViewHeight()) - BONDVIEW_VIEW_TOP_OFFSET_1; - } - else - { - view_top = (viGetViewTop() + viGetViewHeight()) - BONDVIEW_VIEW_TOP_OFFSET_2; - } -#if !defined(VERSION_EU) - if (get_cur_playernum() == 1) - { - view_top -= 8; - } -#endif - } - else - { - view_top = viGetViewTop() -#if defined(VERSION_JP) || defined(VERSION_EU) - + (((j_text_trigger != 0) && (get_cur_playernum() < 2)) ? 8 : 0) -#endif - + BONDVIEW_VIEW_TOP_OFFSET_3; - } - - view_vert = view_top - view_top_offset; - arg0 = draw_blackbox_to_screen(arg0, (s32) &view_left, (s32) &view_vert, (s32) &view_horiz, (s32) &view_top); - arg0 = combiner_bayer_lod_perspective(textRenderOutlined(arg0, &view_left, &view_vert, stringbuffer_lowerleft[status_bar_text_buffer_index], BONDVIEW_2ND_FONTTABLE(status_bar_text_buffer_index), BONDVIEW_1ST_FONTTABLE(status_bar_text_buffer_index), -1, 0x646464FFU, (s16) (s32) viGetX(), (s16) viGetY(), 0, 0)); - } - } - - return arg0; -} - - -void bondviewResetUpperTextDisplay(void) -{ - upper_text_window_timer = -1; - display_upper_text_window = 0; - upper_text_buffer_index = 0; - g_UpperTextDisplayFlag = 0; -} - - -void bondviewClearUpperTextDisplayFlag(int param_1) -{ - int new_var; - new_var = ~param_1; - g_UpperTextDisplayFlag = g_UpperTextDisplayFlag & new_var; -} - - -void bondviewSetUpperTextDisplayFlag(PLAYERFLAG flag) -{ - g_UpperTextDisplayFlag |= flag; -} - - -void hudmsgTopShow(char* mess) -{ - s32 index; - #ifdef DEBUG - assert(strlen(mess)<=MAXTALKMESSLEN); - #endif - if (display_upper_text_window >= 2) { return; } - - index = (upper_text_buffer_index + display_upper_text_window) % 2; -#if defined(LEFTOVERDEBUG) - strncpy(stringbuffer_top[index], mess, (BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH-1)); - display_upper_text_window += 1; - stringbuffer_top[index][(BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH-1)] = 0; -#else - strncpy(dword_CODE_bss_80079DC8[index], mess, (BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH-1)); - display_upper_text_window += 1; - dword_CODE_bss_80079DC8[index][(BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH-1)] = 0; -#endif -} - - -/** - * Address 0x7F08A9F8. - */ -void bondviewUpperTextWindowTimerTick(void) -{ - if ((g_UpperTextDisplayFlag == FALSE) && (g_CurrentPlayer->mpmenuon == FALSE)) - { - if (upper_text_window_timer >= 0) - { - upper_text_window_timer -= g_ClockTimer; - - if (upper_text_window_timer < 0) - { - upper_text_buffer_index = (s32) (upper_text_buffer_index + 1) % 2; - display_upper_text_window += -1; - } - else if ((display_upper_text_window >= 2) && (upper_text_window_timer >= BONDVIEW_UPPER_TEXT_TIMER_A)) - { - upper_text_window_timer = BONDVIEW_UPPER_TEXT_TIMER_B; - } - } - - if ((upper_text_window_timer < 0) && (display_upper_text_window > 0)) - { - if (display_upper_text_window >= 2) - { - upper_text_window_timer = BONDVIEW_UPPER_TEXT_TIMER_B; - } - else - { - upper_text_window_timer = BONDVIEW_UPPER_TEXT_TIMER_C; - } - } - } - -} - - -extern char a8s[]; /* "%8s" */ -extern char aX4_0f[]; /* "x %4.0f" */ -extern char aY4_0f[]; /* "y %4.0f" */ -extern char aZ4_0f[]; /* "z %4.0f" */ -extern char aS3d[]; /* "%s %3d" */ - - -Gfx *sub_GAME_7F08AAE8(Gfx *gdl) -{ - TopMessageLocals msg; - DebugTextBuffers debugtext; - s32 debug_x; - s32 debug_y; - f32 theta_x; - s32 debug_boxbottom; - s32 pad; - s32 *roomid; - s32 debug_angle; - DirectionLabels directions; - - struct - { - s16 screenwidth; - s16 pad; - } sw; - - if (g_UpperTextDisplayFlag == 0) - { - if (upper_text_window_timer >= 0) - { -#if defined(LEFTOVERDEBUG) - if (stringbuffer_top[upper_text_buffer_index][0] != '\0') -#else - if (dword_CODE_bss_80079DC8[upper_text_buffer_index][0] != '\0') -#endif - { - if (g_CurrentPlayer->mpmenuon == 0) - { - gdl = microcode_constructor(gdl); - msg.textwidth = 0; - msg.textheight = 0; -#if defined(LEFTOVERDEBUG) - textMeasure(&msg.textheight, &msg.textwidth, stringbuffer_top[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, 0); -#else - textMeasure(&msg.textheight, &msg.textwidth, dword_CODE_bss_80079DC8[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, 0); -#endif - if (cameraBufferToggle != 0) - { - msg.x = viGetViewLeft() + 0x46; - msg.y = viGetViewTop() + 0x10; - msg.y += 0x10; - msg.y = msg.y / 11; - msg.y *= 11; - msg.y -= 2; - } - else - { - msg.x = viGetViewLeft() + 0x1e; -#ifdef VERSION_EU - msg.y = viGetViewTop() + 0x10; -#else - msg.y = viGetViewTop() + 0xd; -#endif - } - - msg.bottom = msg.y + msg.textheight; - gdl = microcode_constructor_related_to_menus(gdl, 0, msg.y - 2, viGetX(), msg.bottom, 0x64); -#ifdef VERSION_US - sw.screenwidth = viGetX(); - gdl = textRender(gdl, &msg.x, &msg.y, stringbuffer_top[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, -1, sw.screenwidth, viGetY(), 0, 0); -#else - if (j_text_trigger != 0) - { - sw.screenwidth = viGetX(); -#if defined(LEFTOVERDEBUG) - gdl = textRenderOutlined(gdl, &msg.x, &msg.y, stringbuffer_top[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, -1, 0x646464FF, sw.screenwidth, viGetY(), 0, 0); -#else - gdl = textRenderOutlined(gdl, &msg.x, &msg.y, dword_CODE_bss_80079DC8[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, -1, 0x646464FF, sw.screenwidth, viGetY(), 0, 0); -#endif - } - else - { - sw.screenwidth = viGetX(); -#if defined(LEFTOVERDEBUG) - gdl = textRender(gdl, &msg.x, &msg.y, stringbuffer_top[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, -1, sw.screenwidth, viGetY(), 0, 0); -#else - gdl = textRender(gdl, &msg.x, &msg.y, dword_CODE_bss_80079DC8[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, -1, sw.screenwidth, viGetY(), 0, 0); -#endif - } -#endif - gdl = combiner_bayer_lod_perspective(gdl); - goto end; - } - } - } - } - - if (get_debug_testingmanpos_flag()) - { - theta_x = g_CurrentPlayer->field_488.theta_transform.x; - debug_angle = (s32) ((atan2f(-theta_x, g_CurrentPlayer->field_488.theta_transform.z) * 180.0f) / M_PI_F); - directions = g_DebugCompassLabels; - roomid = bgDebPrintROOMID(g_CurrentPlayer->field_488.current_tile_ptr->room); - - sprintf(debugtext.room, a8s, roomid); - sprintf(debugtext.x, aX4_0f, g_CurrentPlayer->field_488.collision_position.x); - sprintf(debugtext.y, aY4_0f, g_CurrentPlayer->field_488.collision_position.y); - sprintf(debugtext.z, aZ4_0f, g_CurrentPlayer->field_488.collision_position.z); - sprintf(debugtext.angle, aS3d, ((char *) (&directions)) + (((debug_angle + 0x16) / 0x2d) * 3), debug_angle); - - debug_x = viGetViewLeft() + 0x11; - debug_y = viGetViewTop() + 0x11; - debug_boxbottom = debug_y + 0xa; - gdl = microcode_constructor(gdl); - gdl = microcode_constructor_related_to_menus(gdl, 0, debug_y, viGetX(), debug_boxbottom + 1, 0x64); - sw.screenwidth = viGetX(); - gdl = textRender(gdl, &debug_x, &debug_y, debugtext.room, ptrFontBankGothicChars, ptrFontBankGothic, -1, sw.screenwidth, viGetY(), 0, 0); - debug_x = viGetViewLeft() + 0x57; - sw.screenwidth = viGetX(); - gdl = textRender(gdl, &debug_x, &debug_y, debugtext.x, ptrFontBankGothicChars, ptrFontBankGothic, -1, sw.screenwidth, viGetY(), 0, 0); - debug_x = viGetViewLeft() + 0x8d; - sw.screenwidth = viGetX(); - gdl = textRender(gdl, &debug_x, &debug_y, debugtext.y, ptrFontBankGothicChars, ptrFontBankGothic, -1, sw.screenwidth, viGetY(), 0, 0); - debug_x = viGetViewLeft() + 0xc3; - sw.screenwidth = viGetX(); - gdl = textRender(gdl, &debug_x, &debug_y, debugtext.z, ptrFontBankGothicChars, ptrFontBankGothic, -1, sw.screenwidth, viGetY(), 0, 0); - debug_x = viGetViewLeft() + 0xf9; - sw.screenwidth = viGetX(); - gdl = textRender(gdl, &debug_x, &debug_y, debugtext.angle, ptrFontBankGothicChars, ptrFontBankGothic, -1, sw.screenwidth, viGetY(), 0, 0); - gdl = combiner_bayer_lod_perspective(gdl); - } - - end: - return gdl; -} - - -/** - * Address: 0x7F08B0F0 - */ -s32 playerTick(PropRecord *prop) -{ - s32 index; - ChrRecord *chr; - s32 group; - s32 ret; - s32 sub; - PropRecord *leftprop; - f32 mtx[15]; - s32 tailret; - s32 anim; - f32 angle; - f32 frame; - f32 local90; - f32 local8c; - f32 local88; - f32 fwd; - f32 startframe; - struct weapon_firing_animation_table *firingtable; - coord3d off; - s32 i; - s32 found; - s32 cur; - PropRecord *rightprop; - struct WeaponObjRecord *leftobj; - struct WeaponObjRecord *rightobj; - s32 setanim; - struct player **ppointers; - - index = getPlayerPointerIndex(prop); - chr = prop->chr; - - if (chr != NULL) - { - if (get_player_position_in_shuffled(get_cur_playernum()) == 0) - { - chr->hidden &= ~CHRHIDDEN_FREEZE; - } - } - - if (chr != NULL) - { - if ((g_playerPointers[index]->bodyModel != NULL) && (!(get_debug_render_raster() && (g_playerPointers[index]->cameramode != 1)))) - { - g_playerPointers[index]->field_AC = 0; - ret = chrTick(prop); - g_playerPointers[index]->field_AC = 1; - - g_playerPointers[index]->field_488.collision_position.x = g_playerPointers[index]->prop->pos.x; - g_playerPointers[index]->field_488.collision_position.y = g_playerPointers[index]->prop->pos.y; - g_playerPointers[index]->field_488.collision_position.z = g_playerPointers[index]->prop->pos.z; - g_playerPointers[index]->field_488.current_tile_ptr = g_playerPointers[index]->prop->stan; - bondviewUpdatePlayerRoom(g_playerPointers[index]); - - if (prop->flags & PROPFLAG_ONSCREEN) - { - RenderPosView *rp = g_playerPointers[index]->bodyModel->render_pos; - matrix_4x4_multiply_homogeneous(currentPlayerGetViewToWorldMtxf(), (Mtxf *) rp, (Mtxf *) mtx); - g_playerPointers[index]->field_488.pos.x = mtx[12] + (mtx[4] * 7.0f); - g_playerPointers[index]->field_488.pos.y = mtx[13] + (mtx[5] * 7.0f); - g_playerPointers[index]->field_488.pos.z = mtx[14] + (mtx[6] * 7.0f); - } - - return ret; - } - } - - if (chr == NULL) - { - goto clear_and_return; - } - - if (g_playerPointers[index]->bodyModel == NULL) - { - goto clear_and_return; - } - - if (getPlayerCount() < 2) - { - goto clear_and_return; - } - - if (get_cur_playernum() == index) - { - goto clear_and_return; - } - - anim = 0; - firingtable = NULL; - local90 = -1.0f; - frame = -1; - leftprop = chrGetEquippedWeaponProp(chr, GUNLEFT); - rightprop = chrGetEquippedWeaponProp(chr, GUNRIGHT); - leftobj = NULL; - rightobj = NULL; - setanim = 0; - - if (leftprop != NULL) - { - leftobj = leftprop->weapon; - } - - if (rightprop != NULL) - { - rightobj = rightprop->weapon; - } - - ppointers = g_playerPointers; - - if (get_player_position_in_shuffled(get_cur_playernum()) == 0) - { - g_PlayerTickCount = g_PlayerTickCount + 1; - } - - /** - * If the player count is 1 we jump to the bottom of the function with goto clear_and_return, so this block only applies to MP. - * g_PlayerTickCount advances once for each remote player's prop ticked during the pass of the viewport whose player is first in the shuffle order. - * That means g_PlayerTickCount reaches 2 after one frame of a 2 player game, and part way through the first frame of a 3 or 4 player game. - * Nothing *ever* resets g_PlayerTickCount, so we're skipping this whole block only once per boot. The reason for doing this though - * isn't quite clear so do chime in if you have any theories. - */ - if (g_PlayerTickCount >= 2) - { - local8c = ((0, ppointers[index]))->field_2A08; - local88 = ppointers[index]->field_2A0C; - - if (ppointers[index]->bonddead != FALSE) - { - found = 0; - - for (i = 0; i < g_bondviewBondDeathAnimationsCount; i++) - { - cur = ppointers[index]->players_cur_animation; - - if (cur == (g_bondviewBondDeathAnimations[i] + ((s32) ptr_animation_table))) - { - found = 1; - } - } - - if (found) - { - anim = ppointers[index]->players_cur_animation; - angle = 0.5f; - } - else - { - anim = g_bondviewBondDeathAnimations[randomGetNext() % g_bondviewBondDeathAnimationsCount] + ((s32) ptr_animation_table); - angle = 0.5f; - } - - cur = ppointers[index]->players_cur_animation; - local8c = 0.0f; - local88 = 0.0f; - goto join_768; - } - - if ((leftprop != NULL) && (rightprop != NULL)) - { - group = 3; - } - else if ((leftprop == NULL) && (rightprop == NULL)) - { - group = 2; - } - else if ((leftobj != NULL) && (bondwalkItemCheckBitflags(leftobj->weaponnum, WEAPONSTATBITFLAG_HOLD_AS_GUN) == 0)) - { - group = 2; - } - else if ((rightobj != NULL) && (bondwalkItemCheckBitflags(rightobj->weaponnum, WEAPONSTATBITFLAG_HOLD_AS_GUN) == 0)) - { - group = 2; - } - else if ((leftobj != NULL) && (bondwalkItemCheckBitflags(leftobj->weaponnum, WEAPONSTATBITFLAG_ONLY_1_HANDED) != 0)) - { - group = 0; - } - else if ((rightobj != NULL) && (bondwalkItemCheckBitflags(rightobj->weaponnum, WEAPONSTATBITFLAG_ONLY_1_HANDED) != 0)) - { - group = 0; - } - else - { - group = 1; - } - - if (playerGetCrouchPos(index) == 1) - { - goto set_crouch_lean; - } - else if (playerGetCrouchPos(index) == 0) - { -set_crouch_lean: - angle = 1.0f; - sub = 5; - } - else if ((ppointers[index]->speedsideways < 0.0f) && (firing_animation_groups[group][4].pointer != NULL)) - { - sub = 4; - angle = -ppointers[index]->speedsideways; - - if (ppointers[index]->field_1280 < 90.0f) - { - ppointers[index]->field_1280 = ppointers[index]->field_1280 + 15.0f; - } - } - else if ((ppointers[index]->speedsideways > 0.0f) && (firing_animation_groups[group][3].pointer != NULL)) - { - sub = 3; - angle = ppointers[index]->speedsideways; - - if (ppointers[index]->field_1280 > (-90.0f)) - { - ppointers[index]->field_1280 = ppointers[index]->field_1280 - 15.0f; - } - } - else - { - frame = ppointers[index]->speedtheta; - - if (frame < 0.0f) - { - frame = -frame; - } - - fwd = ppointers[index]->speedforwards; - - if (fwd < -0.050000001f) - { - frame = -frame; - - if (fwd < frame) - { - frame = fwd; - } - - if (ppointers[index]->headanim == 0) - { - goto shared_double_neg; - } - - sub = 2; - - if (-0.40000001f < fwd) - { -shared_double_neg: - angle = frame + frame; - sub = 1; - - if (angle < (-1.0f)) - { - angle = -1.0f; - } - } - else - { - angle = frame; - goto lean_return_to_centre; - } - } - else - { - if (0.050000001f < fwd) - { - goto shared_framefwd; - } - else if (0.050000001f < frame) - { -shared_framefwd: - if (frame < fwd) - { - frame = fwd; - } - } - else - { - goto set_full_lean; - } - - if (ppointers[index]->headanim == 0) - { - goto shared_double_pos; - } - - sub = 2; - - if (fwd < 0.40000001f) - { -shared_double_pos: - angle = frame + frame; - sub = 1; - - if (1.0f < angle) - { - angle = 1.0f; - } - } - else - { - angle = frame; - goto lean_return_to_centre; - } - } - - goto lean_return_to_centre; - -set_full_lean: - angle = 1.0f; - sub = 0; - -lean_return_to_centre: - if (0.0f < ppointers[index]->field_1280) - { - ppointers[index]->field_1280 = ppointers[index]->field_1280 - 15.0f; - } - - if (ppointers[index]->field_1280 < 0.0f) - { - ppointers[index]->field_1280 = ppointers[index]->field_1280 + 15.0f; - } - } - - { - struct firing_anim_struct *fa = &firing_animation_groups[group][sub]; - - firingtable = fa->pointer; - - if (fa->anim != 0) - { - anim = fa->anim + (s32) ptr_animation_table; - } - - angle *= fa->x; - local90 = fa->z; - frame = fa->y; - } - - cur = ppointers[index]->players_cur_animation; - -join_768: - if ((firingtable != NULL) && (anim == 0)) - { - anim = *((s32 *) firingtable); - } - - if (anim != cur) - { - setanim = 1; - } - - if (0.0f <= frame) - { - if ((ppointers[index]->bodyModel->animlooping == 0) || (frame != ppointers[index]->bodyModel->animloopframe)) - { - setanim = 1; - } - } - - if (frame < 0.0f) - { - if (ppointers[index]->bodyModel->animlooping) - { - setanim = 1; - } - } - - if (setanim != 0) - { - if (ppointers[index]->bodyModel->anim2 == NULL) - { - startframe = (0.0f <= frame) ? (frame) : (0.0f); - modelSetAnimation(ppointers[index]->bodyModel, (ModelAnimation *) anim, 0, startframe, angle, 16.0f); - ppointers[index]->players_cur_animation = anim; - ppointers[index]->field_1288 = angle; - - if (0.0f <= frame) - { - modelSetAnimLooping(ppointers[index]->bodyModel, frame, 16.0f); - } - - if (0.0f <= local90) - { - modelSetAnimEndFrame(ppointers[index]->bodyModel, local90); - } - } - - cur = ppointers[index]->players_cur_animation; - } - else - { - if (angle != ppointers[index]->field_1288) - { - modelSetAnimSpeed(ppointers[index]->bodyModel, angle, 1.0f); - ppointers[index]->field_1288 = angle; - } - - cur = ppointers[index]->players_cur_animation; - } - - if (anim == cur) - { - if (firingtable != NULL) - { - chr->hidden &= ~CHRHIDDEN_0400; - chrlvUpdateAimendbackShoulders(chr, firingtable, 0, 1, local8c); - } - else - { - chr->aimendrshoulder = 0.0f; - chr->aimendlshoulder = 0.0f; - chr->hidden |= CHRHIDDEN_0400; - chr->aimendback = local8c; - } - } - - chr->aimendsideback = local88; - chr->aimendcount = 10; - } - - prop->pos.x = ppointers[index]->field_488.collision_position.x; - prop->pos.y = ppointers[index]->field_488.collision_position.y; - prop->pos.z = ppointers[index]->field_488.collision_position.z; - prop->stan = ppointers[index]->field_488.current_tile_ptr; - - getsuboffset(chr->model, &off); - off.x = prop->pos.x; - off.z = prop->pos.z; - setsuboffset(chr->model, &off); - setsubroty(chr->model, (((360.0f - ppointers[index]->vv_theta) + ppointers[index]->field_1280) * M_TAU_F) / 360.0f); - - chr->chrflags |= CHRFLAG_INIT; - chr->actiontype = ACT_BONDMULTI; - chr->act_bondmulti.unk2c = (f32 *) firingtable; - - chrSetFiring(chr, GUNRIGHT, ppointers[index]->hands[GUNRIGHT].field_87D); - chrSetFiring(chr, GUNLEFT, ppointers[index]->hands[GUNLEFT].field_87D); - - tailret = chrTick(prop); - - for (i = 0; i != 2; i++) - { - if (sub_GAME_7F02D630(chr, i, &ppointers[index]->field_2A18[i]) != 0) - { - (&ppointers[index]->field_2A30)[i] = D_80048380; - } - else if ((&ppointers[index]->field_2A30)[i] < (D_80048380 - 1)) - { - ppointers[index]->field_2A18[i].x = ppointers[index]->hands[i].field_B58.x; - ppointers[index]->field_2A18[i].y = ppointers[index]->hands[i].field_B58.y; - ppointers[index]->field_2A18[i].z = ppointers[index]->hands[i].field_B58.z; - } - } - - chr->hidden |= CHRHIDDEN_FREEZE; - - prop->pos.x = ppointers[index]->field_488.collision_position.x; - prop->pos.y = ppointers[index]->field_488.collision_position.y; - prop->pos.z = ppointers[index]->field_488.collision_position.z; - prop->stan = ppointers[index]->field_488.current_tile_ptr; - - return tailret; - -clear_and_return: - prop->flags &= ~PROPFLAG_ONSCREEN; - - return TICKOP_NONE; -} - - -/** - * Address 0x7F08BCB8. - */ -Gfx * bondviewRemoved7F08BCB8(Gfx *arg0) -{ - #ifdef DEBUG - // removed - #endif - - return arg0; -} - - -/** - * Address 0x7F08BCC0. - */ -Gfx *bondviewRenderProp(PropRecord *arg0, Gfx *arg1, s32 arg2) -{ - if (arg0->chr != NULL) - { - arg1 = chrRenderProp(arg0, arg1, arg2); - } - - return arg1; -} - - - - - -/** - * Address 0x7F08BCF4. - */ -Gfx* bondviewGfxPlayerField5cMatrix(Gfx* gdl) -{ - gSPMatrix(gdl++, g_CurrentPlayer->field_5C, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - return gdl; -} - - - - - -/** - * Unreferenced. - * - * Address 0x7F08BD18. - */ -void bondviewTransformPosToViewMatrix(RenderPosView *arg0) -{ - Mtxf sp18; - - matrix_4x4_copy(&arg0->pos, (Mtxf *) &sp18); - matrix_4x4_f32_to_s32((Mtxf *) &sp18, &arg0->view); -} - - - -/** - * Address 0x7F08BD48. - * - * Notes: Similar to sub_GAME_7F08BE2C. - * - */ -void bondviewTransformManyPosToViewMatrix(RenderPosView * arg0, s32 arg1) -{ - Mtxf mtx; - RenderPosView* rpv_entry; - s32 i; - - i = 0; - if (arg1 <= 0) { return; } - - // Couldn't find a better matching loop - rpv_entry = arg0; - do - { - matrix_4x4_copy(&rpv_entry->pos, &mtx); - matrix_4x4_f32_to_s32(&mtx, &arg0[i].pos); - i++; - rpv_entry++; - } while (i != arg1); -} - - - -/** - * Unreferenced. - * - * Address 0x7F08BDC4. - */ -void sub_GAME_7F08BDC4(Mtxf *arg0) -{ - Mtxf sp20; - - matrix_4x4_copy(arg0, (Mtxf *) &sp20); - sp20.m[3][0] -= g_CurrentPlayer->previous_model_pos.f[0]; - sp20.m[3][1] -= g_CurrentPlayer->previous_model_pos.f[1]; - sp20.m[3][2] -= g_CurrentPlayer->previous_model_pos.f[2]; - matrix_4x4_f32_to_s32((Mtxf *) &sp20, arg0); -} - - -/** - * Unreferenced. - * - * Address 0x7F08BE2C. - */ -void sub_GAME_7F08BE2C(Mtxf *matrices, s32 count) -{ - Mtxf copy; - s32 i; - - for (i = 0; i < count; i++) - { - matrix_4x4_copy((Mtxf *)((uintptr_t)matrices + i * sizeof(Mtxf)), ©); - - copy.m[3][0] -= g_CurrentPlayer->previous_model_pos.x; - copy.m[3][1] -= g_CurrentPlayer->previous_model_pos.y; - copy.m[3][2] -= g_CurrentPlayer->previous_model_pos.z; - - matrix_4x4_f32_to_s32(©, matrices + i); - } -} - - -void sub_GAME_7F08BEEC(Mtxf *matrices, s32 count) -{ - Mtxf sp40; - s32 i; - s32 j; - - for (i = 0, j = 0; i < count; i++, j += sizeof(Mtxf)) - { - matrix_4x4_multiply_homogeneous(currentPlayerGetViewToWorldMtxf(), (Mtxf *)((u32)matrices + j), &sp40); - - sp40.m[3][0] -= g_CurrentPlayer->current_model_pos.f[0]; - sp40.m[3][1] -= g_CurrentPlayer->current_model_pos.f[1]; - sp40.m[3][2] -= g_CurrentPlayer->current_model_pos.f[2]; - - matrix_4x4_f32_to_s32(&sp40, matrices + i); - } -} - - -s32 getMissiontimer(void) { -#ifdef VERSION_EU - return (mission_timer * 60) / 50; -#else - return mission_timer; -#endif -} - - -void SurroundWithExplosions(int delay) -{ - g_SurroundBondWithExplosionsFlag = 1; - g_SurroundBondWithExplosionsTicks = delay + g_GlobalTimer; - g_PlayerTickExplodeCreatePosition = 0; -} - diff --git a/src/game/bondview2.c b/src/game/bondview2.c new file mode 100644 index 00000000..677ea82b --- /dev/null +++ b/src/game/bondview2.c @@ -0,0 +1,10757 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bg.h" +#include "bgroomtrans.h" +#include "blood_animation.h" +#include "bondhead.h" +#include "bondinv.h" +#include "bondview.h" +#include "chr.h" +#include "chr_b.h" +#include "chraction.h" +#include "chrai.h" +#include "debugmenu_handler.h" +#include "explosion.h" +#include "file.h" +#include "frametiming.h" +#include "front.h" +#include "glass.h" +#include "gun.h" +#include "initanitable.h" +#include "language.h" +#include "loadobjectmodel.h" +#include "lv.h" +#include "math_atan2f.h" +#include "matrixmath.h" +#include "model.h" +#include "mp_music.h" +#include "mpmenu.h" +#include "objecthandler.h" +#include "objective_status.h" +#include "os_extension.h" +#include "player.h" +#include "propobj.h" +#include "quaternion.h" +#include "random.h" +#include "stan.h" +#include "stanintersection.h" +#include "textrelated.h" + +#ifdef VERSION_EU + + #define BONDVIEW_AUTOAIM_TIME 0x19 /* 25 */ + + #define BONDVIEW_INTRO_CAMERA_BONDMESSCNT_A 0x1a + #define BONDVIEW_INTRO_CAMERA_BONDMESSCNT_B 0x19 + #define BONDVIEW_INTRO_CAMERA_BONDMESSCNT_C 0x64 + + #define BONDVIEW_UPPER_TEXT_TIMER_A 0x33 + #define BONDVIEW_UPPER_TEXT_TIMER_B 0x32 + #define BONDVIEW_UPPER_TEXT_TIMER_C 0xc8 + + #define EU_CAMERA_8003642C_ASPECT 1.19047617912f + +#else + + #define BONDVIEW_AUTOAIM_TIME 0x1e /* 30 */ + + #define BONDVIEW_INTRO_CAMERA_BONDMESSCNT_A 0x1f + #define BONDVIEW_INTRO_CAMERA_BONDMESSCNT_B 0x1e + #define BONDVIEW_INTRO_CAMERA_BONDMESSCNT_C 0x78 + + #define BONDVIEW_UPPER_TEXT_TIMER_A 0x3d + #define BONDVIEW_UPPER_TEXT_TIMER_B 0x3c + #define BONDVIEW_UPPER_TEXT_TIMER_C 0xf0 + +#endif + +/*cannonically these are both*/ +#define BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH 0x97 +#define BONDVIEW_HUD_MSG_BOTTOM_BUFFER_LENGTH 0x65 +/*these*/ +#define MAXTALKMESSLEN 150 +#define MAXMESSAGELEN 100 + + + +#if defined(VERSION_US) + #define BONDVIEW_2ND_FONTTABLE(_param) copy_2ndfonttable + #define BONDVIEW_1ST_FONTTABLE(_param) copy_1stfonttable +#elif defined(VERSION_JP) || defined(VERSION_EU) + #define BONDVIEW_2ND_FONTTABLE(_param) dword_CODE_bss_jp80079CEC[_param] + #define BONDVIEW_1ST_FONTTABLE(_param) dword_CODE_bss_jp80079Cd8[_param] +#endif + + +#if defined(VERSION_US) || defined(VERSION_JP) + #define BONDVIEW_VIEW_TOP_OFFSET_1 0x0C + #define BONDVIEW_VIEW_TOP_OFFSET_2 0x28 + #define BONDVIEW_VIEW_TOP_OFFSET_3 0x10 +#elif defined(VERSION_EU) + #define BONDVIEW_VIEW_TOP_OFFSET_1 0x16 + #define BONDVIEW_VIEW_TOP_OFFSET_2 0x32 + #define BONDVIEW_VIEW_TOP_OFFSET_3 0x14 +#endif + + +#if defined(VERSION_EU) + #define TANKUPDATEROTATION_SCALE 0.904799997807f + #define TANKTURRETVERTICALANGLERELATED_SCALE 0.928399980068f + #define TANK_UNKD0_SCALE 0.79960000515f + #define CHR_OBJ_ACCEL_SPEED_FACTOR 0.6f + #define CHR_OBJ_MAXSPEED 6.0f + #define MAX_SPEED_FACTOR 0.8f + #define TANK_DAMAGE_PENTALTY_TICKS 75 + + #define TANK_VERT_ANGLE_FACTOR 0.0716000199318f + #define TANK_VERT_ANGLE_RAD_FACTOR 0.0952f + + #define MAX_AIMLOCK_SPEED_DEFAULT 0.8344f + + #define THREE_SECOND_TICKS 150 + #define PLAYER_TICKEXPLODE_FACTOR 12 + + #define CLIPPING_CLOCK_FACTOR 0.765100002289f + #define CLIPPING_FIELD88_FACTOR 0.234899997711f + #define CLIPPING_FIELD8C_VALUE 12 + #define CLIPPING_FIELD90_VALUE -5.625f +#else + #define TANKUPDATEROTATION_SCALE 0.92f + #define TANKTURRETVERTICALANGLERELATED_SCALE 0.94f + #define TANK_UNKD0_SCALE 0.83f + #define CHR_OBJ_ACCEL_SPEED_FACTOR 0.5f + #define CHR_OBJ_MAXSPEED 5.0f + #define MAX_SPEED_FACTOR 0.8f + #define TANK_DAMAGE_PENTALTY_TICKS 90 + + #define TANK_VERT_ANGLE_FACTOR 0.0600000023842f + #define TANK_VERT_ANGLE_RAD_FACTOR 0.0799999833107f + #define MAX_AIMLOCK_SPEED_DEFAULT 0.86f + + #define THREE_SECOND_TICKS 180 + #define PLAYER_TICKEXPLODE_FACTOR 15 + + #define CLIPPING_CLOCK_FACTOR 0.8f + #define CLIPPING_FIELD88_FACTOR 0.19999999f + #define CLIPPING_FIELD8C_VALUE 15 + #define CLIPPING_FIELD90_VALUE -4.5f +#endif + +#define FULL_CROUCH_OFFSET -100.0f + +#define SPEED_REGULAR_MAX 1.0f +#define SPEED_RUN_MAX 1.25f +#define SPEED_TICK_ADJUST 0.01f +#define TANK_MAX_SPEED 15.0f + + +#define FLOAT_TEN_A 10.0f +#define FLOAT_TEN_B 10.00f + +#include "bondview_internal.h" + +#define a8s "%8s" +#define aX4_0f "x %4.0f" +#define aY4_0f "y %4.0f" +#define aZ4_0f "z %4.0f" +#define aS3d "%s %3d" + + +vec3d g_ForceBondMoveOffset; + +//CODE.bss:8007999C +s32 g_SurroundBondWithExplosionsTicks; +//CODE.bss:800799A0 +s32 g_PlayerTickExplodeCreatePosition; +//CODE.bss:800799A4 +s32 dword_CODE_bss_800799A4; // unused + +//CODE.bss:800799A8 +struct coord3d g_TankModelPositionOffset; + +//CODE.bss:800799B4 +s32 g_TankEngineSfxVolume; + +/** + * Address 0x800799B8. + * State 0: begin. + * State 1: Finished sitting down/turning, queue audio. + * State 2: complete +*/ +s32 g_EnterTankAudioState; + +/** + * Address 0x800799BC. +*/ +f32 g_TankEnteringSitHeight; + +/** + * Address 0x800799C0. +*/ +f32 g_TankEnteringSitHeightRemain; + +/** + * Address 0x800799C4. +*/ +f32 g_TankEnterBondHorizAngleDeg; + +/** + * Address 0x800799C8. +*/ +f32 g_TankEnterBondVertAngleDeg; + +//CODE.bss:800799CC +f32 flt_CODE_bss_800799CC; // unused/padding + +//CODE.bss:800799D0 +struct coord3d g_EnterTankCoord; + +//CODE.bss:800799DC +f32 flt_CODE_bss_800799DC; // unused/padding + +//CODE.bss:800799E0 +ITEM_IDS starting_weapon[2]; + +//CODE.bss:800799E8 +struct coord3d flt_CODE_bss_800799E8; + +//CODE.bss:800799F4 +struct PropRecord* dword_CODE_bss_800799F4; + +//CODE.bss:800799F8 +PadRecord * g_CameraLookAtBondPad; +//CODE.bss:800799FC +CutsceneRecord *gBondViewCutscene; +//CODE.bss:80079A00 +f32 flt_CODE_bss_80079A00; +//CODE.bss:80079A04 +f32 flt_CODE_bss_80079A04; +//CODE.bss:80079A08 +f32 flt_CODE_bss_80079A08; +//CODE.bss:80079A0C +f32 flt_CODE_bss_80079A0C; +//CODE.bss:80079A10 +f32 flt_CODE_bss_80079A10; +//CODE.bss:80079A14 +s32 dword_CODE_bss_80079A14; +//CODE.bss:80079A18 +enum CAMERAMODE dword_CODE_bss_80079A18; +//CODE.bss:80079A1C +s32 dword_CODE_bss_80079A1C; +//CODE.bss:80079A20 +s32 mission_timer; + +#if defined(VERSION_JP) || defined(VERSION_EU) +//CODE.bss:80079A24 +f32 watch_time_0; +#else +//CODE.bss:80079A24 +s32 watch_time_0; +#endif + +/** + * Address 80079A28 + * EU .bss 80068508 +*/ +char stringbuffer_lowerleft[0x5][BONDVIEW_HUD_MSG_BOTTOM_BUFFER_LENGTH]; +char dword_CODE_bss_80079c21[0x04]; + +#if defined(BUGFIX_R1) +//CODE.bss:80079Cd8 +s32 dword_CODE_bss_jp80079Cd8[0x05]; +s32 dword_CODE_bss_jp80079CEC[0x05]; +#endif + +/** + * Address 80079C28 + * EU .bss 80068738 +*/ +PadRecord *g_Startpad[0x10]; + +//CODE.bss:80079C68 +s32 startpadcount; +//CODE.bss:80079C6C +s32 dword_CODE_bss_80079C6C; + +#if defined LEFTOVERDEBUG +//CODE.bss:80079C70 +/***/ +char stringbuffer_top[0x2][BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH]; +u16 dword_CODE_bss_80079d9E; +#endif + +//CODE.bss:80079DA0 +/** + * EU .bss 80078780 +*/ +StandTilePoint *dword_CODE_bss_80079DA0; +//CODE.bss:80079DA4 +StandTilePoint *dword_CODE_bss_80079DA4; + +//CODE.bss:80079DA8 +s32 dword_CODE_bss_80079DA8[BSS_80079DA8_LENGTH]; + +#ifndef VERSION_EU +//CODE.bss:80079DC8 +char dword_CODE_bss_80079DC8[0x3C]; +#else +char dword_CODE_bss_80079DC8[0x2][BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH]; +char dword_CODE_bss_80079EF6[0x3C]; +#endif + +//CODE.bss:80079E04 +f32 g_MpSwirlRotateSpeed; +//CODE.bss:80079E08 +f32 g_MpSwirlAngleDegrees; +//CODE.bss:80079E0C +f32 g_MpSwirlForwardSpeed; +//CODE.bss:80079E10 +f32 g_MpSwirlDistance; + +#define ALIGN64_V3(val) (((val) | 0x3f) ^ 0x3f) + +void solo_char_load(void) +{ + f32 yaw; + ChrRecord *self; + struct texpool pool; + ModelFileHeader *bodyheader; + ModelFileHeader *headheader; + ModelFileHeader *pitemheader; + u8 *weaponbuf0; + u8 *weaponbuf1; + s32 cursor; + s32 size0; + s32 size1; + s32 helddst; + WeaponObjRecord weapon; + struct player **pp; + s32 prop; + ITEM_IDS item; + s32 body; + s32 head; + struct ItemModelFileRecord *unusedpitem; + Model *model; + + yaw = bondviewGetPlayerYawRadians(); + if (g_CurrentPlayer->prop->chr == NULL) + { + weaponbuf0 = getPlayerWeaponBufferForHand(GUNRIGHT); + weaponbuf1 = getPlayerWeaponBufferForHand(GUNLEFT); + cursor = 0; + size0 = getSizeBufferWeaponInHand(GUNRIGHT); + size1 = getSizeBufferWeaponInHand(GUNLEFT); + weapon = dummy_08_pp7_obj[0]; + item = get_item_in_hand_or_watch_menu(GUNRIGHT); + body = BODY_Formal_Wear; + head = HEAD_Male_Brosnan_Default; + model = NULL; + bodyheader = NULL; + + bondviewDeregisterPlayerRoom(g_CurrentPlayer); + + if (getPlayerCount() == 1) + { + helddst = fileGetBondForCurrentFolder(); + switch (g_CurrentPlayer->bondtype) + { + case CUFF_BLUE: + break; + + case CUFF_BOILER: + body = BODY_Special_Operations_Uniform; + break; + + case CUFF_JUNGLE: + body = BODY_Jungle_Fatigues; + break; + + case CUFF_SNOW: + body = BODY_Parka; + break; + + case CUFF_BROSNAN: + body = BODY_Brosnan_Tuxedo; + break; + + case CUFF_CONNERY: + body = BODY_Brosnan_Tuxedo; + break; + + case CUFF_DALTON: + body = BODY_Brosnan_Tuxedo; + break; + + case CUFF_MOORE: + body = BODY_Brosnan_Tuxedo; + break; + + case CUFF_FOLDER: + switch (helddst) + { + case BOND_BROSNAN: + body = BODY_Brosnan_Tuxedo; + break; + + case BOND_CONNERY: + body = BODY_Brosnan_Tuxedo; + break; + + case BOND_DALTON: + body = BODY_Brosnan_Tuxedo; + break; + + case BOND_MOORE: + body = BODY_Brosnan_Tuxedo; + break; + } + + break; + } + + switch (helddst) + { + case BOND_BROSNAN: + switch (g_CurrentPlayer->bondtype) + { + case CUFF_BLUE: + break; + + case CUFF_BOILER: + head = HEAD_Male_Brosnan_Boiler; + break; + + case CUFF_JUNGLE: + head = HEAD_Male_Brosnan_Jungle; + break; + + case CUFF_BROSNAN: + head = HEAD_Male_Brosnan_Tuxedo; + break; + + case CUFF_CONNERY: + head = HEAD_Male_Brosnan_Tuxedo; + break; + + case CUFF_DALTON: + head = HEAD_Male_Brosnan_Tuxedo; + break; + + case CUFF_MOORE: + head = HEAD_Male_Brosnan_Tuxedo; + break; + + case CUFF_FOLDER: + head = HEAD_Male_Brosnan_Tuxedo; + break; + } + + break; + + case BOND_CONNERY: + head = HEAD_Male_Brosnan_Tuxedo; + break; + + case BOND_DALTON: + head = HEAD_Male_Brosnan_Tuxedo; + break; + + case BOND_MOORE: + head = HEAD_Male_Brosnan_Tuxedo; + break; + } + } + else + { + head = get_player_mp_char_head(get_cur_playernum()); + body = get_player_mp_char_body(get_cur_playernum()); + } + + if (g_CameraMode == CAMERAMODE_SWIRL) + { + item = starting_weapon[GUNRIGHT]; + } + + if (getPlayerCount() == 1) + { + remove_item_in_hand(GUNLEFT); + remove_item_in_hand(GUNRIGHT); + texInitPool(&pool, weaponbuf1, size1); + bodyheader = get_ptr_itemheader_in_hand(GUNRIGHT); + *bodyheader = *c_item_entries[body].header; + load_object_fill_header(bodyheader, (u8 *)c_item_entries[body].filename, weaponbuf0, size0, &pool); + cursor = get_pc_buffer_remaining_value((u8 *)c_item_entries[body].filename); + + do + { + cursor = ALIGN64_V3(cursor + 0x3f); + headheader = (ModelFileHeader *)(weaponbuf0 + cursor); + cursor = ALIGN64_V3(cursor + sizeof(ModelFileHeader) + 0x3f); + *headheader = *c_item_entries[head].header; + + if(1); + + load_object_fill_header(headheader, (u8 *)c_item_entries[head].filename, weaponbuf0 + cursor, size0 - cursor, &pool); + cursor = ALIGN64_V3(get_pc_buffer_remaining_value((u8 *)c_item_entries[head].filename) + cursor + 0x3f); + model = (Model *)(weaponbuf0 + cursor); + cursor = ALIGN64_V3(cursor + 0xfb); + modelCalculateRwDataLen(bodyheader); + modelCalculateRwDataLen(headheader); + + { + u32 *animdata; + s32 nrec; + animdata = (u32 *)(weaponbuf0 + cursor); + nrec = (bodyheader->numRecords + headheader->numRecords) + 0xa; + cursor = ALIGN64_V3(cursor + (nrec << 2) + 0x3f); + animInit(model, bodyheader, animdata); + model->rwdatalen = nrec; + } + + } while (FALSE); + } + else + { + bodyheader = c_item_entries[body].header; + + if (bodyheader->RootNode == NULL) + { + fileLoad(bodyheader, c_item_entries[body].filename); + } +#ifndef VERSION_US + if (c_item_entries[body].hasHead) + { + head = -1; + headheader = NULL; + } + else +#endif + { + headheader = c_item_entries[head].header; + + if (headheader->RootNode == NULL) + { + fileLoad(headheader, c_item_entries[head].filename); + } + } + } + + g_CurrentPlayer->bodyModel = makeonebody(body, head, bodyheader, headheader, 0, model); + modelSetScale(g_CurrentPlayer->bodyModel, g_CurrentPlayer->bodyModel->scale * 0.97f); + init_GUARDdata_with_set_values(g_CurrentPlayer->prop, g_CurrentPlayer->bodyModel, &g_CurrentPlayer->prop->pos, yaw, g_CurrentPlayer->prop->stan, NULL); + pp = &g_CurrentPlayer; + (*pp)->prop->type = PROP_TYPE_VIEWER; + self = (*pp)->prop->chr; + self->chrflags |= CHRFLAG_INIT; + setsuboffset((*pp)->bodyModel, &(*pp)->prop->pos); + setsubroty(g_CurrentPlayer->bodyModel, yaw); +#ifndef VERSION_US + self->headnum = head; + self->bodynum = body; +#endif + prop = getPropForHeldItem(item); + + if (prop >= 0) + { + if (getPlayerCount() == 1) + { + helddst = cursor; + helddst = ((s32)weaponbuf0) + helddst; + cursor = ALIGN64_V3(cursor + 0xc7); + pitemheader = get_ptr_itemheader_in_hand(GUNLEFT); + *pitemheader = *PitemZ_entries[prop].header; + load_object_fill_header(pitemheader, (u8 *)PitemZ_entries[prop].filename, weaponbuf0 + cursor, size0 - cursor, &pool); + get_pc_buffer_remaining_value((u8 *)PitemZ_entries[prop].filename); + modelCalculateRwDataLen(pitemheader); + } + else + { + helddst = 0; + pitemheader = NULL; + } + + something_with_generating_object(self, prop, item, 0, (WeaponObjRecord *)helddst, (ItemModelFileRecord *)pitemheader); + } + + chrlvMergeKneelToStand(self, 0.0f); + } + else + { + self = g_CurrentPlayer->prop->chr; + + if (self->model->anim != NULL) + { + return; + } + + self->chrflags |= CHRFLAG_INIT; + chrlvMergeKneelToStand(self, 0.0f); + setsuboffset(g_CurrentPlayer->bodyModel, &g_CurrentPlayer->prop->pos); + setsubroty(g_CurrentPlayer->bodyModel, yaw); + } +} + + +/** + * Address 0x7F07A4A0. + */ +void bondviewRemovePlayerBody(void) +{ + if ((g_CurrentPlayer->prop->chr) && (getPlayerCount() == 1)) + { + chrpropCleanupForRemoval(g_CurrentPlayer->prop); + g_CurrentPlayer->prop->chr = NULL; + g_CurrentPlayer->bodyModel = 0; + g_bondviewForceDisarm = 1; + bondviewUpdatePlayerRoom(g_CurrentPlayer); + } +} + + +u32 bondviewGetCameraMode(void) { + return g_CameraMode; +} + + +s32 pickDeathCameraAngles(PropRecord *prop1, coord3d *pos, PropRecord *prop2, coord3d *collision_pos, StandTile *tile, f32 camera_dist) +{ + s32 found; + s32 outertries; + f32 camclearance; + f32 spD0; + f32 angle; + StandTile *spC8; + coord3d spBC; + coord3d spB0; + f32 angleRange; + f32 frac; + f32 floorY; + s32 lineok; + s32 angletries; + + dword_CODE_bss_800799F4 = prop1; + + found = 0; + outertries = 0; + angleRange = M_TAU_F; + + while ((outertries <= 0x80) && (!found)) + { + camclearance = g_CurrentPlayer->field_488.collision_radius; + spD0 = 1500.0f + camclearance; + + angle = ((f32) randomGetNext()) * 2.3283064e-10f; + angle = angle * angleRange; + + angletries = 0; + + while ((angletries < 0x10) && (!found)) + { + angleRange = M_TAU_F; + + angle += 0.39269909f; + + if (angleRange <= angle) + { + angle -= angleRange; + } + + spBC.x = sinf(angle); + spBC.y = 0.0f; + spBC.z = cosf(angle); + + spB0.x = (((f32 *) (&spBC))[0] * spD0) + pos->x; + spB0.y = pos->y; + spB0.z = (((f32 *) (&spBC))[2] * spD0) + pos->z; + + stanResetHits(); + + spC8 = tile; + + sub_GAME_7F03D058(prop2, 0); + + lineok = stanTestLineUnobstructed(&spC8, collision_pos->x, collision_pos->z, spB0.x, spB0.z, 0x13, 0.0f, 1.0f, 0.0f, 1.0f); + + sub_GAME_7F03D058(prop2, 1); + + if (!lineok) + { + chrlvStanPointPointIntersection(collision_pos, &spBC, &spB0); + + { + f32 dx = spB0.x - collision_pos->x; + f32 dz = spB0.z - collision_pos->z; + + spD0 = sqrtf((dx * dx) + (dz * dz)); + } + } + + spD0 -= camclearance; + + if (camera_dist <= spD0) + { + frac = 1.0f; + + while ((0.0f < frac) && (!found)) + { + f32 sp90; + f32 candidateDist; + + sp90 = spD0 - camera_dist; + + candidateDist = ((f32) randomGetNext()) * 2.3283064e-10f; + candidateDist *= sp90; + candidateDist *= frac; + candidateDist += camera_dist; + + flt_CODE_bss_800799E8.x = (spBC.x * candidateDist) + pos->x; + flt_CODE_bss_800799E8.y = pos->y; + flt_CODE_bss_800799E8.z = (spBC.z * candidateDist) + pos->z; + + spC8 = tile; + + sub_GAME_7F03D058(prop2, 0); + + lineok = stanTestLineUnobstructed(&spC8, collision_pos->x, collision_pos->z, flt_CODE_bss_800799E8.x, flt_CODE_bss_800799E8.z, 0x13, 0.0f, 1.0f, 0.0f, 1.0f); + + sub_GAME_7F03D058(prop2, 1); + + if (lineok) + { + lineok = stanTestVolume(&spC8, flt_CODE_bss_800799E8.x, flt_CODE_bss_800799E8.z, camclearance, 0x1f, 0.0f, 1.0f); + + if (lineok < 0) + { + floorY = stanGetPositionYValue(spC8, flt_CODE_bss_800799E8.x, flt_CODE_bss_800799E8.z); + + flt_CODE_bss_800799E8.y = (floorY + camclearance) + ((((f32) randomGetNext()) * 2.3283064e-10f) * (185.0f - camclearance)); + + candidateDist = flt_CODE_bss_800799E8.y - pos->y; + + if (((-1000.0f) < candidateDist) && (candidateDist < 1000.0f)) + { + found = 1; + } + } + } + + frac -= 0.25f; + + if (pos); + } + } + + angletries++; + } + + angleRange = M_TAU_F; + + outertries++; + } + + return found; +} + + +// Address 0x7F07A9B8 NTSC. +void bondviewSetCameraMode(s32 arg0) +{ + s32 padding; + s32 padding2; + + g_CameraMode = arg0; + g_CameraAfterCinema = 0; + + if (g_CameraMode == CAMERAMODE_INTRO) + { + if ((ptr_random06cam_entry != NULL) && (get_recording_ramrom_flag() == 0) && (get_is_ramrom_flag() == 0)) + { + camera_transition_timer = 0.0f; + currentPlayerSetFadeColour(0, 0, 0, 1.0f); + currentPlayerSetFadeFrac(60.0f, 0.0f); + fogLoadLevelEnvironment(bossGetStageNum(), 1); + g_CurrentPlayer->cameratile = NULL; + } + else + { + bondviewSetCameraMode(CAMERAMODE_SWIRL); + } + } + else if (g_CameraMode == CAMERAMODE_FADESWIRL) + { + currentPlayerSetFadeColour(0, 0, 0, 0.0f); + currentPlayerSetFadeFrac(60.0f, 1.0f); + } + else if (g_CameraMode == CAMERAMODE_MP) + { + g_MpSwirlRotateSpeed = 0.0f; + g_MpSwirlAngleDegrees = -90.0f; + g_MpSwirlForwardSpeed = 0.0f; + g_MpSwirlDistance = 80.0f; + fogLoadLevelEnvironment(bossGetStageNum(), 0); + } + else if (g_CameraMode == CAMERAMODE_SWIRL) + { + struct ModelAnimation *sp38; + f32 sp78; + f32 ftemp_3; + f32 ftemp_1; + struct ChrRecord *temp_v1; + + camera_fade_active = 0; + currentPlayerSetFadeColour(0, 0, 0, 1.0f); + currentPlayerSetFadeFrac(60.0f, 0.0f); + fogLoadLevelEnvironment(bossGetStageNum(), 0); + + if ((g_IntroSwirl != 0) && (get_recording_ramrom_flag() == 0) && (get_is_ramrom_flag() == 0)) + { + camera_transition_timer = 0.0f; + intro_camera_index = CAMERAMODE_INTRO; + currentPlayerStartChrFade(0.0f, 1.0f); + solo_char_load(); + + // HACK: ptr_animation_table->data regalloc is backwards + sp38 = (struct ModelAnimation *)((s32)stage_intro_anim_table[g_IntroAnimationIndex].anonymous_0 + (s32)&ptr_animation_table->data); + sp78 = stage_intro_anim_table[g_IntroAnimationIndex].anonymous_2; + ftemp_1 = stage_intro_anim_table[g_IntroAnimationIndex].anonymous_1; + ftemp_3 = stage_intro_anim_table[g_IntroAnimationIndex].anonymous_3; + + modelSetAnimation( + g_CurrentPlayer->bodyModel, + sp38, + 0, + ftemp_1, + ftemp_3, + 0.0f); + + if (sp78 > 0.0f) + { + modelSetAnimEndFrame(g_CurrentPlayer->bodyModel, sp78); + } + + temp_v1 = g_CurrentPlayer->prop->chr; + temp_v1->actiontype = ACT_BONDINTRO; + temp_v1->sleep = 0; + g_CurrentPlayer->cameratile = NULL; + } + else + { + bondviewSetCameraMode(CAMERAMODE_FP); + } + } + else if (g_CameraMode == CAMERAMODE_FP) + { + if (bossGetStageNum() == LEVELID_CUBA) + { + currentPlayerSetFadeColour(0, 0, 0, 1.0f); + currentPlayerSetFadeFrac(0.0f, 1.0f); + } + else if (camera_fade_active != 0) + { + currentPlayerSetFadeColour(0, 0, 0, 1.0f); + currentPlayerSetFadeFrac(60.0f, 0.0f); + } + + if (getPlayerCount() >= 2) + { + fogLoadLevelEnvironment(bossGetStageNum(), 0); + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) + { + currentPlayerEquipWeaponWrapper(GUNLEFT, starting_weapon[GUNLEFT]); + currentPlayerEquipWeaponWrapper(GUNRIGHT, starting_weapon[GUNRIGHT]); + } + + stop_time_flag = 0; + } + else if (g_CameraMode == CAMERAMODE_DEATH_CAM_SP) + { + f32 var_f0; + PropRecord *sp64; + struct coord3d sp58; + StandTile *var_v1; + struct coord3d sp48; + PropRecord *var_a2; + struct ChrRecord *temp_v1_2; + + camera_transition_timer = 0.0f; + intro_camera_index = CAMERAMODE_INTRO; + currentPlayerSetFadeColour(0, 0, 0, 1.0f); + currentPlayerSetFadeFrac(60.0f, 0.0f); + + if (g_ExplodeTankOnDeathFlag && (g_PlayerTankProp != NULL)) + { + // removed + } + else + { + // This branch restarts Bond's death animation for his death replay + g_PlayerIsInTank = 0; + + // struct copy + g_CurrentPlayer->field_488 = g_CurrentPlayer->previous_collision_info; + + g_CurrentPlayer->vv_theta = g_CurrentPlayer->thetadie; + g_CurrentPlayer->vv_verta = g_CurrentPlayer->vertadie; + g_CurrentPlayer->prop->pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; + g_CurrentPlayer->prop->pos.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; + g_CurrentPlayer->prop->pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; + g_CurrentPlayer->prop->stan = g_CurrentPlayer->field_488.current_tile_ptr; + + bondviewApplyVertaTheta(); + bondviewMoveAnimationTick(0, 0, 0); + bondviewUpdatePlayerCollisionPositionFields(); + currentPlayerStartChrFade(0.0f, 1.0f); + solo_char_load(); + + modelSetAnimation( + g_CurrentPlayer->bodyModel, + objecthandlerGetModelAnim((Model *) &g_CurrentPlayer->model), + objecthandlerGetModelGunhand(&g_CurrentPlayer->model), + 0.0f, + 0.5f, + 0.0f); + + temp_v1_2 = g_CurrentPlayer->prop->chr; + temp_v1_2->actiontype = ACT_BONDDIE; + temp_v1_2->sleep = 0; + temp_v1_2->chrflags |= CHRFLAG_INIT; + + setsuboffset(g_CurrentPlayer->bodyModel, &g_CurrentPlayer->prop->pos); + var_f0 = bondviewGetPlayerYawRadians(); + setsubroty(g_CurrentPlayer->bodyModel, var_f0); + } + + if (g_ExplodeTankOnDeathFlag && (g_PlayerTankProp != NULL)) + { + sp64 = g_PlayerTankProp; + var_f0 = 500.0f; // distance to place the camera + sp58.f[0] = g_PlayerTankProp->pos.f[0]; + sp58.f[1] = g_PlayerTankProp->pos.f[1]; + sp58.f[2] = g_PlayerTankProp->pos.f[2]; + var_a2 = g_PlayerTankProp; + sp48.f[0] = g_PlayerTankProp->pos.f[0]; + sp48.f[1] = g_PlayerTankProp->pos.f[1]; + sp48.f[2] = g_PlayerTankProp->pos.f[2]; + var_v1 = g_PlayerTankProp->stan; + } + else + { + var_f0 = 200.0f; // distance to place the camera + sp64 = g_CurrentPlayer->prop; + sp58.f[0] = g_CurrentPlayer->field_3C4; + sp58.f[1] = g_CurrentPlayer->field_3C8; + sp58.f[2] = g_CurrentPlayer->field_3CC; + var_a2 = g_CurrentPlayer->prop; + sp48.f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; + sp48.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; + sp48.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; + var_v1 = g_CurrentPlayer->field_488.current_tile_ptr; + } + + if (pickDeathCameraAngles(sp64, &sp58, var_a2, &sp48, var_v1, var_f0) != 0) + { + if (camera_mode == 0) + { +#ifdef DEBUG + osSyncPrintf("mute\n"); +#endif + + musicTrack1Play(M_INTROSWOOSH); + sndSetScalerApplyVolumeAllSfxSlot(0.5f); + } + + if ((g_ExplodeTankOnDeathFlag != 0) && (g_PlayerTankProp != NULL)) + { + explosionCreate(g_PlayerTankProp, &g_PlayerTankProp->pos, g_PlayerTankProp->stan, 0xD, 0, get_cur_playernum(), g_PlayerTankProp->rooms, 0); + } + } + else + { + // pickDeathCameraAngles has returned 0. This happens when no possible angles were found + // to place the camera at the requested distance or when the three death replays are finished. + bossRunTitleStage(); + } + } + else if (g_CameraMode == CAMERAMODE_DEATH_CAM_MP) + { + currentPlayerSetFadeColour(0, 0, 0, 0.0f); + currentPlayerSetFadeFrac(60.0f, 1.0f); + } + else if (g_CameraMode == CAMERAMODE_POSEND) + { + solo_char_load(); + g_CurrentPlayer->cameratile = NULL; + } + else if (g_CameraMode == CAMERAMODE_FP_NOINPUT) + { + bondviewRemovePlayerBody(); + g_CameraMode = CAMERAMODE_FP; + } + else if (g_CameraMode == CAMERAMODE_FADE_TO_TITLE) + { + s32 var_s0; + + for (var_s0 = 0; var_s0 < getPlayerCount(); var_s0++) + { + set_cur_player(var_s0); + currentPlayerSetFadeColour(0, 0, 0, 0.0f); + currentPlayerSetFadeFrac(60.0f, 1.0f); + } + + set_cur_player(0); + } +} + + +void bondviewAdvanceCameraMode(void) +{ + enum CAMERAMODE mode = g_CameraMode; + + g_CameraMode = CAMERAMODE_NONE; + g_CameraAfterCinema = CAMERAMODE_NONE; + + if (mode == CAMERAMODE_INTRO) + { + bondviewSetCameraMode(CAMERAMODE_FADESWIRL); + } + else if (mode == CAMERAMODE_FADESWIRL) + { + bondviewResetIntroCameraMessageDialogs(); + bondviewSetCameraMode(CAMERAMODE_SWIRL); + } + else if (mode != CAMERAMODE_MP) + { + if (mode == CAMERAMODE_SWIRL) + { + bondviewRemovePlayerBody(); + currentPlayerStartChrFade(0.0f, 1.0f); // What's the point of this call? + bondviewSetCameraMode(CAMERAMODE_FP); + } + else if (mode != CAMERAMODE_FP) + { + if (mode == CAMERAMODE_DEATH_CAM_SP) + { + bondviewSetCameraMode(CAMERAMODE_DEATH_CAM_MP); + } + else if (mode == CAMERAMODE_DEATH_CAM_MP) + { + camera_mode++; + + if (camera_mode < CAMERAMODE_SWIRL) + { + bondviewSetCameraMode(CAMERAMODE_DEATH_CAM_SP); + } + } + } + } +} + + +/** + * Smoothly interpolate the camera between the points on the intro swirl path. + */ +void bondviewCalcIntroSwirlCamera(s32 index, f32 time, coord3d *pos, coord3d *lookat) +{ + struct SetupIntroSwirl *base; + struct SetupIntroSwirl *loopbase; + f32 pointbuf[10]; + struct SetupIntroSwirl *swirl; + f32 frac; + f32 *dst; + + base = g_IntroSwirl; + swirl = base; + swirl += index; + frac = 0.0f; + + if (swirl->duration.fval > 0.0f) + { + frac = time / swirl->duration.fval; + } + + { + struct SetupIntroSwirl *entry; + union { + struct SetupIntroSwirl *swirl; + struct player *player; + } target; + s32 i; + + loopbase = base + (u32) index; + + for (i = -1; i < 3; i++) + { + entry = loopbase; + loopbase = base + (u32) index; + target.swirl = entry + i; + dst = &pointbuf[i * 3]; + + if (i < 0) + { + if (target.swirl < base) + { + entry = base; + } + else + { + entry = target.swirl; + } + } + else + { + while (entry < target.swirl) + { + if (entry[1].bitflags & 1) + { + break; + } + + entry++; + } + } + + if (entry->bitflags & 2) + { + target.player = g_CurrentPlayer; + dst[3] = (entry->offsetfromBond[2].fval * target.player->field_488.theta_transform.f[0]) + + (entry->offsetfromBond[0].fval * target.player->field_488.theta_transform.f[2]); + dst[4] = entry->offsetfromBond[1].fval; + dst[5] = (entry->offsetfromBond[2].fval * target.player->field_488.theta_transform.f[2]) + - (entry->offsetfromBond[0].fval * target.player->field_488.theta_transform.f[0]); + } + else + { + dst[3] = entry->offsetfromBond[0].fval; + dst[4] = entry->offsetfromBond[1].fval; + dst[5] = entry->offsetfromBond[2].fval; + } + } + } + + { + f32 scale; + + base = swirl; + scale = base->scale.fval; + base = (void *)(index << 5); + + coord3dCubicSplineInterp((coord3d *) &pointbuf[0], (coord3d *) &pointbuf[3], (coord3d *) &pointbuf[6], (coord3d *) &pointbuf[9], frac, scale, pos); + + pos->x += g_CurrentPlayer->field_3C4; + pos->y += g_CurrentPlayer->field_3C8; + pos->z += g_CurrentPlayer->field_3CC; + + lookat->x = g_CurrentPlayer->field_3C4; + lookat->y = g_CurrentPlayer->field_3C8; + lookat->z = g_CurrentPlayer->field_3CC; + + swirl = (void *)(((u32) g_IntroSwirl) + (u32) base); + + if (!(swirl->bitflags & 4)) + { + if (!(swirl[1].bitflags & 4)) + { + scale = 1.0f; + } + else + { + scale = 1.0f - frac; + } + } + else if (swirl[1].bitflags & 4) + { + scale = 0.0f; + } + else + { + scale = frac; + } + + lookat->x += (g_CurrentPlayer->field_488.applied_view.x * 40.0f) * scale; + lookat->y += (g_CurrentPlayer->field_488.applied_view.y * 40.0f) * scale; + lookat->z += (g_CurrentPlayer->field_488.applied_view.z * 40.0f) * scale; + } +} + + +/** + * US address 7F07B56C. + * JP address 7F07BB8C. + * EU address 7F07B604. +*/ +void bondviewFrozenCameraTick(u16 buttons, u16 oldbuttons, struct coord3d *pos, struct coord3d *pos2, struct coord3d *offset, StandTile **stan, struct coord3d *arg6) +{ + s32 i; + f32 sp38; + s32 i2; + f32 sp30 = 0.0f; + s32 padding2; + f32 zero = 0.0f; + void *p; + struct PadRecord *setupPad; + + if ((g_CameraMode == CAMERAMODE_INTRO) || (g_CameraMode == CAMERAMODE_FADESWIRL)) + { + if (g_CameraMode == CAMERAMODE_INTRO) + { + if ((camera_transition_timer < 120.0f) && ((camera_transition_timer + g_GlobalTimerDelta) >= 120.0f)) + { +#if defined(VERSION_US) + setFontTables(ptrFontZurichBoldChars, ptrFontZurichBold); + hudmsgBottomShow(ptr_random06cam_entry->lang1c.lang_ptr); +#else + hudmsgBottomShow(ptr_random06cam_entry->lang1c.lang_ptr, ptrFontZurichBoldChars, ptrFontZurichBold); +#endif + } + + if (ptr_random06cam_entry->lang20.lang_ptr != NULL) + { + if ((camera_transition_timer < 300.0f) && ((camera_transition_timer + g_GlobalTimerDelta) >= 300.0f)) + { +#if defined(VERSION_US) + hudmsgBottomShow(ptr_random06cam_entry->lang20.lang_ptr); +#else + hudmsgBottomShow(ptr_random06cam_entry->lang20.lang_ptr, ptrFontZurichBoldChars, ptrFontZurichBold); +#endif + } + + if (camera_transition_timer > 480.0f) + { + g_CameraAfterCinema = CAMERAMODE_INTRO; + } + } + else if (camera_transition_timer > 300.0f) + { + g_CameraAfterCinema = CAMERAMODE_INTRO; + } + + camera_transition_timer += g_GlobalTimerDelta; + + if ((lvlGetControlsLockedFlag() == 0) + && (buttons & ~oldbuttons & (CONT_A | B_BUTTON | Z_TRIG | START_BUTTON | CONT_R | CONT_L))) + { + g_CameraAfterCinema = CAMERAMODE_INTRO; + } + } + else if (g_CurrentPlayer->colourfadetimemax60 < 0.0f) + { + g_CameraAfterCinema = CAMERAMODE_INTRO; + } + + pos->f[0] = ptr_random06cam_entry->unk04.fval; + pos->f[1] = ptr_random06cam_entry->unk08.fval; + pos->f[2] = ptr_random06cam_entry->unk0C.fval; + + pos2->f[0] = pos->f[0] + (cosf(ptr_random06cam_entry->unk14.fval) * sinf(ptr_random06cam_entry->unk10.fval)); + pos2->f[1] = pos->f[1] + sinf(ptr_random06cam_entry->unk14.fval); + pos2->f[2] = pos->f[2] - (cosf(ptr_random06cam_entry->unk14.fval) * cosf(ptr_random06cam_entry->unk10.fval)); + + p = &g_CurrentSetup.pads[ptr_random06cam_entry->unk18]; + setupPad = p; + *stan = setupPad->stan; + + arg6->f[0] = setupPad->pos.f[0]; + arg6->f[1] = setupPad->pos.f[1]; + arg6->f[2] = setupPad->pos.f[2]; + } + else if (g_CameraMode == CAMERAMODE_MP) + { + /** + * CAMERAMODE_MP: Perfect Dark method playerTickMpSwirl + */ + if (get_player_position_in_shuffled(get_cur_playernum()) == 0) + { + for (i2=0; i2 110.0f) + { + g_MpSwirlRotateSpeed -= 0.1f; + } + + g_MpSwirlAngleDegrees += g_MpSwirlRotateSpeed; + } +#if defined(VERSION_EU) + if (g_MpSwirlAngleDegrees >= 179.5f) +#else + else +#endif + { + g_MpSwirlAngleDegrees = 180.0f; + } + + if (g_MpSwirlAngleDegrees > 80.0f) + { + if (g_MpSwirlDistance > 60.0f) + { + g_MpSwirlForwardSpeed -= 0.1f; + } + else + { + g_MpSwirlForwardSpeed += 0.015f; + } + + g_MpSwirlDistance += g_MpSwirlForwardSpeed; + + if (g_MpSwirlDistance < 1.0f) + { + g_MpSwirlDistance = 1.0f; + } + } + } + } + + sp38 = ((g_MpSwirlAngleDegrees - g_CurrentPlayer->vv_theta) * M_PI_F) / 180.0f; + + pos->f[0] = g_CurrentPlayer->field_488.pos.f[0] + (sinf(sp38) * g_MpSwirlDistance); + pos->f[1] = g_CurrentPlayer->field_488.pos.f[1] + (g_MpSwirlDistance * 0.08f); + pos->f[2] = g_CurrentPlayer->field_488.pos.f[2] + (cosf(sp38) * g_MpSwirlDistance); + + pos2->f[0] = g_CurrentPlayer->field_488.pos.f[0]; + pos2->f[1] = g_CurrentPlayer->field_488.pos.f[1]; + pos2->f[2] = g_CurrentPlayer->field_488.pos.f[2]; + + *stan = g_CurrentPlayer->prop->stan; + + arg6->f[0] = g_CurrentPlayer->field_488.pos.f[0]; + arg6->f[1] = g_CurrentPlayer->field_488.pos.f[1] + (g_MpSwirlDistance * 0.08f); + arg6->f[2] = g_CurrentPlayer->field_488.pos.f[2]; + +#if defined(VERSION_EU) + if (((get_player_position_in_shuffled(get_cur_playernum()) + 1) == getPlayerCount()) && (g_MpSwirlDistance < 5.0f)) + { + g_CameraAfterCinema = CAMERAMODE_INTRO; + } +#else + if (g_MpSwirlDistance < 5.0f) + { + g_CameraAfterCinema = CAMERAMODE_INTRO; + } +#endif + } + else if (g_CameraMode == CAMERAMODE_SWIRL) + { + camera_transition_timer += g_GlobalTimerDelta; + + while (g_IntroSwirl[intro_camera_index].unk18.fval <= camera_transition_timer) + { + if (!(g_IntroSwirl[intro_camera_index + 3].unk04 & 1)) + { + camera_transition_timer -= g_IntroSwirl[intro_camera_index].unk18.fval; + intro_camera_index++; + } + else + { + camera_transition_timer = g_IntroSwirl[intro_camera_index].unk18.fval; + g_CameraAfterCinema = CAMERAMODE_INTRO; + break; + } + } + + sp30 += (g_IntroSwirl[intro_camera_index].unk18.fval - camera_transition_timer); + + for (i = intro_camera_index + 1; !(g_IntroSwirl[i+2].unk04 & 1); i++) + { + sp30 += g_IntroSwirl[i].unk18.fval; + } + + // Fade player body from opaque to transparent just before the player takes control. + if ((sp30 < 30.0f) && ((sp30 + g_GlobalTimerDelta) >= 30.0f)) + { + currentPlayerStartChrFade(30.0f, 0.0f); + } + + if (camera_fade_active != 0) + { + if (currentPlayerIsFadeComplete() != 0) + { + g_CameraAfterCinema = CAMERAMODE_INTRO; + } + } + + if ((sp30 > 60.0f) && (camera_fade_active == 0)) + { + if ((lvlGetControlsLockedFlag() == 0) + && (buttons & ~oldbuttons & (A_BUTTON | B_BUTTON | Z_TRIG | START_BUTTON | L_TRIG | R_TRIG))) + { + camera_fade_active = 1; + currentPlayerSetFadeColour(0, 0, 0, g_CurrentPlayer->colourscreenfrac); + + if (currentPlayerIsFadeComplete() != 0) + { + currentPlayerSetFadeFrac(60.0f, 1.0f); + } + else + { + currentPlayerSetFadeFrac(g_CurrentPlayer->colourfadetime60, 1.0f); + } + } + } + + bondviewCalcIntroSwirlCamera(intro_camera_index, camera_transition_timer, pos, pos2); + + if (g_IntroSwirl[intro_camera_index].unk1C >= 0) + { + p = &g_CurrentSetup.pads[g_IntroSwirl[intro_camera_index].unk1C]; + setupPad = p; + *stan = setupPad->stan; + + arg6->f[0] = setupPad->pos.f[0]; + arg6->f[1] = setupPad->pos.f[1]; + arg6->f[2] = setupPad->pos.f[2]; + } + else + { + *stan = g_CurrentPlayer->field_488.current_tile_ptr; + arg6->f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; + arg6->f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; + arg6->f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; + } + } + else if ((g_CameraMode == CAMERAMODE_DEATH_CAM_SP) || (g_CameraMode == CAMERAMODE_DEATH_CAM_MP)) + { + if (g_CameraMode == CAMERAMODE_DEATH_CAM_SP) + { + camera_transition_timer += g_GlobalTimerDelta; + + if (g_CurrentPlayer->bodyModel != NULL) + { + if (modelGetAnimFrame((Model *) g_CurrentPlayer->bodyModel) + >= modelGetAnimEndFrame((Model *) g_CurrentPlayer->bodyModel)) + { + g_CameraAfterCinema = CAMERAMODE_INTRO; + } + } + else if (camera_transition_timer >= 180.0f) + { + g_CameraAfterCinema = CAMERAMODE_INTRO; + } + + if ((buttons & ~oldbuttons & (CONT_A | B_BUTTON | Z_TRIG | START_BUTTON)) + && (g_CurrentPlayer->bonddead) + && (g_CurrentPlayer->redbloodfinished) + && (g_CurrentPlayer->deathanimfinished)) + { + g_CameraAfterCinema = CAMERAMODE_INTRO; + camera_mode = CAMERAMODE_FADESWIRL; + } + } + else if (g_CameraMode == CAMERAMODE_DEATH_CAM_MP) + { + camera_transition_timer += g_GlobalTimerDelta; + + if (g_CurrentPlayer->colourfadetimemax60 < 0.0f) + { + g_CameraAfterCinema = CAMERAMODE_INTRO; + } + + if ((buttons & ~oldbuttons & (CONT_A | B_BUTTON | Z_TRIG | START_BUTTON)) + && (g_CurrentPlayer->bonddead) + && (g_CurrentPlayer->redbloodfinished) + && (g_CurrentPlayer->deathanimfinished)) + { + camera_mode = CAMERAMODE_FADESWIRL; + } + } + + pos->f[0] = flt_CODE_bss_800799E8.f[0]; + pos->f[1] = flt_CODE_bss_800799E8.f[1]; + pos->f[2] = flt_CODE_bss_800799E8.f[2]; + + if (dword_CODE_bss_800799F4 == g_CurrentPlayer->prop) + { + pos2->f[0] = g_CurrentPlayer->field_3C4; + pos2->f[1] = g_CurrentPlayer->field_3C8; + pos2->f[2] = g_CurrentPlayer->field_3CC; + } + else + { + pos2->f[0] = dword_CODE_bss_800799F4->pos.f[0]; + pos2->f[1] = dword_CODE_bss_800799F4->pos.f[1]; + pos2->f[2] = dword_CODE_bss_800799F4->pos.f[2]; + } + + *stan = g_CurrentPlayer->field_488.current_tile_ptr; + + arg6->f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; + arg6->f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; + arg6->f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; + } + else if (g_CameraMode == CAMERAMODE_POSEND) + { + if (g_CameraLookAtBondPad != NULL) + { + pos->f[0] = g_CameraLookAtBondPad->pos.f[0]; + pos->f[1] = g_CameraLookAtBondPad->pos.f[1]; + pos->f[2] = g_CameraLookAtBondPad->pos.f[2]; + + pos2->f[0] = g_CurrentPlayer->field_3C4; + pos2->f[1] = g_CurrentPlayer->field_3C8; + pos2->f[2] = g_CurrentPlayer->field_3CC; + + *stan = g_CameraLookAtBondPad->stan; + + arg6->f[0] = g_CameraLookAtBondPad->pos.f[0]; + arg6->f[1] = g_CameraLookAtBondPad->pos.f[1]; + arg6->f[2] = g_CameraLookAtBondPad->pos.f[2]; + + return; + } + + if (gBondViewCutscene != NULL) + { + if (isNotBoundPad(gBondViewCutscene->pad)) + { + p = &g_CurrentSetup.pads[gBondViewCutscene->pad]; + } + else + { + p = &g_CurrentSetup.boundpads[getBoundPadNum(gBondViewCutscene->pad)]; + } + + pos->f[0] = gBondViewCutscene->pos.f[0]; + pos->f[1] = gBondViewCutscene->pos.f[1]; + pos->f[2] = gBondViewCutscene->pos.f[2]; + + setupPad = p; + *stan = setupPad->stan; + + arg6->f[0] = setupPad->pos.f[0]; + arg6->f[1] = setupPad->pos.f[1]; + arg6->f[2] = setupPad->pos.f[2]; + + if (dword_CODE_bss_80079A18 == CAMERAMODE_INTRO) + { + pos2->f[0] = g_CurrentPlayer->field_3C4; + pos2->f[1] = g_CurrentPlayer->field_3C8; + pos2->f[2] = g_CurrentPlayer->field_3CC; + } + else + { + pos2->f[0] = pos->f[0] + (cosf(gBondViewCutscene->verta) * sinf(gBondViewCutscene->theta)); + pos2->f[1] = pos->f[1] + sinf(gBondViewCutscene->verta); + pos2->f[2] = pos->f[2] - (cosf(gBondViewCutscene->verta) * cosf(gBondViewCutscene->theta)); + } + + return; + } + + if (isNotBoundPad(dword_CODE_bss_80079A14)) + { + setupPad = &g_CurrentSetup.pads[dword_CODE_bss_80079A14]; + } + else + { + setupPad = (struct PadRecord*)&g_CurrentSetup.boundpads[getBoundPadNum(dword_CODE_bss_80079A14)]; + } + + *stan = setupPad->stan; + + arg6->f[0] = setupPad->pos.f[0]; + arg6->f[1] = setupPad->pos.f[1]; + arg6->f[2] = setupPad->pos.f[2]; + + pos2->f[0] = setupPad->pos.f[0] + cosf(flt_CODE_bss_80079A00) * 0.0f; + pos2->f[1] = setupPad->pos.f[1] + flt_CODE_bss_80079A10; + pos2->f[2] = setupPad->pos.f[2] + sinf(flt_CODE_bss_80079A00) * 0.0f; + + pos->f[0] = setupPad->pos.f[0] + (sinf(flt_CODE_bss_80079A00) * flt_CODE_bss_80079A08) + cosf(flt_CODE_bss_80079A00) * 0.0f; + pos->f[1] = setupPad->pos.f[1] + flt_CODE_bss_80079A10 + flt_CODE_bss_80079A0C; + pos->f[2] = setupPad->pos.f[2] + (cosf(flt_CODE_bss_80079A00) * flt_CODE_bss_80079A08) + sinf(flt_CODE_bss_80079A00) * 0.0f; + + flt_CODE_bss_80079A00 += flt_CODE_bss_80079A04 * g_GlobalTimerDelta; + + while (flt_CODE_bss_80079A00 >= M_TAU_F) + { + flt_CODE_bss_80079A00 -= M_TAU_F; + } + + while (flt_CODE_bss_80079A00 < 0.0f) + { + flt_CODE_bss_80079A00 += M_TAU_F; + } + } +} + + +//begin bondmove.c per pd + +void sub_GAME_7F07C540(s32 arg0) +{ + g_CurrentPlayer->field_42c = arg0; +} + + +void currentPlayerSetLookAheadSetting(bool enabled) +{ + g_CurrentPlayer->automovecentreenabled = enabled; +} + + +/** + * Unreferenced + */ +bool currentPlayerGetLookAheadSetting(void) +{ + return g_CurrentPlayer->automovecentreenabled; +} + + +void currentPlayerSetYAutoAimEnabled(bool enabled) +{ + g_CurrentPlayer->autoyaimenabled = enabled; +} + + +/** + * Address 0x7F07C580. + */ +bool currentPlayerGetYAutoAimEnabled(void) +{ + if (getPlayerCount() == 1) + { + return g_CurrentPlayer->autoyaimenabled; + } + + return (bool) g_playerPerm->autoaim; +} + + +bool currentPlayerGetYAutoAimEnabledRedirect(void) +{ + return currentPlayerGetYAutoAimEnabled(); +} + + +bool currentPlayerGetIsAiming(void) +{ + return g_CurrentPlayer->insightaimmode; +} + + +/** + * Updates autoyaimtime60 by g_ClockTimer. + * Will update player->autoaimy if new autoyaimtime60 < 0 or autoaim_target != g_CurrentPlayer->autoaim_target_y. + * + * Address 0x7F07C5F0. + */ +void bondviewUpdateYAutoAimTime(struct PropRecord *autoaim_target, f32 auto_aim_y) +{ + if (g_CurrentPlayer->autoyaimtime60 >= 0) + { + g_CurrentPlayer->autoyaimtime60 = g_CurrentPlayer->autoyaimtime60 - g_ClockTimer; + } + + if (autoaim_target != g_CurrentPlayer->autoaim_target_y) + { + if (g_CurrentPlayer->autoyaimtime60 < 0) + { + g_CurrentPlayer->autoyaimtime60 = BONDVIEW_AUTOAIM_TIME; + g_CurrentPlayer->autoaim_target_y = autoaim_target; + } + else + { + return; + } + } + + g_CurrentPlayer->autoaimy = auto_aim_y; +} + + +void currentPlayerSetXAutoAimEnabled(bool enabled) +{ + g_CurrentPlayer->autoxaimenabled = enabled; + + return; +} + + +/** + * Address 0x7F07C668. + */ +bool currentPlayerGetXAutoAimEnabled(void) +{ + if (getPlayerCount() == 1) + { + return g_CurrentPlayer->autoxaimenabled; + } + + return (bool) g_playerPerm->autoaim; +} + + +bool currentPlayerGetXAutoAimEnabledRedirect(void) +{ + return currentPlayerGetXAutoAimEnabled(); +} + + +/** + * Updates autoxaimtime60 by g_ClockTimer. + * Will update player->autoaimx if new autoxaimtime60 < 0 or autoaim_target_x != g_CurrentPlayer->autoaim_target_x. + * + * Address 0x7F07C6C8. + */ +void bondviewUpdateXAutoAimTime(struct PropRecord *autoaim_target, f32 auto_aim_x) +{ + if (g_CurrentPlayer->autoxaimtime60 >= 0) + { + g_CurrentPlayer->autoxaimtime60 = g_CurrentPlayer->autoxaimtime60 - g_ClockTimer; + } + + if (autoaim_target != g_CurrentPlayer->autoaim_target_x) + { + if (g_CurrentPlayer->autoxaimtime60 < 0) + { + g_CurrentPlayer->autoxaimtime60 = BONDVIEW_AUTOAIM_TIME; + g_CurrentPlayer->autoaim_target_x = autoaim_target; + } + else + { + return; + } + } + + g_CurrentPlayer->autoaimx = auto_aim_x; + +} + + +void change_player_pos_to_target(struct collision434 *col, coord3d *pos, StandTile *stan) +{ + f32 store_x; + f32 store_x2; + f32 store_z; + f32 store_y; + col->collision_position.x = pos->x; + store_x = col->collision_position.x; + col->collision_position.y = pos->y; + store_y = col->collision_position.y; + col->collision_position.z = pos->z; + store_z = col->collision_position.z; + store_x2 = pos->x; + col->current_tile_ptr = stan; + col->current_tile_ptr_for_portals = stan; + col->applied_view.y = 0.0f; + col->applied_view.z = 0.0f; + col->applied_view2.x = 0.0f; + col->applied_view2.z = store_x2 * 0.0f; + col->theta_transform.x = 0.0f; + col->theta_transform.y = 0.0f; + col->pos.x = store_x; + col->pos3.x = store_x; + col->applied_view.x = 1.0f; + col->applied_view2.y = 1.0f; + col->theta_transform.z = 1.0f; + col->pos.y = store_y; + col->pos3.y = store_y; + col->pos.z = store_z; + col->pos3.z = store_z; + col->collision_radius = 30; +} + + +/** + * US address 7F07C7B4. +*/ +void bondviewTankModelRotationRelated(void) { + struct ObjectRecord *obj; + struct coord3d *sp68; + struct coord3d *sp64; + Mtxf sp24; + ModelNode **temp_v0; + + if (g_PlayerTankProp != NULL) + { + obj = g_PlayerTankProp->obj; + + /// TODO: Fix Model struct Data type. + temp_v0 = obj->model->obj->Switches; + sp68 = (struct coord3d *)temp_v0[2]->Data; + sp64 = (struct coord3d *)temp_v0[1]->Data; + matrix_4x4_set_rotation_around_y(M_TAU_F - g_TankTurretOrientationAngleRad, &sp24); + g_TankModelPositionOffset.f[0] = sp68->f[0]; + g_TankModelPositionOffset.f[1] = sp68->f[1]; + g_TankModelPositionOffset.f[2] = sp68->f[2]; + mtx4RotateVecInPlace(&sp24, g_TankModelPositionOffset.f); + g_TankModelPositionOffset.f[0] += sp64->f[0]; + g_TankModelPositionOffset.f[1] += sp64->f[1]; + g_TankModelPositionOffset.f[2] += sp64->f[2]; + } +} + + +/** + * Address 0x7F07C888. +*/ +void bondviewGetTankCollisionBounds(struct rect4f *tank_collision_bounds, struct coord3d *collision_position, f32 tank_orientation_angle) +{ + ObjectRecord *sp4C; + f32 sp48; + f32 sp44; + f32 sp40; + f32 sp3C; + f32 sp38; + f32 sp34; + struct ModelRoData_BoundingBoxRecord *bbox; + + #ifdef DEBUG + assert(bondonprop2); // canonically g_PlayerTankProp is bondonprop2 - presumably because it was also motorbike code +#endif + + sp4C = g_PlayerTankProp->obj; + + bbox = chrobjGetBboxFromObjectRecord(sp4C); + + sp44 = bbox->Bounds.xmin - g_TankModelPositionOffset.f[0]; + sp40 = bbox->Bounds.xmax - g_TankModelPositionOffset.f[0]; + + sp3C = bbox->Bounds.zmin - g_TankModelPositionOffset.f[2]; + sp38 = bbox->Bounds.zmax - g_TankModelPositionOffset.f[2]; + + sp34 = sp4C->model->scale * cosf(tank_orientation_angle); + sp48 = sp4C->model->scale * sinf(tank_orientation_angle); + + tank_collision_bounds->points[0].f[0] = collision_position->f[0] + (-sp3C * sp48) + (sp44 * sp34); + tank_collision_bounds->points[0].f[1] = collision_position->f[2] + (sp3C * sp34) + (sp44 * sp48); + + tank_collision_bounds->points[1].f[0] = collision_position->f[0] + (-sp3C * sp48) + (sp40 * sp34); + tank_collision_bounds->points[1].f[1] = collision_position->f[2] + (sp3C * sp34) + (sp40 * sp48); + + tank_collision_bounds->points[2].f[0] = collision_position->f[0] + (-sp38 * sp48) + (sp40 * sp34); + tank_collision_bounds->points[2].f[1] = collision_position->f[2] + (sp38 * sp34) + (sp40 * sp48); + + tank_collision_bounds->points[3].f[0] = collision_position->f[0] + (-sp38 * sp48) + (sp44 * sp34); + tank_collision_bounds->points[3].f[1] = collision_position->f[2] + (sp38 * sp34) + (sp44 * sp48); +} + + +/** + * Address 0x7F07CA2C. +*/ +s32 bondviewTestLineUnobstructed(StandTile **pTile, f32 p_x, f32 p_z, f32 dest_x, f32 dest_z, s32 cdtypes, struct coord3d *coord_p, struct coord3d *coord_dest) +{ + s32 temp_v0; + + temp_v0 = stanTestLineUnobstructed(pTile, p_x, p_z, dest_x, dest_z, cdtypes, 0.0f, 1.0f, 0.0f, 1.0f); + if ((temp_v0 == 0) && (coord_p != NULL)) + { + coord_p->f[0] = p_x; + coord_p->f[1] = 0.0f; + coord_p->f[2] = p_z; + coord_dest->f[0] = dest_x; + coord_dest->f[1] = 0.0f; + coord_dest->f[2] = dest_z; + } + + return temp_v0; +} + + +/** + * Address 0x7F07CAC8. +*/ +s32 bondviewTankCollisionStatus(struct coord3d *collision_position, StandTile *arg1, f32 tank_orientation_angle, struct coord3d *arg3, struct coord3d *arg4) +{ + StandTile *spBC; + s32 stack_padding; + struct rect4f tank_collision_bounds; + s32 sp94; + f32 temp_f0; + + Model *sp8C; + + ModelNode **switches; + struct coord3d *temp_a1; + struct coord3d *temp_a2; + struct coord3d sp74; + Mtxf sp34; + struct coord3d *temp_v1; + + spBC = arg1; + sp94 = 0; + + bondviewGetTankCollisionBounds(&tank_collision_bounds, collision_position, tank_orientation_angle); + + if (g_PlayerTankProp != NULL) + { + sub_GAME_7F03D058(g_PlayerTankProp, 0); + } + + if ((bondviewTestLineUnobstructed(&spBC, collision_position->f[0], collision_position->f[2], tank_collision_bounds.points[0].f[0], tank_collision_bounds.points[0].f[1], CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PATHBLOCKER | CDTYPE_OBJSIMMUNETOEXPLOSIONS, arg3, arg4) != 0) + && (bondviewTestLineUnobstructed(&spBC, tank_collision_bounds.points[0].f[0], tank_collision_bounds.points[0].f[1], tank_collision_bounds.points[1].f[0], tank_collision_bounds.points[1].f[1], CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PATHBLOCKER | CDTYPE_OBJSIMMUNETOEXPLOSIONS, arg3, arg4) != 0) + && (bondviewTestLineUnobstructed(&spBC, tank_collision_bounds.points[1].f[0], tank_collision_bounds.points[1].f[1], tank_collision_bounds.points[2].f[0], tank_collision_bounds.points[2].f[1], CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PATHBLOCKER | CDTYPE_OBJSIMMUNETOEXPLOSIONS, arg3, arg4) != 0) + && (bondviewTestLineUnobstructed(&spBC, tank_collision_bounds.points[2].f[0], tank_collision_bounds.points[2].f[1], tank_collision_bounds.points[3].f[0], tank_collision_bounds.points[3].f[1], CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PATHBLOCKER | CDTYPE_OBJSIMMUNETOEXPLOSIONS, arg3, arg4) != 0) + && (bondviewTestLineUnobstructed(&spBC, tank_collision_bounds.points[3].f[0], tank_collision_bounds.points[3].f[1], tank_collision_bounds.points[0].f[0], tank_collision_bounds.points[0].f[1], CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PATHBLOCKER | CDTYPE_OBJSIMMUNETOEXPLOSIONS, arg3, arg4) != 0)) + { + sp94 = 1; + + if (g_PlayerTankProp != NULL) + { + ObjectRecord *obj = g_PlayerTankProp->obj; + sp8C = obj->model; + switches = sp8C->obj->Switches; + + temp_v1 = switches[3]->Data; + temp_a1 = switches[4]->Data; + temp_a2 = switches[2]->Data; + + sp74.f[0] = temp_a1->f[0] + temp_v1->f[0] - temp_a2->f[0]; + sp74.f[1] = 0.0f; + sp74.f[2] = temp_a1->f[2] + temp_v1->f[2] - temp_a2->f[2]; + + temp_f0 = tank_orientation_angle + g_TankTurretOrientationAngleRad; + + if (temp_f0 >= M_TAU_F) + { + temp_f0 -= M_TAU_F; + } + + if (temp_f0 < 0.0f) + { + temp_f0 += M_TAU_F; + } + + matrix_4x4_set_rotation_around_y(M_TAU_F - temp_f0, &sp34); + mtx4RotateVecInPlace(&sp34, (f32*)&sp74); + + sp74.f[0] *= sp8C->scale; + sp74.f[2] *= sp8C->scale; + + sp74.f[0] += collision_position->f[0]; + sp74.f[2] += collision_position->f[2]; + + spBC = arg1; + + if (bondviewTestLineUnobstructed(&spBC, collision_position->f[0], collision_position->f[2], sp74.f[0], sp74.f[2], CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PATHBLOCKER | CDTYPE_OBJSIMMUNETOEXPLOSIONS, arg3, arg4) == 0) + { + sp94 = 0; + } + + } + } + + if (g_PlayerTankProp != NULL) + { + sub_GAME_7F03D058(g_PlayerTankProp, 1); + } + + return sp94; +} + + + + +/** + * Address 0x7F07CDA8. +*/ +s32 bondviewCallTankCollisionStatus(struct coord3d *collision_position, StandTile *arg1, f32 tank_orientation_angle) +{ + return bondviewTankCollisionStatus(collision_position, arg1, tank_orientation_angle, NULL, NULL); +} + + + + + +/** + * Address 0x7F07CDD4. +*/ +s32 sub_GAME_7F07CDD4(struct coord3d *arg0, f32 arg1, StandTile **arg2) +{ + StandTile *sp3C; + s32 unused_padding[2]; + + sp3C = g_CurrentPlayer->field_488.current_tile_ptr; + + if (( + stanTestLineUnobstructed( + &sp3C, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2], + arg0->f[0], + arg0->f[2], + 0, + 0.0f, + 1.0f, + 0.0f, + 1.0f) != 0) + && (bondviewCallTankCollisionStatus(arg0, sp3C, arg1) != 0)) + { + *arg2 = sp3C; + return 1; + } + + return 0; +} + + + + + +bool isBondInTank(void) +{ + return g_PlayerIsInTank; +} + + + + + + +struct PropRecord *get_ptr_for_players_tank(void) +{ + if (g_PlayerIsInTank == 1) + { + return g_PlayerTankProp; + } + + return 0; +} + + + + + +/** + * Sets paraameter position based on global variables g_TankOrientationAngle, g_TankTurretOrientationAngleRad, g_TankTurretVerticalAngle. + * + * Address 0x7F07CEB0. + */ +void bondviewSet3dCoord7F07CEB0(coord3d *arg0) +{ + f32 f; + + f = g_TankOrientationAngle + g_TankTurretOrientationAngleRad; + + if (f >= M_TAU_F) + { + f = f - M_TAU_F; + } + + if (f < 0.0f) + { + f = f + M_TAU_F; + } + + arg0->f[0] = -sinf(f) * cosf(g_TankTurretVerticalAngle); + arg0->f[1] = sinf(g_TankTurretVerticalAngle); + arg0->f[2] = cosf(f) * cosf(g_TankTurretVerticalAngle); +} + + + + + + +/** + * Unreferenced. + * + * Returns global variable g_TankTurretVerticalAngle, which is in radians. + * + * Address 0x7F07CF80. + */ +f32 bondviewGet8003646CRad(void) +{ + return g_TankTurretVerticalAngle; +} + + + +/** + * Address 0x7F07CF8C. +*/ +s32 bondviewTryMoveToStan(struct coord3d *arg0, StandTile **stan) +{ + s32 sp94; + StandTile *sp90; + s32 cdtypes; + f32 height; + f32 always_30; + f32 collision_radius; + s32 sp7C; + struct TankRecord *tank; + s32 stack_padding[11]; + struct StandTileLocusCallbackRecord sp3C; + + sp94 = 0; + + if ((g_PlayerIsInTank == 1) && (g_EnterTankAudioState != TANK_RUN_STATE_NOT_RUNNING)) + { + sp94 = sub_GAME_7F07CDD4(arg0, g_TankOrientationAngle, stan); + } + else + { + sp90 = g_CurrentPlayer->field_488.current_tile_ptr; + + if (obj_collision_flag) + { + cdtypes = CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PLAYERS | CDTYPE_CHRS | CDTYPE_PATHBLOCKER; + } + else + { + cdtypes = 0; + } + + bondviewGetCollisionRadius(g_CurrentPlayer->prop, &collision_radius, &height, &always_30); + + if (g_WorldTankProp != NULL) + { + sub_GAME_7F03D058(g_WorldTankProp, 0); + } + + sub_GAME_7F03D058(g_CurrentPlayer->prop, 0); + sp7C = stanTileDistanceRelated(&sp90, arg0->f[0], arg0->f[2], collision_radius, &sp3C); + + if (stanGetLocusField0(&sp3C) != 0) + { + g_CurrentPlayer->autocrouchpos = CROUCH_SQUAT; + } + + if ((stanTestLineUnobstructed( + &sp90, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2], + arg0->f[0], + arg0->f[2], + cdtypes, + height, + always_30, + 0.0f, + 1.0f) != 0) + && stanTestVolume(&sp90, arg0->f[0], arg0->f[2], collision_radius, cdtypes, height, always_30) < 0) + { + if (g_CurrentPlayer->ducking_height_offset == FULL_CROUCH_OFFSET || sp7C < 0) + { + if (stanGetLocusCount(&sp3C) == 0 && stanTestLocusEdgeAboveY(&sp90, arg0->f[0], arg0->f[2], collision_radius, g_CurrentPlayer->field_488.collision_position.f[1] + 175.0f) >= 0) + { + goto block_20; + } + else + { + *stan = sp90; + sp94 = 1; + } + } + else + { + goto block_20; + } + } + else + { +block_20: + /* I'm sorry, this is the only way I could make it match. */ + if (g_PlayerTankProp == NULL + && (stanSavedColl_posData != NULL) + && (stanSavedColl_posData->type == PROP_TYPE_OBJ)) + { + tank = (struct TankRecord *)stanSavedColl_posData->obj; + if (tank->type == PROPDEF_TANK) + { + g_WorldTankProp = stanSavedColl_posData; + } + } + } + + sub_GAME_7F03D058(g_CurrentPlayer->prop, 1); + + if (g_WorldTankProp != NULL) + { + sub_GAME_7F03D058(g_WorldTankProp, 1); + } + } + + return sp94; +} + + + +/** + * Calculates collision with current player. + * + * @param next_pos: 3d coordinate to attempt to move to. + * @param collision_pt0: Out parameter. Will set {x,0,z} position of first point (from line edge) if Bond is in collision, otherwise {0}. + * @param collision_pt1: Out parameter. Will set {x,0,z} position of second point (from line edge) if Bond is in collision, otherwise ... Bond's look angle? + * + * @return 1 if able to update stan and collision position, zero otherwise. + * + * Address 0x7F07D234. + */ +s32 bondviewTrySimpleMovePlayerCollision(coord3d *next_pos, coord3d *collision_pt0, coord3d *collision_pt1) +{ + struct StandTile *stan; + + // resets stan global collision variables + stanResetHits(); + + if (bondviewTryMoveToStan(next_pos, &stan) != 0) + { + g_CurrentPlayer->field_488.current_tile_ptr = stan; + g_CurrentPlayer->field_488.collision_position.f[0] = next_pos->f[0]; + g_CurrentPlayer->field_488.collision_position.f[2] = next_pos->f[2]; + + return 1; + } + + getCollisionEdge_maybe(collision_pt0, collision_pt1); + + return 0; +} + + +/** + * This is a fallback method used when bondviewTrySimpleMovePlayerCollision fails. + * Instead of moving to the full coordinate specified by `next_pos`, it will + * scale the position using `calculateRayToSegmentIntersectionNormalized` and try to move to that position. + * + * @param next_pos: 3d coordinate to attempt to move to. + * @param collision1_pt0: Prior collision point 0. + * @param collision1_pt1: Prior collision point 1. + * @param collision2_pt0: Out parameter. Will set {x,0,z} position of first point (from line edge) if Bond is in collision, otherwise {0}. + * @param collision2_pt1: Out parameter. Will set {x,0,z} position of second point (from line edge) if Bond is in collision, otherwise ... Bond's look angle? + * + * @return 1 if able to update stan and collision position, zero if still unable to move by failing on the same collision edge, -1 otherwise (still unable to move). + * + * US address 7F07D2B4. + * Perfect Dark, see bondwalk.c bwalk0f0c47d0, bondbike.c bbike0f0d36d4. +*/ +s32 bondviewTryFractionMovePlayerCollision( + struct coord3d *next_pos, + struct coord3d *collision1_pt0, + struct coord3d *collision1_pt1, + struct coord3d *collision2_pt0, + struct coord3d *collision2_pt1) +{ + StandTile *stan; + f32 height; + f32 always_30; + struct coord3d try_next_pos; + struct coord3d delta_pos; + struct coord3d sp50; + struct coord2d sp48; + struct coord2d sp40; + struct coord2d sp38; + f32 temp_f0; + f32 collision_radius; + + bondviewGetCollisionRadius(g_CurrentPlayer->prop, &collision_radius, &height, &always_30); + + delta_pos.f[0] = next_pos->f[0] - g_CurrentPlayer->field_488.collision_position.f[0]; + delta_pos.f[2] = next_pos->f[2] - g_CurrentPlayer->field_488.collision_position.f[2]; + + sp50.f[0] = collision_radius; + sp50.f[1] = g_CurrentPlayer->field_488.collision_position.f[0]; + sp50.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; + + sp48.f[0] = collision1_pt0->f[0]; + sp48.f[1] = collision1_pt0->f[2]; + + sp40.f[0] = collision1_pt1->f[0]; + sp40.f[1] = collision1_pt1->f[2]; + + sp38.f[0] = delta_pos.f[0]; + sp38.f[1] = delta_pos.f[2]; + + temp_f0 = calculateRayToSegmentIntersectionNormalized(&sp50, &sp48, &sp40, &sp38); + + try_next_pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0] + (delta_pos.f[0] * temp_f0 * 0.25f); + try_next_pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2] + (delta_pos.f[2] * temp_f0 * 0.25f); + + if (bondviewTryMoveToStan(&try_next_pos, &stan) != 0) + { + g_CurrentPlayer->field_488.current_tile_ptr = stan; + g_CurrentPlayer->field_488.collision_position.f[0] = try_next_pos.f[0]; + g_CurrentPlayer->field_488.collision_position.f[2] = try_next_pos.f[2]; + + return 1; + } + + getCollisionEdge_maybe(collision2_pt0, collision2_pt1); + + if (collision2_pt0->f[0] != collision1_pt0->f[0] + || collision2_pt0->f[1] != collision1_pt0->f[1] + || collision2_pt0->f[2] != collision1_pt0->f[2] + || collision2_pt1->f[0] != collision1_pt1->f[0] + || collision2_pt1->f[1] != collision1_pt1->f[1] + || collision2_pt1->f[2] != collision1_pt1->f[2]) + { + return 0; + } + + return -1; +} + + + + +/** + * This is a fallback method used when bondviewTrySimpleMovePlayerCollision fails. + * Instead of moving to the full coordinate specified by `next_pos`, it will + * attempt to move along the collision edge. + * + * @param prior_next_pos: Prior 3d coordinate that Bond failed to move to. + * @param collision1_pt0: Prior collision point 0. + * @param collision1_pt1: Prior collision point 1. + * + * @return -1 if either x or z coordinates are the same for the collision points, 1 if able to update stan and collision position, zero otherwise. + * + * US address 7F07D4C0. + */ +s32 bondviewTryEdgeMovePlayerCollision(struct coord3d *prior_next_pos, struct coord3d *collision_pt0, struct coord3d *collision_pt1) +{ + struct coord3d delta_pos; + f32 tempf; + struct coord3d norm_collision_edge; + struct coord3d try_next_pos; + StandTile *stan; + + delta_pos.f[0] = prior_next_pos->f[0] - g_CurrentPlayer->field_488.collision_position.f[0]; + delta_pos.f[2] = prior_next_pos->f[2] - g_CurrentPlayer->field_488.collision_position.f[2]; + + if (collision_pt0->f[0] != collision_pt1->f[0] || collision_pt0->f[2] != collision_pt1->f[2]) + { + norm_collision_edge.f[0] = collision_pt1->f[0] - collision_pt0->f[0]; + norm_collision_edge.f[2] = collision_pt1->f[2] - collision_pt0->f[2]; + + tempf = (norm_collision_edge.f[0] * norm_collision_edge.f[0]) + (norm_collision_edge.f[2] * norm_collision_edge.f[2]); + tempf = 1.0f / sqrtf(tempf); + norm_collision_edge.f[0] *= tempf; + norm_collision_edge.f[2] *= tempf; + + /** + * Normalizing gives you the direction vector of the wall, so the dot product in the assignment to + * tempf gives you the distance moved along the direction of the wall. + * Then try_next_pos is simply the point of the collision with the wall, plus the + * length moved along the wall times the direction vector of the wall. + **/ + tempf = (delta_pos.f[0] * norm_collision_edge.f[0]) + (delta_pos.f[2] * norm_collision_edge.f[2]); + try_next_pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0] + (tempf * norm_collision_edge.f[0]); + try_next_pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2] + (tempf * norm_collision_edge.f[2]); + + if (bondviewTryMoveToStan(&try_next_pos, &stan)) + { + g_CurrentPlayer->field_488.current_tile_ptr = stan; + g_CurrentPlayer->field_488.collision_position.f[0] = try_next_pos.f[0]; + g_CurrentPlayer->field_488.collision_position.f[2] = try_next_pos.f[2]; + + return 1; + } + + return 0; + } + + return -1; +} + + + +/** + * This is a fallback method used when bondviewTrySimpleMovePlayerCollision fails. + * If Bond previously failed to move because of a collision, this will check + * if Bond is near the end point of the collision edge. If within the collision + * radius of Bond to the edge endpoint, then allow movement. + * + * @param prior_next_pos: Prior 3d coordinate that Bond failed to move to. + * @param collision1_pt0: Prior collision point 0. + * @param collision1_pt1: Prior collision point 1. + * + * @return 1 if able to update stan and collision position, zero otherwise. + * + * US address 7F07D61C. + * + * Perfect Dark bwalk0f0c4a5c. +*/ +s32 bondviewTryEndHopPlayerCollision(struct coord3d *prior_next_pos, struct coord3d *collision_pt0, struct coord3d *collision_pt1) +{ + struct coord3d delta_pos; + struct coord3d sp50; + struct coord3d try_next_pos; + f32 height; + f32 always_30; + f32 tempf; + StandTile *stan; + f32 collision_radius; + + bondviewGetCollisionRadius(g_CurrentPlayer->prop, &collision_radius, &height, &always_30); + + delta_pos.f[0] = prior_next_pos->f[0] - g_CurrentPlayer->field_488.collision_position.f[0]; + delta_pos.f[2] = prior_next_pos->f[2] - g_CurrentPlayer->field_488.collision_position.f[2]; + + sp50.f[0] = collision_pt0->f[0] - prior_next_pos->f[0]; + sp50.f[2] = collision_pt0->f[2] - prior_next_pos->f[2]; + + if (((sp50.f[0] * sp50.f[0]) + (sp50.f[2] * sp50.f[2])) <= (collision_radius * collision_radius)) + { + if (collision_pt0->f[0] != g_CurrentPlayer->field_488.collision_position.f[0] || collision_pt0->f[2] != g_CurrentPlayer->field_488.collision_position.f[2]) + { + sp50.f[0] = -(collision_pt0->f[2] - g_CurrentPlayer->field_488.collision_position.f[2]); + sp50.f[2] = collision_pt0->f[0] - g_CurrentPlayer->field_488.collision_position.f[0]; + + tempf = (sp50.f[0] * sp50.f[0]) + (sp50.f[2] * sp50.f[2]); + tempf = 1.0f / sqrtf(tempf); + sp50.f[0] *= tempf; + sp50.f[2] *= tempf; + + tempf = (delta_pos.f[0] * sp50.f[0]) + (delta_pos.f[2] * sp50.f[2]); + sp50.f[0] *= tempf; + sp50.f[2] *= tempf; + try_next_pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0] + (sp50.f[0]); + try_next_pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2] + (sp50.f[2]); + + if (bondviewTryMoveToStan(&try_next_pos, &stan)) + { + g_CurrentPlayer->field_488.current_tile_ptr = stan; + g_CurrentPlayer->field_488.collision_position.f[0] = try_next_pos.f[0]; + g_CurrentPlayer->field_488.collision_position.f[2] = try_next_pos.f[2]; + + return 1; + } + } + } + else + { + sp50.f[0] = collision_pt1->f[0] - prior_next_pos->f[0]; + sp50.f[2] = collision_pt1->f[2] - prior_next_pos->f[2]; + + if (((sp50.f[0] * sp50.f[0]) + (sp50.f[2] * sp50.f[2])) <= (collision_radius * collision_radius)) + { + if (collision_pt1->f[0] != g_CurrentPlayer->field_488.collision_position.f[0] || collision_pt1->f[2] != g_CurrentPlayer->field_488.collision_position.f[2]) + { + sp50.f[0] = -(collision_pt1->f[2] - g_CurrentPlayer->field_488.collision_position.f[2]); + sp50.f[2] = collision_pt1->f[0] - g_CurrentPlayer->field_488.collision_position.f[0]; + + tempf = (sp50.f[0] * sp50.f[0]) + (sp50.f[2] * sp50.f[2]); + tempf = 1.0f / sqrtf(tempf); + sp50.f[0] *= tempf; + sp50.f[2] *= tempf; + + tempf = (delta_pos.f[0] * sp50.f[0]) + (delta_pos.f[2] * sp50.f[2]); + sp50.f[0] *= tempf; + sp50.f[2] *= tempf; + try_next_pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0] + (sp50.f[0]); + try_next_pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2] + (sp50.f[2]); + + if (bondviewTryMoveToStan(&try_next_pos, &stan)) + { + g_CurrentPlayer->field_488.current_tile_ptr = stan; + g_CurrentPlayer->field_488.collision_position.f[0] = try_next_pos.f[0]; + g_CurrentPlayer->field_488.collision_position.f[2] = try_next_pos.f[2]; + + return 1; + } + } + } + } + + return 0; +} + + +/** + * Unreferenced. + * + * Bitwise convert 32bit int to float. + * + * Address 0x7F07D954. + */ +f32 bondviewBitconvertIntToFloat(s32 arg0) +{ + return *(f32*)&arg0; +} + + + + +struct dummy_struct { + s32 unk00; + s32 unk04; +}; + +/** + * Sets Bond bondprevpos, attempts to move by `offset`. + * + * @param offset: Attempt to move Bond by {x,0,z} amount. + * @param allow_scoot: If movement causes collision, when set will allow Bond to scoot along the collision edge and to bump around corner edges. Otherwise, any collision will stop movement. + * + * US address 7F07D960. + * JP address 7F07DA34 (maybe). + */ +void bondviewCalcUpdatePlayerCollision(struct coord3d *offset, s32 allow_scoot) +{ + struct coord3d next_pos; // spb4 + struct coord3d collision1_pt0; // spa8 + struct coord3d collision1_pt1; // sp9c + struct rect4f *polygon; // sp98 + s32 edges; // sp94 + struct TankRecord *tank_objrecord; // no stack + struct ObjectRecord *obj; + f32 *farr5; + f32 *farr6; + f32 temp_f2; // sp80 + struct coord3d collision2_pt0; // sp74 + struct coord3d collision2_pt1; // sp68 + StandTile *stan; // no stack + struct coord3d collision3_pt0; // sp58 + struct coord3d collision3_pt1; // sp4c + s32 tile_count; // sp48 + s32 i; // sp44 + s32 temp_a3; // no stack + s32 phi_a0_3; // sp3c + s32 temp_v0_7; // no stack + + + g_CurrentPlayer->bondprevpos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; + g_CurrentPlayer->bondprevpos.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; + g_CurrentPlayer->bondprevpos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; + + next_pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0] + offset->f[0]; + next_pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2] + offset->f[2]; + + g_BondCanEnterTank = 0; + + g_CurrentPlayer->autocrouchpos = CROUCH_STAND; + + if (g_WorldTankProp != NULL) + { + chraiGetCollisionBoundsWithoutY(g_WorldTankProp, &polygon, &edges); + + if ((g_PlayerIsInTank == 1) + || (chrpropTestPointInPolygon(&g_CurrentPlayer->field_488.collision_position, polygon, edges) != 0) + || ((chrobjTestPointPolygonCollision(&g_CurrentPlayer->field_488.collision_position, g_CurrentPlayer->field_488.collision_radius, polygon, edges) != 0))) + { + + obj = g_WorldTankProp->obj; + tank_objrecord = (struct TankRecord *)g_WorldTankProp->obj; + + /// TODO: replace with ModelNode structs + farr5 = (f32*)obj->model->obj->Switches[5]->Data; + farr6 = (f32*)obj->model->obj->Switches[6]->Data; + g_PlayerTankProp = g_WorldTankProp; + + temp_f2 = (farr5[4] - farr5[3]) * obj->model->scale; + + if (g_PlayerIsInTank == 1 + || (chrpropTestPointInPolygon(&g_CurrentPlayer->field_488.collision_position, &tank_objrecord->rect, (s32)tank_objrecord->collision) != 0)) + { + temp_f2 += (farr6[4] - farr6[3]) * obj->model->scale; + g_BondCanEnterTank = 1; + } + + if ((g_PlayerIsInTank == 0) && (g_PlayerTankYOffset < temp_f2)) + { + g_PlayerTankYOffset += (20.0f * g_GlobalTimerDelta); + if ((temp_f2 < g_PlayerTankYOffset)) + { + //empty; + } + else + { + return; + } + + g_PlayerTankYOffset = temp_f2; + } + else + { + g_PlayerTankYOffset = temp_f2; + } + + if (g_PlayerIsInTank == 1) + { + if (g_EnterTankAudioState == TANK_RUN_STATE_NOT_RUNNING) + { + g_PlayerTankYOffset += -37.0f * (1.0f - g_TankEnteringSitHeightRemain); + } + else + { + g_PlayerTankYOffset += -37.0f; + } + } + } + else + { + if (g_PlayerTankProp != NULL) + { + g_WorldTankProp = NULL; + g_PlayerTankProp = NULL; + g_PlayerTankYOffset = 0.0f; + } + } + } + + // This `if` block looks like Perfect Dark bbike0f0d3c60 + if (bondviewTrySimpleMovePlayerCollision(&next_pos, &collision1_pt0, &collision1_pt1) == 0) + { + // return values are: + // 1 if able to update stan and collision position + // zero if still unable to move by failing on the same collision edge + // -1 otherwise (still unable to move). + temp_v0_7 = bondviewTryFractionMovePlayerCollision(&next_pos, &collision1_pt0, &collision1_pt1, &collision2_pt0, &collision2_pt1); + + if ((temp_v0_7 > 0) || (temp_v0_7 < 0)) + { + if ((allow_scoot != 0) + && (bondviewTryEdgeMovePlayerCollision(&next_pos, &collision1_pt0, &collision1_pt1) <= 0) + && (bondviewTryEndHopPlayerCollision(&next_pos, &collision1_pt0, &collision1_pt1) == 0)) + { + // empty + } + } + else if (temp_v0_7 == 0) + { + bondviewTryFractionMovePlayerCollision(&next_pos, &collision2_pt0, &collision2_pt1, &collision3_pt0, &collision3_pt1); + + if ((allow_scoot != 0) + && (bondviewTryEdgeMovePlayerCollision(&next_pos, &collision2_pt0, &collision2_pt1) <= 0) + && (bondviewTryEdgeMovePlayerCollision(&next_pos, &collision1_pt0, &collision1_pt1) <= 0) + && (bondviewTryEndHopPlayerCollision(&next_pos, &collision2_pt0, &collision2_pt1) == 0)) + { + bondviewTryEndHopPlayerCollision(&next_pos, &collision1_pt0, &collision1_pt1); + } + } + } + + /** + * This block seems to be some error checking code, this will only occur when Bond + * goes out of bounds. + */ + if (stanTestPointWithinTileBoundsMaybe( + g_CurrentPlayer->field_488.current_tile_ptr, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2]) == 0) + { + if(1); + + stan = g_CurrentPlayer->field_488.current_tile_ptr; + + for (tile_count=0; tile_count<5; tile_count++) + { + /// TODO: fix the horrible casts below. + + for (i=0, phi_a0_3 = 0; i<((stan->tail.half >> 0xC) & 0xF); i++) + { + // maybe: if (( stan->points[i+1].link >> 4) != 0) + if (( ((struct StandTilePoint*)stan) [i+1].link >> 4) != 0) + { + if(1); + phi_a0_3++; + } + } + + temp_a3 = randomGetNext() % (u32)phi_a0_3; + + for (i=0, phi_a0_3 = 0; i<(((s16) stan->tail.half >> 0xC) & 0xF); i++) + { + // maybe: if (( stan->points[i+1].link >> 4) != 0) + if (( ((struct StandTilePoint*)stan) [i+1].link >> 4) != 0) + { + if (phi_a0_3 == temp_a3) + { + // note: no `>> 4` + // maybe: stan = &(standTileStart)[stan->points[i+1].link]; + stan = (struct StandTile*)&((struct dummy_struct*)standTileStart)[( ((struct StandTilePoint*)stan)[i+1].link)]; + break; + } + + phi_a0_3++; + } + } + + if(1); + + if (stanTestPointWithinTileBoundsMaybe( + stan, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2])) + { + g_CurrentPlayer->field_488.current_tile_ptr = stan; + break; + } + } + } + + bondviewUpdatePlayerRoom(g_CurrentPlayer); + + if (g_CurrentPlayer->field_488.current_tile_ptr != NULL) + { + objectivestatusCheckRoomEntered(g_CurrentPlayer->field_488.current_tile_ptr->room); + } +} + + +/** + * Address: 7F07DE64 + */ +void bondviewDeregisterPlayerRoom(struct player *player) +{ + chrpropDeregisterRoom(player->prop, player->registeredroom); + player->registeredroom = -1; +} + + +/** + * Address 0x7F07DE9C. + */ +void bondviewUpdatePlayerRoom(struct player *player) +{ + bondviewDeregisterPlayerRoom(player); + + if (player->prop->chr) + { + chrDetectRooms(player->prop->chr); + return; + } + + if (player->field_488.current_tile_ptr) + { + player->registeredroom = (s16) player->field_488.current_tile_ptr->room; + + chrpropRegisterRoom(player->prop, player->registeredroom); + } +} + + +/** + * Address: 7F07DEFC + */ +void bondviewInitPauseTransition(void) +{ + g_CurrentPlayer->pause_starting_angle = g_CurrentPlayer->vv_verta; + g_CurrentPlayer->pause_transition_time = 0.0f; + g_CurrentPlayer->pause_state = 0; +} + + +/** + * Set the pause tilt's start and end pitch. Also calculates how long the transition should take. + * The greater the angular distance between the player's camera pitch and the pause pitch of -40 degrees, + * the longer it takes to pause. + * + * @param topause: When set, pause_target_verta will be -40.0f, otherwise g_CurrentPlayer->vv_verta. + * @return: How long the tilt should take. + * + * Address 0x7F07DF28. + */ +f32 bondviewSetupPauseTransition(bool topause) +{ + f32 anglediff; + f32 duration; + + if (topause) + { + g_CurrentPlayer->pause_saved_verta = g_CurrentPlayer->vv_verta; + g_CurrentPlayer->pause_target_verta = -40.0f; + } + else + { + g_CurrentPlayer->pause_saved_verta = g_CurrentPlayer->pause_starting_angle; + g_CurrentPlayer->pause_target_verta = g_CurrentPlayer->vv_verta; + } + + anglediff = g_CurrentPlayer->pause_saved_verta - g_CurrentPlayer->pause_target_verta; + + if (anglediff < 0.0f) + { + anglediff = -anglediff; + } + + /** + * If the delta between pause_saved_verta and pause_target_verta is large, + * the time penalty per degree above 60 is cut in half. + */ + if (anglediff >= 60.0f) + { + duration = (((anglediff - 60.0f) * 60.0f * 0.5f) / 60.0f) + 60.0f; + } + else if (anglediff <= 0.0f) + { + duration = 0.0f; + } + else + { + // this is a different `60` than the other values above! + duration = (anglediff * 60.f) / 60.f; + } + + return duration; +} + + +void bondviewStartPauseTransition(f32 duration) { + g_CurrentPlayer->pause_transition_time = 0.0f; + g_CurrentPlayer->pause_transition_duration = duration; + g_CurrentPlayer->pause_state = 1; +} + + +void bondviewStartUnpauseTransition(f32 duration) { + g_CurrentPlayer->pause_transition_time = 0.0f; + g_CurrentPlayer->pause_transition_duration = duration; + g_CurrentPlayer->pause_state = 2; +} + + +bool bondViewIsPauseTransitioning(void) { + return (g_CurrentPlayer->pause_state != 0 && g_CurrentPlayer->pause_state != 3); +} + + +/** + * Transition camera pitch from playing to watch menu (-40.0f degrees). + * Then when the game is unpaused, transition the camera pitch back to its pitch before pausing began. + */ +void bondviewUpdatePauseTransition(void) { + f32 prevverta; + f32 frac; + f32 weight; + + prevverta = g_CurrentPlayer->vv_verta; + + // Entering pause. + if (g_CurrentPlayer->pause_state == 1) { + g_CurrentPlayer->pause_transition_time += g_GlobalTimerDelta * watch_transition_time; + + if (g_CurrentPlayer->pause_transition_time < g_CurrentPlayer->pause_transition_duration) { + // Cosine ease-in-out + frac = g_CurrentPlayer->pause_transition_time / g_CurrentPlayer->pause_transition_duration; + weight = (1.0f - cosf((frac * M_TAU_F) * 0.5f)) * 0.5f; + + g_CurrentPlayer->vv_verta = g_CurrentPlayer->pause_saved_verta + + ((g_CurrentPlayer->pause_target_verta - g_CurrentPlayer->pause_saved_verta) * weight); + } else { + g_CurrentPlayer->vv_verta = g_CurrentPlayer->pause_target_verta; + // Set pause state to paused. + g_CurrentPlayer->pause_state = 3; + } + // Leaving pause. + } else if (g_CurrentPlayer->pause_state == 2) { + g_CurrentPlayer->pause_transition_time += g_GlobalTimerDelta * watch_transition_time; + + if (g_CurrentPlayer->pause_transition_time < g_CurrentPlayer->pause_transition_duration) { + // Cosine ease-in-out + frac = g_CurrentPlayer->pause_transition_time / g_CurrentPlayer->pause_transition_duration; + weight = (1.0f - cosf((frac * M_TAU_F) * 0.5f)) * 0.5f; + + g_CurrentPlayer->vv_verta = g_CurrentPlayer->pause_target_verta + + ((g_CurrentPlayer->pause_saved_verta - g_CurrentPlayer->pause_target_verta) * weight); + } else { + g_CurrentPlayer->vv_verta = g_CurrentPlayer->pause_saved_verta; + // Set pause state to unpaused. + g_CurrentPlayer->pause_state = 0; + } + } + + // Wrap vv_verta into [-180, 180) + if (g_CurrentPlayer->vv_verta < -180.0f) { + g_CurrentPlayer->vv_verta += 360.0f; + } else if (g_CurrentPlayer->vv_verta >= 180.0f) { + g_CurrentPlayer->vv_verta -= 360.0f; + } + + /** + * Calculate shortest angular velocity from previous frame, + * scale it by g_GlobalTimerDelta, + * clamp it to [-0.7, 0.7] so the pitch change is never too fast. + */ + if (g_ClockTimer > 0) { + g_CurrentPlayer->speedverta = g_CurrentPlayer->vv_verta - prevverta; + + if (g_CurrentPlayer->speedverta < 0.0f) { + g_CurrentPlayer->speedverta += 360.0f; + } + + if (g_CurrentPlayer->speedverta > 180.0f) { + g_CurrentPlayer->speedverta -= 360.0f; + } + + g_CurrentPlayer->speedverta /= g_GlobalTimerDelta + g_GlobalTimerDelta; + + if (g_CurrentPlayer->speedverta < -0.7f) { + g_CurrentPlayer->speedverta = -0.7f; + } else if (g_CurrentPlayer->speedverta > 0.7f) { + g_CurrentPlayer->speedverta = 0.7f; + } + } +} + + +f32 bondViewGetPauseTransitionFrac(void) { + + // Entering pause + if (g_CurrentPlayer->pause_state == 1) { + return g_CurrentPlayer->pause_transition_time / g_CurrentPlayer->pause_transition_duration; + } + // Leaving pause + if (g_CurrentPlayer->pause_state == 2) { + return 1.0f - (g_CurrentPlayer->pause_transition_time / g_CurrentPlayer->pause_transition_duration); + } + // Fully paused + if (g_CurrentPlayer->pause_state == 3) { + return 1.0f; + } + // Unpaused + return 0.0f; +} + +void trigger_watch_zoom(f32 final,f32 time) +{ + g_CurrentPlayer->zoomintime = 0.00000000; + g_CurrentPlayer->zoomintimemax = time; + g_CurrentPlayer->zoominfovyold = g_CurrentPlayer->zoominfovy; + g_CurrentPlayer->zoominfovynew = final; +} + + +f32 bondviewGetWatchZoomFovy(void) { + + if (g_CurrentPlayer->zoomintime < g_CurrentPlayer->zoomintimemax) + { + return g_CurrentPlayer->zoominfovynew; + } + + return g_CurrentPlayer->zoominfovy; +} + +/** + * Triggers watch zoom if new value. + * + * @param zoominfovy: watch zoom fovy. + * + * Address 0x7F07E46C. + */ +void bondviewTriggerWatchZoom(f32 zoominfovy) +{ + if (bondviewGetWatchZoomFovy() != zoominfovy) + { + if (zoominfovy < g_CurrentPlayer->zoominfovy) + { + trigger_watch_zoom(zoominfovy, ((g_CurrentPlayer->zoominfovy - zoominfovy) * 15.0f) / 30.0f); + + return; + } + + trigger_watch_zoom(zoominfovy, ((zoominfovy - g_CurrentPlayer->zoominfovy) * 15.0f) / 30.0f); + } +} + + +/** + * Trigger watch zoom with default angle. + * + * Address 0x7F07E504. + */ +void bondviewTriggerWatchZoomDefault(void) +{ + bondviewTriggerWatchZoom(60.0f); +} + + +/** + * Address 0x7F07E52C. + */ +void bondviewZoomToWatchOnOpen(void) +{ + f32 f; + +#if defined(VERSION_EU) + f = ((6.09999990463f - g_CurrentPlayer->zoominfovy) * 45.0f) / -53.9000015259f; +#else + f = ((5.9f - g_CurrentPlayer->zoominfovy) * 45.0f) / -54.1f; +#endif + + if (f < 0.0f) + { + f = -f; + } + +#if defined(VERSION_EU) + trigger_watch_zoom(6.09999990463f, f); +#else + trigger_watch_zoom(5.9f, f); +#endif + +} + + + +/** + * Address 0x7F07E594. + */ +void bondviewZoomFromWatchOnExit(void) +{ + f32 f; + +#if defined(VERSION_EU) + f = ((60.0f - g_CurrentPlayer->zoominfovy) * 45.0f) / -53.9000015259f; +#else + f = ((60.0f - g_CurrentPlayer->zoominfovy) * 45.0f) / -54.1f; +#endif + + if (f < 0.0f) + { + f = -f; + } + + trigger_watch_zoom(60.0f, f); +} + + + +s32 check_watch_page_transistion_running(void) +{ + return (g_CurrentPlayer->zoomintime < g_CurrentPlayer->zoomintimemax); +} + + +/** + * Address 0x7F07E62C. + */ +void bondviewUpdateWatchZoomIn(void) +{ + if (g_CurrentPlayer->zoomintime < g_CurrentPlayer->zoomintimemax) + { + if ((g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x5) || (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xc)) + { +#if defined(BUGFIX_R1) + g_CurrentPlayer->zoomintime = g_CurrentPlayer->zoomintime + (f32) jpD_800484D0; +#else + g_CurrentPlayer->zoomintime = g_CurrentPlayer->zoomintime + (f32) speedgraphframes; +#endif + } + else + { +#if defined(BUGFIX_R1) + g_CurrentPlayer->zoomintime = g_CurrentPlayer->zoomintime + (jpD_800484D0 * watch_transition_time); +#else + g_CurrentPlayer->zoomintime = g_CurrentPlayer->zoomintime + (speedgraphframes * watch_transition_time); +#endif + } + + if (g_CurrentPlayer->zoomintimemax < g_CurrentPlayer->zoomintime) + { + g_CurrentPlayer->zoomintime = g_CurrentPlayer->zoomintimemax; + } + + g_CurrentPlayer->zoominfovy = + g_CurrentPlayer->zoominfovyold + + ( + (g_CurrentPlayer->zoomintime * + (g_CurrentPlayer->zoominfovynew - g_CurrentPlayer->zoominfovyold) + ) + / g_CurrentPlayer->zoomintimemax + ); + } + else + { + g_CurrentPlayer->zoomintime = g_CurrentPlayer->zoomintimemax; + g_CurrentPlayer->zoominfovy = g_CurrentPlayer->zoominfovynew; + } + + set_cur_player_fovy(g_CurrentPlayer->zoominfovy); + viSetFovY(g_CurrentPlayer->zoominfovy); +} + + + + +/** + * Address 0x7F07E740. + */ +f32 bondviewWatchAnimationRelated(void) +{ + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x4) + { + return ((45.0f - g_CurrentPlayer->zoomintimemax) + g_CurrentPlayer->zoomintime) / 45.0f; + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x6) + { + return (g_CurrentPlayer->zoomintimemax - g_CurrentPlayer->zoomintime) / 45.0f; + } + + if ((g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x5) || (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xc)) + { + return 1.0f; + } + + return 0.0f; +} + + + + + +void sub_GAME_7F07E7CC(void) { + ModelFileHeader *itemheader; + + itemheader = get_ptr_itemheader_in_hand(1); + modelCalculateRwDataLen(itemheader); +#ifndef VERSION_EU + if (0x32 < itemheader->numRecords) { + return_null(); + } +#endif + animInit((Model *)((u8 *)g_CurrentPlayer + 0x230), itemheader, (u32 *)((u8 *)g_CurrentPlayer + 0x2ec)); + modelSetScale((Model *)((u8 *)g_CurrentPlayer + 0x230), c_item_entries[41].scale * 0.10000001f); + modelSetAnimation((Model *)((u8 *)g_CurrentPlayer + 0x230), (ModelAnimation *)&ptr_animation_table->data[(s32)&ANIM_DATA_bond_watch], 0, 0.0f, 0.5f * watch_transition_time, 0.0f); + *(s32 *)((u8 *)g_CurrentPlayer + 0x220) = 0; +} + + + + + +/** + * Address 0x7F07E8B0. + */ +void bondviewSetPauseWatchRelated(f32 arg0) +{ + if (g_CurrentPlayer->step_in_view_watch_animation == 0) + { + g_CurrentPlayer->pause_watch_related_scaled = 20.0f / arg0; + } + else + { + g_CurrentPlayer->pause_watch_related_scaled = (20.0f - g_CurrentPlayer->pause_watch_related_adjust) / arg0; + } + + g_CurrentPlayer->step_in_view_watch_animation = 1; + g_CurrentPlayer->pause_watch_related = arg0; +} + + + + +/** + * Address 0x7F07E910. + */ +void bondviewSetPauseWatchRelatedAlt(f32 arg0) +{ + if (g_CurrentPlayer->step_in_view_watch_animation == 3) + { + g_CurrentPlayer->pause_watch_related_scaled = 20.0f / arg0; + } + else + { + g_CurrentPlayer->pause_watch_related_scaled = g_CurrentPlayer->pause_watch_related_adjust / arg0; + } + + g_CurrentPlayer->step_in_view_watch_animation = 2; + g_CurrentPlayer->pause_watch_related = arg0; +} + + + + + +/** + * Address 0x7F07E964. + */ +void bondviewStepWatchAnimation(void) +{ + if ((g_CurrentPlayer->step_in_view_watch_animation != 0) && (g_CurrentPlayer->step_in_view_watch_animation != 3)) + { + if (g_CurrentPlayer->step_in_view_watch_animation == 1) + { + g_CurrentPlayer->pause_animation_counter += g_GlobalTimerDelta * watch_transition_time * g_CurrentPlayer->pause_watch_related_scaled; + + if (g_CurrentPlayer->pause_animation_counter > 20.0f) + { + g_CurrentPlayer->pause_animation_counter = 20.0f; + g_CurrentPlayer->step_in_view_watch_animation = 3; + } + } + else if (g_CurrentPlayer->step_in_view_watch_animation == 2) + { + g_CurrentPlayer->pause_animation_counter -= g_GlobalTimerDelta * watch_transition_time * g_CurrentPlayer->pause_watch_related_scaled; + + if (g_CurrentPlayer->pause_animation_counter < 0.0f) + { + g_CurrentPlayer->pause_animation_counter = 0.0f; + g_CurrentPlayer->step_in_view_watch_animation = 0; + } + } + + modelSetAnimFrame2((void*)&g_CurrentPlayer->something_with_watch_object_instance, g_CurrentPlayer->pause_animation_counter, 0.0f); + } +} + + + + + + +/** + * Address 0x7F07EA78. + */ +f32 bondviewGetPauseAnimationPercent(void) +{ + if ((g_CurrentPlayer->step_in_view_watch_animation == 1) || (g_CurrentPlayer->step_in_view_watch_animation == 2)) + { + return g_CurrentPlayer->pause_animation_counter / 20.0f; + } + + if (g_CurrentPlayer->step_in_view_watch_animation == 3) + { + return 1.0f; + } + + return 0.0f; +} + + + + +void set_BONDdata_outside_watch_menu_flag(s32 arg0) { + g_CurrentPlayer->outside_watch_menu = arg0; +} + +s32 get_BONDdata_outside_watch_menu_flag(void) { + return g_CurrentPlayer->outside_watch_menu; +} + + + + + +void bondviewPlayerStopAudioForPause(void) +{ + struct hand *hand; + s32 i; + ObjectRecord *obj; + PropRecord *prop; + + deactivate_alarm_sound_effect(); + check_deactivate_gas_sound(); + + for (i = 0; i < 2; i++) + { + hand = &g_CurrentPlayer->hands[i]; + + if (hand->audioHandle && sndGetPlayingState(hand->audioHandle) != AL_STOPPED) { + sndDeactivate(hand->audioHandle); + } + } + + for (i = 0; i < 2; i++) + { + if (g_TankSfxState[i] && sndGetPlayingState(g_TankSfxState[i]) != AL_STOPPED) { + sndDeactivate(g_TankSfxState[i]); + } + } + + for (prop = chrpropGetActiveTail(); prop; prop = prop->prev) + { + if (prop->type != PROP_TYPE_DOOR && prop->type == PROP_TYPE_OBJ) + { + obj = prop->obj; + + if (obj->type == PROPDEF_VEHICHLE) + { + VehichleRecord *vehicle = (VehichleRecord *)prop->obj; + if (vehicle->Sound && sndGetPlayingState(vehicle->Sound) != AL_STOPPED) { + sndDeactivate(vehicle->Sound); + } + } + else if (obj->type == PROPDEF_AIRCRAFT) + { + AircraftRecord *aircraft = (AircraftRecord *)prop->obj; + if (aircraft->Sound && sndGetPlayingState(aircraft->Sound) != AL_STOPPED) { + sndDeactivate(aircraft->Sound); + } + } + + if(1); + } + } +} + + + + + +/** + * US address 7F07EC54. + * JP address 7F07F260. + * EU address 7F07ECF4. +*/ +void bondviewWatchAnimationTick(void) +{ +#if defined(VERSION_EU) + #define WATCH_VAR_LOWER 14 + #define WATCH_VAR_UPPER 29 +#else + #define WATCH_VAR_LOWER 17 + #define WATCH_VAR_UPPER 35 +#endif + + s32 sp3c; + s32 sp38; + s32 sp34; + f32 sp30; + f32 sp2c; + f32 sp28; + f32 sp24; + f32 sp20; + + if (g_CurrentPlayer->watch_animation_state) + { + sp34 = getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_TRIGGER || getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_WATCHLASER; + sp3c = sp34; + +#if defined (VERSION_US) + sp38 = WATCH_VAR_LOWER; + + if (sp34) + { + sp38 = WATCH_VAR_UPPER; + } +#else + sp38 = (sp34) ? WATCH_VAR_UPPER : WATCH_VAR_LOWER; +#endif + + g_CurrentPlayer->timer_1C4 += g_ClockTimer; + g_CurrentPlayer->watch_pause_time += 1; + g_CurrentPlayer->pausing_flag = FALSE; + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x1) + { + g_CurrentPlayer->pausing_flag = FALSE; + + if (g_CurrentPlayer->watch_pause_time == 1) + { + draw_item_in_hand(GUNLEFT, ITEM_SUIT_LF_HAND); + } + else if (g_CurrentPlayer->watch_pause_time == 2) + { + if (sp34) + { + draw_item_in_hand(GUNRIGHT, ITEM_UNARMED); + } + } + else + { + if ( + (get_item_in_hand_or_watch_menu(1) == ITEM_SUIT_LF_HAND) + && (Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED) + && ( + (sp34 == 0) + || ( + (get_item_in_hand_or_watch_menu(0) == ITEM_UNARMED) + && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED))) + && (g_CurrentPlayer->timer_1C4 >= sp38)) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x2; + g_CurrentPlayer->watch_pause_time = 1; + g_CurrentPlayer->timer_1C4 = 0; + } + } + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x2) + { + g_CurrentPlayer->pausing_flag = FALSE; + + if (g_CurrentPlayer->watch_pause_time == 1) + { + gunSetSightVisible(GUNAMMOREASON_DAMAGE, FALSE); + gunSetGunAmmoVisible(GUNSIGHTREASON_NOCONTROL, FALSE); + hudmsgsSetOff(PLAYERFLAG_LOCKCONTROLS); + bondviewSetUpperTextDisplayFlag(PLAYERFLAG_LOCKCONTROLS); + countdownTimerSetVisible(4, 0); + + if ((g_CurrentPlayer->pause_state == 0) || (g_CurrentPlayer->pause_state == 2) || (g_CurrentPlayer->pause_state == 3)) + { + sp20 = bondviewSetupPauseTransition(TRUE); + + if (sp20 < 30.0f) + { + sp20 = 30.0f; + } + + bondviewStartPauseTransition(sp20); + } + } + + if ((g_CurrentPlayer->pause_transition_duration - g_CurrentPlayer->pause_transition_time) < 30.0f) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x3; + g_CurrentPlayer->watch_pause_time = 1; + g_CurrentPlayer->timer_1C4 = 0; + + sub_GAME_7F07E7CC(); + } + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x3) + { + if (g_CurrentPlayer->watch_pause_time == 1) + { + sp30 = 40.0f; + + if ((g_CurrentPlayer->step_in_view_watch_animation != 0) && (g_CurrentPlayer->step_in_view_watch_animation != 3)) + { + sp30 = ((20.0f - g_CurrentPlayer->pause_watch_related_adjust) * 40.0f) / 20.0f; + } + + if ((g_CurrentPlayer->pause_state == 0) || (g_CurrentPlayer->pause_state == 2) || (g_CurrentPlayer->pause_state == 3)) + { + sp2c = bondviewSetupPauseTransition(TRUE); + sp20 = sp30 - 10.0f; + + if (sp2c < sp20) + { + sp2c = sp20; + } + + bondviewStartPauseTransition(sp2c); + + sp20 = sp2c + 10.0f; + + if (sp30 < sp20) + { + sp30 = sp20; + } + } + + bondviewSetPauseWatchRelated(sp30); + } + + if ( + ((g_CurrentPlayer->step_in_view_watch_animation != 0) && (g_CurrentPlayer->step_in_view_watch_animation != 3)) + || + bondViewIsPauseTransitioning() + ) + { + g_CurrentPlayer->pausing_flag = TRUE; + } + else + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x4; + g_CurrentPlayer->watch_pause_time = 1; + g_CurrentPlayer->timer_1C4 = 0; + } + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x4) + { + if ((g_CurrentPlayer->watch_pause_time == 1) && (g_CurrentPlayer->field_21C != 0)) + { + sndPlaySfx(g_musicSfxBufferPtr, WATCH_ON_SFX, NULL); + g_CurrentPlayer->field_21C = 0; + } + + bondviewZoomToWatchOnOpen(); + + if (check_watch_page_transistion_running() != 0) + { + g_CurrentPlayer->pausing_flag = TRUE; + } + else + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x5; + g_CurrentPlayer->watch_pause_time = 1; + g_CurrentPlayer->timer_1C4 = 0; + g_CurrentPlayer->field_21C = 1; + } + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x5) + { + if (g_CurrentPlayer->watch_pause_time == 1) + { + sub_GAME_7F0C1310(); + } + + g_CurrentPlayer->pausing_flag = TRUE; + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xc) + { + g_CurrentPlayer->pausing_flag = TRUE; + + if (g_CurrentPlayer->watch_pause_time >= 3) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x6; + g_CurrentPlayer->watch_pause_time = 1; + g_CurrentPlayer->timer_1C4 = 0; + sndPlaySfx(g_musicSfxBufferPtr, WATCH_OFF_SFX, NULL); + } + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x6) + { + if (g_CurrentPlayer->watch_pause_time == 1) + { + bondviewZoomFromWatchOnExit(); + if (sp34) + { + draw_item_in_hand(GUNRIGHT, ITEM_UNARMED); + } + else + { + sub_GAME_7F05DAE4(0); + } + } + if (check_watch_page_transistion_running()) + { + g_CurrentPlayer->pausing_flag = TRUE; + } + else + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x7; + g_CurrentPlayer->watch_pause_time = 1; + g_CurrentPlayer->timer_1C4 = 0; + g_CurrentPlayer->field_21C = 1; + } + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x7) + { + if (g_CurrentPlayer->watch_pause_time == 1) + { + sp28 = 40.0f; + sp24 = bondviewSetupPauseTransition(FALSE); + + if ((g_CurrentPlayer->step_in_view_watch_animation != 0) && (g_CurrentPlayer->step_in_view_watch_animation != 3)) + { + sp28 = (g_CurrentPlayer->pause_watch_related_adjust * 40.0f) / 20.0f; + } + + sp20 = sp28 + 20.0f; + + if (sp24 < sp20) + { + sp24 = sp20; + } + + bondviewStartUnpauseTransition(sp24); + bondviewSetPauseWatchRelatedAlt(sp28); + } + + if ((g_CurrentPlayer->step_in_view_watch_animation != 0) && (g_CurrentPlayer->step_in_view_watch_animation != 3)) + { + g_CurrentPlayer->pausing_flag = TRUE; + } + else + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x8; + g_CurrentPlayer->watch_pause_time = 1; + g_CurrentPlayer->timer_1C4 = 0; + } + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x8) + { + g_CurrentPlayer->pausing_flag = FALSE; + + if (g_CurrentPlayer->watch_pause_time == 1) + { + + if ((get_item_in_hand_or_watch_menu(GUNLEFT) != getCurrentPlayerWeaponId(GUNLEFT)) && (Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED)) + { + draw_item_in_hand(GUNLEFT, getCurrentPlayerWeaponId(GUNLEFT)); + } + + if (sp3c) + { + if ((get_item_in_hand_or_watch_menu(GUNRIGHT) != getCurrentPlayerWeaponId(GUNRIGHT)) && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED)) + { + draw_item_in_hand(GUNRIGHT, getCurrentPlayerWeaponId(GUNRIGHT)); + } + } + } + else if (!bondViewIsPauseTransitioning()) + { + if ( + (get_item_in_hand_or_watch_menu(GUNLEFT) == getCurrentPlayerWeaponId(GUNLEFT)) + && (Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED) + && ( + (sp3c == 0) + || (((get_item_in_hand_or_watch_menu(GUNRIGHT) == getCurrentPlayerWeaponId(GUNRIGHT))) && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED)))) + { + sub_GAME_7F05DAE4(1); + + if (sp3c) + { + sub_GAME_7F05DAE4(0); + } + + gunSetSightVisible(GUNAMMOREASON_DAMAGE, TRUE); + gunSetGunAmmoVisible(GUNSIGHTREASON_NOCONTROL, TRUE); + hudmsgsSetOn(1); + bondviewClearUpperTextDisplayFlag(1); + countdownTimerSetVisible(4, 1); + + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x0; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + } + } + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x9) + { + g_CurrentPlayer->pausing_flag = FALSE; + + if ( + (getCurrentPlayerWeaponId(GUNLEFT) != get_item_in_hand_or_watch_menu(GUNLEFT)) + && (Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED) + && ( + (sp3c == 0) + || (((getCurrentPlayerWeaponId(GUNRIGHT) != get_item_in_hand_or_watch_menu(GUNRIGHT))) && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED)))) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x8; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + } + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xa) + { + g_CurrentPlayer->pausing_flag = FALSE; + + if (g_CurrentPlayer->watch_pause_time == 1) + { + bondviewStartUnpauseTransition(bondviewSetupPauseTransition(FALSE)); + } + + if ( + (getCurrentPlayerWeaponId(GUNLEFT) != get_item_in_hand_or_watch_menu(GUNLEFT)) + && (Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED) + && ( + (sp3c == 0) + || (((getCurrentPlayerWeaponId(GUNRIGHT) != get_item_in_hand_or_watch_menu(GUNRIGHT))) && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED)))) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x8; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + } + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xb) + { + g_CurrentPlayer->pausing_flag = FALSE; + + if ( + (getCurrentPlayerWeaponId(GUNLEFT) == get_item_in_hand_or_watch_menu(GUNLEFT)) + && (Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED) + && ( + (sp3c == 0) + || ( + ( (getCurrentPlayerWeaponId(GUNRIGHT) == get_item_in_hand_or_watch_menu(GUNRIGHT))) + && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED)))) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x1; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + } + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xd) + { + g_CurrentPlayer->pausing_flag = FALSE; + + if (Gun_hand_without_item(GUNLEFT) + && Gun_hand_without_item(GUNRIGHT)) + { + if ((g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_LOWER) + && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_SWAP) + && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_HOLD) + && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_RAISE)) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x1; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + } + } + } + + bondviewUpdatePauseTransition(); + bondviewStepWatchAnimation(); + bondviewUpdateWatchZoomIn(); + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x5) + { + lvlSetControlsLockedFlag(TRUE); + sub_GAME_7F0A6A80(); + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xc) + { + lvlSetControlsLockedFlag(TRUE); + } + else + { + lvlSetControlsLockedFlag(FALSE); + } + +#undef WATCH_VAR_LOWER +#undef WATCH_VAR_UPPER +} + + +void set_open_close_solo_watch_menu_to1(void) +{ + g_CurrentPlayer->open_close_solo_watch_menu = TRUE; +} + + +/** + * US address 7F07F874. + * EU address 7F07F918. +*/ +void trigger_solo_watch_menu(s32 arg0) +{ + struct WatchVertex *ptr_a; + Gfx *ptr_b; + struct WatchVertex *next; + struct WatchVertex *ptr_copy; + s32 i; + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) + { + if (arg0 == 0) + { + watch_transition_time *= 1.1f; + if (watch_transition_time > 1.7f) + { + watch_transition_time = 1.7f; + } + + if ((Gun_hand_without_item(GUNLEFT) != ITEM_UNARMED) + && (Gun_hand_without_item(GUNRIGHT) != ITEM_UNARMED) + && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_LOWER) + && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_SWAP) + && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_HOLD) + && (g_CurrentPlayer->hands[GUNLEFT].weapon_action_state != GUN_ANIM_STATE_SWITCH_RAISE)) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x1; + } + else + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0xd; + } + + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + + bondviewInitPauseTransition(); + bondviewTriggerWatchZoomDefault(); + + hudMakeDamageSegments(&g_CurrentPlayer->armor_display_values, 23*2, 1, currentPlayerGetArmor()); + buildGaugeBarDL(&g_CurrentPlayer->watch_body_armor_bar_gdl, OS_K0_TO_PHYSICAL(&g_CurrentPlayer->armor_display_values), 0x2E); + + hudMakeDamageSegments(&g_CurrentPlayer->health_display_values, 23*2, -1, currentPlayerGetHealth()); + buildGaugeBarDL(&g_CurrentPlayer->watch_health_bar_gdl, OS_K0_TO_PHYSICAL(&g_CurrentPlayer->health_display_values), 0x2E); + + sub_GAME_7F0A69A8(); + + /** + * This section is for rendering the selected screen rectangles. + */ + ptr_b = g_CurrentPlayer->buffer_for_watch_greenbackdrop_DL; // Gfx + ptr_a = &g_CurrentPlayer->buffer_for_watch_greenbackdrop_vertices->vtx[0]; // struct WatchRectangle + + for (i=0; + i<(WATCH_NUMBER_SCREENS * WATCH_SCREEN_SELECT_RECTANGLE_HSTEP); + i+=WATCH_SCREEN_SELECT_RECTANGLE_HSTEP) + { + // Note: colors are set here but overwritten in watch.c set_page_rectangle_colors + ptr_copy = ptr_a; + ptr_a = setup_watch_rectangles(ptr_a, i, 0, 0x64, 0x14, -0x12B, 0x136); + ptr_b = sub_GAME_7F0A3B40(ptr_b, OS_K0_TO_PHYSICAL(ptr_copy)); + } + + gSPEndDisplayList(ptr_b); + /** + * End watch screen select rectangles. + */ + + /** + * This section is related to rendering static on the watch menu. + * Static is defined by a horizontal bar in the middle of the screen. + */ + ptr_a = &g_CurrentPlayer->buffer_for_watch_static_vertices->vtx[0]; // struct WatchRectangle + ptr_b = g_CurrentPlayer->buffer_for_watch_static_DL; // Gfx + + ptr_copy = &g_CurrentPlayer->buffer_for_watch_static_vertices->vtx[0]; + next = setup_watch_rectangles(ptr_a, 0, 0, 0x398, 0x14, -0x1CC, 0); + ptr_b = sub_GAME_7F0A3B40(ptr_b, OS_K0_TO_PHYSICAL(ptr_copy)); + + gSPEndDisplayList(ptr_b); + /** + * End watch static section. + */ + } + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x1) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x9; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x2) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0xa; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x3) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x7; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x4) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x6; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x5) + { + deleteCurrentSelectedFolder(); + sub_GAME_7F0C1340(); + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0xc; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + g_CurrentPlayer->open_close_solo_watch_menu = FALSE; + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xc) + { + // removed + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x6) + { + if (arg0 == 0) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x4; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + sub_GAME_7F0A69A8(); + } + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x7) + { + if (arg0 == 0) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x3; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + sub_GAME_7F0A69A8(); + } + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x8) + { + if (arg0 == 0) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0xb; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + sub_GAME_7F0A69A8(); + } + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x9) + { + if (arg0 == 0) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x1; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + } + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xa) + { + if (arg0 == 0) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x1; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + } + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xb) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x8; + g_CurrentPlayer->watch_pause_time = 0; + g_CurrentPlayer->timer_1C4 = 0; + } + else if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0xd) + { + g_CurrentPlayer->watch_animation_state = WATCH_ANIMATION_0x0; + } +} + +/** + * US address 7F07FCC4. + * Perfect Dark bwalkUpdateSpeedSideways. +*/ +void bondviewUpdateSpeedSideways(s32 arg0) { + if (arg0 == -1) { + g_CurrentPlayer->speedstrafe = (g_CurrentPlayer->speedstrafe - g_GlobalTimerDelta); + if (g_CurrentPlayer->speedstrafe < -1.0f) { + g_CurrentPlayer->speedstrafe = -1.0f; + } + } + else { + if (arg0 == 1) { + g_CurrentPlayer->speedstrafe = (g_CurrentPlayer->speedstrafe + g_GlobalTimerDelta); + if (1.0f < g_CurrentPlayer->speedstrafe) { + g_CurrentPlayer->speedstrafe = 1.0f; + } + } else { + if (0.0f < g_CurrentPlayer->speedstrafe) { + g_CurrentPlayer->speedstrafe = (g_CurrentPlayer->speedstrafe - g_GlobalTimerDelta); + if (g_CurrentPlayer->speedstrafe < 0.0f) { + g_CurrentPlayer->speedstrafe = 0.0f; + } + } else { + g_CurrentPlayer->speedstrafe = (g_CurrentPlayer->speedstrafe + g_GlobalTimerDelta); + if (0.0f < g_CurrentPlayer->speedstrafe) { + g_CurrentPlayer->speedstrafe = 0.0f; + } + } + } + } + g_CurrentPlayer->speedsideways = g_CurrentPlayer->speedstrafe; +} + +/** + * US address 7F07FE1C. + * Perfect Dark bwalkUpdateSpeedForwards. +*/ +void bondviewUpdateSpeedForwards(s32 arg0) { + if (arg0 == 1) { + g_CurrentPlayer->speedgo = (g_CurrentPlayer->speedgo + g_GlobalTimerDelta); + if (1.0f < g_CurrentPlayer->speedgo) { + g_CurrentPlayer->speedgo = 1.0f; + } + } else { + if (arg0 == -1) { + g_CurrentPlayer->speedgo = (g_CurrentPlayer->speedgo - g_GlobalTimerDelta); + if (g_CurrentPlayer->speedgo < -1.0f) { + g_CurrentPlayer->speedgo = -1.0f; + } + } else { + if (0.0f < g_CurrentPlayer->speedgo) { + g_CurrentPlayer->speedgo = (g_CurrentPlayer->speedgo - g_GlobalTimerDelta); + if (g_CurrentPlayer->speedgo < 0.0f) { + g_CurrentPlayer->speedgo = 0.0f; + } + } else { + g_CurrentPlayer->speedgo = (g_CurrentPlayer->speedgo + g_GlobalTimerDelta); + if (0.0f < g_CurrentPlayer->speedgo) { + g_CurrentPlayer->speedgo = 0.0f; + } + } + } + } + g_CurrentPlayer->speedforwards = g_CurrentPlayer->speedgo; +} + +/** + * US address 7F07FF74. + * Duplicate of sub_GAME_7F080228. +*/ +f32 sub_GAME_7F07FF74(f32 value) { + if (value > 0) { + return (viGetFovY() * value * -0.7f) / FOV_Y_F; + } + + if (value < 0) { + return (viGetFovY() * -value * 0.7f) / FOV_Y_F; + } + + return 0; +} + + +/** + * Address 0x7F080010. + */ +void bondviewCurrentPlayerUpdateSpeedVerta(f32 value) +{ + f32 mult = viGetFovY() / FOV_Y_F; + f32 limit = sub_GAME_7F07FF74(value); + + if (value > 0.0f) + { + if (g_CurrentPlayer->speedverta > 0.0f) + { + g_CurrentPlayer->speedverta -= (0.05f * g_GlobalTimerDelta * mult); + } + else + { + g_CurrentPlayer->speedverta -= (0.0125f * g_GlobalTimerDelta * mult); + } + + if (g_CurrentPlayer->speedverta < limit) + { + g_CurrentPlayer->speedverta = limit; + } + } + else if (value < 0.0f) + { + if (g_CurrentPlayer->speedverta < 0.0f) + { + g_CurrentPlayer->speedverta += (0.05f * g_GlobalTimerDelta * mult); + } + else + { + g_CurrentPlayer->speedverta += (0.0125f * g_GlobalTimerDelta * mult); + } + + if (g_CurrentPlayer->speedverta > limit) + { + g_CurrentPlayer->speedverta = limit; + } + } + else + { + if (g_CurrentPlayer->speedverta > limit) + { + g_CurrentPlayer->speedverta -= (0.05f * g_GlobalTimerDelta * mult); + + if (g_CurrentPlayer->speedverta < limit) + { + g_CurrentPlayer->speedverta = limit; + } + } + else + { + g_CurrentPlayer->speedverta += (0.05f * g_GlobalTimerDelta * mult); + + if (g_CurrentPlayer->speedverta > limit) + { + g_CurrentPlayer->speedverta = limit; + } + } + } +} + + + +/** + * US address 7F080228. + * Duplicate of sub_GAME_7F07FF74. +*/ +f32 sub_GAME_7F080228(f32 arg0) { + if (0.0f < arg0) { + return (viGetFovY() * arg0 * -0.7f) / FOV_Y_F; + } else if (arg0 < 0.0f) { + return (viGetFovY() * -arg0 * 0.7f) / FOV_Y_F; + } else { + return 0.0f; + } +} + +/** + * Address 0x7F0802C4. + */ +void bondviewCurrentPlayerUpdateSpeedTheta(f32 value) +{ + f32 mult = viGetFovY() / FOV_Y_F; + f32 limit = sub_GAME_7F080228(value); + + if (value > 0.0f) + { + if (g_CurrentPlayer->speedtheta > 0.0f) + { + g_CurrentPlayer->speedtheta -= (0.05f * g_GlobalTimerDelta * mult); + } + else + { + g_CurrentPlayer->speedtheta -= (0.0125f * g_GlobalTimerDelta * mult); + } + + if (g_CurrentPlayer->speedtheta < limit) + { + g_CurrentPlayer->speedtheta = limit; + } + } + else if (value < 0.0f) + { + if (g_CurrentPlayer->speedtheta < 0) + { + g_CurrentPlayer->speedtheta += (0.05f * g_GlobalTimerDelta * mult); + } + else + { + g_CurrentPlayer->speedtheta += (0.0125f * g_GlobalTimerDelta * mult); + } + + if (limit < g_CurrentPlayer->speedtheta) + { + g_CurrentPlayer->speedtheta = limit; + } + } + else + { + if (limit < g_CurrentPlayer->speedtheta) + { + g_CurrentPlayer->speedtheta -= (0.05f * g_GlobalTimerDelta * mult); + + if (g_CurrentPlayer->speedtheta < limit) + { + g_CurrentPlayer->speedtheta = limit; + } + } + else + { + g_CurrentPlayer->speedtheta += (0.05f * g_GlobalTimerDelta * mult); + + if (limit < g_CurrentPlayer->speedtheta) + { + g_CurrentPlayer->speedtheta = limit; + } + } + } +} + + +Gfx *currentPlayerDrawFade(Gfx *gdl) +{ + f32 frac = g_CurrentPlayer->colourscreenfrac; + s32 r = g_CurrentPlayer->colourscreenred; + s32 g = g_CurrentPlayer->colourscreengreen; + s32 b = g_CurrentPlayer->colourscreenblue; + if ((cameraFrameCounter1 != 0) || (cameraFrameCounter2 != 0)) { + frac = 1.0f; + b = 0; + g = 0; + r = 0; + } + if (frac > 0) { + gDPPipeSync(gdl++); + gDPSetCycleType(gdl++, G_CYC_1CYCLE); + gDPSetColorDither(gdl++, G_CD_DISABLE); + gDPSetTexturePersp(gdl++, G_TP_NONE); + gDPSetAlphaCompare(gdl++, G_AC_NONE); + gDPSetTextureLOD(gdl++, G_TL_TILE); + gDPSetTextureFilter(gdl++, G_TF_BILERP); + gDPSetTextureConvert(gdl++, G_TC_FILT); + gDPSetTextureLUT(gdl++, G_TT_NONE); + gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_CLD_SURF2); + gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); + gDPSetPrimColor(gdl++, 0, 0, r, g, b, (s32)(frac * 255.0f)); + gDPFillRectangle(gdl++, viGetViewLeft(), viGetViewTop(), (viGetViewLeft() + viGetViewWidth()), (viGetViewTop() + viGetViewHeight())); + gDPPipeSync(gdl++); + gDPSetColorDither(gdl++, G_CD_BAYER); + gDPSetTexturePersp(gdl++, G_TP_PERSP); + gDPSetTextureLOD(gdl++, G_TL_LOD); + } + + return gdl; +} + +void currentPlayerSetFadeColour(s32 r, s32 g, s32 b, f32 frac) { + g_CurrentPlayer->colourscreenred = r; + g_CurrentPlayer->colourscreengreen = g; + g_CurrentPlayer->colourscreenblue = b; + g_CurrentPlayer->colourscreenfrac = frac; +} + +void currentPlayerAdjustFade(f32 maxfadetime, s32 r, s32 g, s32 b, f32 frac) +{ + g_CurrentPlayer->colourfadetime60 = 0; + g_CurrentPlayer->colourfadetimemax60 = maxfadetime; + g_CurrentPlayer->colourfaderedold = g_CurrentPlayer->colourscreenred; + g_CurrentPlayer->colourfaderednew = r; + g_CurrentPlayer->colourfadegreenold = g_CurrentPlayer->colourscreengreen; + g_CurrentPlayer->colourfadegreennew = g; + g_CurrentPlayer->colourfadeblueold = g_CurrentPlayer->colourscreenblue; + g_CurrentPlayer->colourfadebluenew = b; + g_CurrentPlayer->colourfadefracold = g_CurrentPlayer->colourscreenfrac; + g_CurrentPlayer->colourfadefracnew = frac; +} + +void currentPlayerSetFadeFrac(f32 maxfadetime, f32 frac) +{ + currentPlayerAdjustFade(maxfadetime, g_CurrentPlayer->colourscreenred, g_CurrentPlayer->colourscreengreen, g_CurrentPlayer->colourscreenblue, frac); +} + +bool currentPlayerIsFadeComplete(void) +{ + return g_CurrentPlayer->colourfadetimemax60 < 0; +} + +void currentPlayerUpdateColourScreenProperties(void) +{ + if (g_CurrentPlayer->colourfadetimemax60 >= 0) + { + g_CurrentPlayer->colourfadetime60 += g_GlobalTimerDelta; + + if (g_CurrentPlayer->colourfadetime60 < g_CurrentPlayer->colourfadetimemax60) + { + f32 mult = g_CurrentPlayer->colourfadetime60 / g_CurrentPlayer->colourfadetimemax60; + g_CurrentPlayer->colourscreenfrac = g_CurrentPlayer->colourfadefracold + (g_CurrentPlayer->colourfadefracnew - g_CurrentPlayer->colourfadefracold) * mult; + g_CurrentPlayer->colourscreenred = g_CurrentPlayer->colourfaderedold + (s32)((g_CurrentPlayer->colourfaderednew - g_CurrentPlayer->colourfaderedold) * mult); + g_CurrentPlayer->colourscreengreen = g_CurrentPlayer->colourfadegreenold + (s32)((g_CurrentPlayer->colourfadegreennew - g_CurrentPlayer->colourfadegreenold) * mult); + g_CurrentPlayer->colourscreenblue = g_CurrentPlayer->colourfadeblueold + (s32)((g_CurrentPlayer->colourfadebluenew - g_CurrentPlayer->colourfadeblueold) * mult); + return; + } + + g_CurrentPlayer->colourscreenfrac = g_CurrentPlayer->colourfadefracnew; + g_CurrentPlayer->colourscreenred = g_CurrentPlayer->colourfaderednew; + g_CurrentPlayer->colourscreengreen = g_CurrentPlayer->colourfadegreennew; + g_CurrentPlayer->colourscreenblue = g_CurrentPlayer->colourfadebluenew; + g_CurrentPlayer->colourfadetimemax60 = -1; + } +} + +void currentPlayerStartChrFade(f32 duration60, f32 targetfrac) +{ + ChrRecord *chr = g_CurrentPlayer->prop->chr; + + if (chr) + { + g_CurrentPlayer->bondfadetime60 = 0; + g_CurrentPlayer->bondfadetimemax60 = duration60; + g_CurrentPlayer->bondfadefracold = chr->fadealpha / 255.0f; + g_CurrentPlayer->bondfadefracnew = targetfrac; + } +} + +void currentPlayerTickChrFade(void) +{ + if (g_CurrentPlayer->bondfadetimemax60 >= 0) + { + ChrRecord *chr = g_CurrentPlayer->prop->chr; + f32 frac; + + g_CurrentPlayer->bondfadetime60 += g_GlobalTimerDelta; + + if (g_CurrentPlayer->bondfadetime60 < g_CurrentPlayer->bondfadetimemax60) + { + frac = g_CurrentPlayer->bondfadefracold + (g_CurrentPlayer->bondfadefracnew - g_CurrentPlayer->bondfadefracold) * g_CurrentPlayer->bondfadetime60 / g_CurrentPlayer->bondfadetimemax60; + } + else + { + frac = g_CurrentPlayer->bondfadefracnew; + g_CurrentPlayer->bondfadetimemax60 = -1; + } + + if (chr) + { + chr->fadealpha = (s8)(frac * 255); + } + } +} + +/** + * Will apply a move animation update. The pass through call to bheadUpdate is + * what allows Bond to move. This will also trigger the death animation once + * Bond dies. This chooses a random death animation from g_bondviewBondDeathAnimations. + * Address 0x7F080B34. +*/ +void bondviewMoveAnimationTick(f32 speed, f32 speedforwards, f32 speedsideways) +{ + f32 percent_speed; + Mtxf sp8C; + Mtxf sp4C; + + percent_speed = 0.0f; + + if (g_CurrentPlayer->bonddead == 0) + { + bheadAdjustAnimation(speed); + + if (speed != 0.0f) + { + percent_speed = speedforwards / speed; + } + else if (speedforwards == 0.0f) + { + // + } + } + else + { + if (g_CurrentPlayer->startnewbonddie) + { + // HACK: ptr_animation_table dereference addition is backwards. + // this should be: + // ptr_animation_table->data[g_bondviewBondDeathAnimations[((u32) randomGetNext() % (u32) g_bondviewBondDeathAnimationsCount)]] + bheadStartDeathAnimation((struct ModelAnimation *) ((s32)g_bondviewBondDeathAnimations[((u32) randomGetNext() % (u32) g_bondviewBondDeathAnimationsCount)] + (s32)&ptr_animation_table->data[0]), randomGetNext() & 1, 0.0f, 1.0f); + g_CurrentPlayer->startnewbonddie = FALSE; + } + + bheadSetSpeed(0.5f); + speedsideways = 0.0f; + } + + bheadUpdate(percent_speed, speedsideways); + + matrix_4x4_set_rotation_around_x((360.0f - g_CurrentPlayer->vv_verta360) * DegToRad1Fact(1), &sp8C); + matrix_4x4_set_basis_and_position_target(&sp4C, 0.0f, 0.0f, 0.0f, -g_CurrentPlayer->headlook.f[0], -g_CurrentPlayer->headlook.f[1], -g_CurrentPlayer->headlook.f[2], g_CurrentPlayer->headup.f[0], g_CurrentPlayer->headup.f[1], g_CurrentPlayer->headup.f[2]); + matrix_4x4_multiply_in_place(&sp4C, &sp8C); + matrix_4x4_set_rotation_around_y((360.0f - g_CurrentPlayer->vv_theta) * DegToRad1Fact(1), &sp4C); + matrix_4x4_multiply_in_place(&sp4C, &sp8C); + + g_CurrentPlayer->field_488.applied_view.f[0] = sp8C.m[2][0]; + g_CurrentPlayer->field_488.applied_view.f[1] = sp8C.m[2][1]; + g_CurrentPlayer->field_488.applied_view.f[2] = sp8C.m[2][2]; + + g_CurrentPlayer->field_488.applied_view2.f[0] = sp8C.m[1][0]; + g_CurrentPlayer->field_488.applied_view2.f[1] = sp8C.m[1][1]; + g_CurrentPlayer->field_488.applied_view2.f[2] = sp8C.m[1][2]; + +} + + +/** + * Address 0x7F080D60. + */ +f32 bondviewYPositionRelated(StandTile *arg0, f32 arg1, f32 arg2) +{ + f32 ret; + + if (g_PlayerTankProp != NULL) + { + ObjectRecord * obj = ((PropRecord *)g_PlayerTankProp)->obj; + PropRecord *p = obj->prop; + + ret = stanGetPositionYValue(p->stan, p->pos.x, p->pos.z); + + ret += g_PlayerTankYOffset; + } + else + { + if (g_CurrentPlayer->field_2A6C) + { + ret = stanGetPositionYValue(g_CurrentPlayer->field_2A70, arg1, arg2); + } + else + { + ret = stanGetPositionYValue(arg0, arg1, arg2); + } + } + + return ret; +} + + + +/** + * US Address 0x7F080DF8. + * EU Address 0x7F080E9C. + */ +void bondviewUpdatePlayerY(s32 use_stanHeight, f32 stanHeight_offset) +{ + s32 i; // sp6c + f32 unused; + f32 sp64; + StandTile *stan; //sp60 + f32 collision_radius; //sp5c + f32 height; //sp58 + f32 always_30; //sp54 + f32 temp_f0; // no stack + f32 new_field_70; // sp4c + f32 new_field_7c; //sp48 + f32 ftemp2; + f32 sp40; + + if (1); + + if (g_PlayerIsInTank == 1) + { + g_CurrentPlayer->stanHeight = bondviewYPositionRelated( + g_CurrentPlayer->field_488.current_tile_ptr, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2]); + + g_CurrentPlayer->field_6C = g_CurrentPlayer->field_70 / (1.0f - TANK_UNKD0_SCALE); + + for (i=0; ifield_6C = (g_CurrentPlayer->field_6C * TANK_UNKD0_SCALE) + g_CurrentPlayer->stanHeight; + } + + g_CurrentPlayer->field_70 = g_CurrentPlayer->field_6C * (1.0f - TANK_UNKD0_SCALE); + } + else + { + if (use_stanHeight != 0) + { + g_CurrentPlayer->stanHeight = g_CurrentPlayer->stanHeight + stanHeight_offset; + + temp_f0 = bondviewYPositionRelated( + g_CurrentPlayer->field_488.current_tile_ptr, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2]); + + if (g_CurrentPlayer->stanHeight < temp_f0) + { + g_CurrentPlayer->stanHeight = temp_f0; + } + } + else + { + stan = g_CurrentPlayer->field_488.current_tile_ptr; + + bondviewGetCollisionRadius(g_CurrentPlayer->prop, &collision_radius, &height, &always_30); + + sp64 = bondviewYPositionRelated( + g_CurrentPlayer->field_488.current_tile_ptr, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2]); + + // Another error checking block, it seems this condition is almost never triggered in the game. + if (stanTestLocusEdgeAboveY( + &stan, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2], + collision_radius, + bondviewGetPlayerDuckingHeightRelated(g_CurrentPlayer) + sp64) >= 0) + { + if (sp64 < g_CurrentPlayer->stanHeight) + { + sp64 = g_CurrentPlayer->stanHeight; + } + } + + g_CurrentPlayer->stanHeight = sp64; + } + + if ((g_CurrentPlayer->field_2A6C != 0) && (g_CurrentPlayer->field_70 < g_CurrentPlayer->stanHeight)) + { + g_CurrentPlayer->field_2A6C = 0; + g_CurrentPlayer->field_488.current_tile_ptr = g_CurrentPlayer->field_2A70; + g_CurrentPlayer->field_2A70 = NULL; + } + + if ((g_CurrentPlayer->field_7C >= 0.0f) || (g_CurrentPlayer->field_70 < g_CurrentPlayer->stanHeight)) + { + g_CurrentPlayer->field_6C = g_CurrentPlayer->field_70 / (1.0f - TANK_UNKD0_SCALE); + + for (i=0; ifield_6C = (g_CurrentPlayer->field_6C * TANK_UNKD0_SCALE) + g_CurrentPlayer->stanHeight; + } + + if (g_CurrentPlayer->field_70 < g_CurrentPlayer->stanHeight) + { + g_CurrentPlayer->field_70 = g_CurrentPlayer->field_6C * (1.0f - TANK_UNKD0_SCALE); + } + } + + if (g_CurrentPlayer->stanHeight < g_CurrentPlayer->field_70) + { + new_field_7c = g_CurrentPlayer->field_7C; + new_field_70 = g_CurrentPlayer->field_70; + + if ((get_debug_fast_bond_flag() != 0) && (g_ForceBondMoveOffset.f[0] == 0.0f) && (g_ForceBondMoveOffset.f[2] == 0.0f)) + { + sp40 = 1.388889f; + } + else + { + sp40 = 0.27777779f; + } + + ftemp2 = new_field_7c - (g_GlobalTimerDelta * sp40); + new_field_70 += (g_GlobalTimerDelta * (new_field_7c + ftemp2) * 0.5f); + new_field_7c = ftemp2; + + if (new_field_70 < g_CurrentPlayer->stanHeight) + { + new_field_70 = g_CurrentPlayer->stanHeight; + new_field_7c = -sqrtf((g_CurrentPlayer->field_7C * g_CurrentPlayer->field_7C) + (((2.0f * (g_CurrentPlayer->field_70 - g_CurrentPlayer->stanHeight) * 0.27777779f) / 60.0f) * 60.0f)); + + + if (g_CurrentPlayer->field_2A6C != 0) + { + g_CurrentPlayer->field_2A6C = 0; + g_CurrentPlayer->field_488.current_tile_ptr = g_CurrentPlayer->field_2A70; + g_CurrentPlayer->field_2A70 = NULL; + } + } + + g_CurrentPlayer->field_70 = new_field_70; + g_CurrentPlayer->field_7C = new_field_7c; + } + + if ((g_CurrentPlayer->field_7C < 0.0f) && (g_CurrentPlayer->field_70 <= g_CurrentPlayer->stanHeight)) + { + if (g_CurrentPlayer->field_7C < -13.333333f) + { + g_CurrentPlayer->field_8C = CLIPPING_FIELD8C_VALUE; + g_CurrentPlayer->vertical_bounce_adjust = -90.0f; + } + else if (g_CurrentPlayer->field_7C < -5.0f) + { + g_CurrentPlayer->field_8C = CLIPPING_FIELD8C_VALUE; + g_CurrentPlayer->vertical_bounce_adjust = ((-5.0f - g_CurrentPlayer->field_7C) * -90.0f) / 8.333333f; + } + + g_CurrentPlayer->field_7C = 0.0f; + } + + if (g_CurrentPlayer->field_2A6C != 0) + { + if (g_CurrentPlayer->field_70 + bondviewGetPlayerDuckingHeightRelated(g_CurrentPlayer) + < stanGetPositionYValue( + g_CurrentPlayer->field_488.current_tile_ptr, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2])) + { + g_CurrentPlayer->field_2A6C = 0; + g_CurrentPlayer->field_488.current_tile_ptr = g_CurrentPlayer->field_2A70; + g_CurrentPlayer->field_2A70 = NULL; + } + } + } + + for (i=0; ifield_8C > 0) + { + g_CurrentPlayer->field_84 = (g_CurrentPlayer->field_84 * CLIPPING_CLOCK_FACTOR) + g_CurrentPlayer->vertical_bounce_adjust; + g_CurrentPlayer->field_8C += -1; + } + else + { + if (g_CurrentPlayer->vertical_bounce_adjust < 0.0f) + { + g_CurrentPlayer->vertical_bounce_adjust -= CLIPPING_FIELD90_VALUE; + + if (0.0f <= g_CurrentPlayer->vertical_bounce_adjust) + { + g_CurrentPlayer->vertical_bounce_adjust = 0.0f; + } + } + + g_CurrentPlayer->field_84 = (g_CurrentPlayer->field_84 * CLIPPING_CLOCK_FACTOR) + g_CurrentPlayer->vertical_bounce_adjust; + } + } + + g_CurrentPlayer->field_88 = g_CurrentPlayer->field_84 * CLIPPING_FIELD88_FACTOR; +} + + + + + +/** + * Address 0x7F081478 (NTSC). + * Address 0x7F08151C (PAL). +*/ +void bondviewUpdatePlayerCollisionPositionFields(void) +{ + f32 phi_f0; + s32 i; + StandTile *sp2C; + s32 sp28; + + g_CurrentPlayer->eyeheight = (g_CurrentPlayer->headpos.f[1] * g_playerPerm->player_perspective_height) + 7.0f; + + phi_f0 = g_CurrentPlayer->eyeheight + + ((g_CurrentPlayer->field_88 + g_CurrentPlayer->ducking_height_offset) * g_playerPerm->player_perspective_height); + + if (phi_f0 < 30.0f) + { + phi_f0 = 30.0f; + } + + g_CurrentPlayer->field_488.collision_position.f[1] = g_CurrentPlayer->field_70 + phi_f0; + + if (((g_CameraMode != CAMERAMODE_DEATH_CAM_SP) && (g_CameraMode != CAMERAMODE_DEATH_CAM_MP) && (g_CameraMode != CAMERAMODE_POSEND)) + || (g_CurrentPlayer->bodyModel == 0)) + { + g_CurrentPlayer->field_488.pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; + g_CurrentPlayer->field_488.pos.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; + g_CurrentPlayer->field_488.pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; + } + + if (g_CurrentPlayer->bonddead != FALSE) + { + if (g_CurrentPlayer->field_29C0 > 0.0f) + { + g_CurrentPlayer->field_29C0 -= 0.25f; + + if (g_CurrentPlayer->field_29C0 < 0.0f) + { + g_CurrentPlayer->field_29C0 = 0.0f; + } + } + } + + if (g_CurrentPlayer->vv_verta < 0.0f) + { + g_CurrentPlayer->field_488.pos.f[1] += -(1.0f - g_CurrentPlayer->vv_cosverta) * g_CurrentPlayer->field_29C0; + } + + sp2C = g_CurrentPlayer->field_488.current_tile_ptr; + sp28 = stanlinelog_flag; + stanlinelog_flag = 0; + + walkTilesBetweenPoints_NoCallback( + &sp2C, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2], + g_CurrentPlayer->field_488.pos.f[0], + g_CurrentPlayer->field_488.pos.f[2]); + + stanlinelog_flag = sp28; + + g_CurrentPlayer->field_488.current_tile_ptr_for_portals = sp2C; + + g_CurrentPlayer->field_488.pos3.f[0] = g_CurrentPlayer->field_488.pos.f[0]; + g_CurrentPlayer->field_488.pos3.f[2] = g_CurrentPlayer->field_488.pos.f[2]; + + g_CurrentPlayer->field_488.pos3.f[1] = bondviewYPositionRelated( + g_CurrentPlayer->field_488.current_tile_ptr_for_portals, + g_CurrentPlayer->field_488.pos.f[0], + g_CurrentPlayer->field_488.pos.f[2]); + + g_CurrentPlayer->prop->stan = g_CurrentPlayer->field_488.current_tile_ptr; + + g_CurrentPlayer->prop->pos.f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; + g_CurrentPlayer->prop->pos.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; + g_CurrentPlayer->prop->pos.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; + +#if defined(VERSION_EU) +#define S7F081478_FACTOR_1 0.881200015545f +#else +#define S7F081478_FACTOR_1 0.9f +#endif + for (i=0; ifield_3B8.f[0] = (S7F081478_FACTOR_1 * g_CurrentPlayer->field_3B8.f[0]) + g_CurrentPlayer->field_488.pos.f[0]; + g_CurrentPlayer->field_3B8.f[1] = (S7F081478_FACTOR_1 * g_CurrentPlayer->field_3B8.f[1]) + g_CurrentPlayer->field_488.pos.f[1]; + g_CurrentPlayer->field_3B8.f[2] = (S7F081478_FACTOR_1 * g_CurrentPlayer->field_3B8.f[2]) + g_CurrentPlayer->field_488.pos.f[2]; + } + +#if defined(VERSION_EU) +#define S7F081478_FACTOR_2 0.118799984455f +#else +#define S7F081478_FACTOR_2 0.100000024f +#endif + g_CurrentPlayer->field_3C4 = g_CurrentPlayer->field_3B8.f[0] * S7F081478_FACTOR_2; + g_CurrentPlayer->field_3C8 = g_CurrentPlayer->field_3B8.f[1] * S7F081478_FACTOR_2; + g_CurrentPlayer->field_3CC = g_CurrentPlayer->field_3B8.f[2] * S7F081478_FACTOR_2; +} + + + + + +/** + * Fixes vv_verta within -90 and +90. + * Updates vv_costheta, vv_sintheta, vv_verta360, vv_cosverta, vv_sinverta, field_488.theta_transform. + * Address 0x7F081790. + * + * Perfect Dark function bmoveUpdateVerta. +*/ +void bondviewApplyVertaTheta(void) +{ + while (g_CurrentPlayer->vv_verta < -180.0f) + { + g_CurrentPlayer->vv_verta += 360.0f; + } + + while (g_CurrentPlayer->vv_verta >= 180.0f) + { + g_CurrentPlayer->vv_verta -= 360.0f; + } + + if (g_CurrentPlayer->vv_verta > 90.0f) + { + g_CurrentPlayer->vv_verta = 90.0f; + } + else if (g_CurrentPlayer->vv_verta < -90.0f) + { + g_CurrentPlayer->vv_verta = -90.0f; + } + + g_CurrentPlayer->vv_costheta = cosf(g_CurrentPlayer->vv_theta * DegToRad1Fact(1)); + g_CurrentPlayer->vv_sintheta = sinf(g_CurrentPlayer->vv_theta * DegToRad1Fact(1)); + + g_CurrentPlayer->vv_verta360 = g_CurrentPlayer->vv_verta; + if (g_CurrentPlayer->vv_verta360 < 0.0f) + { + g_CurrentPlayer->vv_verta360 += 360.0f; + } + + g_CurrentPlayer->vv_cosverta = cosf(g_CurrentPlayer->vv_verta360 * DegToRad1Fact(1)); + g_CurrentPlayer->vv_sinverta = sinf(g_CurrentPlayer->vv_verta360 * DegToRad1Fact(1)); + + g_CurrentPlayer->field_488.theta_transform.f[0] = -g_CurrentPlayer->vv_sintheta; + g_CurrentPlayer->field_488.theta_transform.f[1] = 0; + g_CurrentPlayer->field_488.theta_transform.f[2] = g_CurrentPlayer->vv_costheta; +} + + +/** + * US address 7F081974. + * EU address 7F081A18. + * Perfect Dark method bmoveProcessInput. +*/ +void bondviewProcessInput(s8 stick_x, s8 stick_y, u16 buttons, u16 oldbuttons) +{ + struct MoveData moveData; // sp120 + + s8 player_joyGetStickX; // sp11F + s8 player_joyGetStickY; // sp11E + u16 player_joyGetButtons; // sp11C + u16 copy_prev_buttons_pressed; // sp11A + s32 adjustedStickX; + s32 tmpc2sticky; + s32 sp10C; + s32 sp108; + s32 sp104; + s32 sp100; + u16 shootButtons; // spFE + u16 aimButtons; // spFC + u16 invButtons; // spFA + // missing spF8 + TankRecord *spF4; + s32 i_0; // spF0 + TankRecord *spEC; + f32 ftemp_nostack_spE8; // unused + f32 noiseRadius; // spE4 + f32 ftemp_nostack_spE0; + f32 targetSpeed; + f32 ftemp_nostack_spD8; + f32 unadjustedTargetSpeed; + f32 ftemp_nostack_spD0; + f32 ftemp_nostack_spCC; + f32 ftemp_nostack_spC8; + f32 targetPitch; + StandTile *spC0; + f32 spBC; + f32 ftemp_nostack_spB8; + struct coord3d spAC; + struct coord3d spA0; + s32 stack_padding_sp9C; // unused + f32 ftemp_nostack_sp98; + f32 ftemp_nostack_sp94; + f32 ftemp_nostack_sp90; // unused + f32 ftemp_nostack_sp8C; + f32 ftemp_nostack_sp88; + f32 ftemp_nostack_sp84; + f32 ftemp_nostack_sp80; + s32 i_1; + f32 ftemp_nostack_sp78; + s32 canCycleWeapons; // sp74 + f32 sp70; + + + moveData.canSwivelGun = 0; + moveData.canManualAim = 0; + moveData.triggerOn = 0; + moveData.btap = 0; + moveData.canLookAhead = 0; + moveData.canTurnTank = 0; + moveData.canNaturalTurn = 0; + moveData.canNaturalPitch = 0; + moveData.digitalStepForward = 0; + moveData.digitalStepBack = 0; + moveData.digitalStepLeft = 0; + moveData.digitalStepRight = 0; + moveData.tankTurnLeftSpeed = 0; + moveData.tankTurnRightSpeed = 0; + moveData.speedVertaDown = 0; + moveData.speedVertaUp = 0; + moveData.aimTurnLeftSpeed = 0; + moveData.aimTurnRightSpeed = 0; + moveData.weaponBackOffset = 0; + moveData.weaponForwardOffset = 0; + moveData.aiming = 0; + moveData.zooming = 0; + moveData.zoomOutFovPersec = 0; + moveData.zoomInFovPersec = 0; + moveData.crouchDown = 0; + moveData.crouchUp = 0; + moveData.rLeanLeft = 0; + moveData.rLeanRight = 0; + moveData.detonating = 0; + moveData.canAutoAim = 0; + moveData.invertPitch = get_cur_player_look_vertical_inverted() == 0; + moveData.disableLookAhead = 0; + + if (stick_x < -5) { + moveData.controlStickXSafe = stick_x + 5; + } else if (stick_x > 5) { + moveData.controlStickXSafe = stick_x - 5; + } else { + moveData.controlStickXSafe = 0; + } + + if (stick_y < -5) { + moveData.controlStickYSafe = stick_y + 5; + } else if (stick_y > 5) { + moveData.controlStickYSafe = stick_y - 5; + } else { + moveData.controlStickYSafe = 0; + } + + moveData.controlStickXRaw = (s32)stick_x; + moveData.controlStickYRaw = (s32)stick_y; + + moveData.analogTurn = moveData.controlStickXSafe; + moveData.analogPitch = moveData.controlStickYSafe; + moveData.analogStrafe = moveData.controlStickXSafe; + moveData.analogWalk = moveData.controlStickYSafe; + + if (g_CurrentPlayer->bonddead == FALSE + && g_bondviewForceDisarm <= 0 + && ( + (g_CurrentPlayer->watch_animation_state != WATCH_ANIMATION_0x5 + && ((buttons & ~oldbuttons) & START_BUTTON) + ) + || + (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x5 + && g_CurrentPlayer->open_close_solo_watch_menu) + ) + && (getPlayerCount() == 1)) + { + trigger_solo_watch_menu(0); + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0 + && g_CurrentPlayer->bonddead == FALSE + && ( + getPlayerCount() == 1 + || ( + g_stopPlayFlag == 0 + && g_gameOverFlag == 0))) + { + if (cur_player_get_control_type() == CONTROLLER_CONFIG_DOMINO /* 2.3 */ + || cur_player_get_control_type() == CONTROLLER_CONFIG_GOODHEAD /* 2.4 */ + || cur_player_get_control_type() == CONTROLLER_CONFIG_GALORE /* 2.2 */ + || cur_player_get_control_type() == CONTROLLER_CONFIG_PLENTY /* 2.1 */ + ) + { + player_joyGetStickX = joyGetStickX(get_cur_playernum() + getPlayerCount()); + player_joyGetStickY = joyGetStickY(get_cur_playernum() + getPlayerCount()); + player_joyGetButtons = joyGetButtons(get_cur_playernum() + getPlayerCount() , (u32)ANY_BUTTON); + + copy_prev_buttons_pressed = g_CurrentPlayer->prev_buttons_pressed; + + if (player_joyGetStickX < -5) + { + adjustedStickX = player_joyGetStickX + 5; + } + else if (player_joyGetStickX > 5) + { + adjustedStickX = player_joyGetStickX - 5; + } + else + { + adjustedStickX = 0; + } + + if (player_joyGetStickY < -5) + { + tmpc2sticky = player_joyGetStickY + 5; + } + else if (player_joyGetStickY >= 6) + { + tmpc2sticky = player_joyGetStickY - 5; + } + else + { + tmpc2sticky = 0; + } + + /* 2.1 and 2.3 */ + if (cur_player_get_control_type() == CONTROLLER_CONFIG_PLENTY || (cur_player_get_control_type() == CONTROLLER_CONFIG_DOMINO)) + { + moveData.analogStrafe = adjustedStickX; + moveData.analogPitch = tmpc2sticky; + } + else + { + if (g_PlayerIsInTank == 1 && !g_CurrentPlayer->insightaimmode) + { + moveData.analogTurn = adjustedStickX; + } + else + { + moveData.analogStrafe = adjustedStickX; + } + + moveData.analogWalk = tmpc2sticky; + } + + /* 2.1 and 2.2 */ + if (cur_player_get_control_type() == CONTROLLER_CONFIG_PLENTY || cur_player_get_control_type() == CONTROLLER_CONFIG_GALORE) + { + sp104 = (player_joyGetButtons & Z_TRIG) != 0; + sp100 = ((player_joyGetButtons & ~copy_prev_buttons_pressed) & Z_TRIG) != 0; + sp10C = (buttons & Z_TRIG) != 0; + sp108 = ((buttons & ~oldbuttons) & Z_TRIG) != 0; + } + else + { + sp104 = (buttons & Z_TRIG) != 0; + sp100 = ((buttons & ~oldbuttons) & Z_TRIG) != 0; + sp10C = (player_joyGetButtons & Z_TRIG) != 0; + sp108 = ((player_joyGetButtons & ~copy_prev_buttons_pressed) & Z_TRIG) != 0; + } + + if (lvlGetControlsLockedFlag() == 0 && disablePlayerActionsWhenPausedOrInMpMenu()) + { + if (cur_player_get_aim_control() == 0) + { + g_CurrentPlayer->insightaimmode = sp104; + } + else if (sp100) + { + g_CurrentPlayer->insightaimmode = !g_CurrentPlayer->insightaimmode; + } + + moveData.canSwivelGun = !g_CurrentPlayer->insightaimmode; + moveData.canAutoAim = !g_CurrentPlayer->insightaimmode; + + moveData.canManualAim = g_CurrentPlayer->insightaimmode; + + moveData.btap = ( + (((buttons & ~oldbuttons) & B_BUTTON) != 0) + || + ((((player_joyGetButtons & ~copy_prev_buttons_pressed) & B_BUTTON)) != 0) + ); + + moveData.canLookAhead = !g_CurrentPlayer->insightaimmode; + moveData.canTurnTank = 1; + moveData.canNaturalTurn = !g_CurrentPlayer->insightaimmode; + moveData.canNaturalPitch = !g_CurrentPlayer->insightaimmode; + + if (g_CurrentPlayer->insightaimmode && (stick_y > 60)) + { + moveData.speedVertaDown = (f32) (stick_y - 60) / FLOAT_TEN_B; + if (moveData.speedVertaDown > 1.0f) + { + moveData.speedVertaDown = 1.0f; + } + } + else + { + //moveData.speedVertaDown = 0; + } + + if (g_CurrentPlayer->insightaimmode && (stick_y < -60)) + { + moveData.speedVertaUp = (f32) (-60 - stick_y) / FLOAT_TEN_B; + if (moveData.speedVertaUp > 1.0f) + { + moveData.speedVertaUp = 1.0f; + } + } + else + { + //moveData.speedVertaUp = 0; + } + + + if (g_CurrentPlayer->insightaimmode && (stick_x < -60)) + { + moveData.aimTurnLeftSpeed = (f32) (-60 - stick_x) / FLOAT_TEN_B; + if (moveData.aimTurnLeftSpeed > 1.0f) + { + moveData.aimTurnLeftSpeed = 1.0f; + } + } + else + { + //moveData.aimTurnLeftSpeed = 0; + } + + if (g_CurrentPlayer->insightaimmode && (stick_x > 60) ) + { + moveData.aimTurnRightSpeed = (f32) (stick_x - 60) / FLOAT_TEN_B; + if (moveData.aimTurnRightSpeed > 1.0f) + { + moveData.aimTurnRightSpeed = 1.0f; + } + } + else + { + //moveData.aimTurnRightSpeed = 0; + } + + moveData.weaponBackOffset = ( + ((buttons & A_BUTTON) != 0) + || + ((player_joyGetButtons & A_BUTTON) != 0) + ) + && (sp108); + + moveData.weaponForwardOffset = ( + ( + (((buttons & ~oldbuttons) & A_BUTTON) != 0) + || + (((player_joyGetButtons & ~copy_prev_buttons_pressed) & A_BUTTON) != 0) + )) + && (!sp10C); + + moveData.aiming = g_CurrentPlayer->insightaimmode; + moveData.zooming = g_CurrentPlayer->insightaimmode; + + if ((bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_DISABLE_CROUCH)) + && g_CurrentPlayer->insightaimmode) + { + if (tmpc2sticky < 0) + { + moveData.zoomOutFovPersec = (f32) -tmpc2sticky / 70.0f; + if (moveData.zoomOutFovPersec > 1.0f) + { + moveData.zoomOutFovPersec = 1.0f; + } + + moveData.zoomOutFovPersec *= 2.0f; + } + + if (tmpc2sticky > 0) + { + moveData.zoomInFovPersec = (f32) tmpc2sticky / 70.0f; + if (moveData.zoomInFovPersec > 1.0f) + { + moveData.zoomInFovPersec = 1.0f; + } + + moveData.zoomInFovPersec *= 2.0f; + } + } + + moveData.crouchDown = (bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_DISABLE_CROUCH) == 0) + && (g_CurrentPlayer->insightaimmode) + && (player_joyGetStickY < -30); + + moveData.crouchUp = (bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_DISABLE_CROUCH) == 0) + && (g_CurrentPlayer->insightaimmode) + && (player_joyGetStickY > 30); + + if (( + (((buttons & A_BUTTON) != 0) && (((buttons & ~oldbuttons) & B_BUTTON) != 0)) + || (((buttons & B_BUTTON) != 0) && (((buttons & ~oldbuttons) & A_BUTTON) != 0)) + || ((player_joyGetButtons & A_BUTTON) && ((player_joyGetButtons & ~copy_prev_buttons_pressed) & B_BUTTON)) + || ((player_joyGetButtons & B_BUTTON) && ((player_joyGetButtons & ~copy_prev_buttons_pressed) & A_BUTTON))) + && (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_REMOTEMINE)) + { + moveData.detonating = 1; + moveData.weaponBackOffset = 0; + moveData.weaponForwardOffset = 0; + moveData.btap = 0; + } + + if (g_PlayerIsInTank == 1 && g_CurrentPlayer->insightaimmode) + { + if (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_TANKSHELLS) + { + moveData.controlStickXRaw = 0; + + if (moveData.analogStrafe == 0) + { + moveData.analogStrafe = moveData.analogTurn; + } + } + else if (moveData.analogStrafe == 0) + { + if (moveData.aimTurnLeftSpeed > 0) + { + moveData.tankTurnLeftSpeed = moveData.aimTurnLeftSpeed; + } + + if (moveData.aimTurnRightSpeed > 0) + { + moveData.tankTurnRightSpeed = moveData.aimTurnRightSpeed; + } + } + + moveData.aimTurnLeftSpeed = 0; + moveData.aimTurnRightSpeed = 0; + } + } + + moveData.triggerOn = (sp10C) + && (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) + && ((buttons & A_BUTTON) == 0) + && ((player_joyGetButtons & A_BUTTON) == 0); + + moveData.disableLookAhead = 1; + g_CurrentPlayer->prev_buttons_pressed = player_joyGetButtons; + } + else + { + /* 1.3 and 1.4 */ + if (cur_player_get_control_type() == CONTROLLER_CONFIG_KISSY + || cur_player_get_control_type() == CONTROLLER_CONFIG_GOODNIGHT) + { + shootButtons = A_BUTTON; + aimButtons = Z_TRIG; + invButtons = L_TRIG | R_TRIG; + } + else + { + shootButtons = Z_TRIG; + aimButtons = L_TRIG | R_TRIG; + invButtons = A_BUTTON; + } + + if (lvlGetControlsLockedFlag() == 0) + { + if (disablePlayerActionsWhenPausedOrInMpMenu()) + { + if (cur_player_get_aim_control() == 0) + { + g_CurrentPlayer->insightaimmode = (buttons & aimButtons) != 0; + } + else if ((buttons & ~oldbuttons) & aimButtons) + { + g_CurrentPlayer->insightaimmode = !g_CurrentPlayer->insightaimmode; + } + + moveData.canSwivelGun = !g_CurrentPlayer->insightaimmode; + moveData.canAutoAim = !g_CurrentPlayer->insightaimmode; + moveData.btap = ((buttons & ~oldbuttons) & B_BUTTON) != 0; + moveData.canManualAim = g_CurrentPlayer->insightaimmode; + + /* 1.2 and 1.4 */ + if (cur_player_get_control_type() == CONTROLLER_CONFIG_SOLITARE + || cur_player_get_control_type() == CONTROLLER_CONFIG_GOODNIGHT) + { + if ((buttons & (L_JPAD | L_CBUTTONS)) != 0) + { + if (!g_CurrentPlayer->insightaimmode) + { + if (g_PlayerIsInTank == 1) + { + moveData.aimTurnLeftSpeed = 1.0f; + } + else + { + moveData.digitalStepLeft = 1; + } + } + else + { + moveData.tankTurnLeftSpeed = 1.0f; + } + } + + if ((buttons & (R_JPAD | R_CBUTTONS)) != 0) + { + if (!g_CurrentPlayer->insightaimmode) + { + if (g_PlayerIsInTank == 1) + { + moveData.aimTurnRightSpeed = 1.0f; + } + else + { + moveData.digitalStepRight = 1; + } + } + else + { + moveData.tankTurnRightSpeed = 1.0f; + } + } + + moveData.digitalStepForward = (!g_CurrentPlayer->insightaimmode) + && ((buttons & (U_JPAD | U_CBUTTONS)) ); + + moveData.digitalStepBack = (!g_CurrentPlayer->insightaimmode) + && ((buttons & (D_JPAD | D_CBUTTONS))); + + moveData.canNaturalPitch = !g_CurrentPlayer->insightaimmode; + + if (g_PlayerIsInTank == 1) + { + moveData.canTurnTank = !g_CurrentPlayer->insightaimmode; + } + else + { + moveData.canNaturalTurn = !g_CurrentPlayer->insightaimmode; + } + } + else + { + if ((buttons & (s32)(L_JPAD | L_CBUTTONS)) != 0) + { + moveData.tankTurnLeftSpeed = 1.0f; + } + /* optional else statement, matches with or without. */ + else + { + moveData.tankTurnLeftSpeed = 0; + } + + if ((buttons & (s32)(R_JPAD | R_CBUTTONS)) != 0) + { + moveData.tankTurnRightSpeed = 1.0f; + } + /* optional else statement, matches with or without. */ + else + { + moveData.tankTurnRightSpeed = 0; + } + + moveData.digitalStepLeft = (!g_CurrentPlayer->insightaimmode) + && ((buttons & (s32)(L_JPAD | L_CBUTTONS)) ); + + moveData.digitalStepRight = (!g_CurrentPlayer->insightaimmode) + && ((buttons & (s32)(R_JPAD | R_CBUTTONS))); + + moveData.canLookAhead = !g_CurrentPlayer->insightaimmode; + + if ((!g_CurrentPlayer->insightaimmode) && (buttons & (U_JPAD | U_CBUTTONS)) ) + { + moveData.speedVertaDown = 1.0f; + } + + if ((!g_CurrentPlayer->insightaimmode) && (buttons & (D_JPAD | D_CBUTTONS))) + { + moveData.speedVertaUp = 1.0f; + } + + moveData.canNaturalTurn = !g_CurrentPlayer->insightaimmode; + } + + if ((g_CurrentPlayer->insightaimmode) && (stick_y > 60)) + { + moveData.speedVertaDown = (f32) (stick_y - 60) / FLOAT_TEN_B; + if (moveData.speedVertaDown > 1.0f) + { + moveData.speedVertaDown = 1.0f; + } + } + else if ((g_CurrentPlayer->insightaimmode) && (stick_y < -60)) + { + moveData.speedVertaUp = (f32) (-60 - stick_y) / FLOAT_TEN_B; + if (moveData.speedVertaUp > 1.0f) + { + moveData.speedVertaUp = 1.0f; + } + } + + if ((g_CurrentPlayer->insightaimmode) && (stick_x < -60)) + { + moveData.aimTurnLeftSpeed = (f32) (-60 - stick_x) / FLOAT_TEN_B; + if (moveData.aimTurnLeftSpeed > 1.0f) + { + moveData.aimTurnLeftSpeed = 1.0f; + } + } + + if ((g_CurrentPlayer->insightaimmode) && (stick_x > 60)) + { + moveData.aimTurnRightSpeed = (f32) (stick_x - 60) / FLOAT_TEN_B; + if (moveData.aimTurnRightSpeed > 1.0f) + { + moveData.aimTurnRightSpeed = 1.0f; + } + } + + moveData.weaponBackOffset = + ((buttons & invButtons) != 0) + && + (((buttons & ~oldbuttons) & shootButtons) != 0) + ; + + moveData.weaponForwardOffset = + (((buttons & ~oldbuttons) & invButtons) != 0) + && + ((buttons & shootButtons) == 0) + ; + + moveData.aiming = g_CurrentPlayer->insightaimmode; + moveData.zooming = g_CurrentPlayer->insightaimmode; + + if ((bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_DISABLE_CROUCH)) + && g_CurrentPlayer->insightaimmode + ) + { + /* down = 0x404 */ + if ((buttons & (D_JPAD | D_CBUTTONS)) != 0) + { + moveData.zoomOutFovPersec = 1.0f; + } + + if ((buttons & (U_JPAD | U_CBUTTONS)) != 0) + { + moveData.zoomInFovPersec = 1.0f; + } + } + + moveData.crouchDown = (bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_DISABLE_CROUCH) == 0) + && (g_CurrentPlayer->insightaimmode) + && ((buttons & (D_JPAD | D_CBUTTONS))); + + moveData.crouchUp = (bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_DISABLE_CROUCH) == 0) + && (g_CurrentPlayer->insightaimmode) + && ((~buttons & (U_JPAD | U_CBUTTONS))); + + moveData.rLeanLeft = (g_CurrentPlayer->insightaimmode) + && ((buttons & (L_JPAD | L_CBUTTONS))); + + moveData.rLeanRight = (g_CurrentPlayer->insightaimmode) + && ((buttons & (R_JPAD | R_CBUTTONS))); + + if ( + ((((buttons & invButtons) != 0) && (((buttons & ~oldbuttons) & B_BUTTON) != 0)) + || ((buttons & B_BUTTON) && (((buttons & ~oldbuttons) & invButtons) != 0))) + && (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_REMOTEMINE)) + { + moveData.detonating = 1; + moveData.weaponBackOffset = 0; + moveData.weaponForwardOffset = 0; + moveData.btap = 0; + } + + if ((g_PlayerIsInTank == 1) && (g_CurrentPlayer->insightaimmode)) + { + if (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_TANKSHELLS) + { + moveData.controlStickXRaw = 0; + moveData.canTurnTank = 1; + } + else if ((moveData.tankTurnLeftSpeed == 0) && (moveData.tankTurnRightSpeed == 0)) + { + if (moveData.aimTurnLeftSpeed > 0) + { + moveData.tankTurnLeftSpeed = moveData.aimTurnLeftSpeed; + } + + if (moveData.aimTurnRightSpeed > 0) + { + moveData.tankTurnRightSpeed = moveData.aimTurnRightSpeed; + } + } + + moveData.aimTurnLeftSpeed = 0; + moveData.aimTurnRightSpeed = 0; + } + } + } + + moveData.triggerOn = ((buttons & shootButtons) != 0) + && (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) + && ((buttons & invButtons) == 0); + + /* 1.2 and 1.4 */ + if (cur_player_get_control_type() == CONTROLLER_CONFIG_SOLITARE || cur_player_get_control_type() == CONTROLLER_CONFIG_GOODNIGHT) + { + moveData.disableLookAhead = 1; + } + } + } + + g_CurrentPlayer->field_D0 = 0; + + if (moveData.btap) + { + /* If Bond is in the tank and pressed B, then exit. */ + if (g_PlayerIsInTank == 1) + { + spF4 = (struct TankRecord *)g_PlayerTankProp->obj; + spF4->unkD8 = get_ammo_count_for_weapon(ITEM_TANKSHELLS); + + add_ammo_to_weapon(ITEM_TANKSHELLS, 0); + bondinvRemoveItemByID(ITEM_TANKSHELLS); + + if (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_TANKSHELLS) + { + spF4->unkD8 += get_ammo_in_hands_magazine(GUNRIGHT); + autoadvance_on_deplete_all_ammo(); + } + + spF4->is_firing_tank = 0; + g_PlayerIsInTank = 0; + g_CurrentPlayer->speedsideways = 0; + g_CurrentPlayer->speedforwards = 0; + g_CurrentPlayer->speedtheta = 0; + + for (i_0=0; i_0<3; i_0++) + { + g_CurrentPlayer->bondshotspeed.f[i_0] = 0; + } + + g_CurrentPlayer->crouchpos = CROUCH_STAND; + } + /* If Bond is standing on the tank and pressed B, enter the tank. */ + else if (g_PlayerTankProp != NULL + && g_PlayerTankProp->type == PROP_TYPE_OBJ + && g_PlayerTankProp->obj->type == PROPDEF_TANK + && g_BondCanEnterTank) + { + spEC = (struct TankRecord *)g_PlayerTankProp->obj; + + bondinvAddInvItem(ITEM_TANKSHELLS); + add_ammo_to_weapon(ITEM_TANKSHELLS, spEC->unkD8); + spEC->unkD8 = 0; + g_TankTurretVerticalAngle = spEC->turret_vertical_angle; + g_TankTurretVerticalAngleRelated = g_TankTurretVerticalAngle / TANK_VERT_ANGLE_FACTOR; + g_TankTurretAngle = spEC->turret_orientation_angle; + g_TankTurretOrientationAngleRad = spEC->turret_orientation_angle; + g_TankTurretOrientationAngleDeg = g_TankTurretOrientationAngleRad / TANK_VERT_ANGLE_RAD_FACTOR; + tank_turret_turn_speed = 0; + g_TankOrientationAngle = spEC->tank_orientation_angle; + g_TankTurnSpeed = 0; + g_PlayerIsInTank = 1; + g_EnterTankAudioState = TANK_RUN_STATE_NOT_RUNNING; + g_CurrentPlayer->speedsideways = 0; + g_CurrentPlayer->speedforwards = 0; + g_CurrentPlayer->speedtheta = 0; + g_CurrentPlayer->crouchpos = CROUCH_HALF; + g_TankEnteringSitHeight = 0; + g_TankEnteringSitHeightRemain = 1.0f; + g_TankEnterBondHorizAngleDeg = g_CurrentPlayer->vv_theta; + g_TankEnterBondVertAngleDeg = g_CurrentPlayer->vv_verta; + g_EnterTankCoord.f[0] = g_CurrentPlayer->field_488.collision_position.f[0]; + g_EnterTankCoord.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; + g_EnterTankCoord.f[2] = g_CurrentPlayer->field_488.collision_position.f[2]; + g_TankDamagePenaltyTicks = 0; + + bondviewTankModelRotationRelated(); + } + else + { + g_CurrentPlayer->field_D0 = 1; + } + } + + if (moveData.invertPitch == 0) + { + f32 ftemp_nostack_spE8; + + moveData.controlStickYRaw = (s32) -stick_y; + moveData.analogPitch = -moveData.analogPitch; + ftemp_nostack_spE8 = moveData.speedVertaDown; + moveData.speedVertaDown = moveData.speedVertaUp; + moveData.speedVertaUp = ftemp_nostack_spE8; + } + + if (bondviewGetIfCurrentPlayerDamageShowTime() && getPlayerCount() == 1) + { + moveData.triggerOn = 0; + } + + gunTickGameplay(moveData.triggerOn); + + if (bondviewGetVisibleToGuardsFlag() + && (get_hands_firing_status(GUNRIGHT) + || get_hands_firing_status(GUNLEFT))) + { + noiseRadius = 0; + + if (get_hands_firing_status(GUNRIGHT) && getCurrentPlayerNoise(GUNRIGHT) > noiseRadius) + { + noiseRadius = getCurrentPlayerNoise(GUNRIGHT); + } + + if (get_hands_firing_status(GUNLEFT) && noiseRadius < getCurrentPlayerNoise(GUNLEFT)) + { + noiseRadius = getCurrentPlayerNoise(GUNLEFT); + } + + chrCheckGuardsHeardSound(noiseRadius); + } + + gunSetSightVisible(GUNSIGHTREASON_NOTAIMING, moveData.aiming); + + if (moveData.zoomOutFovPersec > 0) + { + camera_sniper_zoom_out(moveData.zoomOutFovPersec); + } + + if (moveData.zoomInFovPersec > 0) + { + camera_sniper_zoom_in(moveData.zoomInFovPersec); + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) + { + ftemp_nostack_spE0 = 60.0f; + + if (moveData.zooming) + { + ftemp_nostack_spE0 = get_item_in_hand_zoom(); + + if (ftemp_nostack_spE0 <= 0) + { + ftemp_nostack_spE0 = 60.0f; + } + } + + bondviewTriggerWatchZoom(ftemp_nostack_spE0); + bondviewUpdateWatchZoomIn(); + } + + if (g_PlayerIsInTank == 1) + { + g_TankTurretTurn = 0; + + if (g_EnterTankAudioState == TANK_RUN_STATE_RUNNING) + { + if (moveData.tankTurnRightSpeed > 0) + { + g_TankTurretTurn += g_GlobalTimerDelta * moveData.tankTurnRightSpeed * DegToRad1Fact(1); + } + else if (moveData.tankTurnLeftSpeed > 0) + { + g_TankTurretTurn -= g_GlobalTimerDelta * moveData.tankTurnLeftSpeed * DegToRad1Fact(1); + } + else if (moveData.canTurnTank) + { + targetSpeed = (f32) moveData.analogStrafe / 70.0f; + + if (targetSpeed > 1.0f) + { + targetSpeed = 1.0f; + } + + if (targetSpeed < -1.0f) + { + targetSpeed = -1.0f; + } + + g_TankTurretTurn += DegToRad1Fact(1) * targetSpeed * g_GlobalTimerDelta; + } + + if (!g_CurrentPlayer->insightaimmode) + { + ftemp_nostack_spD8 = 0; + targetSpeed = 1.0f; + ftemp_nostack_spE8 = 1.0f; + + if (moveData.canLookAhead) + { + ftemp_nostack_spD8 = (f32) moveData.analogWalk / 70.0f; + } + else if (moveData.digitalStepForward) + { + ftemp_nostack_spD8 = 1.0f; + } + else if (moveData.digitalStepBack) + { + ftemp_nostack_spD8 = -1.0f; + } + + if (ftemp_nostack_spD8 > 1.0f) + { + ftemp_nostack_spD8 = 1.0f; + } + else if (ftemp_nostack_spD8 < -1.0f) + { + ftemp_nostack_spD8 = -1.0f; + } + + unadjustedTargetSpeed = ftemp_nostack_spD8 * TANK_MAX_SPEED; + targetSpeed = unadjustedTargetSpeed; + + if (g_TankDamagePenaltyTicks > 0) + { + targetSpeed = unadjustedTargetSpeed * 0.5f; + ftemp_nostack_spE8 = 4.0f; + g_TankDamagePenaltyTicks -= g_ClockTimer; + } + + if (targetSpeed != g_CurrentPlayer->speedforwards) + { + if (g_CurrentPlayer->speedforwards < targetSpeed) + { + unadjustedTargetSpeed = ((((((targetSpeed - g_CurrentPlayer->speedforwards) / 4.0f) / TANK_MAX_SPEED) + 0.5f) * ftemp_nostack_spE8 * FLOAT_TEN_A) / 60.0f); + + g_CurrentPlayer->speedforwards += (unadjustedTargetSpeed) * g_GlobalTimerDelta; + + if (targetSpeed < g_CurrentPlayer->speedforwards) + { + g_CurrentPlayer->speedforwards = targetSpeed; + } + } + else if (targetSpeed < g_CurrentPlayer->speedforwards) + { + unadjustedTargetSpeed = ((((((g_CurrentPlayer->speedforwards - targetSpeed) / 4.0f) / TANK_MAX_SPEED) + 0.5f) * ftemp_nostack_spE8 * -FLOAT_TEN_A) / 60.0f); + + g_CurrentPlayer->speedforwards += (unadjustedTargetSpeed) * g_GlobalTimerDelta; + + if (g_CurrentPlayer->speedforwards < targetSpeed) + { + g_CurrentPlayer->speedforwards = targetSpeed; + } + } + } + } + } + } + else + { + if (moveData.digitalStepLeft) + { + bondviewUpdateSpeedSideways(-1); + } + else if (moveData.digitalStepRight) + { + bondviewUpdateSpeedSideways(1); + } + else + { + bondviewUpdateSpeedSideways(0); + } + + if (moveData.canTurnTank) // ?? not sure why this tank property is used here. Is the name wrong? + { + g_CurrentPlayer->speedsideways = (f32) moveData.analogStrafe / 70.0f; + } + + if (moveData.digitalStepForward) + { + bondviewUpdateSpeedForwards(1); + g_CurrentPlayer->speedmaxtime60 += g_ClockTimer; + } + else if (moveData.digitalStepBack) + { + bondviewUpdateSpeedForwards(-1); + } + else + { + bondviewUpdateSpeedForwards(0); + } + + if (moveData.canLookAhead) + { + g_CurrentPlayer->speedforwards = (f32) moveData.analogWalk / 70.0f; + + if (moveData.analogWalk > 60) + { + g_CurrentPlayer->speedmaxtime60 += g_ClockTimer; + } + else + { + g_CurrentPlayer->speedmaxtime60 = 0; + } + } + + if (g_CurrentPlayer->speedforwards > 1.0f) + { + g_CurrentPlayer->speedforwards = 1; + } + + if (g_CurrentPlayer->speedforwards < -1.0f) + { + g_CurrentPlayer->speedforwards = -1.0f; + } + + if (g_CurrentPlayer->speedsideways > 1) + { + g_CurrentPlayer->speedsideways = 1; + } + + if (g_CurrentPlayer->speedsideways < -1) + { + g_CurrentPlayer->speedsideways = -1; + } + + g_CurrentPlayer->speedforwards *= 1.08f; + g_CurrentPlayer->speedforwards *= g_CurrentPlayer->speedboost; + + if ((moveData.canLookAhead == 0) && (moveData.digitalStepForward == 0)) + { + g_CurrentPlayer->speedmaxtime60 = 0; + } + + if (moveData.rLeanLeft) + { + currentPlayerSetSwayTarget(-1); + } + else if (moveData.rLeanRight) + { + currentPlayerSetSwayTarget(1); + } + else + { + currentPlayerSetSwayTarget(0); + } + + if (moveData.crouchDown) + { + currentPlayerAdjustCrouchPos(-2); + } + else if (moveData.crouchUp) + { + currentPlayerAdjustCrouchPos(2); + } + } + + if (g_CurrentPlayer->speedmaxtime60 >= THREE_SECOND_TICKS) + { + if (g_CurrentPlayer->speedboost < SPEED_RUN_MAX) + { + g_CurrentPlayer->speedboost += (SPEED_TICK_ADJUST * g_GlobalTimerDelta); + } + + if (g_CurrentPlayer->speedboost > SPEED_RUN_MAX) + { + g_CurrentPlayer->speedboost = SPEED_RUN_MAX; + } + } + else + { + if (g_CurrentPlayer->speedboost > SPEED_REGULAR_MAX) + { + g_CurrentPlayer->speedboost -= (SPEED_TICK_ADJUST * g_GlobalTimerDelta); + } + + if (g_CurrentPlayer->speedboost < SPEED_REGULAR_MAX) + { + g_CurrentPlayer->speedboost = SPEED_REGULAR_MAX; + } + } + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) + { + // By default the camera is pitched slightly below the horizon + targetPitch = -4.0f; + + // lookaheadcentreenabled is always true, so this block always executes. + if (g_CurrentPlayer->lookaheadcentreenabled) + { + spC0 = g_CurrentPlayer->field_488.current_tile_ptr; + spBC = 300.0f; + + // prop, f32 *collision_radius, f32 *height, f32 *always_30 + bondviewGetCollisionRadius(g_CurrentPlayer->prop, &spA0.f[0], &spA0.f[2], &spA0.f[1]); + + spAC.f[0] = g_CurrentPlayer->field_488.collision_position.f[0] + (g_CurrentPlayer->field_488.theta_transform.f[0] * 300.0f); + spAC.f[1] = g_CurrentPlayer->field_488.collision_position.f[1]; + spAC.f[2] = g_CurrentPlayer->field_488.collision_position.f[2] + (g_CurrentPlayer->field_488.theta_transform.f[2] * 300.0f); + + stanResetHits(); + + if (stanTestLineUnobstructed(&spC0, g_CurrentPlayer->field_488.collision_position.f[0], g_CurrentPlayer->field_488.collision_position.f[2], spAC.f[0], spAC.f[2], CDTYPE_CLOSEDDOORS, spA0.f[2], spA0.f[1], 0, 1.0f)) + { + spAC.f[1] = bondviewYPositionRelated(spC0, spAC.f[0], spAC.f[2]); + } + else + { + chrlvStanPointPointIntersection(&g_CurrentPlayer->field_488.collision_position, &g_CurrentPlayer->field_488.theta_transform, (struct coord3d *) &spAC); + ftemp_nostack_spD0 = spAC.f[0] - g_CurrentPlayer->field_488.collision_position.f[0]; + ftemp_nostack_spCC = spAC.f[2] - g_CurrentPlayer->field_488.collision_position.f[2]; + spBC = sqrtf((ftemp_nostack_spD0 * ftemp_nostack_spD0) + (ftemp_nostack_spCC * ftemp_nostack_spCC)); + spAC.f[1] = bondviewYPositionRelated(spC0, spAC.f[0], spAC.f[2]); + } + + if (spBC > 0) + { + ftemp_nostack_spC8 = spAC.f[1] - g_CurrentPlayer->stanHeight; + + if ((ftemp_nostack_spC8 > -300.0f) && (ftemp_nostack_spC8 < 500.0f)) + { + targetPitch = ((atan2f(ftemp_nostack_spC8, spBC) * 360.0f) / M_TAU_F) + -4.0f; + + if (targetPitch >= 180.0f) + { + targetPitch -= 360.0f; + } + + if (targetPitch > 0) + { + targetPitch *= 0.8666667f; + } + } + } + } + + if ((g_CurrentPlayer->movecentrerelease) && (moveData.analogWalk < 40) && (moveData.analogWalk > -40)) + { + g_CurrentPlayer->movecentrerelease = FALSE; + } + + + if (g_PlayerIsInTank == 0) + { + /** + * If the player is giving manual pitch inputs, stop the automatic look ahead pitch adjust. + */ + if ((moveData.speedVertaDown > 0) || (moveData.speedVertaUp > 0)) + { + g_CurrentPlayer->docentreupdown = FALSE; + g_CurrentPlayer->prevupdown = TRUE; + g_CurrentPlayer->automovecentre = FALSE; + } + else + { + if (moveData.disableLookAhead) + { + g_CurrentPlayer->automovecentre = FALSE; + } + else if (g_CurrentPlayer->automovecentreenabled) + { + if ((moveData.canLookAhead) && ((moveData.analogWalk > 60) || (moveData.analogWalk < -60))) + { + g_CurrentPlayer->automovecentre = TRUE; + } + + /** + * If the player's camera pitch is 5 degrees above the target pitch or 10 degrees below the target pitch, + * and move centre is allowed, look ahead (docentreupdown) can be activated. + */ + if ((g_CurrentPlayer->automovecentre) + && (( ((targetPitch + 5.0f) < g_CurrentPlayer->vv_verta)) || (g_CurrentPlayer->vv_verta < (targetPitch + -FLOAT_TEN_A))) + && (g_CurrentPlayer->movecentrerelease == FALSE)) + { + g_CurrentPlayer->docentreupdown = TRUE; + } + } + /** + * fastmovecentreenabled is never set to true, so this block can never execute. Cut option? + */ + else if ((g_CurrentPlayer->fastmovecentreenabled) + && (moveData.canLookAhead) + && ((moveData.analogWalk > 60) || (moveData.analogWalk < -60)) + && (( ((targetPitch + 5.0f) < g_CurrentPlayer->vv_verta)) || (g_CurrentPlayer->vv_verta < (targetPitch + -FLOAT_TEN_A))) + && (g_CurrentPlayer->movecentrerelease == FALSE)) + { + g_CurrentPlayer->docentreupdown = TRUE; + } + + g_CurrentPlayer->prevupdown = FALSE; + } + } + + /** + * If look ahead (docentreupdown) is active, adjust the player's camera pitch to the target pitch. + */ + if (g_CurrentPlayer->docentreupdown) + { + if (g_PlayerIsInTank == 0) + { + ftemp_nostack_spB8 = (g_CurrentPlayer->speedverta * g_CurrentPlayer->speedverta * 0.5f) / 0.05f; + + if ((targetPitch + ftemp_nostack_spB8) < g_CurrentPlayer->vv_verta) + { + bondviewCurrentPlayerUpdateSpeedVerta(1.0f); + } + else if (g_CurrentPlayer->vv_verta < (targetPitch - ftemp_nostack_spB8)) + { + bondviewCurrentPlayerUpdateSpeedVerta(-1.0f); + } + else + { + bondviewCurrentPlayerUpdateSpeedVerta(0); + } + + ftemp_nostack_spB8 = g_CurrentPlayer->vv_verta + (2.0f * (g_CurrentPlayer->speedverta * g_GlobalTimerDelta)); + + if ((targetPitch < g_CurrentPlayer->vv_verta) && (targetPitch < ftemp_nostack_spB8)) + { + g_CurrentPlayer->vv_verta = ftemp_nostack_spB8; + } + else if ((g_CurrentPlayer->vv_verta < targetPitch) && (ftemp_nostack_spB8 < targetPitch)) + { + g_CurrentPlayer->vv_verta = ftemp_nostack_spB8; + } + else + { + g_CurrentPlayer->vv_verta = targetPitch; + g_CurrentPlayer->speedverta = 0; + + if (g_CurrentPlayer->prevupdown == FALSE) + { + g_CurrentPlayer->docentreupdown = FALSE; + } + } + } + } + else + { + if (moveData.canNaturalPitch) + { + ftemp_nostack_sp98 = viGetFovY() / 60.0f; + ftemp_nostack_sp94 = (f32) moveData.analogPitch / 70.0f; + + if (ftemp_nostack_sp94 > 1) + { + ftemp_nostack_sp94 = 1; + } + else if (ftemp_nostack_sp94 < -1) + { + ftemp_nostack_sp94 = -1; + } + + if (ftemp_nostack_sp94 >= 0) + { + ftemp_nostack_sp94 *= ftemp_nostack_sp94; + } + else + { + ftemp_nostack_sp94 *= -ftemp_nostack_sp94; + } + + g_CurrentPlayer->speedverta = -ftemp_nostack_sp94 * ftemp_nostack_sp98; + } + else if (moveData.speedVertaDown > 0) + { + bondviewCurrentPlayerUpdateSpeedVerta(moveData.speedVertaDown); + + // Bug? This is true for every value except exactly 60. + if ((moveData.canLookAhead) && ((moveData.analogWalk > 60) || (moveData.analogWalk < 60))) + { + g_CurrentPlayer->movecentrerelease = TRUE; + } + } + else if (moveData.speedVertaUp > 0) + { + bondviewCurrentPlayerUpdateSpeedVerta(-moveData.speedVertaUp); + + if ((moveData.canLookAhead) && ((moveData.analogWalk > 60) || (moveData.analogWalk < 60))) + { + g_CurrentPlayer->movecentrerelease = TRUE; + } + } + else + { + bondviewCurrentPlayerUpdateSpeedVerta(0); + } + + g_CurrentPlayer->vv_verta += g_CurrentPlayer->speedverta * g_GlobalTimerDelta * 3.5f; + + if ((g_PlayerIsInTank == 1) && (g_EnterTankAudioState == TANK_RUN_STATE_RUNNING) && (g_CurrentPlayer->vv_verta < -20.0f)) + { + g_CurrentPlayer->vv_verta = -20.0f; + } + } + } + + if (moveData.canNaturalTurn) + { + ftemp_nostack_sp8C = viGetFovY(); + ftemp_nostack_sp84 = (f32) moveData.analogTurn / 70.0f; + + if (ftemp_nostack_sp84 > 1) + { + ftemp_nostack_sp84 = 1; + } + else if (ftemp_nostack_sp84 < -1) + { + ftemp_nostack_sp84 = -1; + } + + if (ftemp_nostack_sp84 >= 0) + { + ftemp_nostack_sp84 *= ftemp_nostack_sp84; + } + else + { + ftemp_nostack_sp84 *= -ftemp_nostack_sp84; + } + + ftemp_nostack_sp88 = (ftemp_nostack_sp8C / FOV_Y_F); + g_CurrentPlayer->speedtheta = ftemp_nostack_sp84 * ftemp_nostack_sp88; + } + else if (moveData.aimTurnLeftSpeed > 0) + { + bondviewCurrentPlayerUpdateSpeedTheta(moveData.aimTurnLeftSpeed); + } + else if (moveData.aimTurnRightSpeed > 0) + { + bondviewCurrentPlayerUpdateSpeedTheta(-moveData.aimTurnRightSpeed); + } + else + { + bondviewCurrentPlayerUpdateSpeedTheta(0); + } + + if (g_PlayerIsInTank == 1) + { + if (g_EnterTankAudioState == TANK_RUN_STATE_RUNNING) + { + ftemp_nostack_sp80 = 0; + + if (moveData.canNaturalTurn) + { + ftemp_nostack_sp80 = g_CurrentPlayer->speedtheta * 0.3f; + } + else if (moveData.aimTurnLeftSpeed > 0) + { + ftemp_nostack_sp80 = sub_GAME_7F080228(1) * 0.3f; + } + else if (moveData.aimTurnRightSpeed > 0) + { + ftemp_nostack_sp80 = sub_GAME_7F080228(-1) * 0.3f; + } + + for (i_1=0; i_1speedtheta = g_TankTurnSpeed * TANK_VERT_ANGLE_RAD_FACTOR; + } + else + { + g_CurrentPlayer->speedtheta = 0; + } + } + + if (moveData.detonating) + { + g_CurrentPlayer->hands[GUNRIGHT].weapon_action_state = GUN_ANIM_STATE_IDLE; + g_CurrentPlayer->hands[GUNRIGHT].weapon_current_animation = 0; + trigger_remote_mine_detonation(); + } + + canCycleWeapons = 1; + + if ((getPlayerCount() >= 2) && (get_scenario() == 2) && (bondinvIsAliveWithFlag())) + { + canCycleWeapons = 0; + } + + if (canCycleWeapons) + { + if (moveData.weaponBackOffset) + { + backstep_through_inventory(); + } + + if (moveData.weaponForwardOffset) + { + advance_through_inventory(); + } + } + + if (moveData.canSwivelGun) + { + g_CurrentPlayer->controldef = CONTROLLER_CONFIG_HONEY; + } + else if (moveData.canManualAim) + { + g_CurrentPlayer->controldef = CONTROLLER_CONFIG_KISSY; + } + + if (g_CurrentPlayer->controldef == CONTROLLER_CONFIG_HONEY) + { + gunSetAimType(0); + + if (moveData.canAutoAim + && currentPlayerGetXAutoAimEnabledRedirect() + && g_CurrentPlayer->autoaim_target_x + && bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_HAS_AUTO_AIM)) + { + sp70 = g_CurrentPlayer->autoaimx; + } + else + { + sp70 = g_CurrentPlayer->speedtheta * 0.3f; + } + + if (moveData.canAutoAim + && currentPlayerGetYAutoAimEnabledRedirect() + && g_CurrentPlayer->autoaim_target_y + && bondwalkItemCheckBitflags(getCurrentPlayerWeaponId(GUNRIGHT), WEAPONSTATBITFLAG_HAS_AUTO_AIM)) + { + ftemp_nostack_sp78 = g_CurrentPlayer->autoaimy; + } + else + { + ftemp_nostack_sp78 = -g_CurrentPlayer->speedverta * 0.1f; + } + + sub_GAME_7F067F58(sp70, ftemp_nostack_sp78, MAX_AIMLOCK_SPEED_DEFAULT); + } + else if (g_CurrentPlayer->controldef == CONTROLLER_CONFIG_KISSY) + { + gunSetAimType(0); + sub_GAME_7F067FBC(((f32) moveData.controlStickXRaw * 0.65f) / 80.0f, ((f32) moveData.controlStickYRaw * 0.65f) / 80.0f); + } +} + + +/** + * Perfect Dark playerTickDamageAndHealth + * + * NTSC address 7F083FC8. + * NTSC-J address 7F0845D8. + * EU address 7F08406C. +*/ +void bondviewPlayerTickDamageAndHealth(void) +{ + // update damage showtime + if (g_CurrentPlayer->damageshowtime >= 0) + { + // 0: This is the first frame of damage + if (g_CurrentPlayer->damageshowtime == 0) + { + gunSetGunAmmoVisible(GUNAMMOREASON_DAMAGE, FALSE); + gunSetSightVisible(GUNSIGHTREASON_DAMAGE, FALSE); + hudmsgsSetOff(4); + bondviewSetUpperTextDisplayFlag(PLAYERFLAG_NOTIMER); + countdownTimerSetVisible(8, 0); + + g_CurrentPlayer->damagetype = (s32)(currentPlayerGetHealth() * 8.0f); + + if (g_CurrentPlayer->damagetype >= 8) + { + g_CurrentPlayer->damagetype = 7; + } + +// Ensure we don't read out of bounds of the g_DamageTypes array. +#if defined(VERSION_EU) || defined(VERSION_JP) + if (g_CurrentPlayer->damagetype < 0) + { + g_CurrentPlayer->damagetype = 0; + } +#endif + } + +#ifdef VERSION_US + if ( + (g_DamageTypes[g_CurrentPlayer->damagetype].field_0x8 >= g_CurrentPlayer->damageshowtime) + || (g_DamageTypes[g_CurrentPlayer->damagetype].flashEndFrame >= g_CurrentPlayer->damageshowtime)) + { + if (!g_CurrentPlayer->bonddead) + { +#else + if (!g_CurrentPlayer->bonddead + && ( + (g_DamageTypes[g_CurrentPlayer->damagetype].field_0x8 >= g_CurrentPlayer->damageshowtime) + || (g_DamageTypes[g_CurrentPlayer->damagetype].flashEndFrame >= g_CurrentPlayer->damageshowtime))) + { +#endif + if (g_CurrentPlayer->damageshowtime >= g_DamageTypes[g_CurrentPlayer->damagetype].flashStartFrame + && g_CurrentPlayer->damageshowtime <= g_DamageTypes[g_CurrentPlayer->damagetype].flashEndFrame) + { + f32 frac; +#ifdef VERSION_US + s32 flashdoneframes; + s32 totalframes; + s32 flashfullframe; +#else + f32 flashdoneframes; + f32 totalframes; + f32 flashfullframe; +#endif + + flashdoneframes = g_CurrentPlayer->damageshowtime - g_DamageTypes[g_CurrentPlayer->damagetype].flashStartFrame; + flashfullframe = g_DamageTypes[g_CurrentPlayer->damagetype].flashFullFrame; + totalframes = g_DamageTypes[g_CurrentPlayer->damagetype].flashEndFrame - g_DamageTypes[g_CurrentPlayer->damagetype].flashStartFrame; + + if (flashdoneframes < flashfullframe) + { + frac = (g_DamageTypes[g_CurrentPlayer->damagetype].maxAlpha * (f32)flashdoneframes) / (f32)flashfullframe; + } + else + { + frac = (g_DamageTypes[g_CurrentPlayer->damagetype].maxAlpha * (f32)(totalframes - flashdoneframes)) / (f32)(totalframes - flashfullframe); + } + + currentPlayerSetFadeColour( + g_DamageTypes[g_CurrentPlayer->damagetype].red, + g_DamageTypes[g_CurrentPlayer->damagetype].green, + g_DamageTypes[g_CurrentPlayer->damagetype].blue, + frac); + } +#ifdef VERSION_US + } +#endif + + if (g_CurrentPlayer->watch_animation_state == WATCH_ANIMATION_0x0) + { +#if defined(VERSION_US) + g_CurrentPlayer->damageshowtime += g_ClockTimer; +#else + g_CurrentPlayer->damageshowtime += g_GlobalTimerDelta; +#endif + } + else + { +#if defined(VERSION_US) + g_CurrentPlayer->damageshowtime += speedgraphframes; +#else + g_CurrentPlayer->damageshowtime += jpD_800484D0; +#endif + } + } + else /* (damage showtime is over) */ + { + g_CurrentPlayer->damageshowtime = -1; + currentPlayerSetFadeColour(0xFF, 0xFF, 0xFF, 0); + + if (!g_CurrentPlayer->bonddead) + { + gunSetGunAmmoVisible(GUNAMMOREASON_DAMAGE, TRUE); + gunSetSightVisible(GUNSIGHTREASON_DAMAGE, TRUE); + hudmsgsSetOn(4); + bondviewClearUpperTextDisplayFlag(PLAYERFLAG_NOTIMER); + countdownTimerSetVisible(8, 1); + } + } + } + + // update health showtime + if (g_CurrentPlayer->healthshowtime >= 0) + { + // 0: This is the first frame of damage + if (g_CurrentPlayer->healthshowtime == 0) + { + g_CurrentPlayer->healthdamagetype = (s32)(currentPlayerGetHealth() * 8.0f); + + if (g_CurrentPlayer->healthdamagetype >= 8) + { + g_CurrentPlayer->healthdamagetype = 7; + } + +#if defined(VERSION_EU) || defined(VERSION_JP) + if (g_CurrentPlayer->healthdamagetype < 0) + { + g_CurrentPlayer->healthdamagetype = 0; + } +#endif + } + + if (!g_CurrentPlayer->bonddead) + { + if ((g_CurrentPlayer->healthshowtime >= g_HealthDisplayDurations[g_CurrentPlayer->healthdamagetype].validStartFrame) + && (g_HealthDisplayDurations[g_CurrentPlayer->healthdamagetype].updateToRealHealthFrame >= g_CurrentPlayer->healthshowtime)) + { + g_CurrentPlayer->apparenthealth = g_CurrentPlayer->oldhealth; + g_CurrentPlayer->apparentarmour = g_CurrentPlayer->oldarmour; +#if defined(VERSION_US) + g_CurrentPlayer->healthshowtime += g_ClockTimer; +#else + g_CurrentPlayer->healthshowtime += g_GlobalTimerDelta; +#endif + } + else if ((g_CurrentPlayer->healthshowtime >= g_HealthDisplayDurations[g_CurrentPlayer->healthdamagetype].validStartFrame) + && (g_HealthDisplayDurations[g_CurrentPlayer->healthdamagetype].hideHealthFrame >= g_CurrentPlayer->healthshowtime)) + { + g_CurrentPlayer->apparenthealth = g_CurrentPlayer->bondhealth; + g_CurrentPlayer->apparentarmour = g_CurrentPlayer->bondarmour; +#if defined(VERSION_US) + g_CurrentPlayer->healthshowtime += g_ClockTimer; +#else + g_CurrentPlayer->healthshowtime += g_GlobalTimerDelta; +#endif + } + else + { + g_CurrentPlayer->healthshowtime = -1; + } + } + else + { + g_CurrentPlayer->healthshowtime = -1; + } + } +} + +/** + * If global flag g_SurroundBondWithExplosionsFlag is set then explosions + * will be randomly created around Bond. + * Perfect Dark method playerTickExplode. + * NTSC address 7F084360. + * EU address 7F0844A4. +*/ +void bondviewPlayerTickExplode(void) +{ + g_PlayerTickExplodeCreatePosition++; + + if (g_SurroundBondWithExplosionsFlag + && (g_PlayerInvincible == FALSE) + && g_SurroundBondWithExplosionsTicks < g_GlobalTimer) + { + struct coord3d pos; + + pos.f[0] = g_CurrentPlayer->prop->pos.f[0]; + pos.f[1] = g_CurrentPlayer->prop->pos.f[1]; + pos.f[2] = g_CurrentPlayer->prop->pos.f[2]; + + switch (g_PlayerTickExplodeCreatePosition % 4) + { + case 0: pos.x += 250.0f + 150.0f * RANDOMGETNEXT_F32(); break; + case 1: pos.x -= 250.0f + 150.0f * RANDOMGETNEXT_F32(); break; + case 2: pos.z += 250.0f + 150.0f * RANDOMGETNEXT_F32(); break; + case 3: pos.z -= 250.0f + 150.0f * RANDOMGETNEXT_F32(); break; + } + + pos.y += 200.0f * RANDOMGETNEXT_F32() - 100.0f; + + explosionCreate(0, &pos, g_CurrentPlayer->prop->stan, EXPLOSION_DEF_PLAYER, 0, 0, g_CurrentPlayer->prop->rooms, 0); + + g_SurroundBondWithExplosionsTicks = (randomGetNext() % (u32)PLAYER_TICKEXPLODE_FACTOR) + g_GlobalTimer + PLAYER_TICKEXPLODE_FACTOR; + } +} + + +/** + * NTSC Address 0x7F084648. + * NTSC-J address 0x7F084CF8. + * + * Met by Saint Jon The Archangel in the writhing pits of hell, the beast was + * pinned, prone on the floor. He had taken many forms throughout the ages. + * From the creator of man to the far reaches of the universe, his perpetual + * reincarnations reigned throughout space and time... until now. His form was + * weak, the opposition strong. The time for atonement had finally come. + * + * Battered, torn, exposed, the beast slacked his gaping maw. + * + * "I'm sorry, Jon" he whispered. + * + * The archangel raised his flaming blade. + * + * "You are forgiven, Garfield" + * + * And the beast exhaled his last. + * + * 10 months of off and on work to match. + * Thanks Trevor. + * - Bethany Burns + */ +void MoveBond(s8 stick_x, s8 stick_y, u16 buttons, u16 oldbuttons) +{ + struct coord3d move_offset; + f32 ftemp; + f32 stack_padding_9; + f32 sp3A0; + s32 i; + f32 maxspeed; + s32 use_stanHeight; + f32 sp390; + + move_offset = g_DefaultMoveBondOffset; + + use_stanHeight = 0; + maxspeed = 0.0f; + sp390 = 0.0f; + + #if defined(VERSION_US) || defined(VERSION_JP) + if (stick_x >= 100 || stick_x <= -100) return_null(); // __LINE__ __FILE__ (#6414 bondview.c) "joystick x has value %d!\n" + if (stick_y >= 100 || stick_y <= -100) return_null(); // __LINE__ __FILE__ (#6415 bondview.c) "joystick y has value %d!\n" + #endif + + if (g_bondviewForceDisarm > 0) + { + g_bondviewForceDisarm++; + if (g_bondviewForceDisarm >= 4) + { + g_bondviewForceDisarm = 0; + g_CurrentPlayer->lock_hand_model[GUNLEFT] = 0; + g_CurrentPlayer->lock_hand_model[GUNRIGHT] = 0; + currentPlayerUnEquipWeaponWrapper(GUNLEFT, getCurrentPlayerWeaponId(GUNLEFT)); + currentPlayerUnEquipWeaponWrapper(GUNRIGHT, getCurrentPlayerWeaponId(GUNRIGHT)); + } + } + + currentPlayerSetCameraMode(0); + bondviewPlayerTickDamageAndHealth(); + bondviewPlayerTickExplode(); + bondviewProcessInput(stick_x, stick_y, buttons, oldbuttons); + + if (lvlGetControlsLockedFlag()) + { + bondviewPlayerStopAudioForPause(); + } + + if (g_CurrentPlayer->watch_animation_state != WATCH_ANIMATION_0x0) + { + bondviewWatchAnimationTick(); + } + + /* + Apply bondshotspeed vector to speedforwards scalar and speedsideways scalar. + Crouching applies a 50% base speed reduction before applying boost. + Bond can't be boosted while in the tank. + */ + if (g_PlayerIsInTank == 0) + { + // This `if` block is Perfect Dark bwalkApplyCrouchSpeed. + if (currentPlayerGetCrouchPos() == CROUCH_SQUAT) + { + g_CurrentPlayer->speedforwards *= 0.5f; + g_CurrentPlayer->speedsideways *= 0.5f; + } + + if ((g_CurrentPlayer->bondshotspeed.f[0] != 0.0f) || (g_CurrentPlayer->bondshotspeed.f[2] != 0.0f)) + { + // boost forwards + f32 shotboost_forward; // sp38C + // boost sideways + f32 shotboost_sideways; // sp388 + f32 shotboost_norm; // sp384 + + // Assigning these two variables is done in Perfect Dark bmove0f0cba88. + shotboost_forward = + (-g_CurrentPlayer->bondshotspeed.f[0] * g_CurrentPlayer->vv_sintheta) + + (g_CurrentPlayer->bondshotspeed.f[2] * g_CurrentPlayer->vv_costheta); + shotboost_sideways = + (-g_CurrentPlayer->bondshotspeed.f[0] * g_CurrentPlayer->vv_costheta) + - (g_CurrentPlayer->bondshotspeed.f[2] * g_CurrentPlayer->vv_sintheta); + + shotboost_norm = sqrtf( + (g_CurrentPlayer->bondshotspeed.f[0] * g_CurrentPlayer->bondshotspeed.f[0]) + + (g_CurrentPlayer->bondshotspeed.f[2] * g_CurrentPlayer->bondshotspeed.f[2])); + + g_CurrentPlayer->speedforwards += shotboost_forward; + g_CurrentPlayer->speedsideways += shotboost_sideways; + + // 3: x,y,z components of bondshotspeed + for (i=0; i<3; i++) + { + if (g_CurrentPlayer->bondshotspeed.f[i] != 0.0f) + { + if (g_CurrentPlayer->bondshotspeed.f[i] > 0.0f) + { + g_CurrentPlayer->bondshotspeed.f[i] -= + ((0.06666667f * g_GlobalTimerDelta * g_CurrentPlayer->bondshotspeed.f[i]) / shotboost_norm); + + if (g_CurrentPlayer->bondshotspeed.f[i] < 0.0f) + { + g_CurrentPlayer->bondshotspeed.f[i] = 0.0f; + } + } + else if (g_CurrentPlayer->bondshotspeed.f[i] < 0.0f) + { + g_CurrentPlayer->bondshotspeed.f[i] -= + ((0.06666667f * g_GlobalTimerDelta * g_CurrentPlayer->bondshotspeed.f[i]) / shotboost_norm); + + if (g_CurrentPlayer->bondshotspeed.f[i] > 0.0f) + { + g_CurrentPlayer->bondshotspeed.f[i] = 0.0f; + } + } + } + } + } + } + + /** + * This section updates the tank turret horizontal position (turning left and right), + * as well as turning the tank left and right. + */ + if (g_PlayerIsInTank == 1) + { + f32 ftemp2; + struct coord3d check_collision_p1; + struct coord3d check_collision_p2; + f32 stack_padding_1; + s32 i_1; + f32 curTankAngleRad; + f32 tankChangeInAngle; + f32 sp354; + struct coord3d tank_collision_pt1; + struct coord3d tank_collision_pt2; + f32 tank_collision_dx; + f32 tank_collision_dz; + + tankChangeInAngle = DegToRad1Fact(g_CurrentPlayer->speedtheta * g_GlobalTimerDelta) * 3.5f; + curTankAngleRad = g_TankOrientationAngle + tankChangeInAngle; + + if (curTankAngleRad >= M_TAU_F) + { + curTankAngleRad -= M_TAU_F; + } + + if (curTankAngleRad < 0.0f) + { + curTankAngleRad += M_TAU_F; + } + + if (bondviewTankCollisionStatus( + &g_CurrentPlayer->field_488.collision_position, + g_CurrentPlayer->field_488.current_tile_ptr, + curTankAngleRad, + &check_collision_p1, + &check_collision_p2)) + { + g_TankOrientationAngle = curTankAngleRad; + } + else + { + f32 sp1E4; //x + s32 stack_padding_1; //x + f32 sp1FC; //x + f32 sp324; + f32 sp320; + f32 sp31C; + f32 sp20C; //x + f32 tank_collision_norm; //x + f32 sp210; //x + f32 sp30C; + f32 sp308; + f32 sp304; + + sp31C = -1; //sp31C: scope within this block, used throughout + sp304 = -1; //sp304: scope within this block, used throughout + + getCollisionEdge_maybe(&tank_collision_pt1, &tank_collision_pt2); + + tank_collision_dx = (tank_collision_pt2.f[0] - tank_collision_pt1.f[0]); + tank_collision_dz = (tank_collision_pt2.f[2] - tank_collision_pt1.f[2]); + + tank_collision_norm = 1.0f / sqrtf((tank_collision_dx * tank_collision_dx) + (tank_collision_dz * tank_collision_dz)); + + // sp320: scoped within this block, used throughout + // sp324: scoped within this block, used throughout + tank_collision_dx *= tank_collision_norm; + tank_collision_dz *= tank_collision_norm; + sp324 = tank_collision_dz; + sp320 = -tank_collision_dx; + + // sp210: short lived variable + sp210 = + ((g_CurrentPlayer->field_488.collision_position.f[0] - check_collision_p2.f[0]) * sp324) + + ((g_CurrentPlayer->field_488.collision_position.f[2] - check_collision_p2.f[2]) * sp320); + + if (sp210 < 0.0f) + { + sp210 = -sp210; + sp324 = -sp324; + sp320 = -sp320; + } + + // sp20C: very short lived variable + sp20C = + ((g_CurrentPlayer->field_488.collision_position.f[0] - tank_collision_pt1.f[0]) * sp324) + + ((g_CurrentPlayer->field_488.collision_position.f[2] - tank_collision_pt1.f[2]) * sp320); + + if (sp20C < sp210) + { + sp31C = sp210 - sp20C; + } + + tank_collision_dx = check_collision_p2.f[0] - check_collision_p1.f[0]; + tank_collision_dz = check_collision_p2.f[2] - check_collision_p1.f[2]; + + tank_collision_norm = 1.0f / sqrtf((tank_collision_dx * tank_collision_dx) + (tank_collision_dz * tank_collision_dz)); + + // sp308: scoped within this block, used throughout + // sp30C: scoped within this block, used throughout + tank_collision_dx *= tank_collision_norm; + tank_collision_dz *= tank_collision_norm; + sp30C = tank_collision_dz; + sp308 = -tank_collision_dx; + + // sp1F8 -> sp210: short lived variable + sp210 = + ((g_CurrentPlayer->field_488.collision_position.f[0] - check_collision_p2.f[0]) * sp30C) + + ((g_CurrentPlayer->field_488.collision_position.f[2] - check_collision_p2.f[2]) * sp308); + + if (sp210 < 0.0f) + { + sp210 = -sp210; + sp30C = -sp30C; + sp308 = -sp308; + } + + // sp1FC: very short lived variable + // sp1E4: very short lived variable + sp1FC = + ((g_CurrentPlayer->field_488.collision_position.f[0] - tank_collision_pt1.f[0]) * sp30C) + + ((g_CurrentPlayer->field_488.collision_position.f[2] - tank_collision_pt1.f[2]) * sp308); + sp1E4 = + ((g_CurrentPlayer->field_488.collision_position.f[0] - tank_collision_pt2.f[0]) * sp30C) + + ((g_CurrentPlayer->field_488.collision_position.f[2] - tank_collision_pt2.f[2]) * sp308); + + if (sp1E4 < sp1FC) + { + sp1FC = sp1E4; + } + + if (sp1FC < sp210) + { + sp304 = sp210 - sp1FC; + } + + if ((sp304 >= 0.0f) && ((sp304 < sp31C) || (sp31C < 0.0f))) + { + sp324 = sp30C; + sp320 = sp308; + sp31C = sp304; + } + + if (sp31C >= 0.0f) + { + move_offset.f[0] = sp31C * sp324 * 1.01f; + move_offset.f[2] = sp31C * sp320 * 1.01f; + + bondviewCalcUpdatePlayerCollision(&move_offset, 1); + + move_offset.f[0] = 0.0f; + move_offset.f[2] = 0.0f; + + if (bondviewTankCollisionStatus( + &g_CurrentPlayer->field_488.collision_position, + g_CurrentPlayer->field_488.current_tile_ptr, + curTankAngleRad, + &check_collision_p1, + &check_collision_p2)) + { + g_TankOrientationAngle = curTankAngleRad; + } + else + { + tankChangeInAngle = 0.0f; + } + } + else + { + tankChangeInAngle = 0.0f; + } + } + + sp354 = g_TankTurretOrientationAngleRad; + g_TankTurretAngle += g_TankTurretTurn; + if (g_TankTurretAngle >= M_TAU_F) + { + g_TankTurretAngle -= M_TAU_F; + } + + if (g_TankTurretAngle < 0.0f) + { + g_TankTurretAngle += M_TAU_F; + } + + ftemp = (DegToRad1Fact(g_CurrentPlayer->speedtheta * 3.5f) * 4.0f) + g_TankTurretAngle; + + if (ftemp < 0.0f) + { + ftemp += M_TAU_F; + } + + if (ftemp >= M_TAU_F) + { + ftemp -= M_TAU_F; + } + + if ((ftemp - g_TankTurretOrientationAngleRad) >= M_PI_F) + { + ftemp -= M_TAU_F; + } + else if ((ftemp - g_TankTurretOrientationAngleRad) < -M_PI_F) + { + ftemp += M_TAU_F; + } + + for (i_1=0; i_1= M_TAU_F) + { + g_TankTurretOrientationAngleRad -= M_TAU_F; + g_TankTurretOrientationAngleDeg = g_TankTurretOrientationAngleRad / (1.0f - TANKUPDATEROTATION_SCALE); + } + + if (g_TankTurretOrientationAngleRad < 0.0f) + { + g_TankTurretOrientationAngleRad += M_TAU_F; + g_TankTurretOrientationAngleDeg = g_TankTurretOrientationAngleRad / (1.0f - TANKUPDATEROTATION_SCALE); + } + + if (bondviewCallTankCollisionStatus( + &g_CurrentPlayer->field_488.collision_position, + g_CurrentPlayer->field_488.current_tile_ptr, + g_TankOrientationAngle) == 0) + { + g_TankTurretOrientationAngleRad = sp354; + g_TankTurretOrientationAngleDeg = g_TankTurretOrientationAngleRad / (1.0f - TANKUPDATEROTATION_SCALE); + g_TankTurretAngle = sp354; + } + + if (g_PlayerTankProp != NULL) + { + // sp 0x300 + struct TankRecord *temp_tank; + struct coord3d tank_move_offset; + Mtxf sp2B4; + f32 stack_padding_4; + + temp_tank = (struct TankRecord *)g_PlayerTankProp->obj; + + tank_move_offset.f[1] = 0.0f; + tank_move_offset.f[0] = g_TankModelPositionOffset.f[0]; + tank_move_offset.f[2] = g_TankModelPositionOffset.f[2]; + + matrix_4x4_set_rotation_around_y(tankChangeInAngle, &sp2B4); + mtx4RotateVecInPlace(&sp2B4, &tank_move_offset); + bondviewTankModelRotationRelated(); + + if (0) { } + + tank_move_offset.f[1] = 0.0f; + tank_move_offset.f[0] = g_TankModelPositionOffset.f[0] - tank_move_offset.f[0]; + tank_move_offset.f[2] = g_TankModelPositionOffset.f[2] - tank_move_offset.f[2]; + + matrix_4x4_set_rotation_around_y(M_TAU_F - g_TankOrientationAngle, &sp2B4); + matrix_scalar_multiply(temp_tank->model->scale, &sp2B4); + mtx4RotateVecInPlace(&sp2B4, &tank_move_offset); + bondviewCalcUpdatePlayerCollision(&tank_move_offset, 1); + } + + if (g_ClockTimer > 0) { + for (i=0; ivv_theta = ( + g_TankOrientationAngle + + g_TankTurretOrientationAngleRad + + ((DegToRad1Fact(g_CurrentPlayer->speedtheta * 3.5f)) * (4.0f)) + + (ftemp * 4.0f) + ) * 360.0f / M_TAU_F; + + while (g_CurrentPlayer->vv_theta < 0.0f) + { + g_CurrentPlayer->vv_theta += 360.0f; + } + while (g_CurrentPlayer->vv_theta >= 360.0f) + { + g_CurrentPlayer->vv_theta -= 360.0f; + } + } + else + { + stack_padding_9 = g_CurrentPlayer->vv_theta + (g_CurrentPlayer->speedtheta * g_GlobalTimerDelta * 3.5f); + + while (stack_padding_9 < 0.0f) + { + stack_padding_9 += 360.0f; + } + while (stack_padding_9 >= 360.0f) + { + stack_padding_9 -= 360.0f; + } + + g_CurrentPlayer->vv_theta = stack_padding_9; + } + + bondviewApplyVertaTheta(); + + // Handle crouching, and animation between standing and crouching. + // Add basic block to declare local variables at the correct stack position. + { + f32 sp2AC; + f32 stack_padding_15; + + sp2AC = 0.0f; + if (currentPlayerGetCrouchPos() == CROUCH_SQUAT) + { + sp2AC = FULL_CROUCH_OFFSET; + } + else if (currentPlayerGetCrouchPos() == CROUCH_HALF) + { + sp2AC = -60.0f; + } + else + { + // removed? + currentPlayerGetCrouchPos(); + } + + if (sp2AC != g_CurrentPlayer->ducking_height_offset) + { + chrobjApplySpeed( + &g_CurrentPlayer->ducking_height_offset, + sp2AC, + &g_CurrentPlayer->field_A4, + CHR_OBJ_ACCEL_SPEED_FACTOR, + CHR_OBJ_ACCEL_SPEED_FACTOR, + CHR_OBJ_MAXSPEED); + } + + if (sp2AC == g_CurrentPlayer->ducking_height_offset) + { + g_CurrentPlayer->field_A4 = 0.0f; + } + } + + /** + * Update forwards/backwards movement. + */ + if (g_PlayerIsInTank == 1) + { + /** + * This section handles the forward/backwards movement of the tank. + */ + + Mtxf sp268; + struct coord3d sp25C; + f32 sp258; + f32 sp254; + s32 stack_padding_14; + s32 i_3; + f32 ftemp_5; + f32 tank_engine_utilization_percent; + struct TankRecord *tank_obj; + + /** + * Check to see if Bond is just now entering the tank. + * If so, initialize the tank prop. + * This also handles spinning Bond around (if required) to face the same direction as the turret. + */ + if (g_EnterTankAudioState == TANK_RUN_STATE_NOT_RUNNING) + { + if (g_PlayerTankProp != NULL) + { + tank_obj = g_PlayerTankProp->obj; + matrix_4x4_set_rotation_around_y(M_TAU_F - g_TankOrientationAngle, &sp268); + matrix_scalar_multiply(tank_obj->model->scale, &sp268); + + sp25C.f[0] = g_TankModelPositionOffset.f[0]; + sp25C.f[1] = g_TankModelPositionOffset.f[1]; + sp25C.f[2] = g_TankModelPositionOffset.f[2]; + mtx4RotateVecInPlace(&sp268, (f32*)&sp25C); + + sp25C.f[0] += tank_obj->runtime_pos.f[0]; + sp25C.f[1] += tank_obj->runtime_pos.f[1]; + sp25C.f[2] += tank_obj->runtime_pos.f[2]; + + sp258 = ((g_TankOrientationAngle + g_TankTurretOrientationAngleRad) * 360.0f) / M_TAU_F; + sp254 = g_CurrentPlayer->vv_verta; + if (sp254 < -20.0f) + { + sp254 = -20.0f; + } + + g_TankEnteringSitHeight += g_GlobalTimerDelta / 45.0f; + if (g_TankEnteringSitHeight >= 1.0f) + { + g_TankEnteringSitHeight = 1.0f; + } + + g_TankEnteringSitHeightRemain = (cosf(g_TankEnteringSitHeight * M_TAU_F * 0.5f) + 1.0f) * 0.5f; + + g_CurrentPlayer->vv_verta = + (g_TankEnteringSitHeightRemain * g_TankEnterBondVertAngleDeg) + + ((1.0f - g_TankEnteringSitHeightRemain) * sp254); + + ftemp_5 = sp258 - g_TankEnterBondHorizAngleDeg; + if (ftemp_5 > 180.0f) + { + sp258 -= 360.0f; + } + if (ftemp_5 < -180.0f) + { + sp258 += 360.0f; + } + + g_CurrentPlayer->vv_theta = + (g_TankEnteringSitHeightRemain * g_TankEnterBondHorizAngleDeg) + + ((1.0f - g_TankEnteringSitHeightRemain) * sp258); + + if (g_CurrentPlayer->vv_theta >= 360.0f) + { + g_CurrentPlayer->vv_theta -= 360.0f; + } + + if (g_CurrentPlayer->vv_theta < 0.0f) + { + g_CurrentPlayer->vv_theta += 360.0f; + } + + move_offset.f[0] = ( + (g_TankEnteringSitHeightRemain * g_EnterTankCoord.f[0]) + + ((1.0f - g_TankEnteringSitHeightRemain) * sp25C.f[0]) + ) - + g_CurrentPlayer->field_488.collision_position.f[0]; + + move_offset.f[1] = 0.0f; + + move_offset.f[2] = ( + (g_TankEnteringSitHeightRemain * g_EnterTankCoord.f[2]) + + ((1.0f - g_TankEnteringSitHeightRemain) * sp25C.f[2]) + ) - + g_CurrentPlayer->field_488.collision_position.f[2]; + } + + if (!(g_TankEnteringSitHeight >= 1.0f)) + { + } + else + { + g_EnterTankAudioState = TANK_RUN_STATE_STARTING; + } + } + /** + * Else, Bond has already entered the tank. + */ + else + { + /** + * There's an initial "starting" step. + */ + if (g_EnterTankAudioState == TANK_RUN_STATE_STARTING) + { + g_EnterTankAudioState = TANK_RUN_STATE_RUNNING; + if ((g_TankSfxState[0] == NULL) && (lvlGetControlsLockedFlag() == 0)) + { + sndPlaySfx(g_musicSfxBufferPtr, TRUCK_START_SFX, &g_TankSfxState[0]); + } + + sndCreatePostEvent(g_TankSfxState[0], 8, 0x61A8); + g_TankEngineSfxVolume = 0x61A8; + } + /** + * Else Bond has fully entered the tank, and the engine is running. + * Update turret vertical angle. + * Update engine sound effect volume based on current tank speed. + */ + else + { + f32 tank_scaled_speedforwards; + f32 tank_scaled_speedtheta; + f32 tank_vertical_angle; + + tank_scaled_speedforwards = g_CurrentPlayer->speedforwards / TANK_MAX_SPEED; + tank_scaled_speedtheta = g_CurrentPlayer->speedtheta / 0.3f; + + if (tank_scaled_speedforwards < 0.0f) + { + tank_scaled_speedforwards = -tank_scaled_speedforwards; + } + if (tank_scaled_speedtheta < 0.0f) + { + tank_scaled_speedtheta = -tank_scaled_speedtheta; + } + + tank_engine_utilization_percent = tank_scaled_speedforwards; + if (tank_scaled_speedforwards < tank_scaled_speedtheta) + { + tank_engine_utilization_percent = tank_scaled_speedtheta; + } + + if (tank_engine_utilization_percent > 0.0f) + { + if (tank_engine_utilization_percent > 1.0f) + { + tank_engine_utilization_percent = 1.0f; + } + + if (g_TankSfxState[1] == NULL) + { + if (lvlGetControlsLockedFlag() == 0) + { + sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, TANK_SFX, &g_TankSfxState[1]); + } + } + + if (g_TankSfxState[1] != NULL) + { + s32 phi_a2; + + phi_a2 = 0x7FFF; + if (tank_engine_utilization_percent < 0.15f) + { + phi_a2 = (s32) ((tank_engine_utilization_percent * 20000.0f) / 0.15f); + } + else if (tank_engine_utilization_percent < 0.9f) + { + phi_a2 = (s32) ((((tank_engine_utilization_percent - 0.15f) * 12767.0f) / 0.75f) + 20000.0f); + } + + sndCreatePostEvent(g_TankSfxState[1], 8, phi_a2); + } + } + else + { + if (g_TankSfxState[1] != NULL) + { + if (sndGetPlayingState(g_TankSfxState[1]) != 0) + { + sndDeactivate(g_TankSfxState[1]); + } + } + } + + if (g_TankSfxState[0] == NULL) + { + if (lvlGetControlsLockedFlag() == 0) + { + sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, TRUCK_RUN_SFX, &g_TankSfxState[0]); + } + } + + if (g_TankSfxState[0] != NULL) + { + g_TankEngineSfxVolume = 0x7FFF; + if (tank_engine_utilization_percent < 0.9f) + { + g_TankEngineSfxVolume = (s32) (((tank_engine_utilization_percent * 7767.0f) / 0.9f) + 25000.0f); + } + + sndCreatePostEvent(g_TankSfxState[0], 8, g_TankEngineSfxVolume); + } + + if (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_TANKSHELLS) + { + tank_vertical_angle = g_CurrentPlayer->field_2A08; + tank_vertical_angle += 0.17453294f; /* should be DegToRad1Fact(10), but that yields 0.17453293f */ + } + else + { + tank_vertical_angle = g_TankTurretVerticalAngle; + } + + if (tank_vertical_angle > DegToRad1Fact(25)) + { + tank_vertical_angle = DegToRad1Fact(25); + } + + /* -0.087266468f should be DegToRad1Fact(-5), but that yields -0.0872664600611 */ + if (tank_vertical_angle < -0.087266468f) + { + tank_vertical_angle = -0.087266468f; + } + + for (i_3=0; i_3bondbreathing -= (0.750f * g_GlobalTimerDelta) / 2700.0f; + + if (g_CurrentPlayer->bondbreathing < 0.0f) + { + g_CurrentPlayer->bondbreathing = 0.0f; + } + + bondviewMoveAnimationTick(0.0f, 0.0f, 0.0f); + + move_offset.f[0] += g_CurrentPlayer->speedforwards * sinf(M_TAU_F - g_TankOrientationAngle) * g_GlobalTimerDelta; + move_offset.f[2] += g_CurrentPlayer->speedforwards * cosf(M_TAU_F - g_TankOrientationAngle) * g_GlobalTimerDelta; + + bondviewCalcUpdatePlayerCollision(&move_offset, 1); + + if ((g_EnterTankAudioState == TANK_RUN_STATE_RUNNING) && (g_ClockTimer > 0)) + { + f32 calc_x; + f32 calc_z; + f32 calc_speedforwards; + +#if defined(VERSION_EU) + // Divide by zero check. + if (g_GlobalTimerDelta == 0) + { + #if DEBUG + // unknown what went here. + return_null(); + #endif + } +#endif + + calc_x = (g_CurrentPlayer->field_488.collision_position.f[0] - g_CurrentPlayer->bondprevpos.f[0]) / g_GlobalTimerDelta; + calc_z = (g_CurrentPlayer->field_488.collision_position.f[2] - g_CurrentPlayer->bondprevpos.f[2]) / g_GlobalTimerDelta; + calc_speedforwards = sqrtf((calc_x * calc_x) + (calc_z * calc_z)); + + if (g_CurrentPlayer->speedforwards < 0.0f) + { + calc_speedforwards = -calc_speedforwards; + } + + g_CurrentPlayer->speedforwards = calc_speedforwards; + } + } + else // not in tank: g_PlayerIsInTank != 1 + { + f32 sp220; + f32 sp21C; + f32 dist; + f32 ftemp_col_x; + f32 ftemp_col_z; + f32 stack_padding_12; + f32 start_collision_pos_x; + f32 start_collision_pos_z; + struct StandTile *sp200; + f32 stack_padding_2; + s32 stack_padding_11; + f32 speedforwards; + f32 ftemp_11; + f32 speedsideways; + f32 speedtheta; + f32 stack_padding_25; + f32 stack_padding_5; + s32 stack_padding_6; + f32 sp164; + f32 sp2B0; + f32 stack_padding_3; + f32 stack_padding_111; + f32 ftemp_26; + f32 nd; // canonical name + f32 ftemp_7; + f32 sp240; + struct move_bond_temp_struct curLocus; + struct move_bond_collision bondCollision; + f32 shorten; // canonical name + f32 headpos_x; + f32 headpos_z; + struct StandTile *sp174; + struct StandTile *sp170; + f32 sp16C; + f32 sp168; + + if ((g_TankSfxState[0] != NULL) && (sndGetPlayingState(g_TankSfxState[0]) != 0)) + { + #if defined(VERSION_US) + g_TankEngineSfxVolume -= (g_ClockTimer * 1000); + #endif + + #if defined(VERSION_JP) || defined(VERSION_EU) + g_TankEngineSfxVolume -= (s32)(1000.0f * g_GlobalTimerDelta); + #endif + + if (g_TankEngineSfxVolume > 0) + { + sndCreatePostEvent(g_TankSfxState[0], 8, g_TankEngineSfxVolume); + } + else + { + sndDeactivate(g_TankSfxState[0]); + } + } + + if ((g_TankSfxState[1] != NULL) && (sndGetPlayingState(g_TankSfxState[1]) != 0)) + { + sndDeactivate(g_TankSfxState[1]); + } + + + ftemp_7 = (g_BondMoveAnimationSetup[1].speedMultiplier * 0.5f * g_GlobalTimerDelta); + sp3A0 = g_CurrentPlayer->speedsideways * ftemp_7; + + /* + The following is similar to a block of Perfect Dark bwalk0f0c69b8. + */ + + ftemp_26 = -g_CurrentPlayer->swaytarget * g_CurrentPlayer->field_488.theta_transform.f[2]; + ftemp_11 = g_CurrentPlayer->swaytarget * g_CurrentPlayer->field_488.theta_transform.f[0]; + + sp220 = (ftemp_26) - g_CurrentPlayer->swayoffset0; + sp21C = (ftemp_11) - g_CurrentPlayer->swayoffset2; + + dist = (sp220 * sp220) + (sp21C * sp21C); + + if (dist >= 100.0f) + { + sp220 *= 0.6f * 1.0f; + sp21C *= 0.6f * 1.0f; + } + + speedsideways = g_CurrentPlayer->speedsideways * MAX_SPEED_FACTOR; + speedforwards = g_CurrentPlayer->speedforwards; + speedtheta = g_CurrentPlayer->speedtheta * MAX_SPEED_FACTOR; + + if (speedsideways < 0.0f) + { + speedsideways = -speedsideways; + } + if (speedforwards < 0.0f) + { + speedforwards = -speedforwards; + } + if (speedtheta < 0.0f) + { + speedtheta = -speedtheta; + } + + maxspeed = speedforwards; + +#if defined(VERSION_EU) + if (maxspeed < speedsideways && 1) +#else + if (maxspeed < speedsideways) +#endif + { + maxspeed = speedsideways; + } + if (maxspeed < speedtheta) + { + maxspeed = speedtheta; + } + + if (dist >= 0.1f && maxspeed < MAX_SPEED_FACTOR) + { + maxspeed = MAX_SPEED_FACTOR; + } + + if (maxspeed >= 0.750f) + { + g_CurrentPlayer->bondbreathing += (maxspeed - 0.750f) * g_GlobalTimerDelta / 900.0f ; + } + else + { + g_CurrentPlayer->bondbreathing -= (0.750f - maxspeed) * g_GlobalTimerDelta / 2700.0f; + } + + if (g_CurrentPlayer->bondbreathing < 0.0f) + { + g_CurrentPlayer->bondbreathing = 0.0f; + } + else if (g_CurrentPlayer->bondbreathing > 1.0f) + { + g_CurrentPlayer->bondbreathing = 1.0f; + } + + // perfect dark call: bmove0f0cc654 + bondviewMoveAnimationTick(maxspeed, g_CurrentPlayer->speedforwards, sp3A0); + + headpos_x = g_CurrentPlayer->headpos.f[0]; + headpos_z = g_CurrentPlayer->headpos.f[2]; + + move_offset.f[0] += + ( + (headpos_z * g_CurrentPlayer->field_488.theta_transform.f[0]) - + (headpos_x * g_CurrentPlayer->field_488.theta_transform.f[2]) + ) * g_GlobalTimerDelta; + + move_offset.f[2] += + ( + (headpos_z * g_CurrentPlayer->field_488.theta_transform.f[2]) + + (headpos_x * g_CurrentPlayer->field_488.theta_transform.f[0]) + ) * g_GlobalTimerDelta; + + + move_offset.f[0] += sp220; + move_offset.f[2] += sp21C; + + start_collision_pos_x = g_CurrentPlayer->field_488.collision_position.f[0]; + start_collision_pos_z = g_CurrentPlayer->field_488.collision_position.f[2]; + sp200 = g_CurrentPlayer->field_488.current_tile_ptr; + + if (get_debug_fast_bond_flag()) + { + move_offset.f[0] += + ( + (g_CurrentPlayer->field_488.theta_transform.f[0] * g_CurrentPlayer->speedforwards) - + (g_CurrentPlayer->field_488.theta_transform.f[2] * g_CurrentPlayer->speedsideways) + ) * g_GlobalTimerDelta * 10.0f; + + move_offset.f[2] += + ( + (g_CurrentPlayer->field_488.theta_transform.f[2] * g_CurrentPlayer->speedforwards) + + (g_CurrentPlayer->field_488.theta_transform.f[0] * g_CurrentPlayer->speedsideways) + ) * g_GlobalTimerDelta * 10.0f; + } + + bondviewCalcUpdatePlayerCollision(&move_offset, (g_CurrentPlayer->swaytarget == 0.0f)); + + stanTileDistanceRelated( + &sp200, + start_collision_pos_x, + start_collision_pos_z, + g_CurrentPlayer->field_488.collision_radius * 1.16f, + &curLocus); + + /* almost never true */ + if (stanGetLocusCount(&curLocus) != 0) + { + use_stanHeight = 1; + } + + stanTileDistanceRelated( + &g_CurrentPlayer->field_488.current_tile_ptr, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2], + g_CurrentPlayer->field_488.collision_radius * 1.01f, + &curLocus); + + /* almost never true */ + if (stanGetLocusCount(&curLocus) != 0) + { + use_stanHeight = 1; + } + + stanTileDistanceRelated( + &g_CurrentPlayer->field_488.current_tile_ptr, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2], + g_CurrentPlayer->field_488.collision_radius, + &curLocus); + + /* almost always true */ + if (stanGetLocusCount(&curLocus) == 0) + { + stanTileDistanceRelated( + &sp200, + start_collision_pos_x, + start_collision_pos_z, + g_CurrentPlayer->field_488.collision_radius * 0.990099f, + &curLocus); + } + + /* almost never true */ + if (stanGetLocusCount(&curLocus)) + { + use_stanHeight = 1; + stanGetMoveBondCollisionTiles(&sp174, &sp170, &bondCollision); + + if (g_CurrentPlayer->stanHeight <= bondCollision.sp19C.f[1]) + { + f32 sp2A8; + f32 sp24C; + f32 sp250; + f32 sp310; + f32 sp314; + + sp168 = bondCollision.bondCollision.f[0] - bondCollision.sp190.f[0]; + sp16C = bondCollision.sp190.f[2] - bondCollision.bondCollision.f[2]; + + nd = sqrtf((sp16C * sp16C) + (sp168 * sp168)); + + sp168 = sp168 / nd; + sp16C = sp16C / nd; + + sp164 = + ((start_collision_pos_x - bondCollision.bondCollision.f[0]) * sp16C) + + ((start_collision_pos_z - bondCollision.bondCollision.f[2]) * sp168); + + sp2B0 = + (((start_collision_pos_x + move_offset.f[0]) - bondCollision.bondCollision.f[0]) * sp16C) + + (((start_collision_pos_z + move_offset.f[2]) - bondCollision.bondCollision.f[2]) * sp168); + + if ((sp164 * sp2B0) <= 0.0f) + { + shorten = 0.0f; + } + else + { + if (sp2B0 < 0.0f) + { + sp164 = -sp164; + sp2B0 = -sp2B0; + } + + if (sp164 <= sp2B0) + { + shorten = 0.0f; + } + else if (g_CurrentPlayer->field_488.collision_radius < sp2B0) + { + shorten = 0.0f; + } + else if (sp164 < g_CurrentPlayer->field_488.collision_radius) + { + shorten = 0.0f; + } + else + { + shorten = (sp164 - g_CurrentPlayer->field_488.collision_radius) / (sp164 - sp2B0); + } + } + + sp2A8 = sqrtf((move_offset.f[0] * move_offset.f[0]) + (move_offset.f[2] * move_offset.f[2])); + if (sp2A8 > 0.0f) + { + f32 sp318; + + sp318 = (1.0f - shorten) * sp2A8; + sp390 = sp318 * 0.25f; + + if (bondCollision.sp19C.f[1] <= (g_CurrentPlayer->stanHeight + sp390)) + { + sp390 = (bondCollision.sp19C.f[1] - g_CurrentPlayer->stanHeight); + sp318 -= (sp390 / 0.25f); + shorten += (sp318 / sp2A8); + } + } + + sp314 = bondCollision.sp19C.f[0] - bondCollision.bondCollision.f[0]; + sp310 = bondCollision.sp19C.f[2] - bondCollision.bondCollision.f[2]; + sp250 = bondCollision.sp1A8.f[0] - bondCollision.bondCollision.f[0]; + sp24C = bondCollision.sp1A8.f[2] - bondCollision.bondCollision.f[2]; + + if (((sp250 * sp250) + (sp24C * sp24C)) < ((sp314 * sp314) + (sp310 * sp310))) + { + sp314 = sp250; + sp310 = sp24C; + } + + move_offset.f[0] = (move_offset.f[0] * shorten) + (sp314 * (sp390 / (bondCollision.sp19C.f[1] - bondCollision.bondCollision.f[1]))); + move_offset.f[2] = (move_offset.f[2] * shorten) + (sp310 * (sp390 / (bondCollision.sp19C.f[1] - bondCollision.bondCollision.f[1]))); + + g_CurrentPlayer->field_488.collision_position.f[0] = start_collision_pos_x; + g_CurrentPlayer->field_488.collision_position.f[2] = start_collision_pos_z; + g_CurrentPlayer->field_488.current_tile_ptr = sp200; + + bondviewCalcUpdatePlayerCollision(&move_offset, (g_CurrentPlayer->swaytarget == 0.0f)); + } + } + + ftemp_col_x = g_CurrentPlayer->field_488.collision_position.f[0] - start_collision_pos_x; + ftemp_col_z = g_CurrentPlayer->field_488.collision_position.f[2] - start_collision_pos_z; + sp240 = (move_offset.f[0] * move_offset.f[0]) + (move_offset.f[2] * move_offset.f[2]); + if (sp240 != 0.0f) + { + sp240 = ((ftemp_col_x * ftemp_col_x) + (ftemp_col_z * ftemp_col_z)) / sp240; + } + sp240 = sqrtf(sp240); + g_CurrentPlayer->swayoffset0 += sp240 * sp220; + g_CurrentPlayer->swayoffset2 += sp240 * sp21C; + } + + // add basic block + { + f32 breathing; + f32 sp14C_temp; + f32 weapon_speed_verta; + + sp14C_temp = g_CurrentPlayer->speedtheta; + weapon_speed_verta = + (g_CurrentPlayer->speedverta / 0.7f) + + (g_CurrentPlayer->field_A4 / CHR_OBJ_MAXSPEED); + + /* + Following matches the end of Perfect Dark bwalk0f0c69b8 + */ + breathing = bheadGetBreathingValue(); + + if (weapon_speed_verta > 1.0f) + { + weapon_speed_verta = 1.0f; + } + else if (weapon_speed_verta < -1.0f) + { + weapon_speed_verta = -1.0f; + } + + if (g_CurrentPlayer->headanim == 1) + { + breathing *= 1.2f; + } + + // Perfect Dark call bgun0f09d8dc + gunSetBondWeaponSway(breathing, maxspeed, weapon_speed_verta, sp14C_temp); + + // Perfect Dark call bgunSetAdjustPos + gunSetOffsetRelated(DegToRad1Fact(g_CurrentPlayer->vv_verta360)); + } + + // end perfect dark `void bwalk0f0c69b8(void)` + + /** + * The following section updates the TankRecord fields, and handles prop collision detection + * with the tank. If colliding with character, play the "arrrhghhg" sound effect, or if + * colliding with prop then set tank movement penalty and create an explosion. + */ + if ((g_PlayerTankProp != NULL) && (g_PlayerIsInTank == 1) && (g_EnterTankAudioState == TANK_RUN_STATE_RUNNING)) + { + struct PropRecord *prop; + struct TankRecord *sp140_tank_as_TankRecord; + struct ObjectRecord *sp138_tank_as_ObjectRecord; + f32 ftemp_12; + struct ModelNode_BoundingBoxRecord *sp130; + Mtxf spF0; + struct coord3d spE4; + s32 stack_padding_13; + s32 i_4; + s32 stemp; + void *stack_padding_8; + struct rect4f spB4_tank_collision_bounds; + // roomids + s32 sp94[8]; + s32 stanlineret; + s16 *lookup_index; + + sp140_tank_as_TankRecord = ((struct TankRecord *)g_PlayerTankProp->obj); + sp138_tank_as_ObjectRecord = (struct ObjectRecord*)g_PlayerTankProp->obj; + sp130 = (struct ModelNode_BoundingBoxRecord *)((struct ModelNode *)sp138_tank_as_ObjectRecord->model->obj->Switches)->Child->Data; + + sp140_tank_as_TankRecord->is_firing_tank = (getCurrentPlayerWeaponId(GUNRIGHT) == ITEM_TANKSHELLS) + && get_hands_firing_status(GUNRIGHT); + + sp140_tank_as_TankRecord->turret_vertical_angle = g_TankTurretVerticalAngle; + sp140_tank_as_TankRecord->turret_orientation_angle = g_TankTurretOrientationAngleRad; + sp140_tank_as_TankRecord->tank_orientation_angle = g_TankOrientationAngle; + + matrix_4x4_set_rotation_around_y(M_TAU_F - g_TankOrientationAngle, &spF0); + matrix_scalar_multiply(sp138_tank_as_ObjectRecord->model->scale, &spF0); + + spE4.f[0] = -g_TankModelPositionOffset.f[0]; + spE4.f[1] = -g_TankModelPositionOffset.f[1]; + spE4.f[2] = -g_TankModelPositionOffset.f[2]; + + mtx4RotateVecInPlace(&spF0, &spE4); + + spE4.f[0] += g_CurrentPlayer->field_488.collision_position.f[0]; + spE4.f[2] += g_CurrentPlayer->field_488.collision_position.f[2]; + + sp138_tank_as_ObjectRecord->prop->stan = g_CurrentPlayer->field_488.current_tile_ptr; + + stanlineret = walkTilesBetweenPoints_NoCallback( + &sp138_tank_as_ObjectRecord->prop->stan, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2], + spE4.f[0], + spE4.f[2]); + #ifdef DEBUG + assert(stanlineret); // #7362 + #endif + + sp140_tank_as_TankRecord->stan_y = stanGetPositionYValue(sp138_tank_as_ObjectRecord->prop->stan, spE4.f[0], spE4.f[2]); + + for (i_4=0; i_4unkD0 = (sp140_tank_as_TankRecord->unkD0 * TANK_UNKD0_SCALE) + sp140_tank_as_TankRecord->stan_y; + } + + ftemp_12 = (sp140_tank_as_TankRecord->unkD0 * (1.0f - TANK_UNKD0_SCALE)); + spE4.f[1] = ftemp_12 + - (chrpropBBOXGetYmin(sp130) * sp138_tank_as_ObjectRecord->model->scale) + + 4.0f; + + matrix_4x4_copy(&spF0, &sp138_tank_as_ObjectRecord->mtx); + + sp138_tank_as_ObjectRecord->runtime_pos.f[0] = sp138_tank_as_ObjectRecord->prop->pos.f[0] = spE4.f[0]; + sp138_tank_as_ObjectRecord->runtime_pos.f[1] = sp138_tank_as_ObjectRecord->prop->pos.f[1] = spE4.f[1]; + sp138_tank_as_ObjectRecord->runtime_pos.f[2] = sp138_tank_as_ObjectRecord->prop->pos.f[2] = spE4.f[2]; + + setupUpdateObjectRoomPosition(sp138_tank_as_ObjectRecord); + chrobjCollisionRelated(sp138_tank_as_ObjectRecord); + bondviewGetTankCollisionBounds(&spB4_tank_collision_bounds, &g_CurrentPlayer->field_488.collision_position, g_TankOrientationAngle); + chraiGetPropRoomIds(sp138_tank_as_ObjectRecord->prop, &sp94); + + // update num_obj_position_data_entries + roomGetProps(&sp94); + + for (lookup_index=ptr_list_object_lookup_indices; *lookup_index>=0; lookup_index++) + { + prop = &g_Props[*lookup_index]; + if (prop != sp138_tank_as_ObjectRecord->prop) + { + if (prop->type == PROP_TYPE_CHR) + { + s32 sp88_collision_bound_height; + s32 sp84_collision_bound_z; + f32 sp80_collision_radius; + s32 sp7C; + struct coord3d sp70; + struct ChrRecord *sp6C; + f32 stack_padding_28; + + sp7C = 1; + sp6C = prop->chr; + chrpropGetCollisionBounds(prop, &sp80_collision_radius, &sp88_collision_bound_height, &sp84_collision_bound_z); + + if (chrpropTestPointInPolygon(&prop->pos, &spB4_tank_collision_bounds, 4)) + { + sp7C = 0; + + if (sp6C->actiontype == ACT_DIE) + { +#if defined(VERSION_US) + if ((sp6C->chrflags << 7) >= 0) +#endif +#if defined(VERSION_JP) || defined(VERSION_EU) + if ((sp6C->chrflags << 7) >= 0 && lvlGetControlsLockedFlag() == 0) +#endif + { + sp6C->chrflags |= CHRFLAG_01000000; + if ((D_80048380 % 3) < 2) + { + chrobjSndCreatePostEventDefault(sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, CRUSHED_YELL_SFX, NULL), &prop->pos); + } + if ((D_80048380 % 3) > 0) + { + chrobjSndCreatePostEventDefault(sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, TANK_CRUSH_MAN_SFX, NULL), &prop->pos); + } + } + } + } + + if (sp7C && (chrobjTestPointPolygonCollision(&prop->pos, sp80_collision_radius, &spB4_tank_collision_bounds, 4))) + { + sp7C = 0; + } + + if (sp7C == 0) + { + sp70.f[0] = sp138_tank_as_ObjectRecord->runtime_pos.f[0]; + sp70.f[1] = prop->pos.f[1]; + sp70.f[2] = sp138_tank_as_ObjectRecord->runtime_pos.f[2]; + + chrlvExplosionDamage(prop->chr, &sp70, 3.0f, 1); + } + } + else if (prop->type == PROP_TYPE_OBJ) + { + struct rect4f *polygon; + s32 edges; + + chraiGetCollisionBoundsWithoutY(prop, &polygon, &edges); + if ((edges > 0) && chrobjTestPolygonsTouchingOrOverlap2D(polygon, edges, &spB4_tank_collision_bounds, 4)) + { + // Explode destroyable props when the tank touches them + maybe_detonate_object_and_its_children(prop, 10000.0f, &prop->obj->runtime_pos, 0x20, get_cur_playernum()); + g_TankDamagePenaltyTicks = TANK_DAMAGE_PENTALTY_TICKS; + } + } + } + } + } + + bondviewUpdatePlayerY(use_stanHeight, sp390); + bondviewUpdatePlayerCollisionPositionFields(); + bondviewUpdatePlayerCollisionBounds(); + + if (get_debug_man_pos_flag() != 0) + { + f32 sp5C_out_unused; + + copy_tile_RGB_as_24bit( + g_CurrentPlayer->field_488.current_tile_ptr, + g_CurrentPlayer->field_488.collision_position.f[0], + g_CurrentPlayer->field_488.collision_position.f[2], + &sp5C_out_unused); + } +} + + +/** + * US address 7F086990. + * EU address 7F086AB0. +*/ +void bondviewFrozenMoveBond(s8 stick_x, s8 stick_y, u16 buttons, u16 oldbuttons) +{ + struct coord3d property_pos; + struct coord3d property_pos2; + struct coord3d property_offset; + struct coord3d offset; + struct StandTile *room_pointer_tile; + struct coord3d stan_walk_start; + + property_pos = g_DefaultFrozenPlayerPos; + property_pos2 = g_DefaultFrozenPlayerPos2; + property_offset = g_DefaultFrozenPlayerOffset; + offset = g_DefaultFrozenMoveOffset; + + bondviewPlayerTickDamageAndHealth(); + bondviewPlayerTickExplode(); + bondviewProcessInput(0, 0, 0, 0); + bondviewApplyVertaTheta(); + bondviewMoveAnimationTick(0, 0, 0); + + if ((g_ForceBondMoveOffset.f[0] != 0.0f) || (g_ForceBondMoveOffset.f[2] != 0.0f)) + { + offset.f[0] += g_ForceBondMoveOffset.f[0] * g_GlobalTimerDelta; + offset.f[2] += g_ForceBondMoveOffset.f[2] * g_GlobalTimerDelta; + } + + offset.f[0] += ((g_CurrentPlayer->headpos.f[2] * g_CurrentPlayer->field_488.theta_transform.f[0]) - (g_CurrentPlayer->headpos.f[0] * g_CurrentPlayer->field_488.theta_transform.f[2])) * g_GlobalTimerDelta; + offset.f[2] += ((g_CurrentPlayer->headpos.f[2] * g_CurrentPlayer->field_488.theta_transform.f[2]) + (g_CurrentPlayer->headpos.f[0] * g_CurrentPlayer->field_488.theta_transform.f[0])) * g_GlobalTimerDelta; + + bondviewCalcUpdatePlayerCollision(&offset, 1); + bondviewUpdatePlayerY(0, 0.0f); + bondviewUpdatePlayerCollisionPositionFields(); + + if ((g_CameraMode == CAMERAMODE_FP_NOINPUT) || (g_CameraMode == CAMERAMODE_FP) || (g_CameraMode == CAMERAMODE_FADE_TO_TITLE)) + { + currentPlayerSetCameraMode(0); + return; + } + + bondviewFrozenCameraTick(buttons, oldbuttons, &property_pos, &property_pos2, &property_offset, &room_pointer_tile, &stan_walk_start); + currentPlayerSetCameraMode(1); + bondviewSetCurrentPlayerPosition(&property_pos, &property_pos2, &property_offset, room_pointer_tile, &stan_walk_start); +} + + +s16 getWidth320or440(void) +{ + if (cameraBufferToggle != 0) + { + return SCREEN_WIDTH_440; + } + + return SCREEN_WIDTH_320; +} + + +s16 getHeight330or240(void) +{ + if (cameraBufferToggle != 0) + { + return SCREEN_HEIGHT_330; + } + + return SCREEN_HEIGHT; +} + +s16 bondviewGetCurrentPlayerViewportWidth(void) +{ + if (getPlayerCount() >= 3) + { + return VIEWPORT_WIDTH_4P; + } + + if (cameraBufferToggle != 0) + { + return SCREEN_WIDTH_440; + } + + if (cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) + { + return VIEWPORT_WIDTH_WIDESCREEN; + } + + if (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA) + { + return VIEWPORT_WIDTH_CINEMA; + } + + return VIEWPORT_WIDTH_FULLSCREEN; +} + +s16 get_curplayer_viewport_ulx(void) +{ + if (2 < getPlayerCount()) + { + if ((get_cur_playernum() == 1) || (get_cur_playernum() == 3)) + { + return 0xa1; + } + } + + return 0; +} + + + + +/** + * Address 0x7F086D24. + */ +s16 bondviewGetCurrentPlayerViewportHeight(void) +{ + f32 t; + + if (getPlayerCount() >= 2) + { + return VIEWPORT_HEIGHT_4P; + } + + if (cameraBufferToggle != 0) + { + if (cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) + { + return VIEWPORT_HEIGHT_WIDESCREEN; + } + else if (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA) + { + return VIEWPORT_HEIGHT_CINEMA; + } + else + { + return VIEWPORT_HEIGHT_FULLSCREEN; + } + } + + if (cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) + { + t = bondviewGetPauseAnimationPercent(); + return (s16) ((s32) (WIDESCREEN_SCALE_FACTOR * t) + VIEWPORT_OFFSET_HEIGHT_WIDESCREEN); + } + else if (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA) + { + t = bondviewGetPauseAnimationPercent(); + return (s16) ((s32) (CINEMA_SCALE_FACTOR * t) + VIEWPORT_OFFSET_HEIGHT_CINEMA); + } + else + { + return VIEWPORT_HEIGHT_DEFAULT; + } +} + + + +/** + * Address 0x7F086E38. + */ +s16 bondviewGetCurrentPlayerViewportUly(void) +{ + f32 t; + + if (getPlayerCount() == 2) + { + if (get_cur_playernum() == 0) + { +#ifdef VERSION_EU + return 0; +#else + return VIEWPORT_ULY_2P_PLAYER_1; +#endif + } + + return VIEWPORT_ULY_2P_PLAYER_2; + } + + if (getPlayerCount() >= 3) + { + if (get_cur_playernum() < 2) + { +#ifdef VERSION_EU + return 0; +#else + return VIEWPORT_ULY_4P_PLAYER_12; +#endif + } + + return VIEWPORT_ULY_4P_PLAYER_34; + } + + if (cameraBufferToggle != 0) + { + if (cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) + { + return VIEWPORT_ULY_CAM_WIDESCREEN; + } + else if (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA) + { + return VIEWPORT_ULY_CAM_CINEMA; + } + else + { + return VIEWPORT_ULY_CAM_FULLSCREEN; + } + } + + if (cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) + { + t = bondviewGetPauseAnimationPercent(); + return (s16) ((s32) (WIDESCREEN_ULY_SCALE_FACTOR * t) + VIEWPORT_ULY_WIDESCREEN_OFFSET); + } + else if (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA) + { + t = bondviewGetPauseAnimationPercent(); + return (s16) ((s32) (CINEMA_ULY_SCALE_FACTOR * t) + VIEWPORT_ULY_CINEMA_OFFSET); + } + else + { +#ifdef VERSION_EU + return 0; +#else + return VIEWPORT_ULY_DEFAULT; +#endif + } +} + +/** + * Sets/updates viewport for player. + * Refreshes autoaim setting. + * Arguments are passed into MoveBond or bondviewFrozenMoveBond. + * Checks if necessary to call bossReturnTitleStage. + * Set player->buttons_pressed to arg2. + * + * Address 0x7F086F9C (VERSION_US). + * Address 0x7F0870BC (VERSION_EU). + * Address 0x7F087668 (VERSION_JP). + */ +void bondviewMovePlayerUpdateViewport(s8 stick_x, s8 stick_y, u16 buttons) +{ +#ifdef VERSION_EU + f32 faspect; +#endif + + set_cur_player_fovy(FOV_Y_F); + + // This call doesn't do anything, the call viSetFovY(g_CurrentPlayer->fovy); in lvlRender + // will actually change the field of view. + // The call above should set g_CurrentPlayer->fovy, but it doesn't seem to affect + // the fov.... + viSetFovY(FOV_Y_F); + + if (cameraFrameCounter1 != 0) + { + if ((cameraFrameCounter1 >= 4) && (resolution != 0) && (viGetFrameBuf2() == (u8*)(cfb_16[1]))) + { + cameraBufferToggle = 1; + cameraFrameCounter1 = 0; + } + else + { + cameraFrameCounter1 += 1; + } + } + else + { + if (cameraFrameCounter2 != 0) + { + if ((cameraFrameCounter2 >= 4) && (viGetFrameBuf2() == (u8*)(cfb_16[0]))) + { + cameraBufferToggle = 0; + cameraFrameCounter2 = 0; + } + else + { + cameraFrameCounter2 += 1; + } + } + } + + if ((cameraBufferToggle != 0) && (viGetFrameBuf2() == (u8*)(cfb_16[1]))) + { + viSetFrameBuf2((u8 *) resolution); + } + +#ifdef VERSION_EU + if (get_screen_ratio() == SCREEN_RATIO_16_9) + { + faspect = ((f32) bondviewGetCurrentPlayerViewportWidth() / (f32) bondviewGetCurrentPlayerViewportHeight()) * 0.75f * WIDESCREEN_ASPECT; + } + else + { + faspect = (f32) bondviewGetCurrentPlayerViewportWidth() / (f32) bondviewGetCurrentPlayerViewportHeight(); + } + + if (cameraBufferToggle == 0) + { + faspect *= EU_CAMERA_8003642C_ASPECT; + } + + set_cur_player_aspect(faspect); + viSetAspect(faspect); + +#else + + if (get_screen_ratio() == SCREEN_RATIO_16_9) + { + set_cur_player_aspect(((f32) bondviewGetCurrentPlayerViewportWidth() / (f32) bondviewGetCurrentPlayerViewportHeight()) * 0.75f * WIDESCREEN_ASPECT); + viSetAspect(((f32) bondviewGetCurrentPlayerViewportWidth() / (f32) bondviewGetCurrentPlayerViewportHeight()) * 0.75f * WIDESCREEN_ASPECT); + } + else + { + set_cur_player_aspect((f32) bondviewGetCurrentPlayerViewportWidth() / (f32) bondviewGetCurrentPlayerViewportHeight()); + viSetAspect((f32) bondviewGetCurrentPlayerViewportWidth() / (f32) bondviewGetCurrentPlayerViewportHeight()); + } +#endif + + set_cur_player_screen_size( bondviewGetCurrentPlayerViewportWidth(), bondviewGetCurrentPlayerViewportHeight()); + set_cur_player_viewport_size( get_curplayer_viewport_ulx(), bondviewGetCurrentPlayerViewportUly()); + viSetXY(getWidth320or440(), getHeight330or240()); + viSetBuf(getWidth320or440(), getHeight330or240()); + viSetViewSize(bondviewGetCurrentPlayerViewportWidth(), bondviewGetCurrentPlayerViewportHeight()); + viSetViewPosition(get_curplayer_viewport_ulx(), bondviewGetCurrentPlayerViewportUly()); + currentPlayerUpdateColourScreenProperties(); + currentPlayerTickChrFade(); + currentPlayerSetYAutoAimEnabled(cur_player_get_autoaim()); + currentPlayerSetXAutoAimEnabled(cur_player_get_autoaim()); + currentPlayerSetLookAheadSetting(cur_player_get_lookahead()); + gunSetGunAmmoVisible(GUNAMMOREASON_OPTION, cur_player_get_ammo_onscreen_setting()); + + gunSetSightVisible( + GUNSIGHTREASON_1, + (getPlayerCount() == 1 && cur_player_get_sight_onscreen_control()) + || (getPlayerCount() >= 2 && g_playerPerm->sight) + ); + +#if defined(VERSION_EU) + if (1); +#endif + + if ((g_CameraMode == CAMERAMODE_NONE) || ((g_CameraMode == CAMERAMODE_FP) && (is_timer_active != 0)) || (g_CameraMode == CAMERAMODE_FADE_TO_TITLE)) + { + if (get_cur_playernum() == 0) + { + mission_timer += g_ClockTimer; + } + + MoveBond(stick_x, stick_y, buttons, (u16) g_CurrentPlayer->buttons_pressed); + } + else + { + bondviewFrozenMoveBond(stick_x, stick_y, buttons, (u16) g_CurrentPlayer->buttons_pressed); + } + +#if defined(BUGFIX_R1) + watch_time_0 += jpD_800484D0; +#else + // VERSION_US + watch_time_0 += speedgraphframes; +#endif + + if (stop_time_flag != 0) + { + if ((lvlGetControlsLockedFlag() == 0) && ((buttons & ~(g_CurrentPlayer->buttons_pressed) & (CONT_A | B_BUTTON | Z_TRIG | START_BUTTON | CONT_R | CONT_L)))) + { + stop_time_flag = 2; + + if (currentPlayerIsFadeComplete()) + { + if (g_CurrentPlayer->colourscreenfrac == 0.0f) + { + currentPlayerSetFadeColour(0, 0, 0, 0.0f); + currentPlayerSetFadeFrac(60.0f, 1.0f); + } + } + else + { + if (g_CurrentPlayer->colourfadefracnew == 0.0f) + { + currentPlayerSetFadeFrac(g_CurrentPlayer->colourfadetime60, 1.0f); + } + } + } + + if ((stop_time_flag == 2) && currentPlayerIsFadeComplete() && (g_CurrentPlayer->colourscreenfrac == 1.0f)) + { + bossReturnTitleStage(); + } + } + + if (g_CameraAfterCinema) + { + bondviewAdvanceCameraMode(); + } + + if (g_CurrentPlayer->bonddead) + { + if (g_CurrentPlayer->redbloodfinished == FALSE) + { + currentPlayerEquipWeaponWrapper(GUNLEFT, 0); + currentPlayerEquipWeaponWrapper(GUNRIGHT, 0); + + if (0) + { + // removed? + }; + } + + if (g_CurrentPlayer->redbloodfinished && g_CurrentPlayer->deathanimfinished && (camera_mode >= CAMERAMODE_SWIRL)) + { + bossRunTitleStage(); + } + } + + if ((g_CameraMode == CAMERAMODE_FADE_TO_TITLE) && currentPlayerIsFadeComplete()) + { + bossRunTitleStage(); + } + + g_CurrentPlayer->buttons_pressed = buttons; +} + + +/** + * Address 0x7F0875E4. + */ +void bondviewUpdateCurrentRoomPosition(s32 arg0) +{ + getRoomPositionScaledByIndex(arg0, &g_CurrentPlayer->current_model_pos); + g_CurrentPlayer->current_room_pos.f[0] = g_CurrentPlayer->current_model_pos.f[0] * get_room_data_float1(); + g_CurrentPlayer->current_room_pos.f[1] = g_CurrentPlayer->current_model_pos.f[1] * get_room_data_float1(); + g_CurrentPlayer->current_room_pos.f[2] = g_CurrentPlayer->current_model_pos.f[2] * get_room_data_float1(); + setPlayerRoomField(arg0); +} + + +void store_BONDdata_curpos_to_previous(void) { + g_CurrentPlayer->previous_model_pos.f[0] = g_CurrentPlayer->current_model_pos.f[0]; + g_CurrentPlayer->previous_model_pos.f[1] = g_CurrentPlayer->current_model_pos.f[1]; + g_CurrentPlayer->previous_model_pos.f[2] = g_CurrentPlayer->current_model_pos.f[2]; + mtx4RotateVecInPlace(camGetWorldToScreenMtxf(), &g_CurrentPlayer->previous_model_pos); +} + + +/** + * Address: 7F0876C4 + */ +void bondviewUpdateCameraMatrices(coord3d* cam_pos, coord3d* cam_look_dir, coord3d* cam_up) +{ + Mtx sp108; + LookAt *lookat; + Mtxf spC4; + coord3d clpos; + coord3d scaledpos; + f32 scale; + Mtx *temp_s0; + Mtxf *projmtx; + Mtxf sp60; + s32 j; + s32 i; + + i = bondviewGetCurrentPlayersRoom(); + bondviewUpdateCurrentRoomPosition(i); + + g_CurrentPlayer->field_5C = dynAllocateMatrix(); + g_CurrentPlayer->field_60 = dynAllocateMatrix(); + g_CurrentPlayer->field_64 = dynAllocateMatrix(); + g_CurrentPlayer->field_68 = dynAllocateMatrix(); + + lookat = dynAllocateLights(2); + + scale = D_800364CC; + + scaledpos.x = (cam_pos->x - g_CurrentPlayer->current_model_pos.x) * scale; + scaledpos.y = (cam_pos->y - g_CurrentPlayer->current_model_pos.y) * scale; + scaledpos.z = (cam_pos->z - g_CurrentPlayer->current_model_pos.z) * scale; + + clpos.f[0] = scaledpos.f[0] + cam_look_dir->f[0]; + clpos.f[1] = scaledpos.f[1] + cam_look_dir->f[1]; + clpos.f[2] = scaledpos.f[2] + cam_look_dir->f[2]; + + matrix_4x4_set_lookat(&spC4, + scaledpos.x, scaledpos.y, scaledpos.z, + cam_look_dir->x, cam_look_dir->y, cam_look_dir->z, + cam_up->x, cam_up->y, cam_up->z); + + guLookAtReflect(&sp108, lookat, + scaledpos.x, scaledpos.y, scaledpos.z, + clpos.x, clpos.y, clpos.z, + cam_up->x, cam_up->y, cam_up->z); + + matrix_4x4_set_lookat((Mtxf*) g_CurrentPlayer->field_64, + cam_pos->x, cam_pos->y, cam_pos->z, + cam_look_dir->x, cam_look_dir->y, cam_look_dir->z, + cam_up->x, cam_up->y, cam_up->z); + + matrix_4x4_set_basis_and_position((Mtxf*) g_CurrentPlayer->field_68, + cam_pos->x, cam_pos->y, cam_pos->z, + cam_look_dir->x, cam_look_dir->y, cam_look_dir->z, + cam_up->x, cam_up->y, cam_up->z); + + temp_s0 = dynAllocateMatrix(); + + projmtx = currentPlayerGetProjectionMatrixF(); + matrix_4x4_multiply(projmtx, &spC4, &sp60); + + for (i = 0; i < 4; i++) + { + for (j = 0; j < 4; j++) + { + if (sp60.m[i][j] > 32000.0f) + { + sp60.m[i][j] = 32000.0f; + } + else if (sp60.m[i][j] < -32000.0f) + { + sp60.m[i][j] = -32000.0f; + } + } + } + + guMtxF2L((f32 (*)[4]) &sp60, temp_s0); + set_BONDdata_field_10E0((s32) temp_s0); + + scale = bgGetLevelVisibilityScale(); + + matrix_scalar_multiply(scale, spC4.m[0]); + guMtxF2L((f32 (*)[4]) &spC4, (Mtx* ) g_CurrentPlayer->field_5C); + sub_GAME_7F059334((s32* ) g_CurrentPlayer->field_5C, (s32* ) g_CurrentPlayer->field_60); + + currentPlayerSetMatrix10C8((Mtx* ) g_CurrentPlayer->field_5C); + currentPlayerSetMatrix10C4((Mtx* ) g_CurrentPlayer->field_60); + currentPlayerSetMatrix10CC((Mtxf* ) g_CurrentPlayer->field_64); + currentPlayerSetViewToWorldMtxf((Mtxf* ) g_CurrentPlayer->field_68); + + sub_GAME_7F078464((s32) lookat); + bondviewUpdateFrustumPlanes(); + store_BONDdata_curpos_to_previous(); +} + + +/** + * Address: 7F087A08 + */ +Gfx *bondviewRenderDebugBondView(Gfx *gdl) +{ + coord3d cam_pos; + coord3d cam_look; + coord3d cam_up; + struct collision434 *collision; + coord3d shake; + coord3d vec; + coord3d zeropos; + f32 vec_y; + f32 horizontal_len; + struct player *player; + f32 angle; + f32 vertical_rot; + f32 ft4; + +#if defined(VERSION_EU) + if (bossGetStageNum() == LEVELID_CUBA) + { + if (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA) + { + gdl = clear_framebuffer_black(gdl); + gdl = clear_framebuffer_black(gdl); + gdl = clear_framebuffer_black(gdl); + gdl = clear_framebuffer_black(gdl); + } + else if (cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) + { + gdl = clear_framebuffer_black(gdl); + gdl = clear_framebuffer_black(gdl); + gdl = clear_framebuffer_black(gdl); + } + else + { + gdl = clear_framebuffer_black(gdl); + gdl = clear_framebuffer_black(gdl); + } + } +#endif + + if (g_CurrentPlayer->cameramode == 1) { + cam_pos.x = g_CurrentPlayer->pos.x; + cam_pos.y = g_CurrentPlayer->pos.y; + cam_pos.z = g_CurrentPlayer->pos.z; + + cam_look.x = g_CurrentPlayer->pos2.x - g_CurrentPlayer->pos.x; + cam_look.y = g_CurrentPlayer->pos2.y - g_CurrentPlayer->pos.y; + cam_look.z = g_CurrentPlayer->pos2.z - g_CurrentPlayer->pos.z; + + cam_up.x = g_CurrentPlayer->offset.x; + cam_up.y = g_CurrentPlayer->offset.y; + cam_up.z = g_CurrentPlayer->offset.z; + } else { + collision = &g_CurrentPlayer->field_488; + + shake = ZeroCoordShake; + + if (!g_CurrentPlayer->bonddead) { + explosionScreenShake( + &collision->pos, + &collision->applied_view, + &shake + ); + } else { + viShake(0.0f); + } + + cam_pos.x = collision->pos.x; + cam_pos.y = collision->pos.y; + cam_pos.z = collision->pos.z; + + cam_look.x = collision->applied_view.x; + cam_look.y = collision->applied_view.y; + cam_look.z = collision->applied_view.z; + + cam_up.x = collision->applied_view2.x; + cam_up.y = collision->applied_view2.y; + cam_up.z = collision->applied_view2.z; + } + + bondviewUpdateCameraMatrices(&cam_pos, &cam_look, &cam_up); + sub_GAME_7F068190(&zeropos, &vec); + + + vec_y = vec.y; + horizontal_len = sqrtf((vec.z * vec.z) + (vec.x * vec.x)); + vertical_rot = bondviewGetPlayerPitchRadians(); + ft4 = atan2f(vec_y, horizontal_len) + vertical_rot; + + if (ft4 >= M_PI_F) { + ft4 -= M_TAU_F; + } + g_CurrentPlayer->field_2A08 = ft4; + + angle = atan2f(-vec.x, -vec.z); + if (angle >= M_PI_F) { + angle -= M_TAU_F; + } + g_CurrentPlayer->field_2A0C = angle; + + return gdl; +} + + +void bondviewSelectCuff(Model *model, ModelFileHeader *header, s32 switchindex) +{ + s32 pad; + s32 local; + ModelNode **switches; + ModelNode **base; + ModelNode *node; + s32 offset; + s32 *rwdata; + s32 index; + s32 visible; + s32 pad2; + + local = fileGetBondForCurrentFolder(); + switches = header->Switches; + offset = switchindex << 2; + + if (1); + + // byte-indexed on purpose: offset = switchindex * 4. &switches[i] won't match. + base = (ModelNode **) (((u8 *) switches) + offset); + + if (base[0] != NULL) + { + rwdata = (s32 *) modelGetNodeRwData(model, base[0]); + *rwdata = g_CurrentPlayer->bondtype == CUFF_BOILER; + switches = header->Switches; + base = (ModelNode **) (((u8 *) switches) + offset); + } + + index = switchindex + 1; + + if (((void *) (index * 0)) != base[1]) + { + node = switches[index]; + rwdata = (s32 *) modelGetNodeRwData(model, node); + visible = g_CurrentPlayer->bondtype == CUFF_BROSNAN; + if (visible == 0) + { + visible = g_CurrentPlayer->bondtype == CUFF_DALTON; + if (visible == 0) + { + visible = g_CurrentPlayer->bondtype == CUFF_MOORE; + if (visible == 0) + { + visible = g_CurrentPlayer->bondtype == CUFF_FOLDER; + if (visible != 0) + { + visible = local != 1; + } + } + } + } + *rwdata = visible; + switches = header->Switches; + base = (ModelNode **) (((u8 *) switches) + offset); + } + + index = switchindex + 2; + + if (base[2] != NULL) + { + rwdata = (s32 *) modelGetNodeRwData(model, switches[index]); + visible = g_CurrentPlayer->bondtype == CUFF_CONNERY; + + if (visible == 0) + { + visible = g_CurrentPlayer->bondtype == CUFF_FOLDER; + if (visible != 0) + { + visible = local == 1; + } + } + + *rwdata = visible; + switches = header->Switches; + base = (ModelNode **) (((u8 *) switches) + offset); + } + + index = switchindex + 3; + + if (base[3] != NULL) + { + rwdata = (s32 *) modelGetNodeRwData(model, switches[index]); + *rwdata = g_CurrentPlayer->bondtype == CUFF_BLUE; + switches = header->Switches; + base = (ModelNode **) (((u8 *) switches) + offset); + } + + index = (switchindex + 4) ^ (((switchindex + 4) ^ 0) * 0); + + if (base[4]) + { + rwdata = (s32 *) modelGetNodeRwData(model, switches[index]); + *rwdata = g_CurrentPlayer->bondtype == CUFF_JUNGLE; + switches = header->Switches; + base = (ModelNode **) (((u8 *) switches) + offset); + } + + index = switchindex + 5; + + if (base[5] != NULL) + { + rwdata = (s32 *) modelGetNodeRwData(model, switches[index]); + *rwdata = g_CurrentPlayer->bondtype == CUFF_SNOW; + } +} + + +/** + * Address: 7F087E74 + */ +Gfx *bondviewRenderWatch(Gfx *gdl) +{ + ModelRenderData renderdata; + Mtxf watchmtx; + coord3d watchpos; + f32 t; + Mtxf *matrices; + ModelFileHeader *objheader; + f32 *nodepos; + union ModelRwData *rwdata; + Mtx *perspmtx; + u16 perspNorm; + + if (g_CurrentPlayer->watch_animation_state == 0) + { + goto end; + } + + if (g_CurrentPlayer->pausing_flag == FALSE) + { + goto end; + } + + renderdata = D_8003683C; + watchpos = ZeroCoordWatchPos; + objheader = get_ptr_itemheader_in_hand(GUNLEFT); + nodepos = (f32 *) objheader->Switches[3]; + rwdata = modelGetNodeRwData((Model *) (&g_CurrentPlayer->something_with_watch_object_instance), (ModelNode *) nodepos); + perspmtx = dynAllocateMatrix(); +#if defined(VERSION_EU) + guPerspective(perspmtx, &perspNorm, g_CurrentPlayer->zoominfovy, 1.4005603f, 10.0f, 300.0f, 1.0f); +#else + guPerspective(perspmtx, &perspNorm, g_CurrentPlayer->zoominfovy, 1.4545455f, 10.0f, 300.0f, 1.0f); +#endif + + gSPMatrix(gdl++, OS_PHYSICAL_TO_K0((u32) perspmtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + gSPPerspNormalize(gdl++, perspNorm); + + // Keep this nested block for matching. + { + Mtxf targetmtx; + coord3d currot; + coord3d targetrot; + quatf quat1; + quatf quat2; + quatf quat3; + coord3d targetpos; + s32 total_seconds; + s32 seconds; + s32 total_minutes; + s32 minutes; + f32 framesfrac; + f32 secondsAngle; + f32 minutesAngle; + f32 hoursAngle; + s32 time; + f32 *nodepos2; + Mtxf handmtx; + Mtx *finalmtx; + + rwdata->Switch.visible = g_CurrentPlayer->outside_watch_menu; + + watchpos.x = (g_CurrentPlayer->field_488.theta_transform.x * (g_CurrentPlayer->headbodyoffset.z + (-12.0f))) + (g_CurrentPlayer->field_488.collision_position.x + (g_CurrentPlayer->headbodyoffset.x * (-g_CurrentPlayer->field_488.theta_transform.z))); + watchpos.y = g_CurrentPlayer->headbodyoffset.y + g_CurrentPlayer->field_488.collision_position.y; + watchpos.z = (g_CurrentPlayer->field_488.theta_transform.z * (g_CurrentPlayer->headbodyoffset.z + (-12.0f))) + (g_CurrentPlayer->field_488.collision_position.z + (g_CurrentPlayer->headbodyoffset.x * g_CurrentPlayer->field_488.theta_transform.x)); + + matrix_4x4_set_position_and_rotation_around_y(watchpos.f, (360.0f - g_CurrentPlayer->vv_theta) * 0.017453292f, &watchmtx); + matrix_4x4_multiply_homogeneous_in_place(camGetWorldToScreenMtxf(), &watchmtx); + matrices = dynAllocate(objheader->numMatrices << 6); + bondviewSelectCuff((Model *) (&g_CurrentPlayer->something_with_watch_object_instance), objheader, 4); + renderdata.basemtx = &watchmtx; + renderdata.mtxlist = matrices; + subcalcmatrices(&renderdata, (Model *) (&g_CurrentPlayer->something_with_watch_object_instance)); + nodepos = (f32 *) objheader->Switches[0]->Data; + time = watch_time_0; + t = g_CurrentPlayer->pause_watch_related_adjust / 20.0f; + + if (t > 1.0f) + { + t = 1.0f; + } + + targetpos.x = matrices->m[3][0] + (((g_CurrentPlayer->field_1D4 - (nodepos[0] * g_CurrentPlayer->watch_scale_destination)) - matrices->m[3][0]) * t); + targetpos.y = matrices->m[3][1] + (((g_CurrentPlayer->field_1D8 + (nodepos[2] * g_CurrentPlayer->watch_scale_destination)) - matrices->m[3][1]) * t); + targetpos.z = matrices->m[3][2] + (((g_CurrentPlayer->pause_watch_position - (nodepos[1] * g_CurrentPlayer->watch_scale_destination)) - matrices->m[3][2]) * t); + + matrix_4x4_set_basis_and_position_target(&targetmtx, 0.0f, 0.0f, 0.0f, g_CurrentPlayer->field_1E0, g_CurrentPlayer->field_1E4, g_CurrentPlayer->field_1E8, g_CurrentPlayer->field_1EC, g_CurrentPlayer->field_1F0, g_CurrentPlayer->field_1F4); + matrix_4x4_get_rotation_around_xyz(matrices, &currot); + matrix_4x4_get_rotation_around_xyz(&targetmtx, &targetrot); + quaternion_set_rotation_around_xyzf(currot.f, quat1); + quaternion_set_rotation_around_xyzf(targetrot.f, quat2); + quaternion_ensure_shortest_path(quat1, quat2); + quaternion_slerp(quat1, quat2, t, quat3); + quaternion_to_matrix(quat3, matrices->m); + matrix_4x4_set_position(&targetpos, matrices); + matrix_scalar_multiply(g_CurrentPlayer->watch_scale_destination, (f32 *) matrices); + total_seconds = time / 60; + seconds = total_seconds % 60; + total_minutes = total_seconds / 60; + minutes = total_minutes % 60; + framesfrac = ((f32) (time % 60)) / 60.0f; + secondsAngle = ((-(((f32) seconds) + framesfrac)) * M_TAU_F) / 60.0f; + minutesAngle = ((((-((f32) minutes)) * M_TAU_F) / 60.0f) * 1.0f) + (secondsAngle / 60.0f); + hoursAngle = ((((-((f32) ((total_seconds / 3600) % 12))) * M_TAU_F) / 12.0f) + (minutesAngle / 12.0f)) + (secondsAngle / 720.0f); + + while (secondsAngle < 0.0f) + { + secondsAngle += M_TAU_F; + } + + while (minutesAngle < 0.0f) + { + minutesAngle += M_TAU_F; + } + + while (hoursAngle < 0.0f) + { + hoursAngle += M_TAU_F; + } + + matrix_4x4_set_position_and_rotation_around_y((f32 *) objheader->Switches[0]->Data, hoursAngle, &matrices[1]); + matrix_4x4_multiply_in_place(matrices, &matrices[1]); + matrix_4x4_set_position_and_rotation_around_y((f32 *) objheader->Switches[1]->Data, minutesAngle, &matrices[2]); + matrix_4x4_multiply_in_place(matrices, &matrices[2]); + matrix_4x4_set_position_and_rotation_around_y((f32 *) objheader->Switches[2]->Data, secondsAngle, &matrices[3]); + matrix_4x4_multiply_in_place(matrices, &matrices[3]); + + renderdata.flags = 3; + renderdata.zbufferenabled = 0; + renderdata.gdl = gdl; + renderdata.PropType = PROP_TYPE_WEAPON; + + if ((g_CurrentPlayer->watch_animation_state == 5) || (g_CurrentPlayer->watch_animation_state == 12)) + { + renderdata.envcolour.word = 0xcd; + } + else + { + renderdata.envcolour.word = g_CurrentPlayer->tileColor.a | (((g_CurrentPlayer->tileColor.r << 24) | (g_CurrentPlayer->tileColor.g << 16)) | (g_CurrentPlayer->tileColor.b << 8)); + } + + subdraw(&renderdata, (Model *) (&g_CurrentPlayer->something_with_watch_object_instance)); + gdl = renderdata.gdl; + nodepos2 = (f32 *) objheader->Switches[2]->Data; + finalmtx = dynAllocateMatrix(); + matrix_4x4_set_identity_and_position((coord3d *) nodepos2, &handmtx); + matrix_4x4_multiply_in_place(matrices, &handmtx); + matrix_4x4_7F058C64(); + matrix_4x4_f32_to_s32(&handmtx, finalmtx); + matrix_4x4_7F058C88(); + gdl = draw_watch_current_page(gdl, finalmtx, (g_CurrentPlayer->watch_animation_state == 5) || (g_CurrentPlayer->watch_animation_state == 12)); + matrix_4x4_7F058C64(); + bondviewTransformManyPosToViewMatrix(g_CurrentPlayer->field_23C, objheader->numMatrices); + matrix_4x4_7F058C88(); + } + + end: + return gdl; +} + + +/** + * Address: 7F088618 + * + * Renders the in-game health and armor gauges. + * The watch menu gauges are handled by trigger_solo_watch_menu(). + */ +Gfx *bondviewRenderGaugeBars(Gfx *gdl) +{ + Mtx *lookatmtx; + Mtx *orthomtx; + Mtxf lookatmtxf; + + //Set up armor bars. + hudMakeDamageSegments(&g_CurrentPlayer->armor_display_values[0].items[0], 0x2e, 1, g_CurrentPlayer->apparentarmour); + buildGaugeBarDL((Gfx *)&g_CurrentPlayer->watch_body_armor_bar_gdl, OS_PHYSICAL_TO_K0(&g_CurrentPlayer->armor_display_values[0].items[0]), 0x2e); + + // Set up health bars. + hudMakeDamageSegments(&g_CurrentPlayer->health_display_values[0].items[0], 0x2e, -1, g_CurrentPlayer->apparenthealth); + buildGaugeBarDL((Gfx *)&g_CurrentPlayer->watch_health_bar_gdl, OS_PHYSICAL_TO_K0(&g_CurrentPlayer->health_display_values[0].items[0]), 0x2e); + + // Create an orthographic render state for the gauge. + lookatmtx = dynAllocateMatrix(); + orthomtx = dynAllocateMatrix(); + + guOrtho(orthomtx, -800.0f * D_800364CC, 800.0f * D_800364CC, -600.0f * D_800364CC, 600.0f * D_800364CC, -100.0f, 1000.0f, 1.0f); + + gSPMatrix(gdl++, osVirtualToPhysical(orthomtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); + + matrix_4x4_set_lookat_target( + &lookatmtxf, + 0.0f, 500.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, -1.0f + ); + + matrix_4x4_f32_to_s32(&lookatmtxf, (Mtxf *)lookatmtx); + + gSPMatrix(gdl++, osVirtualToPhysical(lookatmtx), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); + + gDPPipeSync(gdl++); + gDPSetCycleType(gdl++, G_CYC_1CYCLE); + gDPSetRenderMode(gdl++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2); + gDPSetAlphaCompare(gdl++, G_AC_NONE); + gDPSetCombineMode(gdl++, G_CC_SHADE, G_CC_SHADE); + gDPSetPrimColor(gdl++, 0, 0, 0xe6, 0xe6, 0xe6, 0x00); + gSPClearGeometryMode(gdl++, G_CULL_BOTH); + + gSPDisplayList(gdl++, OS_PHYSICAL_TO_K0(&g_CurrentPlayer->watch_body_armor_bar_gdl)); + gSPDisplayList(gdl++, OS_PHYSICAL_TO_K0(&g_CurrentPlayer->watch_health_bar_gdl)); + + gSPMatrix(gdl++, osVirtualToPhysical(currentPlayerGetProjectionMatrix()), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); + + return gdl; +} + + +void mp_respawn_handler(void) +{ + coord3d start_pos = ZeroCoordSpawnPos; + f32 start_look_angle; + s32 start_stan; + s32 pad; + f32 stan_height; + s32 var_v0; + s32 var_v1; + u32 var_v0_2; + struct SetupIntroEmpty* intro_record; + + intro_record = g_CurrentSetup.intro; + + init_player_BONDdata(); + bondviewPlayerBeginLife(); + + g_CurrentPlayer->bonddead = 0; + g_CurrentPlayer->deathanimfinished = 0; + g_CurrentPlayer->redbloodfinished = 0; + g_CurrentPlayer->startnewbonddie = 1; + g_CurrentPlayer->healthdamagetype = 7; + g_CurrentPlayer->damagetype = 7; + g_CurrentPlayer->gunammooff = 0; + g_CurrentPlayer->gunsightmode = 2; + + hudmsgsSetOn(-1); + bondviewClearUpperTextDisplayFlag(-1); + + + if ((getPlayerCount() >= 2) && (startpadcount > 0)) + { + var_v1 = bondviewGetRandomSpawnPadIndex(); + } + else + { + var_v1 = 0; + } + + #ifdef DEBUG + assert(g_Startpad[var_v1]->stan); + #endif + + start_pos.x = g_Startpad[var_v1]->pos.x; + start_pos.z = g_Startpad[var_v1]->pos.z; + start_stan = g_Startpad[var_v1]->stan; + + stan_height = bondviewYPositionRelated(start_stan, start_pos.x, start_pos.z); + + start_pos.y = g_CurrentPlayer->eyeheight + stan_height; + g_CurrentPlayer->field_70 = stan_height; + + start_look_angle = randomGetNext() * 2.3283064e-10f * 6.2831855f; + + g_CurrentPlayer->vv_theta = (f32) ((start_look_angle * 360.0f) / 6.2831855f); + g_CurrentPlayer->stanHeight = stan_height; +#if defined(VERSION_EU) + g_CurrentPlayer->field_6C = (f32) (stan_height / 0.2004f); +#else + g_CurrentPlayer->field_6C = (f32) (stan_height / 0.17000002f); +#endif + + change_player_pos_to_target(&g_CurrentPlayer->field_488, &start_pos, start_stan); + + g_CurrentPlayer->field_488.theta_transform.x = -sinf(start_look_angle); + g_CurrentPlayer->field_488.theta_transform.y = 0.0f; + g_CurrentPlayer->field_488.theta_transform.z = cosf(start_look_angle); + g_CurrentPlayer->prop->pos.x = g_CurrentPlayer->bondprevpos.x = start_pos.f[0]; + g_CurrentPlayer->prop->pos.y = g_CurrentPlayer->bondprevpos.y = start_pos.f[1]; + g_CurrentPlayer->prop->pos.z = g_CurrentPlayer->bondprevpos.z = start_pos.f[2]; + g_CurrentPlayer->prop->stan = start_stan; +#if defined(VERSION_EU) + g_CurrentPlayer->field_3B8.x = (f32) (g_CurrentPlayer->field_488.pos.x / 0.118799984f); + g_CurrentPlayer->field_3B8.y = (f32) (g_CurrentPlayer->field_488.pos.y / 0.118799984f); + g_CurrentPlayer->field_3B8.z = (f32) (g_CurrentPlayer->field_488.pos.z / 0.118799984f); +#else + g_CurrentPlayer->field_3B8.x = (f32) (g_CurrentPlayer->field_488.pos.x / 0.100000024f); + g_CurrentPlayer->field_3B8.y = (f32) (g_CurrentPlayer->field_488.pos.y / 0.100000024f); + g_CurrentPlayer->field_3B8.z = (f32) (g_CurrentPlayer->field_488.pos.z / 0.100000024f); +#endif + + bondinvReinitInv(); + var_v0 = 0; + + while (var_v0 != 30) + { + g_CurrentPlayer->ammoheldarr[var_v0++] = 0; + } + + if (intro_record != NULL) + { + while (intro_record->type != 9) // INTROTYPE_END + { + switch (intro_record->type) + { + case 0: // INTROTYPE_SPAWN + intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroSpawn)); + break; + case 1: // INTROTYPE_ITEM + if (check_ramrom_flags() == ((struct SetupIntroAmmo*)intro_record)->is_demo_playback) { + if ( ((struct SetupIntroItem*)intro_record)->item_left >= 0) { + bondinvAddDoublesInvItem(((struct SetupIntroItem*)intro_record)->item_right, ((struct SetupIntroItem*)intro_record)->item_left); + } else { + bondinvAddInvItem(((struct SetupIntroItem*)intro_record)->item_right); + } + } + intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroItem)); + break; + case 2: // INTROTYPE_AMMO + if (check_ramrom_flags() == ((struct SetupIntroAmmo*)intro_record)->is_demo_playback) { + give_cur_player_ammo(((struct SetupIntroAmmo*)intro_record)->ammo_type, ((struct SetupIntroAmmo*)intro_record)->ammo_amount); + } + intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroAmmo)); + break; + case 3: // INTROTYPE_SWIRL + intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroSwirl)); + break; + case 4: // INTROTYPE_ANIM + intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroAnim)); + break; + case 5: // INTROTYPE_CUFF + intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroCuff)); + break; + case 6: // INTROTYPE_CAMERA + intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroCamera)); + break; + default: // INTROTYPE_WATCH, INTROTYPE_CREDITS + intro_record = (struct SetupIntroEmpty*)((s32)intro_record + sizeof(struct SetupIntroEmpty)); + break; + } + #ifdef DEBUG + ossyncprintf("unknown bondstart type %d!\n", var_v0_2); + #endif + } + } + + g_CurrentPlayer->field_78 = 0.0f; + g_CurrentPlayer->field_7C = -0.0001f; + g_CurrentPlayer->field_80 = 0.0f; + currentPlayerStartChrFade(120.0f, 1.0f); +} + + +/** + * Address: 7F088CD8 + */ +Gfx *bondviewRenderCredits(Gfx *gdl) +{ + s32 frame; + s32 start; + s32 x; + s32 y; + s32 xpos1; + s32 xpos2; + s32 textheight; + s32 textwidth; + s32 i; + s32 end; + s32 x2; + s32 entrysize; + s32 align1; + s32 align2; + s16 viewheight; + char *text; + + if (bossGetStageNum() == LEVELID_CUBA && credits_state == 1 && credits_pointer != NULL) + { + xpos1 = 0xdc; + xpos2 = 0xdc; + align1 = CREDITS_ALIGN_RIGHT; + align2 = CREDITS_ALIGN_RIGHT; + camera_80036438++; + frame = camera_80036438; + gdl = microcode_constructor(gdl); + start = (frame - viGetViewHeight()) / 16; + end = (frame / 16) + 1; + + if (start < 0) + { + start = 0; + } + + for (i = 0; i < start; i++) + { + if (credits_pointer[i].TextId1 == 0 && credits_pointer[i].TextId2 == 0) + { + end = i; + start = i; + credits_state = 2; + break; + } + + if (credits_pointer[i].TextId1 != 0x5011) + { + if (credits_pointer[i].Position1 >= 0) + { + xpos1 = credits_pointer[i].Position1; + } + + if ((s16) credits_pointer[i].Alignment1 >= CREDITS_ALIGN_RIGHT) + { + align1 = (s16) credits_pointer[i].Alignment1; + } + } + + if (credits_pointer[i].TextId2 != 0x5011) + { + if (credits_pointer[i].Position2 >= 0) + { + xpos2 = credits_pointer[i].Position2; + } + + if ((s16) credits_pointer[i].Alignment2 + >= CREDITS_ALIGN_RIGHT) + { + align2 = (s16) credits_pointer[i].Alignment2; + } + } + } + + for (i = start; i < end && (credits_pointer[i].TextId1 || credits_pointer[i].TextId2); i++) + { + if ((u32) credits_pointer[i].TextId1 != 0x5011) + { + text = langGet(credits_pointer[i].TextId1); + + if (credits_pointer[i].Position1 >= 0) + { + xpos1 = credits_pointer[i].Position1; + } + + if ((s16) credits_pointer[i].Alignment1 >= CREDITS_ALIGN_RIGHT) + { + align1 = (s16) credits_pointer[i].Alignment1; + } + + viewheight = viGetViewHeight(); + y = ((viGetViewTop() + (i * 16)) - frame) + viewheight; + textheight = 0; + textwidth = 0; + + textMeasure(&textheight, &textwidth, text, ptrFontZurichBoldChars, ptrFontZurichBold, 0); + + entrysize = y + textheight; + + if (align1 == CREDITS_ALIGN_LEFT) + { + x = xpos1 - textwidth; + x2 = xpos1; + } + else if (align1 == CREDITS_ALIGN_CENTER) + { + x = xpos1 - (textwidth >> 1); + x2 = x + textwidth; + } + else + { + x = xpos1; + x2 = xpos1 + textwidth; + } + + gdl = microcode_constructor_related_to_menus(gdl, x, y - 1, x2 + 1, entrysize + 1, 0); + + gdl = textRender(gdl, &x, &y, text, ptrFontZurichBoldChars, ptrFontZurichBold, -1, viGetX(), viGetY(), 0, 0); + } + + if (credits_pointer[i].TextId2 != 0x5011) + { + text = langGet(credits_pointer[i].TextId2); + + if (credits_pointer[i].Position2 >= 0) + { + xpos2 = credits_pointer[i].Position2; + } + + if ((s16) credits_pointer[i].Alignment2 >= CREDITS_ALIGN_RIGHT) + { + align2 = (s16) credits_pointer[i].Alignment2; + } + + viewheight = viGetViewHeight(); + y = ((viGetViewTop() + (i * 16)) - frame) + viewheight; + textheight = 0; + textwidth = 0; + + textMeasure(&textheight, &textwidth, text, ptrFontZurichBoldChars, ptrFontZurichBold, 0); + + entrysize = y + textheight; + + if (align2 == CREDITS_ALIGN_LEFT) + { + x = xpos2 - textwidth; + x2 = xpos2; + } + else if (align2 == CREDITS_ALIGN_CENTER) + { + x = xpos2 - (textwidth >> 1); + x2 = x + textwidth; + } + else + { + x = xpos2; + x2 = xpos2 + textwidth; + } + + gdl = microcode_constructor_related_to_menus(gdl, x, y - 1, x2 + 1, entrysize + 1, 0); + + gdl = textRender(gdl, &x, &y, text, ptrFontZurichBoldChars, ptrFontZurichBold, -1, viGetX(), viGetY(), 0, 0); + } + } + + gdl = combiner_bayer_lod_perspective(gdl); + } + + return gdl; +} + + +Gfx *maybe_mp_interface(Gfx *gdl) +{ + s32 ulx; + s32 uly; + s32 lrx; + s32 lry; + s32 doblood; + s32 scenario; + s32 cur; + s32 count; + s32 i; + s32 total; + + if (g_CurrentPlayer->cameramode == 1) + { + bondviewIntroCameraTextTick(); + gdl = hudmsgBottomRender(gdl); + bondviewUpperTextWindowTimerTick(); + gdl = sub_GAME_7F08AAE8(gdl); + gdl = countdownTimerRender(gdl); + gdl = currentPlayerDrawFade(gdl); + return bondviewRenderCredits(gdl); + } + + gunUpdateAndFireBothHands(); + gunRenderCasings(&gdl); + gunRenderFirstPersonGunModels(&gdl); + gdl = bondviewRenderWatch(gdl); + + if (g_CurrentPlayer->mpmenuon != 0) + { + ulx = viGetViewLeft(); + uly = viGetViewTop(); + lrx = viGetViewLeft() + viGetViewWidth(); + lry = viGetViewTop() + viGetViewHeight(); + gdl = microcode_constructor(gdl); + gdl = microcode_constructor_related_to_menus(gdl, ulx, uly, lrx, lry, 160); + } + + if (bondviewGetIfCurrentPlayerHealthShowTime() && + (g_CurrentPlayer->watch_animation_state == 0)) + { + gdl = bondviewRenderGaugeBars(gdl); + } + else if (mpwatchShouldDisplayGauges()) + { + gdl = bondviewRenderGaugeBars(gdl); + if (g_CurrentPlayer->healthdisplaytime > 0) + { + g_CurrentPlayer->healthdisplaytime -= g_ClockTimer; + } + if (g_CurrentPlayer->healthdisplaytime < 0) + { + g_CurrentPlayer->healthdisplaytime = 0; + } + } + + if (getPlayerCount() == 1) + { + display_objective_status_text_on_status_change(); + } + + if (g_CurrentPlayer->bonddead != 0) + { + if (g_CurrentPlayer->deathanimfinished == 0) + { + doblood = 0; + if (g_CurrentPlayer->bonddead == 1) + { + doblood = 1; + g_CurrentPlayer->bonddead = 2; + } + if (doblood) + { + die_blood_image_routine(0); + if (getPlayerCount() == 1) + { + // This unusual comma-expression syntax is required for a byte match. + set_missionstate((musicStopSlot(-1), 0)); + musicTrack1ApplySeqpVol(sub_GAME_7F0C0BF0()); + g_musicXTrack1Fade = 0; + musicTrack2ApplySeqpVol(0); + g_musicXTrack2Fade = 0; + musicTrack1Play(27); + } + else + { + set_missionstate(6); + } + } + else + { + if (g_CurrentPlayer->redbloodfinished) + { + currentPlayerSetFadeColour(150, 0, 0, 0.7058824f); + } + else + { + if (g_ClockTimer > 0) + { + doblood = 1; + } + else + { + doblood = 2; + } + if (die_blood_image_routine(doblood)) + { + g_CurrentPlayer->redbloodfinished = TRUE; + } + gdl = gameplayBloodOverlayDL(gdl); + } + } + } + if (modelGetAnimFrame(&g_CurrentPlayer->model) >= + modelGetAnimEndFrame(&g_CurrentPlayer->model)) + { + if (g_CurrentPlayer->redbloodfinished) + { + if (!g_CurrentPlayer->deathanimfinished) + { + g_CurrentPlayer->deathanimfinished = TRUE; + currentPlayerAdjustFade(60.0f, 0, 0, 0, 1.0f); + currentPlayerStartChrFade(120.0f, 0.0f); + } + if (currentPlayerIsFadeComplete()) + { + if (getPlayerCount() == 1) + { + bondviewSetCameraMode(CAMERAMODE_DEATH_CAM_SP); + } + else + { + scenario = get_scenario(); + cur = get_cur_playernum(); + count = getPlayerCount(); + total = 0; + for (i = 0; i < count; i++) + { + total += g_playerPlayerData[i].kill_counts[cur]; + } + if ((scenario != SCENARIO_YOLT) || (total < 2)) + { + if (joyGetButtons(get_cur_playernum(), 0xB000)) + { + mp_respawn_handler(); + } + } + } + } + } + } + } + + bondviewIntroCameraTextTick(); + gdl = hudmsgBottomRender(gdl); + bondviewUpperTextWindowTimerTick(); + gdl = sub_GAME_7F08AAE8(gdl); + gunDrawSight(&gdl); + gdl = generate_ammo_total_microcode(gdl); + gdl = countdownTimerRender(gdl); + gdl = display_red_blue_on_radar(gdl); + return currentPlayerDrawFade(gdl); +} + + + + + +/** + * Address 0x7F0896C0. + */ +Gfx *write_stan_tiles_in_yellow(Gfx *gdl) +{ + if (dword_CODE_bss_80079DA0 != NULL) + { + gdl = sub_GAME_7F0B3024(gdl, dword_CODE_bss_80079DA0, 0xFF00FF80U); + } + + if (dword_CODE_bss_80079DA4 != NULL) + { + gdl = sub_GAME_7F0B3024(gdl, dword_CODE_bss_80079DA4, 0xFF00FF80U); + } + + return gdl; +} + + +void sub_GAME_7F089718(f32 arg0) +{ + f32 scalar; + struct collision434* col; + + scalar = D_800364D0 / arg0; + + col = &g_CurrentPlayer->field_488; + col->collision_position.x *= scalar; + col->collision_position.z *= scalar; + + D_800364D0 = arg0; + D_800364D4 = 1.0f / arg0; +} + + +void sub_GAME_7F08976C(f32 param_1) +{ + D_800364CC = param_1; +} + + +/** + * Address 0x7F089778. + */ +f32 bondviewGetPlayerStanHeight(struct player *player) +{ + return player->stanHeight; +} + + +/** + * Address 0x7F089780. + */ +f32 bondviewGetPlayerDuckingHeightRelated(struct player *player) +{ + return player->eyeheight + player->field_88 + player->ducking_height_offset; +} + + +PropRecord* getCurrentPlayerProp(void) { + return g_CurrentPlayer->prop; +} + + +/** + * Address 0x7F0897A8. + */ +void bondviewKillCurrentPlayer(void) +{ + if ((g_CurrentPlayer->cheatBondInvincible == 0) && (g_CurrentPlayer->bonddead == FALSE)) + { + if (g_CurrentPlayer->watch_animation_state != WATCH_ANIMATION_0x0) + { + trigger_solo_watch_menu(1); + } + + g_isBondKIA = 1; + g_CurrentPlayer->bonddead = 1; + + g_CurrentPlayer->previous_collision_info = g_CurrentPlayer->field_488; + + g_CurrentPlayer->thetadie = g_CurrentPlayer->vv_theta; + g_CurrentPlayer->vertadie = g_CurrentPlayer->vv_verta; + + if (g_PlayerTankProp != NULL) + { + g_ExplodeTankOnDeathFlag = 1; + } + + currentPlayerEquipWeaponWrapper(GUNLEFT, 0); + currentPlayerEquipWeaponWrapper(GUNRIGHT, 0); + + if ((getMissiontimer() - g_CurrentPlayer->lifestarttime60) < g_playerPerm->shortest_inning) + { + g_playerPerm->shortest_inning = getMissiontimer() - g_CurrentPlayer->lifestarttime60; + } + + g_CurrentPlayer->lifestarttime60 = getMissiontimer(); + } +} + + +/** + * Unreferenced. + * + * Address 0x7F0898E8. + */ +s32 sub_GAME_7F0898E8(void) +{ + return (s32) ((joyGetStickY(0) * 8) + 0x280) / 0xA0; +} + + +/** + * @param damage_amount: damage amount + * @param vectorx: damage source x coordinate + * @param vectorz: damage source y coordinate + * @param playerid: player index of player causing the damage + * @param arg4: boolean, does the damage apply to body armor (e.g. false when gas) + * + * Address US 7F08991C. + * Address EU 7F089A84. + * Address JP 7F089FF0. + */ +void record_damage_kills(f32 damage_amount, f32 vectorx, f32 vectorz, s32 playerid, s32 affects_armor) { + f32 damage_dealt = g_playerPerm->handicap * damage_amount; + s32 cur_player_num; + f32 angle; + s32 padding; + s32 sp2C; + s32 sp28; + + if (g_CurrentPlayer->watch_animation_state != WATCH_ANIMATION_0x0) + { + hudMakeDamageSegments(g_CurrentPlayer->armor_display_values, 0x2E, 1, currentPlayerGetArmor()); + hudMakeDamageSegments(g_CurrentPlayer->health_display_values, 0x2E, -1, currentPlayerGetHealth()); + } + + if (getPlayerCount() < 2 || (g_stopPlayFlag == 0 && g_gameOverFlag == 0)) + { + if (g_PlayerIsInTank == 1) + { + damage_dealt *= 0.25f; + } + + if (g_CurrentPlayer->bonddead == FALSE && g_CurrentPlayer->cheatBondInvincible == FALSE) + { + joyRumblePakStart(get_cur_playernum(), 0.25); + if (cur_player_get_control_type() >= 4) + { + // rumble second controller in 2.x + joyRumblePakStart(get_cur_playernum() + getPlayerCount(), 0.25); + } + } + + if (getPlayerCount() >= 2 && get_scenario() == SCENARIO_LTK) + { + // the damage dealt is always equivalent to how much health and armor the player has + // the result of this is to always kill the player regardless of how much damage he can sustain + damage_dealt = (g_CurrentPlayer->bondhealth * g_CurrentPlayer->actual_health) + (g_CurrentPlayer->bondarmour * g_CurrentPlayer->actual_armor); + } + + if (g_CurrentPlayer->cheatBondInvincible == FALSE && g_CurrentPlayer->bonddead == FALSE && g_PlayerInvincible == FALSE && + (g_CurrentPlayer->damageshowtime < 0 || (getPlayerCount() >= 2 && g_CurrentPlayer->damageshowtime == 0))) + { + if (g_CurrentPlayer->watch_animation_state != WATCH_ANIMATION_0x5 && g_CurrentPlayer->watch_animation_state != WATCH_ANIMATION_0xc) + { + g_CurrentPlayer->oldhealth = g_CurrentPlayer->bondhealth; + g_CurrentPlayer->oldarmour = g_CurrentPlayer->bondarmour; + + if (getPlayerCount() >= 2) + { + cur_player_num = get_cur_playernum(); + angle = g_playerPointers[cur_player_num]->vv_theta - (360.0f - ((atan2f(vectorx, vectorz) * 180.0f) / 3.1415927f)); + + if (angle < 0.0f) + { + angle = -angle; + } + + if (angle < 90.0f || angle > 270.0f) + { + // danger: if Bond could be damaged by toxic gas in multiplayer, playerid would be -1 + // thus causing an out of bounds access + g_playerPlayerData[playerid].damage_to_backside++; + } + } + + if (affects_armor && damage_dealt <= g_CurrentPlayer->bondarmour * g_CurrentPlayer->actual_armor) + { + g_CurrentPlayer->bondarmour = g_CurrentPlayer->bondarmour - (damage_dealt / g_CurrentPlayer->actual_armor); + } + else + { + if (affects_armor) + { + damage_dealt -= g_CurrentPlayer->bondarmour / g_CurrentPlayer->actual_armor; + g_CurrentPlayer->bondarmour = 0.0f; + g_CurrentPlayer->actual_armor = 1.0f; + } + + g_CurrentPlayer->bondhealth = g_CurrentPlayer->bondhealth - (damage_dealt / g_CurrentPlayer->actual_health); + + if (g_CurrentPlayer->bondhealth <= 0.0f) + { + if (getPlayerCount() >= 2) + { + sp2C = get_cur_playernum(); + sp28 = 0; + + if (get_scenario() == 3 && bondinvHasGoldenGun()) + { + sp28 = 1; + } + +#if defined(VERSION_EU) || defined(VERSION_JP) + drop_inventory(); +#endif + if (sp2C != playerid) + { +#if defined(VERSION_US) + drop_inventory(); +#endif + increment_num_deaths(); + } + + set_cur_player(playerid); + + if (sp2C == playerid) + { + increment_num_suicides_display_MP(); + } + else + { + increment_num_kills_display_text_in_MP(); + + if (sp28 != 0) + { + increment_num_times_killed_MwtGC(); + } + } + + set_cur_player(sp2C); + + if(1); + + g_playerPlayerData[playerid].kill_counts[sp2C]++; + } + + bondviewKillCurrentPlayer(); + } + } + +#if defined(VERSION_EU) || defined(VERSION_JP) + #define ZERO_7F08991C 0.0f +#else + #define ZERO_7F08991C 0 +#endif + if (g_CurrentPlayer->damageshowtime < ZERO_7F08991C) + { + g_CurrentPlayer->bondshotspeed.x = g_CurrentPlayer->bondshotspeed.x + 2.0f * vectorx; + g_CurrentPlayer->bondshotspeed.z = g_CurrentPlayer->bondshotspeed.z + 2.0f * vectorz; + } + + g_CurrentPlayer->damageshowtime = ZERO_7F08991C; + g_CurrentPlayer->healthshowtime = ZERO_7F08991C; + +#undef ZERO_7F08991C + +#if defined(VERSION_EU) || defined(VERSION_JP) + if (!lvlGetControlsLockedFlag()) + { + sndPlaySfx(g_musicSfxBufferPtr, BOND_GET_HIT1_SFX, 0); + } +#else + sndPlaySfx(g_musicSfxBufferPtr, BOND_GET_HIT1_SFX, 0); +#endif + } + } + } +} + + +/** + * @param damage_amount: damage amount + * @param rad: damage source angle + * @param player_id: player index of player causing the damage + * @param affects_armor: boolean, does the damage apply to body armor (e.g. false when gas) + * + * Address 0x7F089E4C. + */ +void bondviewCallRecordDamageKills(f32 damage_amount, f32 angle, s32 playerid, s32 affects_armor) +{ + record_damage_kills(damage_amount, sinf(angle), cosf(angle), playerid, affects_armor); +} + + +int bondviewGetIfCurrentPlayerDamageShowTime(void) +{ + return (g_CurrentPlayer->damageshowtime >= (s32)0); +} + + +int bondviewGetIfCurrentPlayerHealthShowTime(void) +{ + return (g_CurrentPlayer->healthshowtime > (s32)0); +} + + +f32 bondviewGetBondBreathing(void) +{ + return g_CurrentPlayer->bondbreathing; +} + + +/** + * Gets the current player's heading angle, converted from degrees to radians. + * @return Heading (Yaw) in Radians +*/ +f32 bondviewGetPlayerYawRadians(void) +{ + return DegToRad(360.0f - g_CurrentPlayer->vv_theta); +} + + +/** + * Gets the current player's vertical look angle, converted from degrees to radians. + * @return Pitch in radians. + */ +f32 bondviewGetPlayerPitchRadians(void) +{ + return DegToRad(g_CurrentPlayer->vv_verta); +} + + +s32 bond_pressed_reload_activate(void) { + return g_CurrentPlayer->field_D0; +} + + +void set_bondata_invincible_flag(u32 arg0) { + g_CurrentPlayer->cheatBondInvincible = arg0; +} + + +u8 get_bondata_invincible_flag(void) { + return g_CurrentPlayer->cheatBondInvincible; +} + + +/** + * Sets g_VisibleToGuardsFlag. + * 1 = visible, 0 = not visible. + */ +void bondviewSetVisibleToGuardsFlag(s32 param_1) +{ + g_VisibleToGuardsFlag = param_1; +} + +/** + * Gets g_VisibleToGuardsFlag. + * 1 = visible, 0 = not visible + */ +s32 bondviewGetVisibleToGuardsFlag(void) +{ + return g_VisibleToGuardsFlag; +} + +void set_obj_collision_flag(s32 flag) { + obj_collision_flag = flag; +} + +s32 get_obj_collision_flag(void) { + return obj_collision_flag; +} + + + + + + +/** + * Address 0x7F089F98. + */ +u8 bondviewGetCurrentPlayersRoom(void) +{ + if ((g_CurrentPlayer->cameramode == 1) && (g_CurrentPlayer->cameratile != 0)) + { + return g_CurrentPlayer->cameratile->room; + } + + return g_CurrentPlayer->field_488.current_tile_ptr_for_portals->room; +} + + + + +/** + * Address 0x7F089FD4. + */ +coord3d *bondviewGetCurrentPlayersPosition(void) +{ + if (g_CurrentPlayer->cameramode == 1) + { + return &g_CurrentPlayer->pos; + } + + return &g_CurrentPlayer->field_488.pos; +} + + + +coord3d * bondviewGetCurrentPlayersPosition3(void) +{ + + if (g_CurrentPlayer->cameramode == 1) + { + return &g_CurrentPlayer->pos3; + } + + return &g_CurrentPlayer->field_488.pos3; +} + +struct coord3d *getCurrentPlayerPrevPos(void) +{ + return &g_CurrentPlayer->bondprevpos; +} + + +/** + * Address 0x7F08A03C. + */ +void bondviewUpdateGuardTankFlagsRelated(PropRecord *prop, s32 flag) +{ + s32 playerIndex; + + playerIndex = getPlayerPointerIndex(prop); + + if (prop->chr != NULL) + { + chrSetMoving(prop->chr, flag); + } + + if (g_PlayerTankProp != NULL) + { + // When commented out tank shells fired from the tank detonate immediately. + sub_GAME_7F04F218(g_PlayerTankProp, flag); + } + + g_playerPointers[playerIndex]->field_AC = flag; +} + + + + + +/** + * Address 0x7F08A0B0. + */ +void bondviewGetPropHeightRelatedValues(PropRecord *arg0, struct rect4f **field_B0, s32 *arg2, f32 *height_related, f32 *collision) +{ + s32 temp_v0; + + temp_v0 = getPlayerPointerIndex(arg0); + if (g_playerPointers[temp_v0]->field_AC != 0) + { + // What is this doing and why is it 1 player only? + if (getPlayerCount() == 1 || g_playerPointers[temp_v0]->bonddead == FALSE) + { + if (g_playerPointers[temp_v0]->cameramode != 1) + { + *arg2 = 4; + *field_B0 = &g_playerPointers[temp_v0]->collision_bounds; + *collision = g_playerPointers[temp_v0]->field_70; + *height_related = *collision + bondviewGetPlayerDuckingHeightRelated(g_playerPointers[temp_v0]) + 10.0f; + + return; + } + } + } + + *arg2 = 0; +} + + + + +/** + * Address 0x7F08A19C. + */ +void bondviewUpdatePlayerCollisionBounds(void) +{ + + if (g_PlayerIsInTank == 1) + { + bondviewGetTankCollisionBounds(&g_CurrentPlayer->collision_bounds, &g_CurrentPlayer->field_488.collision_position, g_TankOrientationAngle); + + return; + } + + g_CurrentPlayer->collision_bounds.f[0] = (g_CurrentPlayer->field_488.collision_position.f[0] + g_CurrentPlayer->field_488.collision_radius); + g_CurrentPlayer->collision_bounds.f[1] = g_CurrentPlayer->field_488.collision_position.f[2]; + g_CurrentPlayer->collision_bounds.f[2] = g_CurrentPlayer->field_488.collision_position.f[0]; + g_CurrentPlayer->collision_bounds.f[3] = (g_CurrentPlayer->field_488.collision_position.f[2] + g_CurrentPlayer->field_488.collision_radius); + g_CurrentPlayer->collision_bounds.f[4] = (g_CurrentPlayer->field_488.collision_position.f[0] - g_CurrentPlayer->field_488.collision_radius); + g_CurrentPlayer->collision_bounds.f[5] = g_CurrentPlayer->field_488.collision_position.f[2]; + g_CurrentPlayer->collision_bounds.f[6] = g_CurrentPlayer->field_488.collision_position.f[0]; + g_CurrentPlayer->collision_bounds.f[7] = (g_CurrentPlayer->field_488.collision_position.f[2] - g_CurrentPlayer->field_488.collision_radius); +} + + + + + +/** + * @param arg0: prop + * @param width: out parameter, will be set to field_488.collision_radius + * @param height: out parameter, will be set to character height - 30 + * @param always_30: out parameter, will be set to 30 + * + * Address 0x7F08A274. + */ +void bondviewGetCollisionRadius(PropRecord* arg0, f32 *collision_radius, f32 *height, f32 *always_30) +{ + struct player **temp_v1; + + temp_v1 = &g_playerPointers[getPlayerPointerIndex(arg0)]; + *collision_radius = (*temp_v1)->field_488.collision_radius; + *height = (bondviewGetPlayerDuckingHeightRelated(*temp_v1) + 10.0f) - 30.0f; + *always_30 = 30.0f; +} + + + + + +/** + * Address 0x7F08A2EC. + */ +f32 currentPlayerGetHealth(void) +{ + return g_CurrentPlayer->bondhealth; +} + + +f32 currentPlayerGetArmor(void) +{ + return g_CurrentPlayer->bondarmour; +} + + + + + +/** + * Address 0x7F08A30C. + */ +void bondviewAddCurrentPlayerArmor(f32 arg0) +{ + g_playerPerm->body_armor_pickups += arg0; + g_CurrentPlayer->bondarmour = arg0; +} + + + + + +/** + * Address 0x7F08A330. + */ +void bondviewResetIntroCameraMessageDialogs(void) +{ + g_CurrentPlayer->hudmessoff = FALSE; + g_CurrentPlayer->bondmesscnt = -1; + display_statusbar = 0; + status_bar_text_buffer_index = 0; + +#ifdef BUGFIX_R0 + copy_1stfonttable = ptrFontBankGothic; + copy_2ndfonttable = ptrFontBankGothicChars; +#endif +} + + + +void hudmsgsSetOn(s32 flag) +{ + g_CurrentPlayer->hudmessoff &= ~flag; +} + + + + + +/** + * Address 0x7F08A39C. + */ +void hudmsgsSetOff(s32 flags) +{ + g_CurrentPlayer->hudmessoff |= flags; +} + + +#ifdef VERSION_US +void setFontTables(s32 arg0, s32 arg1) +{ + copy_2ndfonttable = arg0; + copy_1stfonttable = arg1; +} +#endif + + +#ifdef BUGFIX_R1 +void hudmsgBottomShow(char *string, s32 font, s32 arg2) +{ + s32 abs_index; + s32 index; + if (getPlayerCount() == 1) + { + if (display_statusbar < 5) + { + abs_index = status_bar_text_buffer_index + display_statusbar; + index = abs_index % 5; + abs_index = index; + strncpy(stringbuffer_lowerleft[abs_index], string, (BONDVIEW_HUD_MSG_BOTTOM_BUFFER_LENGTH-1)); + stringbuffer_lowerleft[abs_index][(BONDVIEW_HUD_MSG_BOTTOM_BUFFER_LENGTH-1)] = 0; + dword_CODE_bss_jp80079CEC[abs_index] = font; + dword_CODE_bss_jp80079Cd8[abs_index] = arg2; + display_statusbar++; + } + } + else + { + index = get_cur_playernum(); + strncpy(stringbuffer_lowerleft[index], string, (BONDVIEW_HUD_MSG_BOTTOM_BUFFER_LENGTH-1)); + stringbuffer_lowerleft[index][(BONDVIEW_HUD_MSG_BOTTOM_BUFFER_LENGTH-1)] = 0; + dword_CODE_bss_jp80079CEC[index] = font; + dword_CODE_bss_jp80079Cd8[index] = arg2; +#if defined(VERSION_EU) + g_CurrentPlayer->bondmesscnt = 0x64; +#elif defined(VERSION_JP) + g_CurrentPlayer->bondmesscnt = 0x78; +#endif + } +} + +#else +#ifdef DEBUG +void hudmsgBottomShow(char *mess, void *font) +#else +void hudmsgBottomShow(char *mess) +#endif +{ + s32 abs_index; + s32 index; + #ifdef DEBUG + assert(font); + assert(strlen(mess)<=MAXMESSAGELEN); + #endif + if (getPlayerCount() == 1) + { + if (display_statusbar < 5) + { + abs_index = status_bar_text_buffer_index + display_statusbar; + index = abs_index % 5; + strncpy(stringbuffer_lowerleft[index], mess, MAXMESSAGELEN); + display_statusbar++; + stringbuffer_lowerleft[index][MAXMESSAGELEN] = 0; + } + } + else + { + index = get_cur_playernum(); + strncpy(stringbuffer_lowerleft[index], mess, MAXMESSAGELEN); + stringbuffer_lowerleft[index][MAXMESSAGELEN] = 0; + g_CurrentPlayer->bondmesscnt = 0x78; + } +} + +#endif + + +#if defined(BUGFIX_R1) +void jp_hudmsgBottomShow(char *string) +{ + hudmsgBottomShow(string, ptrFontBankGothicChars, ptrFontBankGothic); +} +#endif + + +/** + * Address 0x7F08A4E4. + */ +void bondviewIntroCameraTextTick(void) +{ + if ((g_CurrentPlayer->hudmessoff == FALSE) && (g_CurrentPlayer->mpmenuon == FALSE)) + { + if (g_CurrentPlayer->bondmesscnt >= 0) + { + g_CurrentPlayer->bondmesscnt -= g_ClockTimer; + + if (getPlayerCount() == 1) + { + if (g_CurrentPlayer->bondmesscnt < 0) + { + status_bar_text_buffer_index = (s32) (status_bar_text_buffer_index + 1) % 5; + display_statusbar = display_statusbar - 1; + } + else if ((display_statusbar >= 2) && (g_CurrentPlayer->bondmesscnt >= BONDVIEW_INTRO_CAMERA_BONDMESSCNT_A)) + { + g_CurrentPlayer->bondmesscnt = BONDVIEW_INTRO_CAMERA_BONDMESSCNT_B; + } + } + } + + if ((getPlayerCount() == 1) && (g_CurrentPlayer->bondmesscnt < 0) && (display_statusbar > 0)) + { + if (display_statusbar >= 2) + { + g_CurrentPlayer->bondmesscnt = BONDVIEW_INTRO_CAMERA_BONDMESSCNT_B; + } + else + { + g_CurrentPlayer->bondmesscnt = BONDVIEW_INTRO_CAMERA_BONDMESSCNT_C; + } + } + } +} + + +/** + * Address: 7F08A5FC + */ +Gfx* hudmsgBottomRender(Gfx* arg0) +{ + s32 var_v1; + s32 view_left; + s32 view_vert; + s32 view_horiz; + s32 view_top; + s32 view_top_offset; + s32 view_left_offset; + + if ((g_CurrentPlayer->hudmessoff == FALSE) && (g_CurrentPlayer->bondmesscnt >= 0) && (g_CurrentPlayer->mpmenuon == FALSE)) + { + var_v1 = 0; + if (getPlayerCount() == 1) + { + if ((u8) *stringbuffer_lowerleft[status_bar_text_buffer_index] != 0) + { + var_v1 = 1; + } + } + else if (g_CurrentPlayer->bondmesscnt >= 0) + { + status_bar_text_buffer_index = get_cur_playernum(); + var_v1 = 1; + } + + if (var_v1 != 0) + { + arg0 = microcode_constructor(arg0); + view_left_offset = 0; + view_top_offset = 0; + textMeasure(&view_top_offset, &view_left_offset ,(u8* ) stringbuffer_lowerleft[status_bar_text_buffer_index], BONDVIEW_2ND_FONTTABLE(status_bar_text_buffer_index), BONDVIEW_1ST_FONTTABLE(status_bar_text_buffer_index), 0); + + if (getPlayerCount() < 3) + { + view_left = viGetViewLeft() + 0x1E; + } + else if (get_cur_playernum() & 1) + { + view_left = viGetViewLeft() + 0xA; + } + else + { + view_left = viGetViewLeft() + 0x1E; + } + + view_horiz = view_left + view_left_offset; + + if (getPlayerCount() < 3) + { + if ((get_ammo_type_for_weapon(getCurrentPlayerWeaponId(GUNLEFT)) == 0) && (is_clock_drawn_onscreen() == 0)) + { + view_top = (viGetViewTop() + viGetViewHeight()) - BONDVIEW_VIEW_TOP_OFFSET_1; + } + else + { + view_top = (viGetViewTop() + viGetViewHeight()) - BONDVIEW_VIEW_TOP_OFFSET_2; + } +#if !defined(VERSION_EU) + if (get_cur_playernum() == 1) + { + view_top -= 8; + } +#endif + } + else + { + view_top = viGetViewTop() +#if defined(VERSION_JP) || defined(VERSION_EU) + + (((j_text_trigger != 0) && (get_cur_playernum() < 2)) ? 8 : 0) +#endif + + BONDVIEW_VIEW_TOP_OFFSET_3; + } + + view_vert = view_top - view_top_offset; + arg0 = draw_blackbox_to_screen(arg0, (s32) &view_left, (s32) &view_vert, (s32) &view_horiz, (s32) &view_top); + arg0 = combiner_bayer_lod_perspective(textRenderOutlined(arg0, &view_left, &view_vert, stringbuffer_lowerleft[status_bar_text_buffer_index], BONDVIEW_2ND_FONTTABLE(status_bar_text_buffer_index), BONDVIEW_1ST_FONTTABLE(status_bar_text_buffer_index), -1, 0x646464FFU, (s16) (s32) viGetX(), (s16) viGetY(), 0, 0)); + } + } + + return arg0; +} + + +void bondviewResetUpperTextDisplay(void) +{ + upper_text_window_timer = -1; + display_upper_text_window = 0; + upper_text_buffer_index = 0; + g_UpperTextDisplayFlag = 0; +} + + +void bondviewClearUpperTextDisplayFlag(int param_1) +{ + int new_var; + new_var = ~param_1; + g_UpperTextDisplayFlag = g_UpperTextDisplayFlag & new_var; +} + + +void bondviewSetUpperTextDisplayFlag(PLAYERFLAG flag) +{ + g_UpperTextDisplayFlag |= flag; +} + + +void hudmsgTopShow(char* mess) +{ + s32 index; + #ifdef DEBUG + assert(strlen(mess)<=MAXTALKMESSLEN); + #endif + if (display_upper_text_window >= 2) { return; } + + index = (upper_text_buffer_index + display_upper_text_window) % 2; +#if defined(LEFTOVERDEBUG) + strncpy(stringbuffer_top[index], mess, (BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH-1)); + display_upper_text_window += 1; + stringbuffer_top[index][(BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH-1)] = 0; +#else + strncpy(dword_CODE_bss_80079DC8[index], mess, (BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH-1)); + display_upper_text_window += 1; + dword_CODE_bss_80079DC8[index][(BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH-1)] = 0; +#endif +} + + +/** + * Address 0x7F08A9F8. + */ +void bondviewUpperTextWindowTimerTick(void) +{ + if ((g_UpperTextDisplayFlag == FALSE) && (g_CurrentPlayer->mpmenuon == FALSE)) + { + if (upper_text_window_timer >= 0) + { + upper_text_window_timer -= g_ClockTimer; + + if (upper_text_window_timer < 0) + { + upper_text_buffer_index = (s32) (upper_text_buffer_index + 1) % 2; + display_upper_text_window += -1; + } + else if ((display_upper_text_window >= 2) && (upper_text_window_timer >= BONDVIEW_UPPER_TEXT_TIMER_A)) + { + upper_text_window_timer = BONDVIEW_UPPER_TEXT_TIMER_B; + } + } + + if ((upper_text_window_timer < 0) && (display_upper_text_window > 0)) + { + if (display_upper_text_window >= 2) + { + upper_text_window_timer = BONDVIEW_UPPER_TEXT_TIMER_B; + } + else + { + upper_text_window_timer = BONDVIEW_UPPER_TEXT_TIMER_C; + } + } + } + +} + + +Gfx *sub_GAME_7F08AAE8(Gfx *gdl) +{ + TopMessageLocals msg; + DebugTextBuffers debugtext; + s32 debug_x; + s32 debug_y; + f32 theta_x; + s32 debug_boxbottom; + s32 pad; + s32 *roomid; + s32 debug_angle; + DirectionLabels directions; + + struct + { + s16 screenwidth; + s16 pad; + } sw; + + if (g_UpperTextDisplayFlag == 0) + { + if (upper_text_window_timer >= 0) + { +#if defined(LEFTOVERDEBUG) + if (stringbuffer_top[upper_text_buffer_index][0] != '\0') +#else + if (dword_CODE_bss_80079DC8[upper_text_buffer_index][0] != '\0') +#endif + { + if (g_CurrentPlayer->mpmenuon == 0) + { + gdl = microcode_constructor(gdl); + msg.textwidth = 0; + msg.textheight = 0; +#if defined(LEFTOVERDEBUG) + textMeasure(&msg.textheight, &msg.textwidth, stringbuffer_top[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, 0); +#else + textMeasure(&msg.textheight, &msg.textwidth, dword_CODE_bss_80079DC8[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, 0); +#endif + if (cameraBufferToggle != 0) + { + msg.x = viGetViewLeft() + 0x46; + msg.y = viGetViewTop() + 0x10; + msg.y += 0x10; + msg.y = msg.y / 11; + msg.y *= 11; + msg.y -= 2; + } + else + { + msg.x = viGetViewLeft() + 0x1e; +#ifdef VERSION_EU + msg.y = viGetViewTop() + 0x10; +#else + msg.y = viGetViewTop() + 0xd; +#endif + } + + msg.bottom = msg.y + msg.textheight; + gdl = microcode_constructor_related_to_menus(gdl, 0, msg.y - 2, viGetX(), msg.bottom, 0x64); +#ifdef VERSION_US + sw.screenwidth = viGetX(); + gdl = textRender(gdl, &msg.x, &msg.y, stringbuffer_top[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, -1, sw.screenwidth, viGetY(), 0, 0); +#else + if (j_text_trigger != 0) + { + sw.screenwidth = viGetX(); +#if defined(LEFTOVERDEBUG) + gdl = textRenderOutlined(gdl, &msg.x, &msg.y, stringbuffer_top[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, -1, 0x646464FF, sw.screenwidth, viGetY(), 0, 0); +#else + gdl = textRenderOutlined(gdl, &msg.x, &msg.y, dword_CODE_bss_80079DC8[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, -1, 0x646464FF, sw.screenwidth, viGetY(), 0, 0); +#endif + } + else + { + sw.screenwidth = viGetX(); +#if defined(LEFTOVERDEBUG) + gdl = textRender(gdl, &msg.x, &msg.y, stringbuffer_top[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, -1, sw.screenwidth, viGetY(), 0, 0); +#else + gdl = textRender(gdl, &msg.x, &msg.y, dword_CODE_bss_80079DC8[upper_text_buffer_index], ptrFontZurichBoldChars, ptrFontZurichBold, -1, sw.screenwidth, viGetY(), 0, 0); +#endif + } +#endif + gdl = combiner_bayer_lod_perspective(gdl); + goto end; + } + } + } + } + + if (get_debug_testingmanpos_flag()) + { + theta_x = g_CurrentPlayer->field_488.theta_transform.x; + debug_angle = (s32) ((atan2f(-theta_x, g_CurrentPlayer->field_488.theta_transform.z) * 180.0f) / M_PI_F); + directions = g_DebugCompassLabels; + roomid = bgDebPrintROOMID(g_CurrentPlayer->field_488.current_tile_ptr->room); + + sprintf(debugtext.room, a8s, roomid); + sprintf(debugtext.x, aX4_0f, g_CurrentPlayer->field_488.collision_position.x); + sprintf(debugtext.y, aY4_0f, g_CurrentPlayer->field_488.collision_position.y); + sprintf(debugtext.z, aZ4_0f, g_CurrentPlayer->field_488.collision_position.z); + sprintf(debugtext.angle, aS3d, ((char *) (&directions)) + (((debug_angle + 0x16) / 0x2d) * 3), debug_angle); + + debug_x = viGetViewLeft() + 0x11; + debug_y = viGetViewTop() + 0x11; + debug_boxbottom = debug_y + 0xa; + gdl = microcode_constructor(gdl); + gdl = microcode_constructor_related_to_menus(gdl, 0, debug_y, viGetX(), debug_boxbottom + 1, 0x64); + sw.screenwidth = viGetX(); + gdl = textRender(gdl, &debug_x, &debug_y, debugtext.room, ptrFontBankGothicChars, ptrFontBankGothic, -1, sw.screenwidth, viGetY(), 0, 0); + debug_x = viGetViewLeft() + 0x57; + sw.screenwidth = viGetX(); + gdl = textRender(gdl, &debug_x, &debug_y, debugtext.x, ptrFontBankGothicChars, ptrFontBankGothic, -1, sw.screenwidth, viGetY(), 0, 0); + debug_x = viGetViewLeft() + 0x8d; + sw.screenwidth = viGetX(); + gdl = textRender(gdl, &debug_x, &debug_y, debugtext.y, ptrFontBankGothicChars, ptrFontBankGothic, -1, sw.screenwidth, viGetY(), 0, 0); + debug_x = viGetViewLeft() + 0xc3; + sw.screenwidth = viGetX(); + gdl = textRender(gdl, &debug_x, &debug_y, debugtext.z, ptrFontBankGothicChars, ptrFontBankGothic, -1, sw.screenwidth, viGetY(), 0, 0); + debug_x = viGetViewLeft() + 0xf9; + sw.screenwidth = viGetX(); + gdl = textRender(gdl, &debug_x, &debug_y, debugtext.angle, ptrFontBankGothicChars, ptrFontBankGothic, -1, sw.screenwidth, viGetY(), 0, 0); + gdl = combiner_bayer_lod_perspective(gdl); + } + + end: + return gdl; +} + + +/** + * Address: 0x7F08B0F0 + */ +s32 playerTick(PropRecord *prop) +{ + s32 index; + ChrRecord *chr; + s32 group; + s32 ret; + s32 sub; + PropRecord *leftprop; + f32 mtx[15]; + s32 tailret; + s32 anim; + f32 angle; + f32 frame; + f32 local90; + f32 local8c; + f32 local88; + f32 fwd; + f32 startframe; + struct weapon_firing_animation_table *firingtable; + coord3d off; + s32 i; + s32 found; + s32 cur; + PropRecord *rightprop; + struct WeaponObjRecord *leftobj; + struct WeaponObjRecord *rightobj; + s32 setanim; + struct player **ppointers; + + index = getPlayerPointerIndex(prop); + chr = prop->chr; + + if (chr != NULL) + { + if (get_player_position_in_shuffled(get_cur_playernum()) == 0) + { + chr->hidden &= ~CHRHIDDEN_FREEZE; + } + } + + if (chr != NULL) + { + if ((g_playerPointers[index]->bodyModel != NULL) && (!(get_debug_render_raster() && (g_playerPointers[index]->cameramode != 1)))) + { + g_playerPointers[index]->field_AC = 0; + ret = chrTick(prop); + g_playerPointers[index]->field_AC = 1; + + g_playerPointers[index]->field_488.collision_position.x = g_playerPointers[index]->prop->pos.x; + g_playerPointers[index]->field_488.collision_position.y = g_playerPointers[index]->prop->pos.y; + g_playerPointers[index]->field_488.collision_position.z = g_playerPointers[index]->prop->pos.z; + g_playerPointers[index]->field_488.current_tile_ptr = g_playerPointers[index]->prop->stan; + bondviewUpdatePlayerRoom(g_playerPointers[index]); + + if (prop->flags & PROPFLAG_ONSCREEN) + { + RenderPosView *rp = g_playerPointers[index]->bodyModel->render_pos; + matrix_4x4_multiply_homogeneous(currentPlayerGetViewToWorldMtxf(), (Mtxf *) rp, (Mtxf *) mtx); + g_playerPointers[index]->field_488.pos.x = mtx[12] + (mtx[4] * 7.0f); + g_playerPointers[index]->field_488.pos.y = mtx[13] + (mtx[5] * 7.0f); + g_playerPointers[index]->field_488.pos.z = mtx[14] + (mtx[6] * 7.0f); + } + + return ret; + } + } + + if (chr == NULL) + { + goto clear_and_return; + } + + if (g_playerPointers[index]->bodyModel == NULL) + { + goto clear_and_return; + } + + if (getPlayerCount() < 2) + { + goto clear_and_return; + } + + if (get_cur_playernum() == index) + { + goto clear_and_return; + } + + anim = 0; + firingtable = NULL; + local90 = -1.0f; + frame = -1; + leftprop = chrGetEquippedWeaponProp(chr, GUNLEFT); + rightprop = chrGetEquippedWeaponProp(chr, GUNRIGHT); + leftobj = NULL; + rightobj = NULL; + setanim = 0; + + if (leftprop != NULL) + { + leftobj = leftprop->weapon; + } + + if (rightprop != NULL) + { + rightobj = rightprop->weapon; + } + + ppointers = g_playerPointers; + + if (get_player_position_in_shuffled(get_cur_playernum()) == 0) + { + g_PlayerTickCount = g_PlayerTickCount + 1; + } + + /** + * If the player count is 1 we jump to the bottom of the function with goto clear_and_return, so this block only applies to MP. + * g_PlayerTickCount advances once for each remote player's prop ticked during the pass of the viewport whose player is first in the shuffle order. + * That means g_PlayerTickCount reaches 2 after one frame of a 2 player game, and part way through the first frame of a 3 or 4 player game. + * Nothing *ever* resets g_PlayerTickCount, so we're skipping this whole block only once per boot. The reason for doing this though + * isn't quite clear so do chime in if you have any theories. + */ + if (g_PlayerTickCount >= 2) + { + local8c = ((0, ppointers[index]))->field_2A08; + local88 = ppointers[index]->field_2A0C; + + if (ppointers[index]->bonddead != FALSE) + { + found = 0; + + for (i = 0; i < g_bondviewBondDeathAnimationsCount; i++) + { + cur = ppointers[index]->players_cur_animation; + + if (cur == (g_bondviewBondDeathAnimations[i] + ((s32) ptr_animation_table))) + { + found = 1; + } + } + + if (found) + { + anim = ppointers[index]->players_cur_animation; + angle = 0.5f; + } + else + { + anim = g_bondviewBondDeathAnimations[randomGetNext() % g_bondviewBondDeathAnimationsCount] + ((s32) ptr_animation_table); + angle = 0.5f; + } + + cur = ppointers[index]->players_cur_animation; + local8c = 0.0f; + local88 = 0.0f; + goto join_768; + } + + if ((leftprop != NULL) && (rightprop != NULL)) + { + group = 3; + } + else if ((leftprop == NULL) && (rightprop == NULL)) + { + group = 2; + } + else if ((leftobj != NULL) && (bondwalkItemCheckBitflags(leftobj->weaponnum, WEAPONSTATBITFLAG_HOLD_AS_GUN) == 0)) + { + group = 2; + } + else if ((rightobj != NULL) && (bondwalkItemCheckBitflags(rightobj->weaponnum, WEAPONSTATBITFLAG_HOLD_AS_GUN) == 0)) + { + group = 2; + } + else if ((leftobj != NULL) && (bondwalkItemCheckBitflags(leftobj->weaponnum, WEAPONSTATBITFLAG_ONLY_1_HANDED) != 0)) + { + group = 0; + } + else if ((rightobj != NULL) && (bondwalkItemCheckBitflags(rightobj->weaponnum, WEAPONSTATBITFLAG_ONLY_1_HANDED) != 0)) + { + group = 0; + } + else + { + group = 1; + } + + if (playerGetCrouchPos(index) == 1) + { + goto set_crouch_lean; + } + else if (playerGetCrouchPos(index) == 0) + { +set_crouch_lean: + angle = 1.0f; + sub = 5; + } + else if ((ppointers[index]->speedsideways < 0.0f) && (firing_animation_groups[group][4].pointer != NULL)) + { + sub = 4; + angle = -ppointers[index]->speedsideways; + + if (ppointers[index]->field_1280 < 90.0f) + { + ppointers[index]->field_1280 = ppointers[index]->field_1280 + 15.0f; + } + } + else if ((ppointers[index]->speedsideways > 0.0f) && (firing_animation_groups[group][3].pointer != NULL)) + { + sub = 3; + angle = ppointers[index]->speedsideways; + + if (ppointers[index]->field_1280 > (-90.0f)) + { + ppointers[index]->field_1280 = ppointers[index]->field_1280 - 15.0f; + } + } + else + { + frame = ppointers[index]->speedtheta; + + if (frame < 0.0f) + { + frame = -frame; + } + + fwd = ppointers[index]->speedforwards; + + if (fwd < -0.050000001f) + { + frame = -frame; + + if (fwd < frame) + { + frame = fwd; + } + + if (ppointers[index]->headanim == 0) + { + goto shared_double_neg; + } + + sub = 2; + + if (-0.40000001f < fwd) + { +shared_double_neg: + angle = frame + frame; + sub = 1; + + if (angle < (-1.0f)) + { + angle = -1.0f; + } + } + else + { + angle = frame; + goto lean_return_to_centre; + } + } + else + { + if (0.050000001f < fwd) + { + goto shared_framefwd; + } + else if (0.050000001f < frame) + { +shared_framefwd: + if (frame < fwd) + { + frame = fwd; + } + } + else + { + goto set_full_lean; + } + + if (ppointers[index]->headanim == 0) + { + goto shared_double_pos; + } + + sub = 2; + + if (fwd < 0.40000001f) + { +shared_double_pos: + angle = frame + frame; + sub = 1; + + if (1.0f < angle) + { + angle = 1.0f; + } + } + else + { + angle = frame; + goto lean_return_to_centre; + } + } + + goto lean_return_to_centre; + +set_full_lean: + angle = 1.0f; + sub = 0; + +lean_return_to_centre: + if (0.0f < ppointers[index]->field_1280) + { + ppointers[index]->field_1280 = ppointers[index]->field_1280 - 15.0f; + } + + if (ppointers[index]->field_1280 < 0.0f) + { + ppointers[index]->field_1280 = ppointers[index]->field_1280 + 15.0f; + } + } + + { + struct firing_anim_struct *fa = &firing_animation_groups[group][sub]; + + firingtable = fa->pointer; + + if (fa->anim != 0) + { + anim = fa->anim + (s32) ptr_animation_table; + } + + angle *= fa->x; + local90 = fa->z; + frame = fa->y; + } + + cur = ppointers[index]->players_cur_animation; + +join_768: + if ((firingtable != NULL) && (anim == 0)) + { + anim = *((s32 *) firingtable); + } + + if (anim != cur) + { + setanim = 1; + } + + if (0.0f <= frame) + { + if ((ppointers[index]->bodyModel->animlooping == 0) || (frame != ppointers[index]->bodyModel->animloopframe)) + { + setanim = 1; + } + } + + if (frame < 0.0f) + { + if (ppointers[index]->bodyModel->animlooping) + { + setanim = 1; + } + } + + if (setanim != 0) + { + if (ppointers[index]->bodyModel->anim2 == NULL) + { + startframe = (0.0f <= frame) ? (frame) : (0.0f); + modelSetAnimation(ppointers[index]->bodyModel, (ModelAnimation *) anim, 0, startframe, angle, 16.0f); + ppointers[index]->players_cur_animation = anim; + ppointers[index]->field_1288 = angle; + + if (0.0f <= frame) + { + modelSetAnimLooping(ppointers[index]->bodyModel, frame, 16.0f); + } + + if (0.0f <= local90) + { + modelSetAnimEndFrame(ppointers[index]->bodyModel, local90); + } + } + + cur = ppointers[index]->players_cur_animation; + } + else + { + if (angle != ppointers[index]->field_1288) + { + modelSetAnimSpeed(ppointers[index]->bodyModel, angle, 1.0f); + ppointers[index]->field_1288 = angle; + } + + cur = ppointers[index]->players_cur_animation; + } + + if (anim == cur) + { + if (firingtable != NULL) + { + chr->hidden &= ~CHRHIDDEN_0400; + chrlvUpdateAimendbackShoulders(chr, firingtable, 0, 1, local8c); + } + else + { + chr->aimendrshoulder = 0.0f; + chr->aimendlshoulder = 0.0f; + chr->hidden |= CHRHIDDEN_0400; + chr->aimendback = local8c; + } + } + + chr->aimendsideback = local88; + chr->aimendcount = 10; + } + + prop->pos.x = ppointers[index]->field_488.collision_position.x; + prop->pos.y = ppointers[index]->field_488.collision_position.y; + prop->pos.z = ppointers[index]->field_488.collision_position.z; + prop->stan = ppointers[index]->field_488.current_tile_ptr; + + getsuboffset(chr->model, &off); + off.x = prop->pos.x; + off.z = prop->pos.z; + setsuboffset(chr->model, &off); + setsubroty(chr->model, (((360.0f - ppointers[index]->vv_theta) + ppointers[index]->field_1280) * M_TAU_F) / 360.0f); + + chr->chrflags |= CHRFLAG_INIT; + chr->actiontype = ACT_BONDMULTI; + chr->act_bondmulti.unk2c = (f32 *) firingtable; + + chrSetFiring(chr, GUNRIGHT, ppointers[index]->hands[GUNRIGHT].field_87D); + chrSetFiring(chr, GUNLEFT, ppointers[index]->hands[GUNLEFT].field_87D); + + tailret = chrTick(prop); + + for (i = 0; i != 2; i++) + { + if (sub_GAME_7F02D630(chr, i, &ppointers[index]->field_2A18[i]) != 0) + { + (&ppointers[index]->field_2A30)[i] = D_80048380; + } + else if ((&ppointers[index]->field_2A30)[i] < (D_80048380 - 1)) + { + ppointers[index]->field_2A18[i].x = ppointers[index]->hands[i].field_B58.x; + ppointers[index]->field_2A18[i].y = ppointers[index]->hands[i].field_B58.y; + ppointers[index]->field_2A18[i].z = ppointers[index]->hands[i].field_B58.z; + } + } + + chr->hidden |= CHRHIDDEN_FREEZE; + + prop->pos.x = ppointers[index]->field_488.collision_position.x; + prop->pos.y = ppointers[index]->field_488.collision_position.y; + prop->pos.z = ppointers[index]->field_488.collision_position.z; + prop->stan = ppointers[index]->field_488.current_tile_ptr; + + return tailret; + +clear_and_return: + prop->flags &= ~PROPFLAG_ONSCREEN; + + return TICKOP_NONE; +} + + +/** + * Address 0x7F08BCB8. + */ +Gfx * bondviewRemoved7F08BCB8(Gfx *arg0) +{ + #ifdef DEBUG + // removed + #endif + + return arg0; +} + + +/** + * Address 0x7F08BCC0. + */ +Gfx *bondviewRenderProp(PropRecord *arg0, Gfx *arg1, s32 arg2) +{ + if (arg0->chr != NULL) + { + arg1 = chrRenderProp(arg0, arg1, arg2); + } + + return arg1; +} + + + + + +/** + * Address 0x7F08BCF4. + */ +Gfx* bondviewGfxPlayerField5cMatrix(Gfx* gdl) +{ + gSPMatrix(gdl++, g_CurrentPlayer->field_5C, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + return gdl; +} + + + + + +/** + * Unreferenced. + * + * Address 0x7F08BD18. + */ +void bondviewTransformPosToViewMatrix(RenderPosView *arg0) +{ + Mtxf sp18; + + matrix_4x4_copy(&arg0->pos, (Mtxf *) &sp18); + matrix_4x4_f32_to_s32((Mtxf *) &sp18, &arg0->view); +} + + + +/** + * Address 0x7F08BD48. + * + * Notes: Similar to sub_GAME_7F08BE2C. + * + */ +void bondviewTransformManyPosToViewMatrix(RenderPosView * arg0, s32 arg1) +{ + Mtxf mtx; + RenderPosView* rpv_entry; + s32 i; + + i = 0; + if (arg1 <= 0) { return; } + + // Couldn't find a better matching loop + rpv_entry = arg0; + do + { + matrix_4x4_copy(&rpv_entry->pos, &mtx); + matrix_4x4_f32_to_s32(&mtx, &arg0[i].pos); + i++; + rpv_entry++; + } while (i != arg1); +} + + + +/** + * Unreferenced. + * + * Address 0x7F08BDC4. + */ +void sub_GAME_7F08BDC4(Mtxf *arg0) +{ + Mtxf sp20; + + matrix_4x4_copy(arg0, (Mtxf *) &sp20); + sp20.m[3][0] -= g_CurrentPlayer->previous_model_pos.f[0]; + sp20.m[3][1] -= g_CurrentPlayer->previous_model_pos.f[1]; + sp20.m[3][2] -= g_CurrentPlayer->previous_model_pos.f[2]; + matrix_4x4_f32_to_s32((Mtxf *) &sp20, arg0); +} + + +/** + * Unreferenced. + * + * Address 0x7F08BE2C. + */ +void sub_GAME_7F08BE2C(Mtxf *matrices, s32 count) +{ + Mtxf copy; + s32 i; + + for (i = 0; i < count; i++) + { + matrix_4x4_copy((Mtxf *)((uintptr_t)matrices + i * sizeof(Mtxf)), ©); + + copy.m[3][0] -= g_CurrentPlayer->previous_model_pos.x; + copy.m[3][1] -= g_CurrentPlayer->previous_model_pos.y; + copy.m[3][2] -= g_CurrentPlayer->previous_model_pos.z; + + matrix_4x4_f32_to_s32(©, matrices + i); + } +} + + +void sub_GAME_7F08BEEC(Mtxf *matrices, s32 count) +{ + Mtxf sp40; + s32 i; + s32 j; + + for (i = 0, j = 0; i < count; i++, j += sizeof(Mtxf)) + { + matrix_4x4_multiply_homogeneous(currentPlayerGetViewToWorldMtxf(), (Mtxf *)((u32)matrices + j), &sp40); + + sp40.m[3][0] -= g_CurrentPlayer->current_model_pos.f[0]; + sp40.m[3][1] -= g_CurrentPlayer->current_model_pos.f[1]; + sp40.m[3][2] -= g_CurrentPlayer->current_model_pos.f[2]; + + matrix_4x4_f32_to_s32(&sp40, matrices + i); + } +} + + +s32 getMissiontimer(void) { +#ifdef VERSION_EU + return (mission_timer * 60) / 50; +#else + return mission_timer; +#endif +} + + +void SurroundWithExplosions(int delay) +{ + g_SurroundBondWithExplosionsFlag = 1; + g_SurroundBondWithExplosionsTicks = delay + g_GlobalTimer; + g_PlayerTickExplodeCreatePosition = 0; +} diff --git a/src/game/bondview_internal.h b/src/game/bondview_internal.h new file mode 100644 index 00000000..e83a09c8 --- /dev/null +++ b/src/game/bondview_internal.h @@ -0,0 +1,217 @@ +#ifndef _BONDVIEW_INTERNAL_H_ +#define _BONDVIEW_INTERNAL_H_ + +extern coord3d g_CamFrustumTopNormal; +extern f32 g_CamFrustumTopOffset; +extern coord3d g_CamFrustumBottomNormal; +extern f32 g_CamFrustumBottomOffset; +extern coord3d g_CamFrustumLeftNormal; +extern f32 g_CamFrustumLeftOffset; +extern coord3d g_CamFrustumRightNormal; +extern f32 g_CamFrustumRightOffset; +extern f32 g_CamFrustumNearOffset; +extern vec3d g_ForceBondMoveOffset; +extern s32 g_SurroundBondWithExplosionsTicks; +extern s32 g_PlayerTickExplodeCreatePosition; +extern struct coord3d g_TankModelPositionOffset; +extern s32 g_TankEngineSfxVolume; +extern s32 g_EnterTankAudioState; +extern f32 g_TankEnteringSitHeight; +extern f32 g_TankEnteringSitHeightRemain; +extern f32 g_TankEnterBondHorizAngleDeg; +extern f32 g_TankEnterBondVertAngleDeg; +extern struct coord3d g_EnterTankCoord; +extern ITEM_IDS starting_weapon[2]; +extern struct coord3d flt_CODE_bss_800799E8; +extern struct PropRecord *dword_CODE_bss_800799F4; +extern PadRecord *g_CameraLookAtBondPad; +extern CutsceneRecord *gBondViewCutscene; +extern f32 flt_CODE_bss_80079A00; +extern f32 flt_CODE_bss_80079A04; +extern f32 flt_CODE_bss_80079A08; +extern f32 flt_CODE_bss_80079A0C; +extern f32 flt_CODE_bss_80079A10; +extern s32 dword_CODE_bss_80079A14; +extern enum CAMERAMODE dword_CODE_bss_80079A18; +extern s32 dword_CODE_bss_80079A1C; +extern s32 mission_timer; +#if defined(VERSION_JP) || defined(VERSION_EU) +extern f32 watch_time_0; +#else +extern s32 watch_time_0; +#endif +extern char stringbuffer_lowerleft[5][BONDVIEW_HUD_MSG_BOTTOM_BUFFER_LENGTH]; +#if defined(BUGFIX_R1) +extern s32 dword_CODE_bss_jp80079Cd8[5]; +extern s32 dword_CODE_bss_jp80079CEC[5]; +#endif +extern PadRecord *g_Startpad[16]; +extern s32 startpadcount; +extern s32 dword_CODE_bss_80079C6C; +#if defined(LEFTOVERDEBUG) +extern char stringbuffer_top[2][BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH]; +#endif +extern StandTilePoint *dword_CODE_bss_80079DA0; +extern StandTilePoint *dword_CODE_bss_80079DA4; +extern s32 dword_CODE_bss_80079DA8[BSS_80079DA8_LENGTH]; +#ifndef VERSION_EU +extern char dword_CODE_bss_80079DC8[0x3c]; +#else +extern char dword_CODE_bss_80079DC8[2][BONDVIEW_HUD_MSG_TOP_BUFFER_LENGTH]; +extern char dword_CODE_bss_80079EF6[0x3c]; +#endif +extern f32 g_MpSwirlRotateSpeed; +extern f32 g_MpSwirlAngleDegrees; +extern f32 g_MpSwirlForwardSpeed; +extern f32 g_MpSwirlDistance; +extern s32 D_80036420; +extern s32 g_bondviewForceDisarm; +extern s32 resolution; +extern s32 cameraBufferToggle; +extern s32 cameraFrameCounter1; +extern s32 cameraFrameCounter2; +extern s32 camera_80036438; +extern s32 credits_state; +extern CreditsEntry *credits_pointer; +extern s32 g_SurroundBondWithExplosionsFlag; +extern s32 g_PlayerIsInTank; +extern struct PropRecord *g_WorldTankProp; +extern struct PropRecord *g_PlayerTankProp; +extern f32 g_PlayerTankYOffset; +extern ALSoundState *g_TankSfxState[2]; +extern f32 g_TankTurnSpeed; +extern f32 g_TankOrientationAngle; +extern f32 tank_turret_unused_angle; +extern f32 g_TankTurretVerticalAngle; +extern f32 g_TankTurretVerticalAngleRelated; +extern f32 g_TankTurretOrientationAngleRad; +extern f32 g_TankTurretOrientationAngleDeg; +extern f32 tank_turret_turn_speed; +extern s32 g_BondCanEnterTank; +extern f32 g_TankTurretAngle; +extern f32 g_TankTurretTurn; +extern s32 g_ExplodeTankOnDeathFlag; +extern s32 g_TankDamagePenaltyTicks; +extern enum CAMERAMODE g_CameraMode; +extern enum CAMERAMODE g_CameraAfterCinema; +extern s32 camera_fade_active; +extern s32 stop_time_flag; +extern f32 camera_transition_timer; +extern s32 intro_camera_index; +extern struct SetupIntroSwirl *g_IntroSwirl; +extern s32 is_timer_active; +extern bool g_PlayerInvincible; +extern struct SetupIntroCamera *g_CurrentSetupIntroCamera; +extern s32 g_SetupIntroCameraCount; +extern struct SetupIntroCamera *ptr_random06cam_entry; +extern s32 g_VisibleToGuardsFlag; +extern s32 obj_collision_flag; +extern f32 D_800364CC; +extern f32 D_800364D0; +extern f32 D_800364D4; +extern s32 g_bondviewBondDeathAnimations[]; +extern s32 g_bondviewBondDeathAnimationsCount; +extern enum CAMERAMODE camera_mode; +extern s32 g_IntroAnimationIndex; +extern struct struct_4 stage_intro_anim_table[]; +extern f32 watch_transition_time; +extern WeaponObjRecord dummy_08_pp7_obj[]; +extern struct DamageType g_DamageTypes[]; +extern struct HealthDisplayDuration g_HealthDisplayDurations[8]; +extern struct coord3d g_DefaultMoveBondOffset; +extern struct coord3d g_DefaultFrozenPlayerPos; +extern struct coord3d g_DefaultFrozenPlayerPos2; +extern struct coord3d g_DefaultFrozenPlayerOffset; +extern struct coord3d g_DefaultFrozenMoveOffset; +extern struct coord3d ZeroCoordShake; +extern ModelRenderData D_8003683C; +extern coord3d ZeroCoordWatchPos; +extern coord3d ZeroCoordSpawnPos; +extern s32 status_bar_text_buffer_index; +extern s32 display_statusbar; +#ifdef BUGFIX_R0 +extern s32 copy_1stfonttable; +extern s32 copy_2ndfonttable; +#endif +extern s32 upper_text_buffer_index; +extern s32 display_upper_text_window; +extern s32 upper_text_window_timer; +extern s32 g_UpperTextDisplayFlag; +extern DirectionLabels g_DebugCompassLabels; +extern s32 g_PlayerTickCount; +extern struct firing_anim_struct firing_animation_groups[][6]; +extern s32 D_80036AB8; +extern s32 D_80036ABC; +extern f32 D_80036AC0; +extern f32 D_80036AC4; +void bondviewUpdatePlayerRoom(struct player *player); +s32 chrTick(PropRecord *prop); +void bondviewDeregisterPlayerRoom(struct player *player); +void bondviewUpdateWatchZoomIn(void); +void bondviewSetPauseWatchRelated(f32 arg0); +void bondviewSetPauseWatchRelatedAlt(f32 arg0); +void bondviewStepWatchAnimation(void); +f32 bondviewGetPauseAnimationPercent(void); +void bondviewCurrentPlayerUpdateSpeedVerta(f32 value); +void bondviewCurrentPlayerUpdateSpeedTheta(f32 value); +s16 bondviewGetCurrentPlayerViewportWidth(void); +s16 bondviewGetCurrentPlayerViewportHeight(void); +s16 bondviewGetCurrentPlayerViewportUly(void); +void currentPlayerTickChrFade(void); +void currentPlayerUpdateColourScreenProperties(void); +s16 getWidth320or440(void); +s16 getHeight330or240(void); +void bondviewAdvanceCameraMode(void); +bool currentPlayerIsFadeComplete(void); +s16 get_curplayer_viewport_ulx(void); +void bondviewFrozenMoveBond(s8, s8, u16, u16); +void bondviewMovePlayerUpdateViewport(s8 arg0, s8 arg1, u16 arg2); +void bondviewUpdateCurrentRoomPosition(s32 arg0); +void trigger_solo_watch_menu(s32 arg0); +void bondviewUpdatePlayerCollisionBounds(void); +void bondviewGetTankCollisionBounds(struct rect4f *, coord3d *, f32); +void bondviewIntroCameraTextTick(void); +void bondviewUpperTextWindowTimerTick(void); +void MoveBond(s8 arg0, s8 arg1, u16 arg2, u16 arg3); +void bondviewProcessInput(s8 arg0, s8 arg1, u16 arg2, u16 arg3); +void bondviewPlayerTickDamageAndHealth(void); +void bondviewPlayerTickExplode(void); +void bondviewPlayerStopAudioForPause(void); +void bondviewWatchAnimationTick(void); +void bondviewUpdatePlayerCollisionPositionFields(void); +void bondviewTankModelRotationRelated(void); +s32 bondviewTankCollisionStatus(struct coord3d *collision_position, StandTile *arg1, f32 tank_orientation_angle, struct coord3d *arg3, struct coord3d *arg4); +s32 bondviewCallTankCollisionStatus(struct coord3d *arg0, struct StandTile *arg1, f32 arg2); +s32 sub_GAME_7F07CDD4(struct coord3d *arg0, f32 arg1, struct StandTile **arg2); +s32 bondviewTryMoveToStan(struct coord3d *arg0, struct StandTile **stan); +s32 bondviewTestLineUnobstructed(StandTile **pTile, f32 p_x, f32 p_z, f32 dest_x, f32 dest_z, s32 cdtypes, struct coord3d *coord_p, struct coord3d *coord_dest); + +s32 bondviewTryFractionMovePlayerCollision(struct coord3d *next_pos, struct coord3d *collision1_pt0, struct coord3d *collision1_pt1, struct coord3d *collision2_pt0, struct coord3d *collision2_pt1); +s32 bondviewTryEdgeMovePlayerCollision(struct coord3d *prior_next_pos, struct coord3d *collision_pt0, struct coord3d *collision_pt1); +s32 bondviewTryEndHopPlayerCollision(struct coord3d *prior_next_pos, struct coord3d *collision_pt0, struct coord3d *collision_pt1); +void bondviewApplyVertaTheta(void); + +f32 bheadGetBreathingValue(void); +void bondviewMoveAnimationTick(f32 speed, f32 speedforwards, f32 speedsideways); +void bondviewCalcUpdatePlayerCollision(struct coord3d *offset, s32 allow_scoot); +f32 bondviewSetupPauseTransition(bool topause); +void bondviewStartPauseTransition(f32 duration); +void bondviewStartUnpauseTransition(f32 duration); +bool bondViewIsPauseTransitioning(void); +f32 sub_GAME_7F080228(f32 arg0); +void currentPlayerSetSwayTarget(s32 value); +void currentPlayerAdjustCrouchPos(s32 value); +void bondviewUpdateSpeedSideways(s32 arg0); +void bondviewUpdateSpeedForwards(s32 arg0); +void bondviewFrozenCameraTick(u16 buttons, u16 oldbuttons, struct coord3d *pos, struct coord3d *pos2, struct coord3d *offset, struct StandTile **stan, struct coord3d *arg6); +void bondviewCalcIntroSwirlCamera(s32, f32, struct coord3d *, struct coord3d *); +s32 pickDeathCameraAngles(PropRecord *prop1, coord3d *pos, PropRecord *prop2, coord3d *collision_pos, StandTile *tile, f32 camera_dist); +Gfx* hudmsgBottomRender(Gfx* arg0); +Gfx *sub_GAME_7F08AAE8(Gfx *gdl); +Gfx *bondviewRenderCredits(Gfx *gdl); +Gfx *bondviewRenderWatch(Gfx *gdl); +Gfx *bondviewRenderGaugeBars(Gfx *gdl); + +// end forward declarations + +#endif diff --git a/src/game/chraction.c b/src/game/chraction.c index 9da891b2..efe9d514 100644 --- a/src/game/chraction.c +++ b/src/game/chraction.c @@ -44,10 +44,10 @@ f32 chrlvGetGuard007ArghRating (ChrRecord *self, f32 min, f32 max void chrlvKneelingAnimationRelated (ChrRecord *self); void chrlvIdleAnimationRelated7F023E14 (ChrRecord *self, f32 arg1); void chrlvKneelingAnimationRelated7F023E48 (ChrRecord *self); -void chrKneelChooseAnimation (ChrRecord *self); +void chrKneelChooseAnimation (ChrRecord *self); void chrlvPerformAnimationForActor (ChrRecord *self, s32 arg1, s32 arg2, s32 arg3, u8 arg4, s32 arg5); -void chrStartAlarmChooseAnimation (ChrRecord *self); -void chrlvThrowGrenadeAnimationRelated (ChrRecord *self, PropRecord *arg1, s32 arg2, s32 arg3); +void chrStartAlarmChooseAnimation (ChrRecord *self); +void chrlvThrowGrenade (ChrRecord *self, PropRecord *prop, GUNHAND hand, s32 startframe); void chrlvSpotBondAnimationRelated (ChrRecord *self, f32 arg1); void chrlvActorShuffleFeet (ChrRecord *self); void chrlvSurrenderAnimationRelated (ChrRecord *self); @@ -372,7 +372,10 @@ void chrlvIdleAnimationRelated(ChrRecord *self, f32 duration) #define RATE 1.0f #endif -void chrlvIdleAnimationRelated7F023A94(ChrRecord *self, f32 mergetime) +/** + * At the end of a character's kneeling animation smoothly merge into their standing animation. + */ +void chrlvMergeKneelToStand(ChrRecord *self, f32 mergetime) { f32 fsleep; @@ -497,7 +500,7 @@ void chrlvKneelingAnimationRelated(ChrRecord *self) return; } - chrlvIdleAnimationRelated7F023A94(self, 16.0f); + chrlvMergeKneelToStand(self, 16.0f); } @@ -508,7 +511,7 @@ void chrlvKneelingAnimationRelated(ChrRecord *self) */ void chrlvIdleAnimationRelated7F023E14(ChrRecord *self, f32 arg1) { - chrlvIdleAnimationRelated7F023A94(self, arg1); + chrlvMergeKneelToStand(self, arg1); self->act_stand.checkfacingwall = 1; } @@ -645,22 +648,26 @@ void chrStartAlarmChooseAnimation(ChrRecord *self) /** * Address 0x7F024238. + * + * Play the grenade throw animation. Takes a PropRecord* as an argument but + * does not use it. + * * PD: chrThrowGrenade */ -void chrlvThrowGrenadeAnimationRelated(ChrRecord *self, PropRecord *arg1, s32 arg2, s32 arg3) +void chrlvThrowGrenade(ChrRecord *self, PropRecord *prop, GUNHAND hand, s32 startframe) { chrStopFiring(self); self->actiontype = ACT_THROWGRENADE; self->sleep = 0; - if (arg3 != 0) + if (startframe != 0) { - modelSetAnimation(self->model, (void*)&ptr_animation_table->data[(s32)&ANIM_DATA_fire_throw_grenade], arg2 != 0, 0.0f, chrlvGetGuard007SpeedRating(self, 0.5f, 0.8f), 16.0f); + modelSetAnimation(self->model, (void*)&ptr_animation_table->data[(s32)&ANIM_DATA_fire_throw_grenade], hand != 0, 0.0f, chrlvGetGuard007SpeedRating(self, 0.5f, 0.8f), 16.0f); } else { - modelSetAnimation(self->model, (void*)&ptr_animation_table->data[(s32)&ANIM_DATA_fire_throw_grenade], arg2 != 0, 84.0f, chrlvGetGuard007SpeedRating(self, 0.5f, 0.8f), 16.0f); + modelSetAnimation(self->model, (void*)&ptr_animation_table->data[(s32)&ANIM_DATA_fire_throw_grenade], hand != 0, 84.0f, chrlvGetGuard007SpeedRating(self, 0.5f, 0.8f), 16.0f); } modelSetAnimEndFrame(self->model, 193.0f); @@ -9327,7 +9334,7 @@ void chrlvActionTick(ChrRecord *self) if (self->actiontype == ACT_INIT) { self->chrflags |= CHRFLAG_INIT; - chrlvIdleAnimationRelated7F023A94(self, 0.0f); + chrlvMergeKneelToStand(self, 0.0f); self->sleep = 0; } @@ -10855,14 +10862,14 @@ bool actor_draws_throws_grenade_at_player_if_possible(ChrRecord *self) if (Right && (RightWep = Right->weapon, RightWep->weaponnum == ITEM_GRENADE)) { - chrlvThrowGrenadeAnimationRelated(self, Right, GUNRIGHT, 0); + chrlvThrowGrenade(self, Right, GUNRIGHT, 0); return TRUE; } if (Left && (LeftWep = Left->weapon, LeftWep->weaponnum == ITEM_GRENADE)) { - chrlvThrowGrenadeAnimationRelated(self, Left, GUNLEFT, 0); + chrlvThrowGrenade(self, Left, GUNLEFT, 0); return TRUE; } @@ -10883,7 +10890,7 @@ bool actor_draws_throws_grenade_at_player_if_possible(ChrRecord *self) NewGrenadeObj = NewGrenadeProp->weapon; NewGrenadeObj->runtime_bitflags |= 0x800; //manual bitflags are more effecient - chrlvThrowGrenadeAnimationRelated(self, NewGrenadeProp, !Right ? GUNRIGHT : GUNLEFT, 1); //this matches + chrlvThrowGrenade(self, NewGrenadeProp, !Right ? GUNRIGHT : GUNLEFT, 1); return TRUE; } diff --git a/src/game/chraction.h b/src/game/chraction.h index 892554fc..8b7334d8 100644 --- a/src/game/chraction.h +++ b/src/game/chraction.h @@ -54,7 +54,7 @@ f32 chrGetDistanceToBond(ChrRecord *guardData); s32 chrCheckTargetInSight(ChrRecord *self); bool actor_fire_or_aim_at_target_update(ChrRecord *self, s32 newtargettype, s32 newtargetid); void chrlvAlertGuardToPlayerPosition(ChrRecord *); -void chrlvIdleAnimationRelated7F023A94(ChrRecord *self, f32 mergetime); +void chrlvMergeKneelToStand(ChrRecord *self, f32 mergetime); f32 chrGetAngleToBond(ChrRecord *arg0); s32 chrHasStoppedOrPatroling(ChrRecord *); s32 chrResolvePadId(ChrRecord *guardData,s32 padNo); diff --git a/src/game/gun.c b/src/game/gun.c index 54b86f55..79e69c8a 100644 --- a/src/game/gun.c +++ b/src/game/gun.c @@ -72,7 +72,9 @@ s32 dword_CODE_bss_80076A48; // Unused #define GUN_SPRING_SCALE 0.050000012f #endif -#define TANK_SHELL_SPEED 66.666664f +extern f32 g_GLGrenadeLaunchUnk8C; +extern f32 g_GLGrenadeLaunchUnk94; +extern f32 g_TankShellSpeed; // data ////D:80032440 @@ -2170,8 +2172,8 @@ void gunSpawnGLGrenade(s32 handnum) if (grenadeobj->runtime_bitflags & RUNTIMEBITFLAG_00000080) { - grenadeobj->projectile->unk8C = 0.3f; - grenadeobj->projectile->unk94 = 0.13333333f; + grenadeobj->projectile->unk8C = g_GLGrenadeLaunchUnk8C; + grenadeobj->projectile->unk94 = g_GLGrenadeLaunchUnk94; grenadeobj->projectile->refreshrate = THROWN_ITEM_REFRESH_RATE; } } @@ -2262,6 +2264,7 @@ void currentPlayerCreateRocket(GUNHAND hand) * Address: 0x7F05FB00 * This function frees some sort of ObjectRecord from the given hand */ +#if defined(VERSION_EU) void sub_GAME_7F05FB00(enum GUNHAND hand) { struct hand* hand_ptr; @@ -2324,9 +2327,9 @@ void gunFireTankShell(s32 handnum) mtx4RotateVecInPlace(currentPlayerGetViewToWorldMtxf(), &aimdir); } - velocity.x = aimdir.x * TANK_SHELL_SPEED; - velocity.y = aimdir.y * TANK_SHELL_SPEED; - velocity.z = aimdir.z * TANK_SHELL_SPEED; + velocity.x = aimdir.x * g_TankShellSpeed; + velocity.y = aimdir.y * g_TankShellSpeed; + velocity.z = aimdir.z * g_TankShellSpeed; if (g_ClockTimer > 0) { velocity.x += (playerprop->pos.x - prevplayerpos->x) / g_GlobalTimerDelta; @@ -2433,5906 +2436,10 @@ void gunFireTankShell(s32 handnum) } } } - - -/** - * D_80053DDC belongs to gunFireTankShell, but must sit here - * immediately ahead of this function's pool for that function to match. - */ -GLOBAL_ASM( -.late_rodata -glabel D_80053DDC -.word 0x3f8e38e3 /*1.111111*/ -) - - -void gunUpdateAndFire(GUNHAND handnum) -{ - Mtxf *rwmtx; - Mtxf gunmtx; - Mtxf flashmtx; - Mtxf flash2mtx; - Mtxf tmpmtx; - ModelFileHeader *mdlhdr; - coord3d gunofs = D_80035C40; - Mtxf rotmtx; - Mtxf aimmtx; - struct hand *hand; - s32 *flashvisptr; - f32 *flashdata; - ModelNode *node; - s32 j; - ITEM_IDS item; - WeaponStats *itemstats; - f32 rndf; - u32 rnd; - f32 stackpad_scale; - coord3d blendedpos; - coord3d blendedlook; - coord3d blendedup; - s32 i; - coord3d trigrot; - coord3d taserrot; - coord3d fistrot; - f32 *cylinderdata; - u8 stackpad1[4]; - ModelNode **hammerdata; - Model *model; - coord3d flashpos; - f32 flashscale; - f32 flashext; - f32 *nodeptr; - f32 *nodepos; - f32 *swdata; - s32 sw6mtxidx; - f32 *hingedata; - f32 *sw7data; - s32 sw7mtxidx; - s32 shellidx; - u8 stackpad2[4]; - - flashvisptr = NULL; - flashdata = NULL; - hand = &g_CurrentPlayer->hands[handnum]; - item = get_item_in_hand_or_watch_menu(handnum); - itemstats = get_ptr_item_statistics(item); - - /** - * When switching from a single weapon to dual wielding, both gun models interpolate a little to the sides of the screen - * over a period of 4 seconds. And when switching back to a single weapon that weapon moves back more towards the - * center of the screen. - */ - if (handnum == GUNRIGHT) - { - if (bondwalkItemCheckBitflags(get_item_in_hand_or_watch_menu(1), WEAPONSTATBITFLAG_SHOW_FIRST_PERSON) != 0) - { - hand->field_A34 += (2.0f * g_GlobalTimerDelta) / 240.0f; - - if (hand->field_A34 > 2.0f) - { - hand->field_A34 = 2.0f; - } - } - else - { - hand->field_A34 -= (2.0f * g_GlobalTimerDelta) / 240.0f; - - if (hand->field_A34 < 0.0f) - { - hand->field_A34 = 0.0f; - } - } - } - else if (bondwalkItemCheckBitflags(get_item_in_hand_or_watch_menu(0), WEAPONSTATBITFLAG_SHOW_FIRST_PERSON) != 0) - { - hand->field_A34 -= (2.0f * g_GlobalTimerDelta) / 240.0f; - - if (hand->field_A34 < (-2.0f)) - { - hand->field_A34 = -2.0f; - } - } - else - { - hand->field_A34 += (2.0f * g_GlobalTimerDelta) / 240.0f; - - if (hand->field_A34 > 0.0f) - { - hand->field_A34 = 0.0f; - } - } - - /** - * Gun sway system. This moves the held weapons in figure-eight pattern which becomes bigger depending how fast the player is moving. - */ - blendedpos = D_80035C4C; - blendedlook = D_80035C58; - blendedup = D_80035C64; - - i = hand->curblendpos; - - coord3dCatmullRomInterp(&hand->blendpos[(i + 3) % 4], &hand->blendpos[i], &hand->blendpos[(i + 1) % 4], &hand->blendpos[(i + 2) % 4], hand->dampt, &blendedpos); - coord3dCatmullRomInterp(&hand->blendlook[(i + 3) % 4], &hand->blendlook[i], &hand->blendlook[(i + 1) % 4], &hand->blendlook[(i + 2) % 4], hand->dampt, &blendedlook); - coord3dCatmullRomInterp(&hand->blendup[(i + 3) % 4], &hand->blendup[i], &hand->blendup[(i + 1) % 4], &hand->blendup[(i + 2) % 4], hand->dampt, &blendedup); - - blendedpos.x *= g_CurrentPlayer->gunposamplitude; - blendedpos.y *= g_CurrentPlayer->gunposamplitude; - blendedpos.z *= g_CurrentPlayer->gunposamplitude; - blendedpos.x += hand->weapon_theta_displacement; - blendedpos.y += hand->weapon_verta_displacement; - blendedpos.x += sub_GAME_7F05DCB8(handnum); - - j = 0; - - if (g_ClockTimer > 0) - { - do - { - j += 1; - hand->spring_pos_x = (GUN_SPRING_DAMP * hand->spring_pos_x) + ((f32 *) (&blendedpos))[0]; - hand->spring_pos_y = (GUN_SPRING_DAMP * hand->spring_pos_y) + ((f32 *) (&blendedpos))[1]; - hand->spring_pos_z = (GUN_SPRING_DAMP * hand->spring_pos_z) + ((f32 *) (&blendedpos))[2]; - hand->spring_look_x = (GUN_SPRING_DAMP * hand->spring_look_x) + ((f32 *) (&blendedlook))[0]; - hand->spring_look_y = (GUN_SPRING_DAMP * hand->spring_look_y) + ((f32 *) (&blendedlook))[1]; - hand->spring_look_z = (GUN_SPRING_DAMP * hand->spring_look_z) + ((f32 *) (&blendedlook))[2]; - hand->spring_up_x = (GUN_SPRING_DAMP * hand->spring_up_x) + ((f32 *) (&blendedup))[0]; - hand->spring_up_y = (GUN_SPRING_DAMP * hand->spring_up_y) + ((f32 *) (&blendedup))[1]; - hand->spring_up_z = (GUN_SPRING_DAMP * hand->spring_up_z) + ((f32 *) (&blendedup))[2]; - } - while (j < g_ClockTimer); - } - - hand->sway_pos_x = hand->spring_pos_x * GUN_SPRING_SCALE; - hand->sway_pos_y = hand->spring_pos_y * GUN_SPRING_SCALE; - hand->sway_pos_z = hand->spring_pos_z * GUN_SPRING_SCALE; - hand->sway_look_x = hand->spring_look_x * GUN_SPRING_SCALE; - hand->sway_look_y = hand->spring_look_y * GUN_SPRING_SCALE; - hand->sway_look_z = hand->spring_look_z * GUN_SPRING_SCALE; - hand->sway_up_x = hand->spring_up_x * GUN_SPRING_SCALE; - hand->sway_up_y = hand->spring_up_y * GUN_SPRING_SCALE; - hand->sway_up_z = hand->spring_up_z * GUN_SPRING_SCALE; - - // Offset the weapon to the right or left side of the screen depending on which hand it's in. - if (handnum == GUNRIGHT) - { - gunofs.x = (gunSetHorizontalOffset(handnum) + hand->sway_pos_x) + (*hand).gunofs2_x; - } - else - { - gunofs.x = (gunSetHorizontalOffset(handnum) + hand->sway_pos_x) - hand->gunofs2_x; - } - - gunofs.y = hand->gunofs2_y + (itemstats->PosY + hand->sway_pos_y); - gunofs.z = hand->gunofs2_z + (itemstats->PosZ + hand->sway_pos_z); - - if (((item == ITEM_ROCKETLAUNCH) || (item == ITEM_TRIGGER)) || (item == ITEM_WATCHLASER)) - { - gunofs.y += g_CurrentPlayer->ducking_height_offset / (-100.0f); - gunofs.z += (3.0f * g_CurrentPlayer->ducking_height_offset) / (-100.0f); - - if ((item == ITEM_ROCKETLAUNCH) && (((cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) || (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA)) || (get_screen_ratio() == SCREEN_RATIO_16_9))) - { - gunofs.y -= 3.0f; - } - } - else if (item == ITEM_TASER) - { - gunofs.y += (2.5f * g_CurrentPlayer->ducking_height_offset) / (-100.0f); - gunofs.z += (7.5f * g_CurrentPlayer->ducking_height_offset) / (-100.0f); - } - else - { - gunofs.y += (5.0f * g_CurrentPlayer->ducking_height_offset) / (-100.0f); - gunofs.z += (15.0f * g_CurrentPlayer->ducking_height_offset) / (-100.0f); - } - - if ((hand->weapon_firing_status != 0) && (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_00000020) != 0)) - { - if (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_00000040) != 0) - { - rnd = randomGetNext(); - rndf = (f32) ((u32) rnd); - gunofs.x += 0.3f - ((rndf * (1.0f / M_U32_MAX_VALUE_F)) * 0.6f); - } - - rnd = randomGetNext(); - rndf = (f32) ((u32) rnd); - gunofs.y += 0.3f - ((rndf * (1.0f / M_U32_MAX_VALUE_F)) * 0.6f); - rnd = randomGetNext(); - rndf = (f32) ((u32) rnd); - gunofs.z += 0.3f - ((rndf * (1.0f / M_U32_MAX_VALUE_F)) * 0.6f); - } - - gunofs.x += (((g_CurrentPlayer->field_FFC.x - getPlayer_c_screenleft()) - (getPlayer_c_screenwidth() * 0.5f)) * itemstats->PlayZ) / (getPlayer_c_screenwidth() * 0.5f); - - if ((g_CurrentPlayer->field_FFC.y - getPlayer_c_screentop()) > (getPlayer_c_screenheight() * 0.5f)) - { - gunofs.y -= (((g_CurrentPlayer->field_FFC.y - getPlayer_c_screentop()) - (getPlayer_c_screenheight() * 0.5f)) * itemstats->PlayY) / (getPlayer_c_screenheight() * 0.5f); - } - else - { - gunofs.y -= (((g_CurrentPlayer->field_FFC.y - getPlayer_c_screentop()) - (getPlayer_c_screenheight() * 0.5f)) * itemstats->PlayX) / (getPlayer_c_screenheight() * 0.5f); - } - - sub_GAME_7F05C614(); - matrix_4x4_set_identity(&rotmtx); - - if ((item == ITEM_TRIGGER) || (item == ITEM_WATCHLASER)) - { - trigrot = D_80035C70; - matrix_4x4_set_rotation_around_xyz(&trigrot, &tmpmtx); - matrix_4x4_multiply_homogeneous_in_place(&tmpmtx, &rotmtx); - } - else if (item == ITEM_TASER) - { - taserrot = D_80035C7C; - matrix_4x4_set_rotation_around_xyz(&taserrot, &tmpmtx); - matrix_4x4_multiply_homogeneous_in_place(&tmpmtx, &rotmtx); - } - else if ((item == ITEM_FIST) && (g_CurrentPlayer->cur_item_weapon_getname == ITEM_SNIPERRIFLE)) - { - fistrot = D_80035C88; - matrix_4x4_set_rotation_around_xyz(&fistrot, &tmpmtx); - matrix_4x4_multiply_homogeneous_in_place(&tmpmtx, &rotmtx); - gunofs.x += -2.5f; - gunofs.y += 27.8f; - gunofs.z += 2.0f; - } - - if (hand->field_92C != 0) - { - gunofs.x += hand->field_8EC.m[3][0]; - gunofs.y += hand->field_8EC.m[3][1]; - gunofs.z += hand->field_8EC.m[3][2]; - matrix_4x4_multiply_homogeneous_in_place(&hand->field_8EC, &rotmtx); - rotmtx.m[3][0] = 0.0f; - rotmtx.m[3][1] = 0.0f; - rotmtx.m[3][2] = 0.0f; - } - else - { - hand->field_8E8 = 0.0f; - hand->field_8DC = (-0.0f) + 0.0f; - hand->field_8E0 = 0.0f; - hand->field_8E4 = (-0.0f) + 0.0f; - } - - matrix_4x4_set_basis_and_position_target(&tmpmtx, 0.0f, 0.0f, 0.0f, hand->sway_look_x, hand->sway_look_y, hand->sway_look_z, hand->sway_up_x, hand->sway_up_y, hand->sway_up_z); - matrix_4x4_multiply_homogeneous_in_place(&tmpmtx, &rotmtx); - matrix_4x4_align(&tmpmtx, 0.0f, gunofs.x - hand->field_A38, gunofs.y - hand->field_A3C, gunofs.z - hand->field_A40); - matrix_4x4_multiply_homogeneous_in_place(&tmpmtx, &rotmtx); - matrix_4x4_copy(&rotmtx, &gunmtx); - matrix_4x4_set_position(&gunofs, &gunmtx); - matrix_4x4_copy(&gunmtx, &hand->gunmtx_camspace); - matrix_4x4_copy(&hand->throw_item_pos_related, &hand->throw_item_pos_related_prev); - matrix_4x4_multiply_homogeneous(currentPlayerGetViewToWorldMtxf(), &hand->gunmtx_camspace, &hand->throw_item_pos_related); - hand->field_87F = 1; - - if (((((((get_ptr_weapon_model_header_line(item) == 0) || (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_SHOW_FIRST_PERSON) == 0)) || (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_HIDE_FIRST_PERSON_HAND) != 0)) - || (hand->weapon_action_state == GUN_ANIM_STATE_SWITCH_SWAP)) || (hand->weapon_action_state == GUN_ANIM_STATE_SWITCH_HOLD)) || (Gun_hand_without_item(handnum) == 0)) || (get_itemtype_in_hand(handnum) == 0)) - { - hand->field_87F = 0; - } - - if ((hand->weapon_ammo_in_magazine <= 0) && (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_SINGLE_USE_RELOAD) != 0)) - { - hand->field_87F = 0; - } - - if (hand->field_87F != 0) - { - mdlhdr = &g_CurrentPlayer->copy_of_body_obj_header[handnum]; - rwmtx = (Mtxf *) dynAllocate(mdlhdr->numMatrices * ((s32) (sizeof(Mtxf)))); - j = 0; - - if (mdlhdr->numMatrices > 0) - { - do - { - matrix_4x4_set_identity((Mtxf *) (((u8 *) rwmtx) + (j * ((s32) (sizeof(Mtxf)))))); - j += 1; - } - while (j < mdlhdr->numMatrices); - } - - modelCalculateRwDataLen(mdlhdr); -#ifdef DEBUG - /** - * The model's runtime data is written into hand->modeldatas, which is a - * fixed run of 32 words (modeldatas .. field_C04, ending at volley). - */ - if (mdlhdr->numRecords >= 32) - { - osSyncPrintf("Increase GUNSAVESIZE to %d!!! ", mdlhdr->numRecords); - } -#endif - model = (Model *) (&hand->field_B68); - - if (mdlhdr->Switches); - - modelInit(model, mdlhdr, (s32 *) (&hand->modeldatas)); - sub_GAME_7F05E978(model, 1); - sub_GAME_7F05EA94(model, hand->field_87E); - node = mdlhdr->Switches[1]; - - if (node != NULL) - { - if (&node->Data->Switch); - - flashvisptr = ((s32 *) (&hand->modeldatas)) + node->Data->Switch.RwDataIndex; - } - - if (mdlhdr->Switches[3] != NULL) - { - flashdata = (f32 *) mdlhdr->Switches[3]->Data; - } - - hand->mtxlist = rwmtx; - - if ((bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_MIRROR_DUAL) != 0) && (handnum == GUNLEFT)) - { - matrix_column_1_scalar_multiply(-1.0f, gunmtx.m[0]); - } - - matrix_scalar_multiply(IDO_POINT_ONE, gunmtx.m[0]); - matrix_4x4_copy(&gunmtx, rwmtx); - - if (mdlhdr->Skeleton == (&skeleton_gun_revolver)) - { - swdata = (f32 *) mdlhdr->Switches[4]; - - if (swdata != NULL) - { - rndf = 0.0f; - cylinderdata = (f32 *) ((ModelNode *) swdata)->Data; - - if (item == ITEM_RUGER) - { - if (hand->weapon_action_state == 1) - { -#if defined(VERSION_EU) - rndf = (((hand->field_890 - (hand->weapon_ammo_in_magazine * 5)) + 0x19) * M_TAU_F) / 30.0f; -#else - rndf = (((hand->field_890 - (hand->weapon_ammo_in_magazine * 6)) + 0x1E) * M_TAU_F) / 36.0f; -#endif - } - else - { - rndf = ((6 - hand->weapon_ammo_in_magazine) * M_TAU_F) / 6.0f; - } - } - else if (hand->weapon_action_state == 1) - { -#if defined(VERSION_EU) - if (hand->field_890 < 5) - { - rndf = (hand->field_890 * M_TAU_F) / 30.0f; - } -#else - if (hand->field_890 < 6) - { - rndf = (hand->field_890 * M_TAU_F) / 36.0f; - } -#endif - } - - matrix_4x4_set_rotation_around_z(rndf, &tmpmtx); - matrix_4x4_set_position((coord3d *) cylinderdata, &tmpmtx); - matrix_4x4_multiply(&gunmtx, &tmpmtx, &rwmtx[3]); - } - - swdata = (f32 *) mdlhdr->Switches[5]; - - if (swdata != NULL) - { - hammerdata = (ModelNode **) ((ModelNode *) swdata)->Data; - - if (hand->weapon_action_state == 1) - { -#if defined(VERSION_EU) - if (hand->field_890 < 2) - { - rndf = (2.0f * ((-((f32) hand->field_890)) * DegToRad(30.0f))) / 5.0f; - } - else - { - rndf = (2.0f * ((-((f32) (5 - hand->field_890))) * DegToRad(30.0f))) / 5.0f; - } -#else - if (hand->field_890 < 3) - { - rndf = (2.0f * ((-((f32) hand->field_890)) * DegToRad(30.0f))) / 6.0f; - } - else - { - rndf = (2.0f * ((-((f32) (6 - hand->field_890))) * DegToRad(30.0f))) / 6.0f; - } -#endif - matrix_4x4_set_rotation_around_x(rndf, &tmpmtx); - matrix_4x4_set_position((coord3d *) hammerdata, &tmpmtx); - } - else - { - matrix_4x4_set_identity_and_position((coord3d *) hammerdata, &tmpmtx); - } - - matrix_4x4_multiply(&gunmtx, &tmpmtx, &rwmtx[4]); - } - } - - if (flashvisptr != NULL) - { - *flashvisptr = 0; - } - - if (flashdata != NULL) - { - rnd = randomGetNext(); - rndf = (f32) ((u32) rnd); - flashscale = ((rndf * (1.0f / M_U32_MAX_VALUE_F)) * 0.25f) + 1.0f; - flashext = itemstats->MuzzleFlashExtension; - - if (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_00000001) != 0) - { - rnd = randomGetNext(); - rndf = (f32) ((u32) rnd); - matrix_4x4_set_rotation_around_z((rndf * (1.0f / M_U32_MAX_VALUE_F)) * M_TAU_F, &flashmtx); - matrix_4x4_set_position((coord3d *) flashdata, &flashmtx); - } - else - { - matrix_4x4_set_identity_and_position((coord3d *) flashdata, &flashmtx); - } - - matrix_scalar_multiply(flashscale, flashmtx.m[0]); - matrix_column_3_scalar_multiply(flashext, flashmtx.m[0]); - matrix_4x4_multiply_in_place(&gunmtx, &flashmtx); - matrix_4x4_copy(&flashmtx, &rwmtx[1]); - - hand->field_B58.x = flashmtx.m[3][0]; - hand->field_B58.y = flashmtx.m[3][1]; - hand->field_B58.z = flashmtx.m[3][2]; - mtx4TransformVecInPlace(currentPlayerGetViewToWorldMtxf(), &hand->field_B58); - hand->field_B64 = -flashmtx.m[3][2]; - - if (hand->field_87D != 0) - { - if (flashvisptr != NULL) - { - *flashvisptr = 1; - } - - nodeptr = (f32 *) mdlhdr->Switches[2]; - - if (nodeptr != NULL) - { - nodepos = (f32 *) ((ModelNode *) nodeptr)->Data; - flashpos.x = (((((f32 *) nodepos)[0] * flashmtx.m[0][0]) + (((f32 *) nodepos)[1] * flashmtx.m[1][0])) + (((f32 *) nodepos)[2] * flashmtx.m[2][0])) + flashmtx.m[3][0]; - flashpos.y = (((((f32 *) nodepos)[0] * flashmtx.m[0][1]) + (((f32 *) nodepos)[1] * flashmtx.m[1][1])) + (((f32 *) nodepos)[2] * flashmtx.m[2][1])) + flashmtx.m[3][1]; - flashpos.z = (((((f32 *) nodepos)[0] * flashmtx.m[0][2]) + (((f32 *) nodepos)[1] * flashmtx.m[1][2])) + (((f32 *) nodepos)[2] * flashmtx.m[2][2])) + flashmtx.m[3][2]; - - matrix_4x4_align(&flash2mtx, (randomGetNext() * (1.0f / M_U32_MAX_VALUE_F)) * M_TAU_F, -flashpos.x, -flashpos.y, -flashpos.z); - matrix_scalar_multiply(IDO_POINT_ONE * flashscale, flash2mtx.m[0]); - matrix_4x4_set_rotation_axis_angle(&aimmtx, 0, gunofs.x - hand->field_A38, gunofs.y - hand->field_A3C, gunofs.z - hand->field_A40); - matrix_4x4_multiply_in_place(&aimmtx, &flash2mtx); - matrix_row_3_scalar_multiply(flashext, flash2mtx.m[0]); - matrix_4x4_multiply_in_place(&rotmtx, &flash2mtx); - matrix_4x4_set_position(&flashpos, &flash2mtx); - matrix_4x4_copy(&flash2mtx, &rwmtx[2]); - } - - if (mdlhdr->Skeleton == (&skeleton_gun_kf7)) - { - nodeptr = (f32 *) mdlhdr->Switches[4]; - - if (nodeptr != NULL) - { - nodepos = (f32 *) ((ModelNode *) nodeptr)->Data; - flashpos.x = (((((f32 *) nodepos)[0] * flashmtx.m[0][0]) + (((f32 *) nodepos)[1] * flashmtx.m[1][0])) + (((f32 *) nodepos)[2] * flashmtx.m[2][0])) + flashmtx.m[3][0]; - flashpos.y = (((((f32 *) nodepos)[0] * flashmtx.m[0][1]) + (((f32 *) nodepos)[1] * flashmtx.m[1][1])) + (((f32 *) nodepos)[2] * flashmtx.m[2][1])) + flashmtx.m[3][1]; - flashpos.z = (((((f32 *) nodepos)[0] * flashmtx.m[0][2]) + (((f32 *) nodepos)[1] * flashmtx.m[1][2])) + (((f32 *) nodepos)[2] * flashmtx.m[2][2])) + flashmtx.m[3][2]; - ((f32 *) stackpad2)[-8] = IDO_POINT_ONE * flashscale; - matrix_4x4_align(&flash2mtx, (randomGetNext() * (1.0f / M_U32_MAX_VALUE_F)) * M_TAU_F, -flashpos.x, -flashpos.y, -flashpos.z); - matrix_scalar_multiply(((f32 *) stackpad2)[-8], flash2mtx.m[0]); - matrix_4x4_set_rotation_axis_angle(&aimmtx, 0, gunofs.x - hand->field_A38, gunofs.y - hand->field_A3C, gunofs.z - hand->field_A40); - matrix_4x4_multiply_in_place(&aimmtx, &flash2mtx); - matrix_row_3_scalar_multiply(flashext, flash2mtx.m[0]); - matrix_4x4_multiply_in_place(&rotmtx, &flash2mtx); - matrix_4x4_set_position(&flashpos, &flash2mtx); - matrix_4x4_copy(&flash2mtx, &rwmtx[3]); - } - } - } - } - else - { - hand->field_B58.x = hand->throw_item_pos_related.m[3][0]; - hand->field_B58.y = hand->throw_item_pos_related.m[3][1]; - hand->field_B58.z = hand->throw_item_pos_related.m[3][2]; - hand->field_B64 = -hand->gunmtx_camspace.m[3][2]; - } - - node = mdlhdr->Switches[6]; - - if (node != NULL) - { - swdata = (f32 *) node->Data; - sw6mtxidx = modelFindNodeMtxIndex(node, 0); - sub_GAME_7F05E6B4(handnum, hand->weapon_hold_time); - - if ((mdlhdr->numSwitches >= 0x1D) && (mdlhdr->Switches[28] != NULL)) - { - hingedata = (f32 *) mdlhdr->Switches[28]->Data; - guRotateF(tmpmtx.m, (((hand->field_A84 + M_TAU_F) - get_value_if_watch_is_on_hand_or_not(handnum)) * 360.0f) / M_TAU_F, hingedata[0] - hingedata[3], hingedata[1] - hingedata[4], hingedata[2] - hingedata[5]); - matrix_4x4_set_position((coord3d *) swdata, &tmpmtx); - } - else - { - matrix_4x4_set_position_and_rotation_around_y(swdata, hand->field_A84, &tmpmtx); - } - - matrix_4x4_multiply_homogeneous(&gunmtx, &tmpmtx, &rwmtx[sw6mtxidx]); - } - - if (mdlhdr->numSwitches >= 0x1E) - { - bondviewSelectCuff(model, mdlhdr, 0x1D); - } - - node = mdlhdr->Switches[7]; - - if (node != NULL) - { - sw7data = (f32 *) node->Data; - sw7mtxidx = modelFindNodeMtxIndex(node, 0); - sub_GAME_7F05E83C(handnum); - matrix_4x4_set_identity_and_position((coord3d *) sw7data, &tmpmtx); - tmpmtx.m[3][2] -= hand->field_A88; - matrix_4x4_multiply(&gunmtx, &tmpmtx, &rwmtx[sw7mtxidx]); - } - - shellidx = 0; - - /** - * For the shotguns, show or hide the shells in the shell holder based on how much ammunition is in the player's reserve. - */ - if (mdlhdr->numSwitches >= 0x13) - { - do - { - if (mdlhdr->Switches[18 + shellidx] != 0) - { - nodeptr = (f32 *) modelGetNodeRwData(model, mdlhdr->Switches[18 + shellidx]); - - if (nodeptr != NULL) - { - *((s32 *) nodeptr) = hand->numvisibleshells >= (5 - shellidx); - } - } - - if (mdlhdr->Switches[23 + shellidx] != 0) - { - nodeptr = (f32 *) modelGetNodeRwData(model, mdlhdr->Switches[23 + shellidx]); - - if (nodeptr != NULL) - { - *((s32 *) nodeptr) = hand->numvisibleshells >= (5 - shellidx); - } - } - - shellidx += 1; - } - while (shellidx != 5); - } - - modelUpdateNodeRelations(model); - - if (hand->weapon_firing_status != 0) - { - switch (item) - { - case ITEM_WPPK: - case ITEM_WPPKSIL: - case ITEM_TT33: - case ITEM_SKORPION: - case ITEM_AK47: - case ITEM_UZI: - case ITEM_MP5K: - case ITEM_MP5KSIL: - case ITEM_SPECTRE: - case ITEM_M16: - case ITEM_FNP90: - case ITEM_SNIPERRIFLE: - case ITEM_RUGER: - case ITEM_GOLDENGUN: - case ITEM_SILVERWPPK: - case ITEM_GOLDWPPK: - gunCreateBeamForHand(handnum); - hand->field_8A0 = hand->field_8A0 + 1; - break; - case ITEM_LASER: - case ITEM_WATCHLASER: -#if defined(VERSION_JP) || defined(VERSION_EU) - hand->field_8A0 = hand->field_8A0 + 1; -#endif - gunCreateBeamForHand(handnum); - break; - } - } - } - - if (item == ITEM_ROCKETLAUNCH) - { - gunUpdateAttachedRocket(handnum); - } - - if (hand->weapon_firing_status != 0) - { - sub_GAME_7F068508(handnum, bondviewGetPlayerStanHeight(g_CurrentPlayer)); - - if (item == ITEM_GRENADELAUNCH) - { - gunSpawnGLGrenade(handnum); - return; - } - - if (item == ITEM_GRENADE) - { - generate_player_thrown_grenade(handnum); - return; - } - - if (item == ITEM_ROCKETLAUNCH) - { - gunFireTankShell(handnum); - return; - } - - if (item == ITEM_THROWKNIFE) - { - generate_player_thrown_knife(handnum); - return; - } - - if ((((((((item == ITEM_REMOTEMINE) || (item == ITEM_PROXIMITYMINE)) || (item == ITEM_TIMEDMINE)) || (item == ITEM_BOMBCASE)) || (item == ITEM_BUG)) || (item == ITEM_MICROCAMERA)) || (item == ITEM_GOLDENEYEKEY)) || (item == ITEM_PLASTIQUE)) - { - generate_player_thrown_object(handnum); - return; - } - - if (item == ITEM_FLAREPISTOL) - { - gunSpawnGLGrenade(handnum); - return; - } - - if (item == ITEM_PITONGUN) - { - gunSpawnGLGrenade(handnum); - } - } -} - - -void gunUpdateAndFireBothHands(void) -{ - gunUpdateAndFire(GUNRIGHT); - gunUpdateAndFire(GUNLEFT); -} - - -/** - * @param arg0: - * @param item: - * @param arg2: - * @param arg3: - * - * Address 0x7F061948. - * - * This function adjusts the length of the bullet beam that's rendered on screen. - * This function is used for both player and guard beams. - * - * The watch laser has a very short beam, in accordance with its range. - * The laser also has a shortened one, but it appears this is to avoid graphical glitches. - * Other weapons have their bullet beam capped at 10000 max length, otherwise if the player - * fires into the void, there may be graphical glitches with the beam. - * -*/ -void CapBeamLengthAndDecideIfRendered(struct BeamRecord *arg0, ITEM_IDS item, coord3d *arg2, coord3d *arg3) -{ - f32 phi_f12_2; - - //arg0->pos.x = arg2->x; - //arg0->pos.y = arg2->y; - //arg0->pos.z = arg2->z; - - //arg0->delta.x = arg3->x - arg2->x; - //arg0->delta.y = arg3->y - arg2->y; - //arg0->delta.z = arg3->z - arg2->z; - - //phi_f12_2 = sqrtf((arg0->delta.f[0] * arg0->delta.f[0]) + (arg0->delta.f[1] * arg0->delta.f[1]) + (arg0->delta.f[2] * arg0->delta.f[2])); - - //arg0->delta.x *= 1.0f / phi_f12_2; - //arg0->delta.y *= 1.0f / phi_f12_2; - //arg0->delta.z *= 1.0f / phi_f12_2; - - - arg0->pos.f[0] = arg2->f[0]; - arg0->pos.f[1] = arg2->f[1]; - arg0->pos.f[2] = arg2->f[2]; - - arg0->delta.f[0] = arg3->x - arg2->x; - arg0->delta.f[1] = arg3->f[1] - arg2->f[1]; - arg0->delta.f[2] = arg3->f[2] - arg2->f[2]; - - phi_f12_2 = sqrtf((arg0->delta.f[0] * arg0->delta.f[0]) + (arg0->delta.f[1] * arg0->delta.f[1]) + (arg0->delta.f[2] * arg0->delta.f[2])); - - arg0->delta.f[0] *= 1.0f / phi_f12_2; - arg0->delta.f[1] *= 1.0f / phi_f12_2; - arg0->delta.f[2] *= 1.0f / phi_f12_2; - - if (item == ITEM_WATCHLASER) - { - if (phi_f12_2 > 300.0f) - { - phi_f12_2 = 300.0f; - } - } - else - { - if (phi_f12_2 > 10000.0f) - { - phi_f12_2 = 10000.0f; - } - } - - arg0->unk00 = 0; - arg0->item_id = (s8) item; - arg0->unk1c = phi_f12_2; - - if (phi_f12_2 < 500.0f) - { - phi_f12_2 = 500.0f; - } - - if (item == ITEM_LASER) - { - arg0->unk20 = 0.25f * phi_f12_2; - arg0->unk24 = 0.6f * phi_f12_2; - - if (arg0->unk24 > 3000.0f) - { - arg0->unk24 = 3000.0f; - } - - // Laser beams are rendered more often than other normal weapons - arg0->unk28 = (-0.1f - ((f32) (u32)randomGetNext() * (1.0f / UINT_MAX) * 0.3f)) * phi_f12_2; - } - else if (item == ITEM_WATCHLASER) - { - arg0->unk24 = phi_f12_2; - arg0->unk20 = 2.0f * phi_f12_2; - - if (phi_f12_2 > 3000.0f) - { - arg0->unk24 = 3000.0f; - } - - // Always render the beam for the watch laser - arg0->unk28 = 0.0f; - } - else - { - arg0->unk20 = 0.2f * phi_f12_2; - arg0->unk24 = arg0->unk20; - - if (arg0->unk20 > 3000.0f) - { - arg0->unk24 = 3000.0f; - } - - // Decide if a beam should be rendered for normal weapon bullets - arg0->unk28 = ((2.0f * ((f32) (u32)randomGetNext() * (1.0f / UINT_MAX))) - 1.0f) * arg0->unk20; - } - - if (arg0->unk1c <= arg0->unk28) - { - // No beam will be rendered - arg0->unk00 = -1; - } -} - - -void gunCreateBeamForHand(enum GUNHAND hand) -{ - coord3d *field_2A18; - Mtxf *player_matrix; - struct hand *hand_ptr; - f32 val; - struct ChrRecord *chr; - f32 diff1_z; - f32 diff1_y; - f32 diff1_x; - f32 diff2_z; - f32 diff2_y; - f32 diff2_x; - BeamRecord *weapon_beam; - - hand_ptr = &g_CurrentPlayer->hands[hand]; - player_matrix = camGetWorldToScreenMtxf(); - - val = -((((hand_ptr->item_related.x * player_matrix->m[0][2]) + (hand_ptr->item_related.y * player_matrix->m[1][2])) + (hand_ptr->item_related.z * player_matrix->m[2][2])) + player_matrix->m[3][2]); - - if (val < hand_ptr->field_B64) - { - return; - } - - weapon_beam = &hand_ptr->weapon_beam; - - CapBeamLengthAndDecideIfRendered(weapon_beam, getCurrentPlayerWeaponId(hand), &hand_ptr->field_B58, &hand_ptr->item_related); - - if ((g_CurrentPlayer->prop->chr == NULL) || (getPlayerCount() < 2)) - { - return; - } - - chr = g_CurrentPlayer->prop->chr; - - diff1_x = hand_ptr->item_related.x - g_CurrentPlayer->field_2A18[hand].x; - diff1_y = hand_ptr->item_related.y - g_CurrentPlayer->field_2A18[hand].y; - diff1_z = hand_ptr->item_related.z - g_CurrentPlayer->field_2A18[hand].z; - guNormalize(&diff1_x, &diff1_y, &diff1_z); - - diff2_x = hand_ptr->item_related.x - hand_ptr->field_B58.x; - diff2_y = hand_ptr->item_related.y - hand_ptr->field_B58.y; - diff2_z = hand_ptr->item_related.z - hand_ptr->field_B58.z; - guNormalize(&diff2_x, &diff2_y, &diff2_z); - - val = acosf( - + (diff2_z * diff1_z) - + ((diff1_x * diff2_x) - + (diff1_y * diff2_y))); - - if (val > 0.08726647f) - { - return; - } - - CapBeamLengthAndDecideIfRendered(&chr->beams[hand], getCurrentPlayerWeaponId(hand), &g_CurrentPlayer->field_2A18[hand], &hand_ptr->item_related); -} - - -Gfx *sub_GAME_7F061E18(Gfx *gdl, BeamRecord *flash, s32 arg2) -{ - f32 posz; - Mtx *mtx; - Mtxf mtxf; - Vtx templatevtx; - coord3d pos; - coord3d *playerpos; - f32 radius; - f32 pad_after_radius[2]; - f32 startoffset; - coord3d up; - coord3d right; - coord3d flareoffset; - coord3d extraorigin; - f32 extra_scale; - struct sImageTableEntry *image; - f32 d; - Mtxf *worldtoscreen; - coord3d tmp; - coord3d divout; - f32 divin[2]; - f32 f14; - f32 f16; - f32 f18; - f32 dist_to_start; - Vtx *vtx; - f32 dist; - Gfx *cmd; - - if (flash->unk00 >= 0) - { - templatevtx = D_80035C98; - playerpos = bondviewGetCurrentPlayersPosition(); - startoffset = flash->unk28; - dist = flash->unk24; - flareoffset = D_80035CA8; - extraorigin = D_80035CB4; - extra_scale = 1.4142f; // ~√2 - image = flareimage3; - worldtoscreen = camGetWorldToScreenMtxf(); - - if (flash->item_id == ITEM_LASER) - { - radius = 50.0f; - image = flareimage4; - } - else if (flash->item_id == ITEM_WATCHLASER) - { - radius = 10.0f; - image = flareimage4; - templatevtx.v.cn[3] = (randomGetNext() % 50) + 150; - - if ((randomGetNext() % 5) == 0) - { - templatevtx.v.cn[0] = (templatevtx.v.cn[1] = 255 - (randomGetNext() % 100)); - } - } - else - { - radius = 30.0f; - } - - pos.f[0] = flash->pos.f[0]; - pos.f[1] = flash->pos.f[1]; - pos.f[2] = flash->pos.f[2]; - - if (startoffset > 0.0f) - { - pos.f[0] += startoffset * flash->delta.f[0]; - pos.f[1] += startoffset * flash->delta.f[1]; - pos.f[2] += startoffset * flash->delta.f[2]; - } - else - { - dist += startoffset; - startoffset = 0.0f; - } - - if (flash->unk1c < (startoffset + dist)) - { - dist = flash->unk1c - startoffset; - } - - right.f[0] = (flash->delta.f[1] * (playerpos->f[2] - (pos.f[2] + (dist * flash->delta.f[2])))) - (flash->delta.f[2] * (playerpos->f[1] - (pos.f[1] + (dist * flash->delta.f[1])))); - right.f[1] = (flash->delta.f[2] * (playerpos->f[0] - (pos.f[0] + (dist * flash->delta.f[0])))) - (flash->delta.f[0] * (playerpos->f[2] - (pos.f[2] + (dist * flash->delta.f[2])))); - right.f[2] = (flash->delta.f[0] * (playerpos->f[1] - (pos.f[1] + (dist * flash->delta.f[1])))) - (flash->delta.f[1] * (playerpos->f[0] - (pos.f[0] + (dist * flash->delta.f[0])))); - - if (((right.f[0] != 0.0f) || (right.f[1] != 0.0f)) || (right.f[2] != 0.0f)) - { - guNormalize(&right.f[0], &right.f[1], &right.f[2]); - right.f[0] *= radius; - right.f[1] *= radius; - right.f[2] *= radius; - } - else - { - right.f[0] = 0.0f; - right.f[1] = radius; - right.f[2] = 0.0f; - } - - up.f[0] = (flash->delta.f[1] * right.f[2]) - (flash->delta.f[2] * right.f[1]); - up.f[1] = (flash->delta.f[2] * right.f[0]) - (flash->delta.f[0] * right.f[2]); - up.f[2] = (flash->delta.f[0] * right.f[1]) - (flash->delta.f[1] * right.f[0]); - - guNormalize(&up.f[0], &up.f[1], &up.f[2]); - - up.f[0] *= radius; - up.f[1] *= radius; - up.f[2] *= radius; - - if (flash->item_id == ITEM_LASER) - { - vtx = dynAllocateVertices(8); - } - else - { - vtx = dynAllocateVertices(4); - } - - mtx = dynAllocateMatrix(); - - matrix_4x4_set_identity_and_position(&pos, &mtxf); - matrix_scalar_multiply(0.1f, (f32 *)&mtxf); - matrix_4x4_multiply_homogeneous_in_place(worldtoscreen, &mtxf); - matrix_4x4_f32_to_s32(&mtxf, (Mtxf *)mtx); - - vtx[0] = templatevtx; - vtx[1] = templatevtx; - vtx[2] = templatevtx; - vtx[3] = templatevtx; - - if (flash->item_id == ITEM_LASER) - { - vtx[4] = templatevtx; - vtx[5] = templatevtx; - vtx[6] = templatevtx; - vtx[7] = templatevtx; - } - - if (flash->item_id == ITEM_WATCHLASER) - { - tmp.f[0] = pos.f[0] + flash->delta.f[0] * dist; - tmp.f[1] = pos.f[1] + flash->delta.f[1] * dist; - tmp.f[2] = pos.f[2] + flash->delta.f[2] * dist; - - mtx4TransformVecInPlace(worldtoscreen, &tmp); - - divin[0] = divin[1] = radius / 10.0f; - - dist_to_start = -tmp.f[2]; - divide3DCoordinates((coord3d *)divin, dist_to_start, &divout); - - if (divout.f[0] < 2.0f) - { - tmp.f[0] *= divout.f[0] * 0.5f; - tmp.f[1] *= divout.f[0] * 0.5f; - tmp.f[2] *= divout.f[0] * 0.5f; - } - - mtx4TransformVecInPlace(currentPlayerGetViewToWorldMtxf(), &tmp); - - tmp.f[0] -= pos.f[0]; - tmp.f[1] -= pos.f[1]; - tmp.f[2] -= pos.f[2]; - - flareoffset.x = tmp.f[0] * 10.0f; - flareoffset.y = tmp.f[1] * 10.0f; - flareoffset.z = tmp.f[2] * 10.0f; - } - else - { - flareoffset.x = flash->delta.f[0] * (dist * 10.0f); - flareoffset.y = flash->delta.f[1] * (dist * 10.0f); - flareoffset.z = flash->delta.f[2] * (dist * 10.0f); - } - - vtx[0].v.ob[0] = right.f[0]; - vtx[0].v.ob[1] = right.f[1]; - vtx[0].v.ob[2] = right.f[2]; - vtx[0].v.tc[0] = image->width << 5; - vtx[0].v.tc[1] = 0; - - vtx[1].v.ob[0] = -right.f[0]; - vtx[1].v.ob[1] = -right.f[1]; - vtx[1].v.ob[2] = -right.f[2]; - vtx[1].v.tc[0] = 0; - vtx[1].v.tc[1] = 0; - - vtx[2].v.ob[0] = flareoffset.f[0] + (right.f[0] * 0.9f); - vtx[2].v.ob[1] = flareoffset.f[1] + (right.f[1] * 0.9f); - vtx[2].v.ob[2] = flareoffset.f[2] + (right.f[2] * 0.9f); - vtx[2].v.tc[0] = image->width << 5; - vtx[2].v.tc[1] = image->height << 5; - - vtx[3].v.ob[0] = flareoffset.f[0] - (right.f[0] * 0.9f); - vtx[3].v.ob[1] = flareoffset.f[1] - (right.f[1] * 0.9f); - vtx[3].v.ob[2] = flareoffset.f[2] - (right.f[2] * 0.9f); - vtx[3].v.tc[0] = 0; - vtx[3].v.tc[1] = image->height << 5; - - if (flash->item_id == ITEM_LASER) - { - f14 = playerpos->f[0] - pos.f[0]; - f16 = playerpos->f[1] - pos.f[1]; - f18 = playerpos->f[2] - pos.f[2]; - - dist_to_start = (f14 * f14) + (f16 * f16) + (f18 * f18); - - f14 = playerpos->f[0] - (pos.f[0] + (flash->delta.f[0] * dist)); - f16 = playerpos->f[1] - (pos.f[1] + (flash->delta.f[1] * dist)); - f18 = playerpos->f[2] - (pos.f[2] + (flash->delta.f[2] * dist)); - - d = (f14 * f14) + (f16 * f16) + (f18 * f18); - - if (d < dist_to_start) - { - extraorigin.f[0] = flareoffset.f[0]; - extraorigin.f[1] = flareoffset.f[1]; - extraorigin.f[2] = flareoffset.f[2]; - extra_scale *= 0.9f; - } - - vtx[4].v.ob[0] = extraorigin.f[0] + (up.f[0] * extra_scale); - vtx[4].v.ob[1] = extraorigin.f[1] + (up.f[1] * extra_scale); - vtx[4].v.ob[2] = extraorigin.f[2] + (up.f[2] * extra_scale); - vtx[4].v.tc[0] = flareimage5->width << 5; - vtx[4].v.tc[1] = flareimage5->height << 5; - - vtx[5].v.ob[0] = extraorigin.f[0] - (up.f[0] * extra_scale); - vtx[5].v.ob[1] = extraorigin.f[1] - (up.f[1] * extra_scale); - vtx[5].v.ob[2] = extraorigin.f[2] - (up.f[2] * extra_scale); - vtx[5].v.tc[0] = 0; - vtx[5].v.tc[1] = 0; - - vtx[6].v.ob[0] = extraorigin.f[0] + (right.f[0] * extra_scale); - vtx[6].v.ob[1] = extraorigin.f[1] + (right.f[1] * extra_scale); - vtx[6].v.ob[2] = extraorigin.f[2] + (right.f[2] * extra_scale); - vtx[6].v.tc[0] = 0; - vtx[6].v.tc[1] = flareimage5->height << 5; - - vtx[7].v.ob[0] = extraorigin.f[0] - (right.f[0] * extra_scale); - vtx[7].v.ob[1] = extraorigin.f[1] - (right.f[1] * extra_scale); - vtx[7].v.ob[2] = extraorigin.f[2] - (right.f[2] * extra_scale); - vtx[7].v.tc[0] = flareimage5->width << 5; - vtx[7].v.tc[1] = 0; - } - - gSPClearGeometryMode(gdl++, G_CULL_BACK); - - // Ideally this should be something like gSPMatrix(gdl++ or cmd++, osVirtualToPhysical(mtx), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH) but I can't get these or similar forms to match - { - cmd = gdl++; - cmd->words.w0 = _SHIFTL(G_MTX, 24, 8) - | _SHIFTL(G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH, 16, 8) - | _SHIFTL(sizeof(Mtx), 0, 16); - cmd->words.w1 = osVirtualToPhysical(mtx); - } - - if (flash->item_id == ITEM_LASER) - { - texSelect(&gdl, flareimage5, 4, arg2, 2); - - gSPVertex(gdl++, osVirtualToPhysical(vtx), 8, 0); - - gSP4Triangles(gdl++, 4, 5, 6, 4, 5, 7, 0, 0, 0, 0, 0, 0); - - texSelect(&gdl, image, 4, arg2, 2); - - gSP4Triangles(gdl++, 0, 2, 3, 0, 3, 1, 0, 0, 0, 0, 0, 0); - } - else - { - texSelect(&gdl, image, 4, arg2, 2); - - gSPVertex(gdl++, osVirtualToPhysical(vtx), 4, 0); - - gSP4Triangles(gdl++, 0, 2, 3, 0, 3, 1, 0, 0, 0, 0, 0, 0); - } - } - - return gdl; -} - - -/* -* Address: 0x7F062B00 -*/ -void gunAdvanceBeamTimer(BeamRecord* beam) -{ - if (beam->unk00 >= 0) - { - if (g_ClockTimer < 3) - { -#ifdef VERSION_US - beam->unk28 += beam->unk20 * g_GlobalTimerDelta; -#else - beam->unk28 += beam->unk20 * g_JP_GlobalTimerDelta; -#endif - } - else - { - beam->unk28 += beam->unk20 * (2.0f + ((f32) randomGetNext() * 2.3283064e-10f * 0.5f)); - } - - if (beam->unk1c <= beam->unk28) - { - beam->unk00 = -1; - return; - } - - beam->unk00++; - } -} - -// Address: 0x7F062BE4 -void gunRenderFirstPersonGunModels(Gfx **gdlptr) -{ - Gfx *gdl = *gdlptr; - ModelRenderData renderdata; - s32 handnum; - Model *model; - - renderdata = *(ModelRenderData *)&D_80035CC0; - - for (handnum = 0; handnum != 2; handnum++) - { - struct hand *handptr = &g_CurrentPlayer->hands[handnum]; - s32 item = get_item_in_hand_or_watch_menu(handnum); - - if (handptr->field_87F == 0) - { - continue; - } - - if (item != ITEM_WATCHLASER) - { - gdl = sub_GAME_7F061E18(gdl, &handptr->weapon_beam, 0); - } - - if (item == ITEM_GOLDENGUN || item == ITEM_RUGER || item == ITEM_KNIFE || item == ITEM_THROWKNIFE || item == ITEM_SILVERWPPK || item == ITEM_GOLDWPPK) - { - gSPSetLights1(gdl++, g_WeaponEnvmapLight); - gSPLookAt(gdl++, sub_GAME_7F078474()); - } - - gSPPerspNormalize(gdl++, matrix_4x4_calc_depth_scale(0.0f, 300.0f)); - - if ((*(Model *)&handptr->field_B68).obj->numSwitches >= 0x11 && (*(Model *)&handptr->field_B68).obj->Switches[16] != NULL) - { - union ModelRwData *rwdata; - model = (Model *)&handptr->field_B68; - rwdata = modelGetNodeRwData(model, (*(Model *)&handptr->field_B68).obj->Switches[17]); - - if (rwdata != NULL) - { - rwdata->Raw.unk00 = 1; - } - - if (item == ITEM_ROCKETLAUNCH) - { - save_img_index_to_obj_ani_slot(&g_UnknownAnimController, crosshairimage); - gdl = process_monitor_animation_microcode(model, (*(Model *)&handptr->field_B68).obj->Switches[16], &g_UnknownAnimController, gdl, 0, 4); - } - else - { - gdl = process_monitor_animation_microcode(model, (*(Model *)&handptr->field_B68).obj->Switches[16], &g_TaserAnimController, gdl, 0, 1); - } - } - - renderdata.gdl = gdl; - renderdata.PropType = 4; - renderdata.envcolour.word = g_CurrentPlayer->tileColor.a - | ((u32)g_CurrentPlayer->tileColor.r << 24) - | ((u32)g_CurrentPlayer->tileColor.g << 16) - | ((u32)g_CurrentPlayer->tileColor.b << 8); - renderdata.zbufferenabled = 0; - - matrix_4x4_7F058C64(); - - if (item == ITEM_ROCKETLAUNCH && handptr->rocket != NULL) - { - model = handptr->rocket->model; - - subdraw(&renderdata, model); - bondviewTransformManyPosToViewMatrix(model->render_pos, model->obj->numMatrices); - - if (handptr->firedrocket != 0) - { - handptr->rocket = NULL; - } - } - - if (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_MIRROR_DUAL) != 0) - { - gSPClearGeometryMode(renderdata.gdl++, G_CULL_BOTH); - - if (handnum == 0) - { - renderdata.cullmode = 3; - } - else - { - renderdata.cullmode = 2; - } - } - - subdraw(&renderdata, (Model *)&handptr->field_B68); - gdl = renderdata.gdl; - - if (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_MIRROR_DUAL) != 0) - { - gSPClearGeometryMode(gdl++, G_CULL_BOTH); - } - - bondviewTransformManyPosToViewMatrix((*(Model *)&handptr->field_B68).render_pos, (*(Model *)&handptr->field_B68).obj->numMatrices); - matrix_4x4_7F058C88(); - - gSPPerspNormalize(gdl++, viGetPerspNorm()); - - if (item == ITEM_WATCHLASER) - { - gdl = sub_GAME_7F061E18(gdl, &handptr->weapon_beam, 0); - } - } - - *gdlptr = gdl; -} - - -Gfx *set_enviro_fog_for_items_in_solo_watch_menu(Gfx *gdl, ITEM_IDS itemid, Mtxf *mtx, s32 arg3, s32 arg4) -{ - ModelRenderData renderdata = *((ModelRenderData *) (&D_80035D00)); - ModelHeader model; - u8 spb8[0x80]; - s32 padb4; - Mtxf sp74; - Mtxf *matrices; - union ModelRwData *rwdata; - s32 i; - s32 j; - ModelFileHeader *bodymodel; - - if ((itemid == ITEM_TRIGGER) || (itemid == ITEM_WATCHLASER)) - { - itemid = ITEM_WATCHMAGNETATTRACT; - } - - sub_GAME_7F05DA8C(GUNRIGHT, itemid); - - if ((!Gun_hand_without_item(GUNRIGHT)) || (!get_itemtype_in_hand(GUNRIGHT))) - { - return gdl; - } - - bodymodel = &g_CurrentPlayer->copy_of_body_obj_header[GUNRIGHT]; - - if (!get_ptr_weapon_model_header_line(itemid)) - { - goto earlyreturn; - } - - if (bondwalkItemCheckBitflags(itemid, WEAPONSTATBITFLAG_HIDE_FIRST_PERSON_MENU)) - { - goto earlyreturn; - } - - matrices = dynAllocate(bodymodel->numMatrices << 6); - - for (i = 0; i < bodymodel->numMatrices; i++) - { - matrix_4x4_set_identity(&matrices[i]); - } - - i = 0; - ((Model *) &model)->render_pos = matrices; - modelCalculateRwDataLen(bodymodel); - modelInit((Model *) &model, bodymodel, spb8); - sub_GAME_7F05E978((Model *) &model, 0); - sub_GAME_7F05EA94((Model *) &model, 1); - - if (bodymodel->Switches[1] != NULL) - { - rwdata = modelGetNodeRwData((Model *) &model, bodymodel->Switches[1]); - - if (rwdata != 0) - { - rwdata->Raw.unk00 = 0; - } - } - - matrix_4x4_copy(mtx, matrices); - - if (bodymodel->Skeleton == (&skeleton_gun_revolver)) - { - if (bodymodel->Switches[4] != NULL) - { - matrix_4x4_set_identity_and_position((coord3d *) bodymodel->Switches[4]->Data, &sp74); - matrix_4x4_multiply(mtx, &sp74, &matrices[3]); - } - if (bodymodel->Switches[5] != NULL) - { - matrix_4x4_set_identity_and_position((coord3d *) bodymodel->Switches[5]->Data, &sp74); - matrix_4x4_multiply(mtx, &sp74, &matrices[4]); - } - } - - if (bodymodel->Switches[6] != NULL) - { - coord3d *pos; - s32 index; - - pos = (coord3d *) bodymodel->Switches[6]->Data; - index = modelFindNodeMtxIndex(bodymodel->Switches[6], 0); - matrix_4x4_set_identity_and_position(pos, &sp74); - matrix_4x4_multiply(mtx, &sp74, &matrices[index]); - } - - if (bodymodel->Switches[7] != NULL) - { - coord3d *pos; - s32 index; - u8 pad[8]; - - pos = (coord3d *) bodymodel->Switches[7]->Data; - index = modelFindNodeMtxIndex(bodymodel->Switches[7], 0); - matrix_4x4_set_identity_and_position(pos, &sp74); - matrix_4x4_multiply(mtx, &sp74, &matrices[index]); - } - - if (bodymodel->numSwitches >= 19) - { - for (j = 0; j != 20; j += 4) - { - if ((*((ModelNode **) ((((u8 *) bodymodel->Switches) + j) + 0x48))) != NULL) - { - rwdata = modelGetNodeRwData((Model *) &model, *((ModelNode **) ((((u8 *) bodymodel->Switches) + j) + 0x48))); - - if (rwdata != NULL) - { - rwdata->Raw.unk00 = 1; - } - } - - if ((*((ModelNode **) ((((u8 *) bodymodel->Switches) + j) + 0x5c))) != NULL) - { - rwdata = modelGetNodeRwData((Model *) &model, *((ModelNode **) ((((u8 *) bodymodel->Switches) + j) + 0x5c))); - - if (rwdata != NULL) - { - rwdata->Raw.unk00 = 1; - } - } - } - } - - modelUpdateNodeRelations((Model *) &model); - - if ((((((itemid == ITEM_GOLDENGUN) || (itemid == ITEM_RUGER)) || (itemid == ITEM_KNIFE)) || (itemid == ITEM_THROWKNIFE)) || (itemid == ITEM_SILVERWPPK)) || (itemid == ITEM_GOLDWPPK)) - { - gSPSetLights1(gdl++, g_WeaponEnvmapLight); - gSPLookAt(gdl++, sub_GAME_7F078474()); - } - - if (bodymodel->numSwitches >= 17) - { - if (bodymodel->Switches[16] != NULL) - { - rwdata = modelGetNodeRwData((Model *) &model, bodymodel->Switches[17]); - - if (rwdata != 0) - { - rwdata->Raw.unk00 = 0; - } - } - } - - renderdata.gdl = gdl; - - if (arg3 >= 0xff) - { - renderdata.PropType = PROP_TYPE_WEAPON; - renderdata.envcolour.word = arg4; - } - else - { - renderdata.PropType = PROP_TYPE_PLAYER; - renderdata.envcolour.word = arg3; - renderdata.fogcolour.word = arg4; - } - - renderdata.zbufferenabled = FALSE; - subdraw(&renderdata, (Model *) &model); - gdl = renderdata.gdl; - matrix_4x4_7F058C64(); - j = 0; - - if (bodymodel->numMatrices > 0) - { - do - { - matrix_4x4_copy((Mtxf *) (((u8 *) ((Model *) &model)->render_pos) + j), &sp74); - matrix_4x4_f32_to_s32(&sp74, (Mtxf *) ((i << 6) + (u8 *) ((Model *) &model)->render_pos)); - i++; - j += 0x40; - } - while (i < bodymodel->numMatrices); - } - - matrix_4x4_7F058C88(); - -earlyreturn: - return gdl; - -} - - -void sub_GAME_7F0634D8(s32 arg0, s32 arg1, s32 arg2, s32 arg3) -{ - set_enviro_fog_for_items_in_solo_watch_menu(arg0, arg1, arg2, arg3, -256); -} - - -// Unreferenced -void sub_GAME_7F0634FC(s32 arg0, s32 arg1, s32 arg2) -{ - sub_GAME_7F0634D8(arg0, arg1, arg2, 0xFF); -} - - -void sub_GAME_7F06351C(struct coord3d* arg0, Mtxf* arg1, Mtxf* arg2, Mtxf* arg3, struct coord3d* arg4, Mtxf* arg5, Mtxf* arg6) -{ - Mtxf sp20; - - matrix_4x4_set_identity_and_position(arg0, arg6); - matrix_4x4_multiply_in_place(arg1, arg6); - matrix_4x4_multiply_in_place(arg2, arg6); - matrix_4x4_multiply_in_place(arg3, arg6); - matrix_4x4_set_identity_and_position(arg4, &sp20); - matrix_4x4_multiply_in_place(&sp20, arg6); - matrix_4x4_multiply_in_place(arg5, arg6); -} - - -/** - * Address: 7F06359C - */ -Gfx* watchRenderController(Gfx* gdl, Mtxf* basemtx, s32 envcolour, bool animatebuttons, WatchContButtonPositions* buttonpositions, s8* contpadnum) -{ - ModelRenderData renderdata; - struct ModelHeader modelstack; - s32 i; - s32 j; - s32 offset; - f32 angle; - u32 rwdata[26]; - u32 pad2; - Mtxf sp41c; - Mtxf sp3dc; - struct ModelFileHeader* objheader; - struct coord3d* position; - Mtxf* matrices; - ModelNode* node; - Mtxf sp38c; - Mtxf sp34c; - Mtxf sp30c; - Mtxf sp2cc; - Mtxf sp28c; - Mtxf sp24c; - Mtxf sp20c; - Mtxf sp1cc; - struct coord3d coord_node2; - struct coord3d coord_node11_pos; - struct coord3d coord_node11_base; - struct coord3d coord_node4_pos; - struct coord3d coord_node4_base; - struct coord3d coord_node5_pos; - struct coord3d coord_node5_base; - struct coord3d coord_node6_pos; - struct coord3d coord_node6_base; - struct coord3d coord_node7_pos; - struct coord3d coord_node7_base; - struct coord3d coord_node9_pos; - struct coord3d coord_node9_base; - struct coord3d coord_node8_pos; - struct coord3d coord_node8_base; - struct coord3d coord_node10_pos; - struct coord3d coord_node10_base; - struct coord3d coord_node3_pos; - Mtxf spb4; - struct coord3d coord_node3_base; - struct coord3d coord_node1_pos; - struct coord3d coord_node1_base; - struct coord3d coord_node12_pos; - struct coord3d coord_node12_base; - - renderdata = *(ModelRenderData *)((u8 *)D_80035D04 + 0x3c); - - sub_GAME_7F05DA8C(GUNRIGHT, 0x55); - - if (!(Gun_hand_without_item(GUNRIGHT) && get_itemtype_in_hand(GUNRIGHT))) - { - return gdl; - } - - objheader = g_CurrentPlayer->copy_of_body_obj_header; - matrices = dynAllocate(objheader->numMatrices * (sizeof(Mtxf))); - modelCalculateRwDataLen(objheader); - - if (objheader); - - modelInit(&modelstack, objheader, rwdata); - modelstack.render_pos = (RenderPosView*) matrices; - matrix_4x4_copy(basemtx, &matrices[0]); - - for (i = 1; i < 13; i++) - { - position = objheader->Switches[i]->Data; - - // Update joy stick position and rotation. - if (i == 2) - { - angle = ((((-(f32) joyGetStickX(*contpadnum)) * M_TAU_F) * 0.6f)) / 360.0f; - matrix_4x4_set_rotation_around_z(angle, &sp41c); - angle = ((((-(f32) joyGetStickY(*contpadnum)) * M_TAU_F) * 0.6f)) / 360.0f; - matrix_4x4_set_rotation_around_x(angle, &sp3dc); - matrix_4x4_multiply_in_place(&sp3dc, &sp41c); - matrix_4x4_set_position(position, &sp41c); - } - else - { - matrix_4x4_set_identity_and_position(position, &sp41c); - } - - matrix_4x4_multiply(basemtx, &sp41c, &matrices[i]); - } - - modelUpdateNodeRelations(&modelstack); - renderdata.gdl = gdl; - - if (envcolour >= 0xff) - { - renderdata.PropType = PROP_TYPE_OBJ; - } - else - { - renderdata.PropType = PROP_TYPE_PLAYER; - renderdata.envcolour.word = envcolour; - renderdata.fogcolour.word = 0xFFFFFF00; - } - - renderdata.zbufferenabled = TRUE; - subdraw(&renderdata, &modelstack); - gdl = renderdata.gdl; - matrix_4x4_7F058C64(); - - for (i = 0; i < objheader->numMatrices; i++) - { - matrix_4x4_copy((u32)modelstack.render_pos + i * sizeof(Mtxf), &sp41c); - matrix_4x4_f32_to_s32(&sp41c, &modelstack.render_pos[i]); - } - - matrix_4x4_7F058C88(); - - if (animatebuttons) - { - node = objheader->Switches[13]; - - if (node) - { - *((s32*) modelGetNodeRwData(&modelstack, node)) = 0; - } - - matrices = dynAllocate(objheader->numMatrices * (sizeof(Mtxf))); - modelstack.render_pos = (RenderPosView*) matrices; - - // Update the positions and/or rotations of the free floating buttons on the sides of the screen. - for (i = 0; i < 13; i++) - { - matrix_4x4_set_lookat_target(&sp20c, -5.0f, 2000.0f, -168.0f, -5.0f, 0.0f, -168.0f, 0.0f, 0.0f, -1.0f); - matrix_4x4_set_lookat_target(&sp38c, -5.0f, 2000.0f, -168.0f, -5.0f, 0.0f, -168.0f, 0.0f, 0.0f, -1.0f); - matrix_4x4_set_identity(&sp24c); - matrix_4x4_set_identity(&sp1cc); - matrix_4x4_copy(&sp1cc, &sp2cc); - - // Joy stick - if (i == 2) - { - coord_node2 = buttonpositions->joystick; - matrix_4x4_set_identity_and_position(&coord_node2, &sp34c); - angle = ((((-(f32) joyGetStickX(*contpadnum)) * M_TAU_F) * 0.6f)) / 360.0f; - matrix_4x4_set_rotation_around_z(angle, &sp41c); - angle = ((((-(f32) joyGetStickY(*contpadnum)) * M_TAU_F) * 0.6f)) / 360.0f; - matrix_4x4_set_rotation_around_x(angle, &sp3dc); - matrix_4x4_multiply_in_place(&sp3dc, &sp41c); - matrix_4x4_multiply_in_place(&sp34c, &sp41c); - matrix_4x4_multiply(&sp20c, &sp41c, &sp30c); - matrix_4x4_copy(&sp30c, &matrices[i]); - } - // R - else if (i == 11) - { - coord_node11_base = ((struct coord3d *)watchControllerButtonBases)[5]; - coord_node11_pos = buttonpositions->r; - - if (joyGetButtons(*contpadnum, R_TRIG)) - { - matrix_4x4_set_rotation_around_y(-0.17453294f, &sp24c); - } - - matrix_4x4_set_rotation_around_x(1.0471976f, &sp28c); - sub_GAME_7F06351C(&coord_node11_base, &sp24c, &sp28c, &sp1cc, &coord_node11_pos, &sp20c, &sp38c); - matrix_4x4_copy(&sp38c, &matrices[i]); - } - // C-Up - else if (i == 4) - { - coord_node4_base = ((struct coord3d *)watchControllerButtonBases)[6]; - coord_node4_pos = buttonpositions->cUp; - - if (joyGetButtons(*contpadnum, U_CBUTTONS)) - { - coord_node4_base.y += -10.0f; - } - - matrix_4x4_set_rotation_around_x(-1.0471976f, &sp28c); - sub_GAME_7F06351C(&coord_node4_base, &sp24c, &sp28c, &sp1cc, &coord_node4_pos, &sp20c, &sp38c); - matrix_4x4_copy(&sp38c, &matrices[i]); - } - // C-Down - else if (i == 5) - { - coord_node5_base = ((struct coord3d *)watchControllerButtonBases)[7]; - coord_node5_pos = buttonpositions->cDown; - - if (joyGetButtons(*contpadnum, D_CBUTTONS)) - { - coord_node5_base.y += -10.0f; - } - - matrix_4x4_set_rotation_around_x(-1.0471976f, &sp28c); - sub_GAME_7F06351C(&coord_node5_base, &sp24c, &sp28c, &sp1cc, &coord_node5_pos, &sp20c, &sp38c); - matrix_4x4_copy(&sp38c, &matrices[i]); - } - // C-Left - else if (i == 6) - { - coord_node6_base = ((struct coord3d *)watchControllerButtonBases)[8]; - coord_node6_pos = buttonpositions->cLeft; - - if (joyGetButtons(*contpadnum, L_CBUTTONS)) - { - coord_node6_base.y += -10.0f; - } - - matrix_4x4_set_rotation_around_x(-1.0471976f, &sp28c); - sub_GAME_7F06351C(&coord_node6_base, &sp24c, &sp28c, &sp1cc, &coord_node6_pos, &sp20c, &sp38c); - matrix_4x4_copy(&sp38c, &matrices[i]); - } - // C-Right - else if (i == 7) - { - coord_node7_base = ((struct coord3d *)watchControllerButtonBases)[9]; - coord_node7_pos = buttonpositions->cRight; - - if (joyGetButtons(*contpadnum, R_CBUTTONS)) - { - coord_node7_base.y += -10.0f; - } - - matrix_4x4_set_rotation_around_x(-1.0471976f, &sp28c); - sub_GAME_7F06351C(&coord_node7_base, &sp24c, &sp28c, &sp1cc, &coord_node7_pos, &sp20c, &sp38c); - matrix_4x4_copy(&sp38c, &matrices[i]); - } - // B - else if (i == 9) - { - coord_node9_base = ((struct coord3d *)watchControllerButtonBases)[10]; - coord_node9_pos = buttonpositions->b; - - if (joyGetButtons(*contpadnum, B_BUTTON)) - { - coord_node9_base.y += -10.0f; - } - - matrix_4x4_set_rotation_around_x(-1.0471976, &sp28c); - sub_GAME_7F06351C(&coord_node9_base, &sp24c, &sp28c, &sp1cc, &coord_node9_pos, &sp20c, &sp38c); - matrix_4x4_copy(&sp38c, &matrices[i]); - } - // A - else if (i == 8) - { - coord_node8_base = ((struct coord3d *)watchControllerButtonBases)[11]; - coord_node8_pos = buttonpositions->a; - - if (joyGetButtons(*contpadnum, A_BUTTON)) - { - coord_node8_base.y += -10.0f; - } - - matrix_4x4_set_rotation_around_x(-1.0471976f, &sp28c); - sub_GAME_7F06351C(&coord_node8_base, &sp24c, &sp28c, &sp1cc, &coord_node8_pos, &sp20c, &sp38c); - matrix_4x4_copy(&sp38c, &matrices[i]); - } - // L - else if (i == 10) - { - coord_node10_base = ((struct coord3d *)watchControllerButtonBases)[12]; - coord_node10_pos = buttonpositions->l; - - if (joyGetButtons(*contpadnum, L_TRIG)) - { - matrix_4x4_set_rotation_around_y(0.17453294f, &sp24c); - } - - matrix_4x4_set_rotation_around_x(1.0471976f, &sp28c); - sub_GAME_7F06351C(&coord_node10_base, &sp24c, &sp28c, &sp1cc, &coord_node10_pos, &sp20c, &sp38c); - matrix_4x4_copy(&sp38c, &matrices[i]); - } - // D-pad - else if (i == 3) - { - coord_node3_base = ((struct coord3d *)watchControllerButtonBases)[13]; - coord_node3_pos = buttonpositions->dPad; - matrix_4x4_set_identity(&spb4); - - if (joyGetButtons(*contpadnum, U_JPAD)) - { - matrix_4x4_set_rotation_around_x(-0.17453294f, &sp24c); - } - else if (joyGetButtons(*contpadnum, D_JPAD)) - { - matrix_4x4_set_rotation_around_x(0.17453294f, &sp24c); - } - - if (joyGetButtons(*contpadnum, L_JPAD)) - { - matrix_4x4_set_rotation_around_z(0.17453294f, &spb4); - } - else if (joyGetButtons(*contpadnum, R_JPAD)) - { - matrix_4x4_set_rotation_around_z(-0.17453294f, &spb4); - } - - matrix_4x4_multiply_in_place(&spb4, &sp24c); - matrix_4x4_set_rotation_around_x(-0.89759791f, &sp28c); - sub_GAME_7F06351C(&coord_node3_base, &sp24c, &sp28c, &sp1cc, &coord_node3_pos, &sp20c, &sp38c); - matrix_4x4_copy(&sp38c, &matrices[i]); - } - // Start - else if (i == 1) - { - coord_node1_base = ((struct coord3d *)watchControllerButtonBases)[14]; - coord_node1_pos = buttonpositions->start; - - if (joyGetButtons(*contpadnum, START_BUTTON)) - { - coord_node1_base.y += -10.0f; - } - - matrix_4x4_set_rotation_around_x(-1.0471976f, &sp28c); - sub_GAME_7F06351C(&coord_node1_base, &sp24c, &sp28c, &sp1cc, &coord_node1_pos, &sp20c, &sp38c); - matrix_4x4_copy(&sp38c, &matrices[i]); - } - // Z - else if (i == 12) - { - coord_node12_base = ((struct coord3d *)watchControllerButtonBases)[15]; - coord_node12_pos = buttonpositions->z; - - if (joyGetButtons(*contpadnum, Z_TRIG)) - { - matrix_4x4_set_rotation_around_x(-0.17453294f, &sp24c); - } - - matrix_4x4_set_rotation_around_z(M_PI_F, &sp28c); - sub_GAME_7F06351C(&coord_node12_base, &sp24c, &sp28c, &sp1cc, &coord_node12_pos, &sp20c, &sp38c); - matrix_4x4_copy(&sp38c, &matrices[i]); - } - else - { - matrix_4x4_copy(basemtx, &matrices[i]); - } - } - - modelUpdateNodeRelations(&modelstack); - renderdata.gdl = gdl; - subdraw(&renderdata, &modelstack); - gdl = renderdata.gdl; - matrix_4x4_7F058C64(); - - for (i = 0; i < objheader->numMatrices; i++) - { - matrix_4x4_copy((u32)modelstack.render_pos + i * sizeof(Mtxf), &sp41c); - matrix_4x4_f32_to_s32(&sp41c, &modelstack.render_pos[i]); - } - - matrix_4x4_7F058C88(); - } - - return gdl; -} - - -/** - * Address: 7F064364 - */ -Gfx *watchRenderControllerOpaque(Gfx *gdl, Mtxf *basemtx, bool animatebuttons, WatchContButtonPositions *buttonpositions, s8 *contpadnum) -{ - return watchRenderController(gdl, basemtx, 0xff, animatebuttons, buttonpositions, contpadnum); -} - - -/** - * Address: 7F0643A0 - */ -ALSoundState* gunGetFreeSfxState(void) -{ - s32 i; - - for (i = 0; i < NUM_IMPACT_SFX_STATES; i++) - { - if (g_ImpactSfxStates[i] == NULL) - { - return &g_ImpactSfxStates[i]; - } - } - - return NULL; -} - - -void recall_joy2_hits_edit_detail_edit_flag(enum ITEM_IDS item, PropRecord* prop, s32 texture_index) -{ - s32 sp6C; - u32 rnd1; - u32 rnd2; - ALSoundState* sound_state; - struct RicochetSoundsSmall ricochet_sounds_small_copy; - struct PunchSounds punch_sounds_copy; - struct BulletFleshSounds bullet_flesh_sounds_copy; - u32 sfx_index; - - sp6C = sub_GAME_7F0539E4(&prop->pos); - - rnd1 = randomGetNext(); - rnd2 = randomGetNext(); - - D_800483C4 = texture_index; - - if (get_debug_joy2hitsedit_flag() == 0) - { - get_debug_joy2detailedit_flag(); - } - - if ((item == ITEM_REMOTEMINE) - || (item == ITEM_PROXIMITYMINE) - || (item == ITEM_TIMEDMINE) - || (item == ITEM_BOMBCASE) - || (item == ITEM_BUG) - || (item == ITEM_MICROCAMERA) - || (item == ITEM_PLASTIQUE) - || (item == ITEM_WATCHLASER) - || (item == ITEM_WATCHMAGNETATTRACT)) - { - return; - } - -#ifdef BUGFIX_R1 - if (g_ClockTimer <= 0) { return; } #endif - sound_state = gunGetFreeSfxState(); - if (sound_state != NULL) - { - if ((prop->type != PROP_TYPE_CHR) && (prop->type != PROP_TYPE_VIEWER)) - { - if (item == ITEM_LASER) - { - sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, RICO_LASER1_SFX, sound_state); - } - else - { - ricochet_sounds_small_copy = ricochet_sounds_small; - sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, ricochet_sounds_small_copy.arr[rnd1 % 20], sound_state); - } - - if (sound_state->link.next != NULL) - { - sndCreatePostEvent((ALSoundState* ) sound_state->link.next, 8, sp6C); - } - } - else - { - if (item == ITEM_KNIFE) - { - sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, HIT_BULLET_SNOW_SFX, sound_state); - } - else if (item == ITEM_FIST) - { - punch_sounds_copy = punch_sounds; - sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, punch_sounds_copy.arr[rnd1 % 3], sound_state); - } - else - { - bullet_flesh_sounds_copy = bullet_flesh_sounds; - sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, bullet_flesh_sounds_copy.arr[rnd1 % 2], sound_state); - } - - if (sound_state->link.next != NULL) { - sndCreatePostEvent((ALSoundState* ) sound_state->link.next, 8, sp6C); - } - } - } - - sound_state = gunGetFreeSfxState(); - if ((sound_state != NULL) && (texture_index >= 0)) - { - if (g_HitTypeSounds[g_Textures[texture_index].hitSound] != NULL) - { - if (g_HitTypeSounds[g_Textures[texture_index].hitSound]->sfx_len > 0) - { - sfx_index = rnd2 % g_HitTypeSounds[g_Textures[texture_index].hitSound]->sfx_len; - sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, g_HitTypeSounds[g_Textures[texture_index].hitSound]->sfx[sfx_index], sound_state); - } - - if (sound_state->link.next != NULL) - { - chrobjSndCreatePostEventDefault((ALSoundState* ) sound_state->link.next, &prop->pos); - } - } - } -#ifdef DEBUG - osSyncPrintf("Shot prop: hittype %d\n", g_Textures[texture_index].hitSound); -#endif -#ifdef ENABLE_LOG - osSyncPrintf("Shot prop: %S\n", HIT_TYPE_ToString[g_Textures[texture_index].hitSound]); -#endif -} - - -void sub_GAME_7F064720(coord3d* pos) -{ - ALSoundState* sound; - ALLink* link; - -#ifdef BUGFIX_R1 - if (g_ClockTimer <= 0) { return; } -#endif - - sound = gunGetFreeSfxState(); - - if (sound != NULL) - { - sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, HIT_BULLET_GLASS_SFX, sound); - - link = sound->link.next; - if (link != NULL) - { - chrobjSndCreatePostEventDefault((ALSoundState* ) link, pos); - } - } -} - - -void recall_joy2_hits_edit_flag(enum ITEM_IDS item, coord3d* arg1, s32 texture_index) -{ - ALSoundState *sound_state; - u32 rnd1; - u32 rnd2; - struct LaserRichochetSounds laser_copied; - struct RicochetSoundsLarge rico_copied; - u32 sfx_index; - struct image_sound *img_sound; - - rnd1 = randomGetNext(); - rnd2 = randomGetNext(); - - D_800483C4 = texture_index; - get_debug_joy2hitsedit_flag(); - -#ifdef BUGFIX_R1 - if (g_ClockTimer <= 0) { return; } -#endif - - sound_state = gunGetFreeSfxState(); - if (sound_state != NULL) - { - if (item != ITEM_WATCHLASER) - { - if (item == ITEM_LASER) - { - laser_copied = laser_ricochet_sounds; - sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, laser_copied.arr[rnd1 % 2], sound_state); - } - else - { - rico_copied = ricochet_sounds_large; - sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, rico_copied.arr[rnd1 % 36], sound_state); - } - } - - if (sound_state->link.next != NULL) - { - chrobjSndCreatePostEventDefault((ALSoundState* ) sound_state->link.next, arg1); - } - } - - sound_state = gunGetFreeSfxState(); - if ((sound_state != NULL) && (texture_index >= 0)) - { - img_sound = g_HitTypeSounds[g_Textures[texture_index].hitSound]; - if (img_sound->sfx_len > 0) - { - if (img_sound != NULL) - { - sfx_index = rnd2 % img_sound->sfx_len; - sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, img_sound->sfx[sfx_index], sound_state); - } - - if (sound_state->link.next != NULL) - { - chrobjSndCreatePostEventDefault((ALSoundState* ) sound_state->link.next, arg1); - } - } - } -} - - -void sub_GAME_7F064934(ITEM_IDS item) -{ - struct EarWhistleSounds copied; - -#ifdef BUGFIX_R1 - if (g_ClockTimer <= 0) { return; } -#endif - if ((item != ITEM_LASER) && (item != ITEM_WATCHLASER)) - { - copied = ear_whistle_sounds; - sndPlaySfx((struct ALBankAlt_s*) g_musicSfxBufferPtr, copied.arr[randomGetNext() % 5], 0); - } -} - - -f32 sub_GAME_7F0649AC(s32 param_1) -{ - f32 fVar1; - - fVar1 = -60.0f; - if (param_1 == 0x19) { - fVar1 -= 20.0f; - } - return fVar1; -} - - - -void sub_GAME_7F0649D8(enum GUNHAND hand) -{ - struct hand* hand_ptr; - enum ITEM_IDS item_id; - s32 ammo_in_magazine; - s32 ammo_in_hands; - WeaponStats* item_stats; - s32 magsize; - s32 ammo_total; - - hand_ptr = &g_CurrentPlayer->hands[hand]; - item_id = getCurrentPlayerWeaponId(hand); - ammo_in_magazine = hand_ptr->weapon_ammo_in_magazine; - ammo_in_hands = get_ammo_in_hands_weapon(hand); - item_stats = get_ptr_item_statistics(item_id); - ammo_total = ammo_in_hands + ammo_in_magazine; - - hand_ptr->weapon_ammo_in_magazine = (ammo_total >= item_stats->MagSize) - ? item_stats->MagSize - : ammo_total; - - g_CurrentPlayer->ammoheldarr[item_stats->AmmoType] = (bondwalkItemCheckBitflags(item_id, WEAPONSTATBITFLAG_AMMO_CLIP_LIMIT) != 0) - ? 0 - : (g_CurrentPlayer->ammoheldarr[item_stats->AmmoType] - hand_ptr->weapon_ammo_in_magazine) + ammo_in_magazine; - - if (item_id == ITEM_ROCKETLAUNCH) - { - currentPlayerCreateRocket(hand); - return; - } - - if ((item_id == ITEM_SHOTGUN) || (item_id == ITEM_AUTOSHOT)) - { - ammo_in_hands = get_ammo_in_hands_weapon(hand); - if (ammo_in_hands >= 5) - { - hand_ptr->numvisibleshells = 5; - return; - } - hand_ptr->numvisibleshells = ammo_in_hands; - } -} - -#if defined(VERSION_US) || defined(VERSION_JP) - #define WEAPON_1P_ANIM_TIME(x) ((f32)(x)) - #define WHEN_1_CASE_GRENADELAUNCH_FLD890 6 - #define WHEN_1_CASE_GRENADE_FLD890 0xf0 - #define WHEN_D_FLD890 0x14 - #define WHEN_5_SP188_INIT 0x10 - #define WHEN_5_SP188_MULTI 0xc - #define WHEN_5_FLD8B0_SP 0x11 - #define WHEN_5_FLD8B0_MULTI 0xd - #define WHEN_8_SP178_INIT 0x17 - #define WHEN_8_SP178_MULTI 0xc - #define WHEN_A_FLD890 0x10 - #define WHEN_A_FLD8B0 0x11 - #define WHEN_C_FLD890 0x17 - #define WHEN_E_FLD890 0x10 - #define WHEN_10_FLD890 0x17 - #define WHEN_11_FLD890_1 0x10 - #define WHEN_11_FLD890_2 0x18 - #define WHEN_1E_FLD890 0x1e -#endif -#if defined(VERSION_EU) - #define WEAPON_1P_ANIM_TIME(x) ((f32)(x)) * 60.0f / 50.0f - #define WHEN_1_CASE_GRENADELAUNCH_FLD890 5 - #define WHEN_1_CASE_GRENADE_FLD890 0xc8 - #define WHEN_D_FLD890 0x10 - #define WHEN_5_SP188_INIT 0xd - #define WHEN_5_SP188_MULTI 0xa - #define WHEN_5_FLD8B0_SP 0xe - #define WHEN_5_FLD8B0_MULTI 0xa - #define WHEN_8_SP178_INIT 0x13 - #define WHEN_8_SP178_MULTI 0xa - #define WHEN_A_FLD890 0xd - #define WHEN_A_FLD8B0 0xe - #define WHEN_C_FLD890 0x13 - #define WHEN_E_FLD890 0xd - #define WHEN_10_FLD890 0x13 - #define WHEN_11_FLD890_1 0xd - #define WHEN_11_FLD890_2 0x14 - #define WHEN_1E_FLD890 0x19 -#endif - - -/** - * Address: 7F064B28 - */ -void gunTickHandState(enum GUNHAND hand, s32 triggerOn) -{ -#if defined(VERSION_US) - s32 stack1; - s32 stack2; - s32 sp1C4; - s32 stack3; - struct hand *sp1BC; - s32 stack4; - s32 sp1B4; - struct sfx2 sp1B0; - s32 stack5; - struct WeaponStats *weapon_stats; - s32 sp1A4; - s32 sp1A0; - f32 sp19C; - f32 sp198; - s32 stack7; - f32 sp190; - f32 sp18C; - s32 sp188; - f32 sp184; - s32 stack8; - s32 stack9; - s32 sp178; - f32 sp174; - s32 stack10; - s32 stack11; - Mtxf sp12C; - f32 sp128; - s32 stack12; - Mtxf spE4; - f32 tempf; - struct hand *handptr; - Mtxf sp9C; - f32 sp98; - f32 sp94; - enum ITEM_IDS temp_v0_3; - f32 sp8C; - f32 sp88; - enum ITEM_IDS var_s1; - struct sfx3 sp7C; - struct PropRecord *temp_v0_8; - Weapon1PTransformKeyframe *sp74; - f32 temp_f0_2; - u32 var_a0_2; - f32 temp_v1_9; - struct hand *temp_v1_5; - f32 un_f32_num = 0.0f; - f32 un_f32_div_1 = 16.0f; - f32 un_f32_div_2 = 23.0f; - s32 stack14; - s32 stack15; -#endif -#if defined(VERSION_JP) - s32 stack1; - s32 stack2; - s32 sp1C4; - s32 stack3; - struct hand *sp1BC; - s32 stack4; - s32 sp1B4; - struct sfx2 sp1B0; - s32 stack5; - struct WeaponStats *weapon_stats; - s32 sp1A4; - s32 sp1A0; - f32 sp19C; - s32 stat_2; - s32 stat_3; - s32 stat_4; - f32 sp198; - s32 stack14; - f32 sp190; - f32 sp18C; - s32 sp188; - f32 sp184; - s32 stack7; - s32 stack8; - s32 sp178; - f32 sp174; - s32 stack9; - s32 stack10; - Mtxf sp12C; - f32 sp128; - s32 stack11; - Mtxf spE4; - s32 stack12; - f32 tempf; - Mtxf sp9C; - f32 sp98; - f32 sp94; - struct hand *handptr; - f32 sp8C; - f32 sp88; - enum ITEM_IDS temp_v0_3; - struct sfx3 sp7C; - enum ITEM_IDS var_s1; - Weapon1PTransformKeyframe *sp74; - struct PropRecord *temp_v0_8; - f32 temp_f0_2; - u32 var_a0_2; - f32 temp_v1_9; - struct hand *temp_v1_5; - f32 un_f32_num = 0.0f; - f32 un_f32_div_1 = 16.0f; - f32 un_f32_div_2 = 23.0f; - s32 stack15; -#endif -#if defined(VERSION_EU) - s32 stack1; - s32 stack2; - s32 sp1C4; - s32 stack3; - struct hand *sp1BC; - s32 stack4; - s32 sp1B4; - struct sfx2 sp1B0; - s32 stack5; - struct WeaponStats *weapon_stats; - s32 sp1A4; - s32 sp1A0; - f32 sp19C; - s32 stat_2; - s32 stat_3; - s32 stat_4; - f32 sp198; - s32 stack14; - f32 sp190; - f32 sp18C; - s32 sp188; - f32 sp184; - s32 stack7; - s32 stack8; - s32 sp178; - f32 sp174; - s32 stack9; - s32 stack10; - Mtxf sp12C; - f32 sp128; - s32 stack11; - Mtxf spE4; - s32 stack12; - f32 tempf; - Mtxf sp9C; - f32 sp98; - f32 sp94; - struct hand *handptr; - f32 sp8C; - f32 sp88; - enum ITEM_IDS temp_v0_3; - struct sfx3 sp7C; - enum ITEM_IDS var_s1; - Weapon1PTransformKeyframe *sp74; - struct PropRecord *temp_v0_8; - f32 temp_f0_2; - u32 var_a0_2; - f32 temp_v1_9; - struct hand *temp_v1_5; - f32 un_f32_num = 0.0f; - f32 un_f32_div_1 = 13.0f; - f32 un_f32_div_2 = 19.0f; - s32 stack15; -#endif - - handptr = &g_CurrentPlayer->hands[hand]; - var_s1 = get_item_in_hand_or_watch_menu(hand); - sp1C4 = get_ammo_type_for_weapon(var_s1); - - handptr->field_884 = handptr->weapon_hold_time; - handptr->weapon_hold_time = triggerOn; - - if (triggerOn == 0) - { - handptr->field_888 = 1; - } - - handptr->weapon_firing_status = 0; - handptr->field_87D = 0; - - if (g_ClockTimer > 0) - { - handptr->field_890 += g_ClockTimer; - handptr->field_88C += 1; - } - - handptr->field_92C = 0; - - if (handptr->weapon_action_state == GUN_ANIM_STATE_IDLE) - { -#if defined(VERSION_JP) || defined(VERSION_EU) - if ((var_s1 == ITEM_LASER) && (handptr->field_888 != 0)) - { - handptr->field_8A0 = 0; - } -#endif - if ( - (handptr->weapon_hold_time != 0) - && (var_s1 != ITEM_UNARMED) - && (((bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_CLICKY) != 0)) || (handptr->weapon_ammo_in_magazine > 0)) -#if defined(VERSION_JP) || defined(VERSION_EU) - && ((var_s1 != ITEM_LASER) || (handptr->field_8A0 < 0xC8)) -#endif - ) - { - handptr->weapon_action_state = GUN_ANIM_STATE_TRIGGER_PRESS; - handptr->field_890 = 0; - handptr->field_88C = 0; - handptr->field_888 = 0; - } - else - { - if (handptr->weapon_current_animation != 0) - { - handptr->weapon_action_state = handptr->weapon_current_animation; - handptr->field_890 = 0; - handptr->field_88C = 0; - } - } - - handptr->weapon_current_animation = 0; - - if ((handptr->weapon_action_state == GUN_ANIM_STATE_IDLE) - && (handptr->weapon_ammo_in_magazine == 0) - && (sp1C4 != 0)) - { - if ((lvlGetControlsLockedFlag() == 0) && (g_CurrentPlayer->mpmenuon == 0)) - { - /** - * D_80032458 is always 0 so this branch can never execute. - */ - if ((D_80032458 != 0) && (sp1C4 == 1) && (g_CurrentPlayer->ammoheldarr[sp1C4] <= 0)) - { - g_CurrentPlayer->ammoheldarr[sp1C4] = 1; - } - - if (get_ammo_in_hands_weapon(hand) > 0) - { - handptr->weapon_action_state = GUN_ANIM_STATE_RELOAD_START; - handptr->field_890 = 0; - handptr->field_88C = 0; - } - else - { - if (g_CurrentPlayer->trigger_released != 0) - { - temp_v0_3 = get_item_in_hand_or_watch_menu(1 - hand); - - sp1BC = (g_CurrentPlayer->hands - hand) + 1; - - if ((sp1BC->weapon_action_state == GUN_ANIM_STATE_IDLE) - && (sp1BC->weapon_current_animation == 0) - && ( - (temp_v0_3 == ITEM_UNARMED) - || ((sp1BC->weapon_ammo_in_magazine == 0) - && ((get_ammo_type_for_weapon(temp_v0_3) != 0)) - && ((get_ammo_in_hands_weapon(1 - hand) <= 0))))) - { - autoadvance_on_deplete_all_ammo(); - - handptr->field_88C = 0; - handptr->field_890 = 0; - handptr->weapon_action_state = handptr->weapon_current_animation; - handptr->weapon_current_animation = 0; - - sp1BC->field_88C = 0; - sp1BC->field_890 = 0; - sp1BC->weapon_action_state = sp1BC->weapon_current_animation; - sp1BC->weapon_current_animation = 0; - } - } - } - } - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_TRIGGER_PRESS) - { - switch (var_s1) - { - case ITEM_RUGER: - case ITEM_GRENADELAUNCH: - if (handptr->field_890 >= WHEN_1_CASE_GRENADELAUNCH_FLD890) - { - handptr->weapon_action_state = GUN_ANIM_STATE_FIRE; - handptr->field_890 = 0; - handptr->field_88C = 0; - } - break; - case ITEM_CAMERA: - if (handptr->field_88C == 0) - { - currentPlayerSetFadeColour(0, 0, 0, 1.0f); - } - else if (handptr->field_890 > 0) - { - currentPlayerAdjustFade(8.0f, 0, 0, 0, 0.0f); - handptr->weapon_action_state = GUN_ANIM_STATE_FIRE; - handptr->field_890 = 0; - handptr->field_88C = 0; - } - break; - case ITEM_WPPK: - case ITEM_WPPKSIL: - case ITEM_TT33: - case ITEM_SKORPION: - case ITEM_AK47: - case ITEM_UZI: - case ITEM_MP5K: - case ITEM_MP5KSIL: - case ITEM_SPECTRE: - case ITEM_M16: - case ITEM_FNP90: - case ITEM_SHOTGUN: - case ITEM_AUTOSHOT: - case ITEM_SNIPERRIFLE: - case ITEM_GOLDENGUN: - case ITEM_SILVERWPPK: - case ITEM_GOLDWPPK: - case ITEM_LASER: - case ITEM_WATCHLASER: - case ITEM_ROCKETLAUNCH: - case ITEM_TRIGGER: - case ITEM_TANKSHELLS: - case ITEM_FLAREPISTOL: - case ITEM_PITONGUN: - case ITEM_WATCHMAGNETATTRACT: - handptr->weapon_action_state = GUN_ANIM_STATE_FIRE; - handptr->field_890 = 0; - handptr->field_88C = 0; - break; - case ITEM_TIMEDMINE: - case ITEM_PROXIMITYMINE: - case ITEM_REMOTEMINE: - case ITEM_BOMBCASE: - case ITEM_PLASTIQUE: - case ITEM_BUG: - case ITEM_MICROCAMERA: - case ITEM_GOLDENEYEKEY: - handptr->weapon_action_state = GUN_ANIM_STATE_MINE_PLACE; - handptr->field_890 = 0; - handptr->field_88C = 0; - break; - case ITEM_KNIFE: - if (!(randomGetNext() & 1)) - { - handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH1_BEGIN; - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH2_BEGIN; - } - handptr->field_890 = 0; - handptr->field_88C = 0; - break; - case ITEM_GRENADE: - if ((handptr->field_888 != 0) || (handptr->field_890 >= WHEN_1_CASE_GRENADE_FLD890)) - { - g_CurrentPlayer->last_z_trigger_timer = handptr->field_890; - handptr->weapon_action_state = GUN_ANIM_STATE_GRENADE_THROW; - handptr->field_88C = 0; - handptr->field_890 = 0; - } - break; - case ITEM_FIST: - if (!(randomGetNext() & 1)) - { - handptr->weapon_action_state = GUN_ANIM_STATE_PUNCH1_STRIKE; - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_PUNCH2_STRIKE; - } - handptr->field_890 = 0; - handptr->field_88C = 0; - break; - case ITEM_THROWKNIFE: - handptr->weapon_action_state = GUN_ANIM_STATE_THROWKNIFE_DRAW; - handptr->field_890 = 0; - handptr->field_88C = 0; - break; - case ITEM_TASER: - tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); - if (gunSample1PTransform(taserFireKeyFrames, tempf, &handptr->field_8EC, hand) != 0) - { - handptr->field_92C = 1; - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_FIRE; - handptr->field_890 = 0; - handptr->field_88C = 0; - } - break; - case ITEM_BUNGEE: - case ITEM_DOORDECODER: - case ITEM_BOMBDEFUSER: - case ITEM_LOCKEXPLODER: - case ITEM_DOOREXPLODER: - case ITEM_WEAPONCASE: - case ITEM_SAFECRACKERCASE: - case ITEM_KEYANALYSERCASE: - case ITEM_BUGDETECTOR: - case ITEM_EXPLOSIVEFLOPPY: - case ITEM_POLARIZEDGLASSES: - case ITEM_DARKGLASSES: - case ITEM_CREDITCARD: - case ITEM_GASKEYRING: - case ITEM_DATATHIEF: - case ITEM_WATCHIDENTIFIER: - case ITEM_WATCHCOMMUNICATOR: - case ITEM_WATCHGEIGERCOUNTER: - case ITEM_WATCHMAGNETREPEL: - case ITEM_DATTAPE: - case ITEM_KEYCARD: - case ITEM_KEYYALE: - case ITEM_KEYBOLT: - handptr->weapon_action_state = GUN_ANIM_STATE_USE_ITEM; - handptr->field_890 = 0; - handptr->field_88C = 0; - break; - case ITEM_SUIT_LF_HAND: - case ITEM_JOYPAD: - case ITEM_ROCKETROUND: - case ITEM_GRENADEROUND: - case ITEM_TOKEN: - default: - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0; - handptr->field_88C = 0; - break; - } - - handptr->volley = 0; - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_FIRE) - { - if ((get_ammo_type_for_weapon(var_s1) == 0) || (handptr->weapon_ammo_in_magazine > 0)) - { - switch (var_s1) - { - case ITEM_CAMERA: - case ITEM_WATCHMAGNETATTRACT: - if (handptr->field_88C == 0) - { - handptr->weapon_firing_status = (lvlGetControlsLockedFlag() == 0) && (g_CurrentPlayer->mpmenuon == 0); - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL1; - handptr->field_890 = 0; - handptr->field_88C = 0; - } - break; - case ITEM_WPPK: - case ITEM_WPPKSIL: - case ITEM_TT33: - case ITEM_SHOTGUN: - case ITEM_AUTOSHOT: - case ITEM_SNIPERRIFLE: - case ITEM_RUGER: - case ITEM_GOLDENGUN: - case ITEM_SILVERWPPK: - case ITEM_GOLDWPPK: - case ITEM_LASER: - case ITEM_WATCHLASER: - case ITEM_GRENADELAUNCH: - case ITEM_ROCKETLAUNCH: - case ITEM_TRIGGER: - case ITEM_TANKSHELLS: - case ITEM_FLAREPISTOL: - case ITEM_PITONGUN: - if (handptr->field_88C == 0) - { - if ((getPlayerCount() == 1) || ((checkGamePaused() == 0) && (g_CurrentPlayer->mpmenuon == 0))) - { - handptr->field_87D = 1; - } - - handptr->weapon_firing_status = (lvlGetControlsLockedFlag() == 0) && (g_CurrentPlayer->mpmenuon == 0); - - sub_GAME_7F05E808(hand); - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL1; - handptr->field_890 = 0; - handptr->field_88C = 0; - } - break; - case ITEM_SKORPION: - case ITEM_AK47: - case ITEM_UZI: - case ITEM_MP5K: - case ITEM_MP5KSIL: - case ITEM_SPECTRE: - case ITEM_M16: - case ITEM_FNP90: - if ((handptr->field_88C == 0) - || (handptr->weapon_hold_time != 0) - || ((bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_BURST_FIRE) != 0) - && (currentPlayerGetIsAiming() == 0) - && (((s32) handptr->volley % 3) != 0))) - { - if (((s32) handptr->field_88C % bondwalkItemGetAutomaticFiringRate(var_s1)) == 0) - { - if ((getPlayerCount() == 1) || ((checkGamePaused() == 0) && (g_CurrentPlayer->mpmenuon == 0))) - { - handptr->field_87D = 1; - } - - handptr->weapon_firing_status = (lvlGetControlsLockedFlag() == 0) - && (g_CurrentPlayer->mpmenuon == 0); - } - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL1; - handptr->field_890 = 0; - handptr->field_88C = 0; - } - break; - case ITEM_KNIFE: - if ((handptr->field_88C == 0) || (handptr->weapon_hold_time != 0)) - { - handptr->weapon_firing_status = 0; - handptr->field_87D = handptr->weapon_firing_status; - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL1; - handptr->field_890 = 0; - handptr->field_88C = 0; - } - break; - case ITEM_TASER: - if ((handptr->field_88C == 0) || (handptr->weapon_hold_time != 0)) - { - gunSample1PTransform(taserRaiseKeyframes, 0.0f, &handptr->field_8EC, hand); - - handptr->weapon_firing_status = 0; - handptr->field_92C = 1; - handptr->field_87D = handptr->weapon_firing_status; - - if (handptr->field_88C == 0) - { - handptr->weapon_firing_status = (lvlGetControlsLockedFlag() == 0) - && (g_CurrentPlayer->mpmenuon == 0); - } - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL1; - handptr->field_890 = 0; - handptr->field_88C = 0; - } - break; - } - - if (handptr->weapon_firing_status != 0) - { - if (var_s1 != ITEM_CAMERA) - { - joyRumblePakStart(get_cur_playernum(), 0.1f); - - if (cur_player_get_control_type() >= 4) - { - joyRumblePakStart(get_cur_playernum() + getPlayerCount(), 0.1f); - } - } - - handptr->weapon_ammo_in_magazine -= 1; - handptr->volley += 1; - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_FIRE) - { - sp1B4 = 0; - - if (bondwalkItemGetSoundTriggerRate(var_s1) > 0) - { - if ((g_CurrentPlayer->hands[1 - hand].field_A50 != g_GlobalTimer) - && (handptr->field_A4C < g_GlobalTimer)) - { - handptr->field_A4C = bondwalkItemGetSoundTriggerRate(var_s1) + g_GlobalTimer; - sp1B4 = 1; - } - } - else if (handptr->weapon_firing_status != 0) - { - sp1B4 = 1; - } - - if ((getPlayerCount() == 1) || ((checkGamePaused() == 0) && (g_CurrentPlayer->mpmenuon == 0))) - { - if (sp1B4 != 0) - { - if ((handptr->audioHandle != NULL) && (sndGetPlayingState(handptr->audioHandle) != 0)) - { - sndDeactivate(handptr->audioHandle); - } - - if (((struct ALSoundState *)handptr->field_A48 != 0) - && (sndGetPlayingState((struct ALSoundState *) handptr->field_A48) != 0)) - { - sndDeactivate((struct ALSoundState *) handptr->field_A48); - } - - if (bondwalkItemGetSound(var_s1) != 0) - { - if (handptr->audioHandle == NULL) - { - sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, bondwalkItemGetSound(var_s1), (struct ALSoundState *) &handptr->audioHandle); - } - else if ((struct ALSoundState *)handptr->field_A48 == 0) - { - sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, bondwalkItemGetSound(var_s1), (struct ALSoundState *) &handptr->field_A48); - } - - handptr->field_A50 = g_GlobalTimer; - } - } - - if (var_s1 == ITEM_WATCHLASER) - { - sp1B0 = watchlaser_fire_sounds; - sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, sp1B0.half[randomGetNext() & 1], NULL); - } - } - } - } - else if (handptr->field_88C > 0) - { - handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL1; - handptr->field_890 = 0; - handptr->field_88C = 0; - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_DRY_FIRE; - handptr->field_890 = 0; - handptr->field_88C = 0; - - if ((getPlayerCount() == 1) -#if defined(VERSION_JP) || defined(VERSION_EU) - || ((checkGamePaused() == 0) && (g_CurrentPlayer->mpmenuon == 0)) -#else - || (checkGamePaused() == 0) -#endif - ) - { - sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, EMPTY_GUN_FIRE_SFX, NULL); - } - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_RECOIL1) - { - if (var_s1 == ITEM_TASER) - { - tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); - if (gunSample1PTransform(taserRaiseKeyframes, tempf, &handptr->field_8EC, hand) != 0) - { - handptr->field_92C = 1; - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - else - { - weapon_stats = get_ptr_item_statistics(var_s1); - -#if defined(VERSION_US) - sp1A4 = weapon_stats->b44[0]; - sp1A0 = weapon_stats->b44[1]; -#endif -#if defined(VERSION_JP) - sp1A4 = weapon_stats->b44[0]; - sp1A0 = weapon_stats->b44[1]; - stat_2 = weapon_stats->b44[2]; - stat_3 = weapon_stats->b44[3]; - stat_4 = weapon_stats->SingleFiringRate; -#endif -#if defined(VERSION_EU) - sp1A4 = ((s32)weapon_stats->b44[0] * 50) / 60; - sp1A0 = ((s32)weapon_stats->b44[1] * 50) / 60; - stat_2 = ((s32)weapon_stats->b44[2] * 50) / 60; - stat_3 = ((s32)weapon_stats->b44[3] * 50) / 60; - stat_4 = weapon_stats->SingleFiringRate * 50 / 60; -#endif - - if (( - (handptr->field_888 != 0) - && (handptr->field_890 >= (sp1A4 + sp1A0)) - ) - || - ( - ((weapon_stats->SingleFiringRate >= 0)) - && (handptr->field_888 == 0) -#if defined(VERSION_US) - && (handptr->field_890 >= (sp1A4 + sp1A0 + weapon_stats->SingleFiringRate)) -#endif -#if defined(VERSION_JP) || defined(VERSION_EU) - && (handptr->field_890 >= (sp1A4 + sp1A0 + stat_4)) -#endif - ) - ) - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - else if ( - (handptr->field_888 != 0) - && (handptr->weapon_hold_time != 0) - -#if defined(VERSION_US) - && (handptr->field_890 >= weapon_stats->b44[2]) -#endif -#if defined(VERSION_JP) || defined(VERSION_EU) - && (handptr->field_890 >= stat_2) -#endif - - && (weapon_stats->b44[3] >= 0) - -#if defined(VERSION_US) - // HACK: registers are swapped - // addu a1, v1, a0 - && (handptr->field_890 + weapon_stats->b44[3] < (0,sp1A4) + sp1A0) - && (handptr->field_890 + weapon_stats->b44[3] >= (s32)weapon_stats->b44[2]) -#endif -#if defined(VERSION_JP) || defined(VERSION_EU) - && (handptr->field_890 + stat_3 < sp1A4 + sp1A0) - && (handptr->field_890 + stat_3 >= (s32)stat_2) -#endif - ) - { - handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL2; - handptr->field_890 = 0; - handptr->field_88C = 0; -#if defined(VERSION_US) - handptr->field_8A8 = weapon_stats->b44[3]; -#endif -#if defined(VERSION_JP) || defined(VERSION_EU) - handptr->field_8A8 = stat_3; -#endif - } - else if (handptr->field_890 < sp1A4 + sp1A0) - { - sp198 = weapon_stats->RecoilBack; - sp19C = weapon_stats->RecoilUp; - - if (handptr->field_890 == 0) - { - handptr->field_8C8 = handptr->field_8E8; - handptr->field_8BC = handptr->field_8DC; - handptr->field_8C0 = handptr->field_8E0; - handptr->field_8C4 = handptr->field_8E4; - } - - if (handptr->field_890 < sp1A4) - { - handptr->field_8D8 = M_TAU_F - ((sp19C * M_TAU_F) / 360.0f); - - handptr->field_8CC = ((gunSetHorizontalOffset(hand) - handptr->field_A38) * sp198) / 1000.0f; - handptr->field_8D0 = 0; - handptr->field_8D4 = ((weapon_stats->PosZ - handptr->field_A40) * sp198) / 1000.0f; - - sp190 = sinf(((f32) handptr->field_890 * M_PI_2F) / (f32) sp1A4); - } - else - { - handptr->field_8D8 = M_TAU_F - ((sp19C * M_TAU_F) / 360.0f); - - handptr->field_8CC = ((gunSetHorizontalOffset(hand) - handptr->field_A38) * sp198) / 1000.0f; - handptr->field_8D0 = 0; - handptr->field_8D4 = ((weapon_stats->PosZ - handptr->field_A40) * sp198) / 1000.0f; - - sp190 = (cosf(((f32) (handptr->field_890 - sp1A4) * M_PI_F) / (f32) sp1A0) * 0.5f) + 0.5f; - } - - temp_f0_2 = sub_GAME_7F06D0CC(handptr->field_8C8, handptr->field_8D8, sp190); - - handptr->field_8E8 = temp_f0_2; - handptr->field_92C = 1; - handptr->field_8DC = ((handptr->field_8CC - handptr->field_8BC) * sp190) + handptr->field_8BC; - handptr->field_8E0 = ((handptr->field_8D0 - handptr->field_8C0) * sp190) + handptr->field_8C0; - handptr->field_8E4 = ((handptr->field_8D4 - handptr->field_8C4) * sp190) + handptr->field_8C4; - - matrix_4x4_set_rotation_around_x(temp_f0_2, &handptr->field_8EC); - matrix_4x4_set_position((struct coord3d *)&handptr->field_8DC, &handptr->field_8EC); - } - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_RECOIL2) - { - if (handptr->field_890 == 0) - { - handptr->field_8C8 = handptr->field_8E8; - handptr->field_8BC = handptr->field_8DC; - handptr->field_8C0 = handptr->field_8E0; - handptr->field_8C4 = handptr->field_8E4; - handptr->field_8D8 = 0.0f; - handptr->field_8CC = 0.0f; - handptr->field_8D0 = 0.0f; - handptr->field_8D4 = 0.0f; - } - - if (handptr->field_890 < handptr->field_8A8) - { - sp18C = (cosf(((f32) (handptr->field_8A8 - handptr->field_890) * M_PI_2F) / (f32) handptr->field_8A8) * 0.5f) + 0.5f; - - temp_f0_2 = sub_GAME_7F06D0CC(handptr->field_8C8, handptr->field_8D8, sp18C); - - handptr->field_8E8 = temp_f0_2; - handptr->field_92C = 1; - handptr->field_8DC = ((handptr->field_8CC - handptr->field_8BC) * sp18C) + handptr->field_8BC; - handptr->field_8E0 = ((handptr->field_8D0 - handptr->field_8C0) * sp18C) + handptr->field_8C0; - handptr->field_8E4 = ((handptr->field_8D4 - handptr->field_8C4) * sp18C) + handptr->field_8C4; - - matrix_4x4_set_rotation_around_x(temp_f0_2, &handptr->field_8EC); - matrix_4x4_set_position((struct coord3d *)&handptr->field_8DC, &handptr->field_8EC); - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_DRY_FIRE) - { - if (handptr->field_88C == 0) - { - sub_GAME_7F05E808(hand); - } - - if ((handptr->field_888 != 0) || ((handptr->field_888 == 0) && (handptr->field_890 >= WHEN_D_FLD890))) - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - - sp188 = WHEN_5_SP188_INIT; - if (handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_LOWER) - { - if (getPlayerCount() >= 2) - { - sp188 = WHEN_5_SP188_MULTI; - } - - if (handptr->field_88C == 0) - { - if (getPlayerCount() == 1) - { - handptr->field_8B0 = WHEN_5_FLD8B0_SP; - } - else - { - handptr->field_8B0 = WHEN_5_FLD8B0_MULTI; - } - } - - if (handptr->field_890 >= sp188) - { - g_CurrentPlayer->ammoheldarr[get_ammo_type_for_weapon(var_s1)] += handptr->weapon_ammo_in_magazine; - handptr->weapon_ammo_in_magazine = 0; - - if (getPlayerCount() >= 2) - { - sub_GAME_7F09B368(hand); - } - - sub_GAME_7F05FB00(hand); - - handptr->weapon_action_state = GUN_ANIM_STATE_SWITCH_SWAP; - - if (bondinvItemAvailable(ITEM_SNIPERRIFLE) != 0) - { - g_CurrentPlayer->cur_item_weapon_getname = ITEM_SNIPERRIFLE; - } - else - { - g_CurrentPlayer->cur_item_weapon_getname = ITEM_FIST; - } - } - else - { - sp184 = ((f32) handptr->field_890 * M_LN2F) / (f32) sp188; - handptr->field_92C = 1; - - matrix_4x4_set_rotation_around_x(sp184, &handptr->field_8EC); - - handptr->field_8EC.m[3][0] = 0.0f; - handptr->field_8EC.m[3][1] = (1.0f - cosf(sp184)) * -60.0f; - handptr->field_8EC.m[3][2] = sinf(sp184) * 15.0f; - } - } - - if ((handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_SWAP) || (handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_HOLD)) - { - if ((handptr->weapon_animation_trigger == 0) || (handptr->field_890 >= handptr->field_8B0)) - { - if (handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_SWAP) - { - temp_v1_5 = (g_CurrentPlayer->hands - hand) + 1; - - if ((temp_v1_5->weapon_action_state != GUN_ANIM_STATE_SWITCH_SWAP) && (temp_v1_5->weapon_action_state != GUN_ANIM_STATE_SWITCH_LOWER)) - { - if ( - (temp_v1_5->weapon_current_animation != 5) - && (temp_v1_5->weapon_action_state != GUN_ANIM_STATE_WATCH_LOWER) - && (temp_v1_5->weapon_action_state != GUN_ANIM_STATE_WATCH_SWAP) - && (temp_v1_5->weapon_action_state != GUN_ANIM_STATE_WATCH_RAISE) - && (temp_v1_5->weapon_current_animation != 0xE)) - { - if (hand == GUNRIGHT) - { - if (bondinvItemAvailableForHand(handptr->weapon_next_weapon, getCurrentPlayerWeaponId(GUNLEFT)) == 0) - { - currentPlayerEquipWeaponWrapper(GUNLEFT, 0); - } - } - else if (bondinvItemAvailableForHand(getCurrentPlayerWeaponId(GUNRIGHT), handptr->weapon_next_weapon) == 0) - { - handptr->weapon_next_weapon = ITEM_UNARMED; - } - } - } - currentPlayerUnEquipWeaponWrapper(hand, handptr->weapon_next_weapon); - var_s1 = get_item_in_hand_or_watch_menu(hand); - handptr->weapon_action_state = GUN_ANIM_STATE_SWITCH_HOLD; - } - else if (Gun_hand_without_item(hand) != 0) - { - handptr->weapon_action_state = GUN_ANIM_STATE_SWITCH_RAISE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - - if ((handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_SWAP) || (handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_HOLD)) - { - handptr->field_92C = 1; - matrix_4x4_set_rotation_around_x(M_LN2F, &handptr->field_8EC); - handptr->field_8EC.m[3][0] = 0.0f; - handptr->field_8EC.m[3][1] = (1.0f - cosf(M_LN2F)) * -60.0f; - handptr->field_8EC.m[3][2] = sinf(M_LN2F) * 15.0f; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_RAISE) - { - sp178 = WHEN_8_SP178_INIT; - - if (getPlayerCount() >= 2) - { - sp178 = WHEN_8_SP178_MULTI; - } - - if (handptr->field_88C == 0) - { - if (getPlayerCount() >= 2) - { - sub_GAME_7F09B398(hand); - } - - sub_GAME_7F0649D8(hand); - - g_CurrentPlayer->trigger_released = 0; - - if ((g_ClockTimer > 0) - && (g_CurrentPlayer->cameramode != CAMERAMODE_INTRO) - && (Gun_hand_without_item(hand) != 0) - && (g_PlayerInvincible == FALSE) -#if defined(VERSION_JP) || defined(VERSION_EU) - && (g_CurrentPlayer->bonddead == 0) -#endif - ) - { - switch (var_s1) - { - case ITEM_LASER: - sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, PICKUP_LASER_SFX, NULL); - break; - - case ITEM_KNIFE: - case ITEM_THROWKNIFE: - sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, PICKUP_KNIFE_SFX, NULL); - break; - - case ITEM_TIMEDMINE: - case ITEM_PROXIMITYMINE: - case ITEM_REMOTEMINE: - sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, PICKUP_MINE_SFX, NULL); - break; - - case ITEM_UNARMED: - case ITEM_FIST: - case ITEM_WATCHLASER: - case ITEM_GRENADE: - case ITEM_TRIGGER: - case ITEM_TASER: - case ITEM_TANKSHELLS: - case ITEM_BOMBCASE: - case ITEM_PLASTIQUE: - case ITEM_CAMERA: - case ITEM_BUG: - case ITEM_MICROCAMERA: - case ITEM_WATCHMAGNETATTRACT: - case ITEM_GOLDENEYEKEY: - case ITEM_TOKEN: - break; - - default: - sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, PICKUP_GUN_SFX, NULL); - break; - } - } - } - - if ((handptr->field_890 >= sp178) - || (get_ptr_weapon_model_header_line(var_s1) == NULL) - || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_SHOW_FIRST_PERSON) == 0) - || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_HIDE_FIRST_PERSON_HAND) != 0)) - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - else - { - sp174 = ((f32) (sp178 - handptr->field_890) * M_LN2F) / (f32) sp178; - handptr->field_92C = 1; - matrix_4x4_set_rotation_around_x(sp174, &handptr->field_8EC); - handptr->field_8EC.m[3][0] = 0.0f; - handptr->field_8EC.m[3][1] = (1.0f - cosf(sp174)) * -60.0f; - handptr->field_8EC.m[3][2] = sinf(sp174) * 15.0f; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_RELOAD_START) - { - if (((handptr->weapon_ammo_in_magazine < get_ptr_item_statistics(var_s1)->MagSize) - || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_AMMO_CLIP_LIMIT) != 0)) - && ((get_ammo_in_hands_weapon(hand) > 0))) - { - handptr->weapon_action_state = GUN_ANIM_STATE_RELOAD_LOWER; - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_RELOAD_LOWER) - { - if ((handptr->field_890 >= WHEN_A_FLD890) || (handptr->field_87F == 0)) - { - handptr->weapon_action_state = GUN_ANIM_STATE_RELOAD_SWAP; - handptr->field_8B0 = WHEN_A_FLD8B0; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - else - { - sp128 = ((f32) handptr->field_890 * M_LN2F) / un_f32_div_1; - handptr->field_92C = 1; - - if (hand == GUNRIGHT) - { - matrix_4x4_set_rotation_around_z((un_f32_num / un_f32_div_1), &handptr->field_8EC); - } - else - { - matrix_4x4_set_rotation_around_z(-(un_f32_num / un_f32_div_1), &handptr->field_8EC); - } - - matrix_4x4_set_rotation_around_x(sp128, &sp12C); - matrix_4x4_multiply_in_place(&sp12C, &handptr->field_8EC); - sinf((un_f32_num / un_f32_div_1)); - handptr->field_8EC.m[3][0] = 0.0f; - handptr->field_8EC.m[3][1] = sub_GAME_7F0649AC(var_s1) * (1.0f - cosf(sp128)); - handptr->field_8EC.m[3][2] = sinf(sp128) * 15.0f; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_RELOAD_SWAP) - { - if ((handptr->field_88C == 0) -#if defined(VERSION_JP) || defined(VERSION_EU) - && (g_ClockTimer > 0) -#endif - && (g_CurrentPlayer->cameramode != CAMERAMODE_INTRO) - && (Gun_hand_without_item(hand) != 0) - && (g_PlayerInvincible == FALSE) -#if defined(VERSION_JP) || defined(VERSION_EU) - && (g_CurrentPlayer->bonddead == 0) -#endif - ) - { - switch (var_s1) - { - case ITEM_UNARMED: - case ITEM_FIST: - case ITEM_KNIFE: - case ITEM_THROWKNIFE: - case ITEM_LASER: - case ITEM_WATCHLASER: - case ITEM_GRENADE: - case ITEM_TIMEDMINE: - case ITEM_PROXIMITYMINE: - case ITEM_REMOTEMINE: - case ITEM_TRIGGER: - case ITEM_TASER: - case ITEM_TANKSHELLS: - case ITEM_BOMBCASE: - case ITEM_PLASTIQUE: - case ITEM_CAMERA: - case ITEM_BUG: - case ITEM_MICROCAMERA: - case ITEM_WATCHMAGNETATTRACT: - case ITEM_GOLDENEYEKEY: - case ITEM_TOKEN: - break; - default: - case ITEM_WPPK: - case ITEM_WPPKSIL: - case ITEM_TT33: - case ITEM_SKORPION: - case ITEM_AK47: - case ITEM_UZI: - case ITEM_MP5K: - case ITEM_MP5KSIL: - case ITEM_SPECTRE: - case ITEM_M16: - case ITEM_FNP90: - case ITEM_SHOTGUN: - case ITEM_AUTOSHOT: - case ITEM_SNIPERRIFLE: - case ITEM_RUGER: - case ITEM_GOLDENGUN: - case ITEM_SILVERWPPK: - case ITEM_GOLDWPPK: - case ITEM_GRENADELAUNCH: - case ITEM_ROCKETLAUNCH: - case ITEM_FLAREPISTOL: - case ITEM_PITONGUN: - case ITEM_BUNGEE: - case ITEM_DOORDECODER: - case ITEM_BOMBDEFUSER: - case ITEM_LOCKEXPLODER: - case ITEM_DOOREXPLODER: - case ITEM_BRIEFCASE: - case ITEM_WEAPONCASE: - case ITEM_SAFECRACKERCASE: - case ITEM_KEYANALYSERCASE: - case ITEM_BUGDETECTOR: - case ITEM_EXPLOSIVEFLOPPY: - case ITEM_POLARIZEDGLASSES: - case ITEM_DARKGLASSES: - case ITEM_CREDITCARD: - case ITEM_GASKEYRING: - case ITEM_DATATHIEF: - case ITEM_WATCHIDENTIFIER: - case ITEM_WATCHCOMMUNICATOR: - case ITEM_WATCHGEIGERCOUNTER: - case ITEM_WATCHMAGNETREPEL: - sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, GUN_RIFLECOCK_SFX, NULL); - break; - } - } - - if ((handptr->field_890 >= handptr->field_8B0) && !(((handptr->field_88C < 2)))) - { - handptr->weapon_action_state = GUN_ANIM_STATE_RELOAD_RAISE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - else - { - handptr->field_92C = 1; - - if (hand == GUNRIGHT) - { - matrix_4x4_set_rotation_around_z(un_f32_num, &handptr->field_8EC); - } - else - { - matrix_4x4_set_rotation_around_z(-un_f32_num, &handptr->field_8EC); - } - - matrix_4x4_set_rotation_around_x(M_LN2F, &spE4); - matrix_4x4_multiply_in_place(&spE4, &handptr->field_8EC); - sinf(un_f32_num); - handptr->field_8EC.m[3][0] = 0.0f; - handptr->field_8EC.m[3][1] = sub_GAME_7F0649AC(var_s1) * (1.0f - cosf(M_LN2F)); - handptr->field_8EC.m[3][2] = sinf(M_LN2F) * 15.0f; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_RELOAD_RAISE) - { - if (handptr->field_88C == 0) - { - sub_GAME_7F0649D8(hand); - g_CurrentPlayer->trigger_released = 0; - } - - if ((handptr->field_890 >= WHEN_C_FLD890) - || (get_ptr_weapon_model_header_line(var_s1) == NULL) - || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_SHOW_FIRST_PERSON) == 0) - || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_HIDE_FIRST_PERSON_HAND) != 0)) - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - else - { - sp98 = ((f32) (WHEN_C_FLD890 - handptr->field_890) * M_LN2F) / un_f32_div_2; - handptr->field_92C = 1; - - if (hand == GUNRIGHT) - { - matrix_4x4_set_rotation_around_z((un_f32_num / un_f32_div_2), &handptr->field_8EC); - } - else - { - matrix_4x4_set_rotation_around_z(-(un_f32_num / un_f32_div_2), &handptr->field_8EC); - } - - matrix_4x4_set_rotation_around_x(sp98, &sp9C); - matrix_4x4_multiply_in_place(&sp9C, &handptr->field_8EC); - sinf(un_f32_num / un_f32_div_2); - handptr->field_8EC.m[3][0] = 0.0f; - handptr->field_8EC.m[3][1] = sub_GAME_7F0649AC(var_s1) * (1.0f - cosf(sp98)); - handptr->field_8EC.m[3][2] = sinf(sp98) * 15.0f; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_WATCH_LOWER) - { - if ((handptr->field_890 >= WHEN_E_FLD890) || (handptr->field_87F == 0)) - { - handptr->weapon_action_state = GUN_ANIM_STATE_WATCH_SWAP; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - else - { - sp94 = ((f32) handptr->field_890 * M_LN2F) / un_f32_div_1; - handptr->field_92C = 1; - - matrix_4x4_set_rotation_around_x(sp94, &handptr->field_8EC); - handptr->field_8EC.m[3][0] = 0.0f; - handptr->field_8EC.m[3][1] = (1.0f - cosf(sp94)) * -60.0f; - handptr->field_8EC.m[3][2] = sinf(sp94) * 15.0f; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_WATCH_SWAP) - { - if ((handptr->field_88C == 0) || (Gun_hand_without_item(hand) == 0)) - { - sub_GAME_7F05DA8C(hand, handptr->weapon_next_weapon); - var_s1 = get_item_in_hand_or_watch_menu(hand); - } - - if (Gun_hand_without_item(hand) != 0) - { - handptr->weapon_action_state = GUN_ANIM_STATE_WATCH_RAISE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - else - { - handptr->field_92C = 1; - matrix_4x4_set_rotation_around_x(M_LN2F, &handptr->field_8EC); - handptr->field_8EC.m[3][0] = 0.0f; - handptr->field_8EC.m[3][1] = (1.0f - cosf(M_LN2F)) * -60.0f; - handptr->field_8EC.m[3][2] = sinf(M_LN2F) * 15.0f; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_WATCH_RAISE) - { - if ((handptr->field_88C == 0) && (var_s1 < 0x21)) - { - if (getPlayerCount() >= 2) - { - sub_GAME_7F09B398(hand); - } - sub_GAME_7F0649D8(hand); - g_CurrentPlayer->trigger_released = 0; - } - - if ((handptr->field_890 >= WHEN_10_FLD890) - || (get_ptr_weapon_model_header_line(var_s1) == NULL) - || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_SHOW_FIRST_PERSON) == 0) - || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_HIDE_FIRST_PERSON_HAND) != 0)) - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - else - { - sp8C = ((f32) (WHEN_10_FLD890 - handptr->field_890) * M_LN2F) / un_f32_div_2; - handptr->field_92C = 1; - matrix_4x4_set_rotation_around_x(sp8C, &handptr->field_8EC); - handptr->field_8EC.m[3][0] = 0.0f; - handptr->field_8EC.m[3][1] = (1.0f - cosf(sp8C)) * -60.0f; - handptr->field_8EC.m[3][2] = sinf(sp8C) * 15.0f; - } - } - - if ((handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_BEGIN) - || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_STRIKE) - || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_RECOVER) - || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH2_BEGIN) - || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH2_STRIKE) - || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH2_RECOVER)) - { - sp88 = WEAPON_1P_ANIM_TIME(handptr->field_890); - - if (((handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_BEGIN) - || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH2_BEGIN)) - && (handptr->field_890 >= WHEN_11_FLD890_1)) - { - sp7C = knife_throw_sounds; - sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, sp7C.half[randomGetNext() % 3U], NULL); - - - if (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_BEGIN) - { - handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH1_STRIKE; - handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH1_STRIKE; - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH2_STRIKE; - handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH2_STRIKE; - } - } - - if ((handptr->weapon_action_state != GUN_ANIM_STATE_KNIFE_SLASH1_RECOVER) - && (handptr->weapon_action_state != GUN_ANIM_STATE_KNIFE_SLASH2_RECOVER) - && (handptr->field_890 >= WHEN_11_FLD890_2)) - { - handptr->weapon_firing_status = 1; - if ((handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_BEGIN) || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_STRIKE)) - { - handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH1_RECOVER; - handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH1_RECOVER; - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH2_RECOVER; - handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH2_RECOVER; - } - } - - if ((handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_BEGIN) - || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_STRIKE) - || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_RECOVER)) - { - var_a0_2 = D_80034CA4; - } - else - { - var_a0_2 = D_80034E0C; - } - - if (gunSample1PTransform(var_a0_2, sp88, &handptr->field_8EC, hand) != 0) - { - handptr->field_92C = 1; - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - - if ((handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH1_STRIKE) - || (handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH1_RECOVER) - || (handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH2_STRIKE) - || (handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH2_RECOVER)) - { - temp_v1_9 = WEAPON_1P_ANIM_TIME(handptr->field_890); - - if ((handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH1_STRIKE) || (handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH1_RECOVER)) - { - if (g_CurrentPlayer->cur_item_weapon_getname == ITEM_SNIPERRIFLE) - { - sp74 = sniperMeleeKeyframes1; - } - else - { - sp74 = fistMeleeKeyframes1; - } - - if ((handptr->weapon_action_state != GUN_ANIM_STATE_PUNCH1_RECOVER) && (handptr->field_890 >= WHEN_1E_FLD890)) - { - handptr->weapon_firing_status = 1; - handptr->weapon_action_state = GUN_ANIM_STATE_PUNCH1_RECOVER; - } - } - else if ((handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH2_STRIKE) || (handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH2_RECOVER)) - { - if (g_CurrentPlayer->cur_item_weapon_getname == ITEM_SNIPERRIFLE) - { - sp74 = sniperMeleeKeyframes2; - } - else - { - sp74 = fistMeleeKeyframes2; - } - - if ((handptr->weapon_action_state != GUN_ANIM_STATE_PUNCH2_RECOVER) && (handptr->field_890 >= WHEN_1E_FLD890)) - { - handptr->weapon_firing_status = 1; - handptr->weapon_action_state = GUN_ANIM_STATE_PUNCH2_RECOVER; - } - } - - if (gunSample1PTransform(sp74, temp_v1_9, &handptr->field_8EC, hand) != 0) - { - handptr->field_92C = 1; - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_GRENADE_THROW) - { - if (handptr->weapon_ammo_in_magazine > 0) - { - tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); - if (gunSample1PTransform(grenadeThrowKeyframes, tempf, &handptr->field_8EC, hand) != 0) - { - handptr->field_92C = 1; - } - else - { - handptr->field_87E = 0; - handptr->weapon_firing_status = 1; - handptr->weapon_ammo_in_magazine -= 1; - handptr->weapon_action_state = GUN_ANIM_STATE_GRENADE_RECOVER; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_GRENADE_RECOVER) - { - tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); - if (gunSample1PTransform(timedMineThrowKeyframes, tempf, &handptr->field_8EC, hand) != 0) - { - handptr->field_92C = 1; - } - else - { - handptr->field_87E = 1; - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_THROWKNIFE_DRAW) - { - if (handptr->weapon_ammo_in_magazine > 0) - { - if (handptr->field_888 != 0) - { - handptr->weapon_action_state = GUN_ANIM_STATE_THROWKNIFE_THROW; - } - else - { - tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); - if (gunSample1PTransform(throwKnifeDrawBackKeyframes, tempf, &handptr->field_8EC, hand) != 0) - { - handptr->field_92C = 1; - } - else if (gunSample1PTransform(throwKnifeReleaseKeyframes, 0.0f, &handptr->field_8EC, hand) != 0) - { - handptr->field_92C = 1; - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_THROWKNIFE_THROW; - } - } - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_THROWKNIFE_THROW) - { - if (handptr->weapon_ammo_in_magazine > 0) - { - tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); - if (gunSample1PTransform(throwKnifeDrawBackKeyframes, tempf, &handptr->field_8EC, hand) != 0) - { - handptr->field_92C = 1; - } - else - { - handptr->field_87E = 0; - handptr->weapon_firing_status = 1; - handptr->weapon_ammo_in_magazine -= 1; - handptr->weapon_action_state = GUN_ANIM_STATE_THROWKNIFE_RECOVER; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_THROWKNIFE_RECOVER) - { - tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); - if (gunSample1PTransform(throwKnifeReleaseKeyframes, tempf, &handptr->field_8EC, hand) != 0) - { - handptr->field_92C = 1; - } - else - { - handptr->field_87E = 1; - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_MINE_PLACE) - { - if ((handptr->weapon_ammo_in_magazine > 0) || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_CLICKY) != 0)) - { - tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); - - if (gunSample1PTransform(proxMineThrowKeyframes, tempf, &handptr->field_8EC, hand) != 0) - { - handptr->field_92C = 1; - } - else - { - handptr->field_87E = 0; - handptr->weapon_firing_status = 1; - handptr->weapon_ammo_in_magazine -= 1; - handptr->weapon_action_state = GUN_ANIM_STATE_MINE_RECOVER; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - else - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_MINE_RECOVER) - { - tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); - if (gunSample1PTransform(remoteMineThrowKeyframes, tempf, &handptr->field_8EC, hand) != 0) - { - handptr->field_92C = 1; - } - else - { - handptr->field_87E = 1; - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } - - if (handptr->weapon_action_state == GUN_ANIM_STATE_USE_ITEM) - { - if (var_s1 == ITEM_KEYANALYSERCASE) - { - if (handptr->field_88C == 0) - { - analyzeGEKey(); - } - } - else if (var_s1 == ITEM_WEAPONCASE) - { - if (handptr->field_88C == 0) - { - give_weapon_case_items(); - } - } - else if ((var_s1 == ITEM_BOMBDEFUSER) - || (var_s1 == ITEM_DATATHIEF) - || (var_s1 == ITEM_DOORDECODER) - || (var_s1 == ITEM_EXPLOSIVEFLOPPY) - || (var_s1 == ITEM_DATTAPE)) - { - if (handptr->field_88C == 0) - { - temp_v0_8 = propFindForInteract(); - - if (temp_v0_8 != NULL) - { - temp_v0_8->obj->state |= 0x40; - } - } - } - else if ((var_s1 != ITEM_POLARIZEDGLASSES) - && (var_s1 != ITEM_DARKGLASSES) - && (var_s1 != ITEM_WATCHGEIGERCOUNTER) - && (var_s1 != ITEM_WATCHMAGNETREPEL) - && (var_s1 != ITEM_KEYCARD) - && (var_s1 != ITEM_KEYYALE) - && (var_s1 != ITEM_KEYBOLT) - && (var_s1 != ITEM_SAFECRACKERCASE) - && (var_s1 != ITEM_LOCKEXPLODER) - && (var_s1 != ITEM_DOOREXPLODER) - && (var_s1 != ITEM_CREDITCARD) - && (var_s1 != ITEM_GASKEYRING) - && (var_s1 == ITEM_BUNGEE)) - { - // removed - } - else if (var_s1 == ITEM_PITONGUN - || var_s1 == ITEM_GASKEYRING - || var_s1 == ITEM_BUNGEE) - { - // removed - } - - if (handptr->field_888 != 0) - { - handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; - handptr->field_890 = 0.0f; - handptr->field_88C = 0; - } - } -} - -#undef WEAPON_1P_ANIM_TIME -#undef WHEN_1_CASE_GRENADELAUNCH_FLD890 -#undef WHEN_1_CASE_GRENADE_FLD890 -#undef WHEN_D_FLD890 -#undef WHEN_5_SP188_INIT -#undef WHEN_5_SP188_MULTI -#undef WHEN_5_FLD8B0_SP -#undef WHEN_5_FLD8B0_MULTI -#undef WHEN_8_SP178_INIT -#undef WHEN_8_SP178_MULTI -#undef WHEN_A_FLD890 -#undef WHEN_A_FLD8B0 -#undef WHEN_C_FLD890 -#undef WHEN_E_FLD890 -#undef WHEN_10_FLD890 -#undef WHEN_11_FLD890_1 -#undef WHEN_11_FLD890_2 -#undef WHEN_1E_FLD890 - - -void analyzeGEKey(void) -{ - if (bondinvHasGEKey()) - { - HUDMESSAGEBOTTOM(langGet(getStringID(LGUN, GUN_STR_D8_ANALYZINGTHEGOLDENEYEKEY_LF))); //Analyzing the GoldenEye key... - g_CurrentPlayer->copiedgoldeneye = TRUE; - sndPlaySfx(g_musicSfxBufferPtr, KEY_ANALYSER_SFX, 0x0); - currentPlayerEquipWeaponWrapper(GUNRIGHT, ITEM_GOLDENEYEKEY); - currentPlayerEquipWeaponWrapper(GUNLEFT, ITEM_UNARMED); - } - else - { - HUDMESSAGEBOTTOM(langGet(getStringID(LGUN, GUN_STR_D9_YOUDONOTHAVETHEGOLDENEYEKEY_LF))); //You do not have the GoldenEye key. - sub_GAME_7F05D690(); - } - return; -} - - -s32 get_keyanalyzer_flag(void) -{ - return g_CurrentPlayer->copiedgoldeneye; -} - - -void give_weapon_case_items(void) -{ - add_ammo_to_inventory(AMMO_KNIFE, 2, 0, 1); - add_ammo_to_inventory(AMMO_GRENADE, 2, 0, 1); - bondinvAddInvItem(ITEM_SNIPERRIFLE); - set_sound_effect_for_weapontype_collection(ITEM_SNIPERRIFLE); - display_text_for_weapon_in_lower_left_corner(ITEM_SNIPERRIFLE); - give_cur_player_ammo(sniperrifle_stats.AmmoType, check_cur_player_ammo_amount_in_inventory(sniperrifle_stats.AmmoType) + sniperrifle_stats.MagSize); - bondinvRemoveItemByID(ITEM_WEAPONCASE); - currentPlayerEquipWeaponWrapper(GUNRIGHT,ITEM_SNIPERRIFLE); - currentPlayerEquipWeaponWrapper(GUNLEFT,ITEM_UNARMED); -} - - -f32 get_vertical_position_solo_watch_menu_main_page_for_item(ITEM_IDS item) -{ - return gitem_structs[item].watch_pos_x; -} - - -f32 get_lateral_position_solo_watch_menu_main_page_for_item(ITEM_IDS item) -{ - return gitem_structs[item].watch_pos_y; -} - - -f32 get_depth_on_solo_watch_menu_page_for_item(ITEM_IDS item) -{ - return gitem_structs[item].watch_pos_z; -} - - -f32 get_xrotation_solo_watch_menu_for_item(ITEM_IDS item) - -{ - return gitem_structs[item].x_rotation; -} - - -f32 get_yrotation_solo_watch_menu_for_item(ITEM_IDS item) -{ - return gitem_structs[item].y_rotation; -} - - -f32 get_45_degree_angle(s32 unk) { - return 45.0f; -} - - -u16 *get_ptr_first_title_line_item(ITEM_IDS item) -{ - return langGet(gitem_structs[item].upper_watch_text); -} - - -u16 *get_ptr_second_title_line_item(ITEM_IDS item) -{ - return langGet(gitem_structs[item].lower_watch_text); -} - - -u16 *get_ptr_short_watch_text_for_item(ITEM_IDS item) -{ - return langGet(gitem_structs[item].watch_equipment_text); -} - - -u16 *get_ptr_long_watch_text_for_item(ITEM_IDS item) -{ - return langGet(gitem_structs[item].weapon_of_choice_text); -} - - -f32 get_45_degree_angle_0(s32 unk) -{ - return 45.0f; -} - - -f32 get_horizontal_offset_on_solo_watch_menu_for_item(ITEM_IDS item) -{ - return gitem_structs[item].equip_watch_x; -} - - -f32 get_vertical_offset_on_solo_watch_menu_for_item(ITEM_IDS item) -{ - return gitem_structs[item].equip_watch_y; -} - - -f32 get_depth_offset_solo_watch_menu_inventory_page_for_item(ITEM_IDS item) -{ - return gitem_structs[item].equip_watch_z; -} - - -f32 getCurrentPlayerNoise(GUNHAND hand) -{ - return g_CurrentPlayer->hands[hand].noise; -} - - -void gunTickNoise(void) -{ - enum ITEM_IDS weapon_id_right; - enum ITEM_IDS weapon_id_left; - s32 unused2; - f32 noise_reduction; - WeaponStats *item_right_stats; - WeaponStats *item_left_stats; - f32 noise_reduction_max; - s32 unused; - - weapon_id_right = getCurrentPlayerWeaponId(GUNRIGHT); - weapon_id_left = getCurrentPlayerWeaponId(GUNLEFT); - item_right_stats = get_ptr_item_statistics(weapon_id_right); - item_left_stats = get_ptr_item_statistics(weapon_id_left); - - if (weapon_id_right != ITEM_UNARMED && get_hands_firing_status(GUNRIGHT)) - { - g_CurrentPlayer->hands[GUNRIGHT].noise += item_right_stats->NoiseIncreasePerShot; - - if (item_right_stats->LoudnessMax < g_CurrentPlayer->hands[GUNRIGHT].noise) - { - g_CurrentPlayer->hands[GUNRIGHT].noise = item_right_stats->LoudnessMax; - } - } - - if (weapon_id_left != ITEM_UNARMED && get_hands_firing_status(GUNLEFT)) - { - g_CurrentPlayer->hands[GUNLEFT].noise += item_left_stats->NoiseIncreasePerShot; - - if (item_left_stats->LoudnessMax < g_CurrentPlayer->hands[GUNLEFT].noise) - { - g_CurrentPlayer->hands[GUNLEFT].noise = item_left_stats->LoudnessMax; - } - } - - noise_reduction = (item_right_stats->NoiseIncreasePerShot * g_GlobalTimerDelta) / (item_right_stats->NoiseDecayLinearTime * 60.0f); - noise_reduction_max = ((g_CurrentPlayer->hands[GUNRIGHT].noise - item_right_stats->LoudnessMin) * g_GlobalTimerDelta) / (item_right_stats->NoiseDecayScaledTime * 60.0f); - - if (noise_reduction < noise_reduction_max) - { - noise_reduction = noise_reduction_max; - } - - g_CurrentPlayer->hands[GUNRIGHT].noise -= noise_reduction; - - if (g_CurrentPlayer->hands[GUNRIGHT].noise < item_right_stats->LoudnessMin) - { - g_CurrentPlayer->hands[GUNRIGHT].noise = item_right_stats->LoudnessMin; - } - - noise_reduction = (item_left_stats->NoiseIncreasePerShot * g_GlobalTimerDelta) / (item_left_stats->NoiseDecayLinearTime * 60.0f); - noise_reduction_max = ((g_CurrentPlayer->hands[GUNLEFT].noise - item_left_stats->LoudnessMin) * g_GlobalTimerDelta) / (item_left_stats->NoiseDecayScaledTime * 60.0f); - - if (noise_reduction < noise_reduction_max) - { - noise_reduction = noise_reduction_max; - } - - g_CurrentPlayer->hands[GUNLEFT].noise -= noise_reduction; - - if (g_CurrentPlayer->hands[GUNLEFT].noise < item_left_stats->LoudnessMin) - { - g_CurrentPlayer->hands[GUNLEFT].noise = item_left_stats->LoudnessMin; - } -} - - -/** - * Returns true if the hand has a melee weapon or has ammo in the magazine. - */ -s32 gunCanUseWeapon(enum GUNHAND hand) -{ - return (get_ammo_type_for_weapon(getCurrentPlayerWeaponId(hand)) == 0) - || (g_CurrentPlayer->hands[hand].weapon_ammo_in_magazine > 0); -} - - -/** - * US address 7F067420. - * Perfect Dark method bgunTickGameplay. - * - * Handles logic for single gun and dual wield trigger presses. - * Calls updates to first person gun animations, gun model loading, noise to AI, and updating color from collision tiles. - * Also handles the Watch Magnet Attract hum noise. -*/ -void gunTickGameplay(s32 triggerOn) -{ - struct gun_trigger_state trigger_state; - enum ITEM_IDS weapon_id_right; - enum ITEM_IDS weapon_id_left; - enum GUNHAND hand = GUNLEFT; - struct rgba_u8 weapon_color; - - trigger_state = g_ZeroTriggerState; - - // Save previous trigger state. - g_CurrentPlayer->prev_trigger_down = g_CurrentPlayer->trigger_down; - - // Save raw trigger state. - g_CurrentPlayer->trigger_down = triggerOn; - - if ((g_CurrentPlayer->trigger_down == 0) && (g_CurrentPlayer->prev_trigger_down != 0)) - { - g_CurrentPlayer->trigger_released = 1; - } - - // Z button pressed this frame. - if (g_CurrentPlayer->trigger_down != 0) - { - weapon_id_right = getCurrentPlayerWeaponId(GUNRIGHT); - weapon_id_left = getCurrentPlayerWeaponId(GUNLEFT); - - g_CurrentPlayer->z_trigger_timer += g_ClockTimer; - - // Dual wielding. - if ((weapon_id_right != ITEM_UNARMED) && (weapon_id_left != ITEM_UNARMED)) - { - // Both guns prefer to take turns firing in dual wield. - if ((bondwalkItemCheckBitflags(weapon_id_right, WEAPONSTATBITFLAG_DUAL_WIELD_ALTERNATING_FIRE) != 0) && (bondwalkItemCheckBitflags(weapon_id_left, WEAPONSTATBITFLAG_DUAL_WIELD_ALTERNATING_FIRE) != 0)) - { - // Trigger has been held longer than 20 ticks on NTSC (24 on PAL). - if (g_CurrentPlayer->z_trigger_timer > DUAL_WIELD_TRIGGER_SWAP_TICKS) - { - // 'hand' still has its default value here, which behaves like trigger-on. - trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = hand; - - // If the gun in the other hand is usable or has been held for any amount of time, depress its trigger as well. - if (gunCanUseWeapon(1 - g_CurrentPlayer->current_trigger_hand) || g_CurrentPlayer->hands[1 - g_CurrentPlayer->current_trigger_hand].weapon_hold_time) - { - trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 1; - } - } - // Z has been held for less than or equal to 20 ticks on NTSC (24 on PAL). - else - { - if ((g_CurrentPlayer->prev_trigger_down == 0) && - ((gunCanUseWeapon(1 - g_CurrentPlayer->current_trigger_hand) != 0) || (gunCanUseWeapon(g_CurrentPlayer->current_trigger_hand) == 0))) - { - g_CurrentPlayer->current_trigger_hand = 1 - g_CurrentPlayer->current_trigger_hand; - } - - trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = 1; - trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 0; - } - } - /** - * One gun prefers to take turns firing in dual wield. - * This doesn't happen much in the vanilla US version with the notable - * exception of equipping Xenia's RC-P90 and Grenade Launcher in Jungle - */ - else if ((bondwalkItemCheckBitflags(weapon_id_right, WEAPONSTATBITFLAG_DUAL_WIELD_ALTERNATING_FIRE) != 0) || (bondwalkItemCheckBitflags(weapon_id_left, WEAPONSTATBITFLAG_DUAL_WIELD_ALTERNATING_FIRE) != 0)) - { - // Z has been held more than 30 ticks on NTSC (36 for PAL), depress trigger on both guns. - if (g_CurrentPlayer->z_trigger_timer > DUAL_WIELD_SINGLE_TRIGGER_SWAP_TICKS) - { - trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = hand; - - if ((gunCanUseWeapon(1 - g_CurrentPlayer->current_trigger_hand) != 0) || g_CurrentPlayer->hands[1 - g_CurrentPlayer->current_trigger_hand].weapon_hold_time != 0) - { - trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 1; - } - } - // Before the hold threshold (30 ticks NTSC or 36 PAL), prefer the hand whose weapon uses alternating dual wield fire. - else - { - hand = bondwalkItemCheckBitflags(weapon_id_right, WEAPONSTATBITFLAG_DUAL_WIELD_ALTERNATING_FIRE) ? GUNRIGHT : GUNLEFT; - - if (gunCanUseWeapon(hand) != 0 || g_CurrentPlayer->hands[hand].weapon_hold_time != 0) - { - g_CurrentPlayer->current_trigger_hand = hand; - } - else - { - if ((gunCanUseWeapon(1 - hand) != 0) || g_CurrentPlayer->hands[1 - hand].weapon_hold_time != 0) - { - g_CurrentPlayer->current_trigger_hand = 1 - hand; - } - else - { - g_CurrentPlayer->current_trigger_hand = 1 - g_CurrentPlayer->current_trigger_hand; - } - } - - trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = 1; - trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 0; - } - } - /** - * Neither weapon uses alternating dual wield fire. - * Once the hold threshold is exceeded, allow the off-hand to become active too. - */ - else if (g_CurrentPlayer->z_trigger_timer > DUAL_WIELD_SINGLE_TRIGGER_SWAP_TICKS) - { - trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = hand; - - if (gunCanUseWeapon(1 - g_CurrentPlayer->current_trigger_hand) || g_CurrentPlayer->hands[1 - g_CurrentPlayer->current_trigger_hand].weapon_hold_time) - { - trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 1; - } - } - /** - * Neither weapon uses alternating dual wield fire. - * On a fresh Z press, switch lead hands if the other hand is usable or the current hand cannot be used. - * The lead hand continues being the lead hand. - */ - else - { - if ((g_CurrentPlayer->prev_trigger_down == 0) && - ((gunCanUseWeapon(1 - g_CurrentPlayer->current_trigger_hand) != 0) || (gunCanUseWeapon(g_CurrentPlayer->current_trigger_hand) == 0))) - { - g_CurrentPlayer->current_trigger_hand = 1 - g_CurrentPlayer->current_trigger_hand; - } - - trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = 1; - trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 0; - } - } - // Not dual wielding. - else - { - if ((getCurrentPlayerWeaponId(g_CurrentPlayer->current_trigger_hand) == ITEM_UNARMED) && (getCurrentPlayerWeaponId(1 - g_CurrentPlayer->current_trigger_hand) != ITEM_UNARMED)) - { - g_CurrentPlayer->current_trigger_hand = 1 - g_CurrentPlayer->current_trigger_hand; - } - - trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = 1; - trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 0; - } - } - // Z button not pressed. Reset the trigger timer. - else - { - g_CurrentPlayer->z_trigger_timer = 0; - } - - gunTickHandState(0, trigger_state.triggerOn[0]); // Right hand - gunTickHandState(1, trigger_state.triggerOn[1]); // Left hand - used_to_load_1st_person_model_on_demand(0); - used_to_load_1st_person_model_on_demand(1); - gunTickNoise(); - - if (g_CurrentPlayer->resetshadecol) - { - set_color_shading_from_tile(getCurrentPlayerProp(), (struct rgba_u8 *) &g_CurrentPlayer->tileColor); - g_CurrentPlayer->resetshadecol = FALSE; - } - else - { - set_color_shading_from_tile(getCurrentPlayerProp(), &weapon_color); - update_color_shading(&g_CurrentPlayer->tileColor, &weapon_color); - } - - bondinvIncrementHeldTime(getCurrentPlayerWeaponId(GUNRIGHT), getCurrentPlayerWeaponId(GUNLEFT)); - - if(1); - - if (g_CurrentPlayer->magnetattracttime >= 0) - { - struct hand *hand_right = &g_CurrentPlayer->hands[0]; - - g_CurrentPlayer->magnetattracttime += g_ClockTimer; - - if (g_CurrentPlayer->magnetattracttime < WATCH_SOUND_DURATION_TICKS) - { - // Start or restart the hum sound if needed - if (hand_right->audioHandle == NULL - || sndGetPlayingState((struct ALSoundState *) hand_right->audioHandle) == 0) - { - if (lvlGetControlsLockedFlag() == 0) - { - sndPlaySfx( - (struct ALBankAlt_s *) g_musicSfxBufferPtr, - MAGNETIC_HUM_SFX, - (struct ALSoundState *) &hand_right->audioHandle); - } - } - } - else - { - g_CurrentPlayer->magnetattracttime = -1; - - if (hand_right->audioHandle != NULL) - { - if (sndGetPlayingState((struct ALSoundState *) hand_right->audioHandle) != 0) - { - sndDeactivate((struct ALSoundState *) hand_right->audioHandle); - } - } - } - } -} - - -void gunSetAimType(s32 param_1) -{ - g_CurrentPlayer->aimtype = param_1; -} - - -void sub_GAME_7F067AB4(coord3d *param_1) -{ - g_CurrentPlayer->hands[GUNRIGHT].field_A38 = sub_GAME_7F05DCB8(GUNRIGHT) + param_1->x; - g_CurrentPlayer->hands[GUNRIGHT].field_A3C = param_1->y; - g_CurrentPlayer->hands[GUNRIGHT].field_A40 = param_1->z; - - g_CurrentPlayer->hands[GUNLEFT].field_A38 = sub_GAME_7F05DCB8(GUNLEFT) + param_1->x; - g_CurrentPlayer->hands[GUNLEFT].field_A3C = param_1->y; - g_CurrentPlayer->hands[GUNLEFT].field_A40 = param_1->z; - -} - - -void gunSetTracerTarget(coord3d* pos) -{ - g_CurrentPlayer->hands[GUNLEFT].item_related.x = g_CurrentPlayer->hands[GUNRIGHT].item_related.x = pos->x; - g_CurrentPlayer->hands[GUNLEFT].item_related.y = g_CurrentPlayer->hands[GUNRIGHT].item_related.y = pos->y; - g_CurrentPlayer->hands[GUNLEFT].item_related.z = g_CurrentPlayer->hands[GUNRIGHT].item_related.z = pos->z; -} - - -void caclulate_gun_crosshair_position_rotation(f32 turn_x, f32 turn_y, f32 guncrossdamp, f32 gunaimdamp) -{ - s32 i; - f32 screen_width; - f32 screen_height; - coord3d coords; - - screen_width = getPlayer_c_screenwidth(); - screen_height = getPlayer_c_screenheight(); - - if (guncrossdamp != g_CurrentPlayer->guncrossdamp) - { - g_CurrentPlayer->crosshair_x_pos = (g_CurrentPlayer->crosshair_x_pos * (1.0f - g_CurrentPlayer->guncrossdamp)) / (1.0f - guncrossdamp); - g_CurrentPlayer->crosshair_y_pos = (g_CurrentPlayer->crosshair_y_pos * (1.0f - g_CurrentPlayer->guncrossdamp)) / (1.0f - guncrossdamp); - g_CurrentPlayer->guncrossdamp = guncrossdamp; - } - - if (gunaimdamp != g_CurrentPlayer->gunaimdamp) - { - g_CurrentPlayer->gun_azimuth_angle = (g_CurrentPlayer->gun_azimuth_angle * (1.0f - g_CurrentPlayer->gunaimdamp)) / (1.0f - gunaimdamp); - g_CurrentPlayer->gun_azimuth_turning = (g_CurrentPlayer->gun_azimuth_turning * (1.0f - g_CurrentPlayer->gunaimdamp)) / (1.0f - gunaimdamp); - g_CurrentPlayer->gunaimdamp = gunaimdamp; - } - - for (i = 0; i < g_ClockTimer; i++) - { - g_CurrentPlayer->crosshair_x_pos = (g_CurrentPlayer->crosshair_x_pos * guncrossdamp) + turn_x; - g_CurrentPlayer->crosshair_y_pos = (g_CurrentPlayer->crosshair_y_pos * guncrossdamp) + turn_y; - } - - g_CurrentPlayer->crosshair_angle.f[0] = (g_CurrentPlayer->crosshair_x_pos * (1.0f - guncrossdamp) * screen_width * 0.5f) + (screen_width * 0.5f); - g_CurrentPlayer->crosshair_angle.f[1] = (g_CurrentPlayer->crosshair_y_pos * (1.0f - guncrossdamp) * screen_height * 0.5f) + (screen_height * 0.5f); - - if (g_CurrentPlayer->crosshair_angle.f[0] < 3.0f) - { - g_CurrentPlayer->crosshair_angle.f[0] = 3.0f; - } - else if ((screen_width - 4.0f) < g_CurrentPlayer->crosshair_angle.f[0]) - { - g_CurrentPlayer->crosshair_angle.f[0] = screen_width - 4.0f; - } - - if (g_CurrentPlayer->crosshair_angle.f[1] < 3.0f) - { - g_CurrentPlayer->crosshair_angle.f[1] = 3.0f; - } - else if ((screen_height - 4.0f) < g_CurrentPlayer->crosshair_angle.f[1]) - { - g_CurrentPlayer->crosshair_angle.f[1] = (screen_height - 4.0f); - } - - g_CurrentPlayer->crosshair_angle.f[0] += getPlayer_c_screenleft(); - g_CurrentPlayer->crosshair_angle.f[1] += getPlayer_c_screentop(); - - for (i = 0; i < g_ClockTimer; i++) - { - g_CurrentPlayer->gun_azimuth_angle = (g_CurrentPlayer->gun_azimuth_angle * gunaimdamp) + turn_x; - g_CurrentPlayer->gun_azimuth_turning = (g_CurrentPlayer->gun_azimuth_turning * gunaimdamp) + turn_y; - } - - g_CurrentPlayer->field_FFC.x = (g_CurrentPlayer->gun_azimuth_angle * (1.0f - gunaimdamp) * screen_width * 0.5f) + (screen_width * 0.5f); - g_CurrentPlayer->field_FFC.y = (g_CurrentPlayer->gun_azimuth_turning * (1.0f - gunaimdamp) * screen_height * 0.5f) + (screen_height * 0.5f); - - g_CurrentPlayer->field_FFC.x += getPlayer_c_screenleft(); - g_CurrentPlayer->field_FFC.y += getPlayer_c_screentop(); - - transformAndNormalizeByLength2Dto3D(&g_CurrentPlayer->field_FFC, &coords, 1000.0f); - sub_GAME_7F067AB4(&coords); -} - - -void sub_GAME_7F067F58(f32 turn_x, f32 turn_y, f32 max_aim_lock_speed) -{ - f32 aim_lock_speed; - -#if defined(VERSION_US) || defined(VERSION_JP) - aim_lock_speed = get_ptr_item_statistics(getCurrentPlayerWeaponId(GUNRIGHT))->AimLockSpeed; -#elif defined(VERSION_EU) - aim_lock_speed = get_ptr_item_statistics(getCurrentPlayerWeaponId(GUNRIGHT))->CrosshairSpeed; -#endif - - if (aim_lock_speed < max_aim_lock_speed) - { - aim_lock_speed = max_aim_lock_speed; - } - - caclulate_gun_crosshair_position_rotation(turn_x, turn_y, max_aim_lock_speed, aim_lock_speed); -} - - -void sub_GAME_7F067FBC(f32 turn_x, f32 turn_y) -{ - WeaponStats * item_stats; - f32 guncrossdamp; - f32 gunaimdamp; - - item_stats = get_ptr_item_statistics(getCurrentPlayerWeaponId(GUNRIGHT)); - -#if defined(VERSION_US) - guncrossdamp = item_stats->CrosshairSpeed; - gunaimdamp = item_stats->AimLockSpeed; -#elif defined(VERSION_EU) - guncrossdamp = 0.7651f; - gunaimdamp = item_stats->CrosshairSpeed; -#elif defined(VERSION_JP) - guncrossdamp = 0.8f; - gunaimdamp = item_stats->AimLockSpeed; -#endif - - caclulate_gun_crosshair_position_rotation(turn_x, turn_y, guncrossdamp, gunaimdamp); -} - - -/* -* Address: 0x7f068008 -*/ -void get_bullet_angle(f32* horizontal_angle, f32* vertical_angle) { - *horizontal_angle = g_CurrentPlayer->crosshair_angle.f[0]; - *vertical_angle = g_CurrentPlayer->crosshair_angle.f[1]; -} - - -void sub_GAME_7F06802C(void) -{ - coord3d coord; - f32 tmp; - - tmp = getPlayer_c_screenleft() + (getPlayer_c_screenwidth() * 0.5f); - g_CurrentPlayer->crosshair_angle.x = tmp; - g_CurrentPlayer->field_FFC.x = tmp; - - tmp = getPlayer_c_screentop() + (getPlayer_c_screenheight() * 0.5f); - g_CurrentPlayer->crosshair_angle.y = tmp; - g_CurrentPlayer->field_FFC.y = tmp; - - transformAndNormalizeByLength2Dto3D((coord2d *) &g_CurrentPlayer->field_FFC, &coord, 1000.0f); - sub_GAME_7F067AB4(&coord); -} - - -void sub_GAME_7F0680D4(coord3d * coord) -{ - coord3d tmp; - - g_CurrentPlayer->field_1010.x = coord->x; - g_CurrentPlayer->field_1010.y = coord->y; - g_CurrentPlayer->field_1010.z = coord->z; - matrix_4x4_set_rotation_around_xyz(coord->f, &g_CurrentPlayer->field_101C); - - tmp.x = g_CurrentPlayer->field_101C.m[2][0] * 1000.0f; - tmp.y = g_CurrentPlayer->field_101C.m[2][1] * 1000.0f; - tmp.z = g_CurrentPlayer->field_101C.m[2][2] * 1000.0f; - transform3Dto2DCoords(&tmp, (coord3d* ) &g_CurrentPlayer->crosshair_angle); - - g_CurrentPlayer->field_FFC.x = g_CurrentPlayer->crosshair_angle.x; - g_CurrentPlayer->field_FFC.y = g_CurrentPlayer->crosshair_angle.y; - - sub_GAME_7F067AB4(&tmp); -} - - -/** - * Address 0x7F068190. -*/ -void sub_GAME_7F068190(coord3d *zeropos, coord3d *vec) -{ - zeropos->x = 0.0f; - zeropos->y = 0.0f; - zeropos->z = 0.0f; - - transformAndNormalizeByLength2Dto3D(&g_CurrentPlayer->crosshair_angle, vec, 1.0f); -} - - -/* -* Address: 0x7f0681cc -* This function computes the angle the player's bullets are fired at -*/ -void bullet_path_from_screen_center(coord3d* arg0, coord3d* result, enum GUNHAND arg2) -{ - coord2d crosspos; - s32 unused; - f32 inaccuracy; - f32 scaledspread; - f32 randfactor; - - inaccuracy = get_ptr_item_statistics(getCurrentPlayerWeaponId(arg2))->Inaccuracy; - if ((bondwalkItemCheckBitflags(get_item_in_hand_or_watch_menu(arg2), WEAPONSTATBITFLAG_FIRST_SHOT_ACCURACY) != 0) && (g_CurrentPlayer->hands[arg2].volley == 1)) - { - // Single shots are four times more accurate - inaccuracy *= 0.25f; - } - - scaledspread = (120.0f * inaccuracy) / viGetFovY(); - - randfactor = (RANDOMFRAC() - 0.5f) * RANDOMFRAC(); - crosspos.x = g_CurrentPlayer->crosshair_angle.f[0] + randfactor * scaledspread * getPlayer_c_screenwidth() * (PAL ? ASPECT_RATIO_PAL : ASPECT_RATIO_SD) - / (getPlayer_c_perspaspect() * 320.0f); - - randfactor = (RANDOMFRAC() - 0.5f) * RANDOMFRAC(); - crosspos.y = g_CurrentPlayer->crosshair_angle.f[1] + randfactor * scaledspread * getPlayer_c_screenheight() - / (PAL ? (f32)(SCREEN_HEIGHT_272) : (f32)(SCREEN_HEIGHT_240)); - - arg0->x = 0.0f; - arg0->y = 0.0f; - arg0->z = 0.0f; - - // Result is a normalized vector describing the path the bullet will follow - // Can be used to compute x,y,z displacement off the center of the screen if done for a projectile - transformAndNormalizeByLength2Dto3D(&crosspos, result, 1.0f); -} - - -/* -* Address: 0x7f068420 -*/ -CasingRecord* casingCreate(ModelFileHeader* header, Mtxf* mtx) -{ - CasingRecord* entry = g_Casings; - CasingRecord* end = g_Casings + ARRAYCOUNT(g_Casings); - - while (entry < end && entry->header != NULL) - { - entry++; - } - - if (entry < end) - { - entry->header = header; - - entry->pos.x = mtx->m[3][0]; - entry->pos.y = mtx->m[3][1]; - entry->pos.z = mtx->m[3][2]; -#if VERSION_EU - matrix_7f05842c_eu(mtx, entry->rot_mtx); -#else - entry->rot_mtx.m[0][0] = mtx->m[0][0]; - entry->rot_mtx.m[0][1] = mtx->m[0][1]; - entry->rot_mtx.m[0][2] = mtx->m[0][2]; - entry->rot_mtx.m[0][3] = 0.0f; - - entry->rot_mtx.m[1][0] = mtx->m[1][0]; - entry->rot_mtx.m[1][1] = mtx->m[1][1]; - entry->rot_mtx.m[1][2] = mtx->m[1][2]; - entry->rot_mtx.m[1][3] = 0.0f; - - entry->rot_mtx.m[2][0] = mtx->m[2][0]; - entry->rot_mtx.m[2][1] = mtx->m[2][1]; - entry->rot_mtx.m[2][2] = mtx->m[2][2]; - entry->rot_mtx.m[2][3] = 0.0f; - - entry->rot_mtx.m[3][0] = 0.0f; - entry->rot_mtx.m[3][1] = 0.0f; - entry->rot_mtx.m[3][2] = 0.0f; - entry->rot_mtx.m[3][3] = 1.0f; -#endif - return entry; - } - - return NULL; -} - - -#if VERSION_EU -#define THROWMTX_OFFSET 0xAD0 -#define THROWPOS_OFFSET 0xB00 -#define THROWPOS_PREV_OFFSET 0xB40 -#else -#define THROWMTX_OFFSET 0xAD8 -#define THROWPOS_OFFSET 0xB08 -#define THROWPOS_PREV_OFFSET 0xB48 -#endif - -#define THROWMTX ((Mtxf *) ((u8 *) g_CurrentPlayer + handoffset + THROWMTX_OFFSET)) -#define THROWPOS(k) (((f32 *) ((u8 *) g_CurrentPlayer + handoffset + THROWPOS_OFFSET))[k]) -#define THROWPREV(k) (((f32 *) ((u8 *) g_CurrentPlayer + handoffset + THROWPOS_PREV_OFFSET))[k]) - -extern f32 D_800543B4; -extern f32 D_800543B8; -extern f32 D_800543BC; -extern f32 D_800543C0; -extern f32 D_800543C4; -extern f32 D_800543C8; -extern f32 D_800543CC; -extern f32 D_800543D0; -extern f32 D_800543D4; -extern f32 expended_shell_initial_gravity_modifier_pistol; -extern f32 D_800543DC; -extern f32 D_800543E0; -extern f32 D_800543E4; -extern f32 D_800543E8; -extern f32 D_800543EC; -extern f32 D_800543F0; -extern f32 D_800543F4; -extern f32 D_800543F8; -extern f32 D_800543FC; -extern f32 expended_shell_initial_gravity_modifier_non_pistol; - -#ifndef VERSION_EU -GLOBAL_ASM( -.late_rodata -glabel D_800543B4 -.word 0x3dccccce /*0.10000001*/ -glabel D_800543B8 -.word 0x3f088888 /*0.5333333*/ -glabel D_800543BC -.word 0x40c90fdb /*6.2831855*/ -glabel D_800543C0 -.word 0x3ec90fdb /*0.39269909*/ -glabel D_800543C4 -.word 0x40c90fdb /*6.2831855*/ -glabel D_800543C8 -.word 0x3ec90fdb /*0.39269909*/ -glabel D_800543CC -.word 0x40c90fdb /*6.2831855*/ -glabel D_800543D0 -.word 0x3ec90fdb /*0.39269909*/ -glabel D_800543D4 -.word 0x493d6c30 /*775875.0*/ -glabel expended_shell_initial_gravity_modifier_pistol -.word 0x3e8e38e4 /*0.27777779*/ -glabel D_800543DC -.word 0x3fb55555 /*1.4166666*/ -glabel D_800543E0 -.word 0x3fd55555 /*1.6666666*/ -glabel D_800543E4 -.word 0x40c90fdb /*6.2831855*/ -glabel D_800543E8 -.word 0x3ec90fdb /*0.39269909*/ -glabel D_800543EC -.word 0x40c90fdb /*6.2831855*/ -glabel D_800543F0 -.word 0x3ec90fdb /*0.39269909*/ -glabel D_800543F4 -.word 0x40c90fdb /*6.2831855*/ -glabel D_800543F8 -.word 0x3ec90fdb /*0.39269909*/ -glabel D_800543FC -.word 0x493d6c30 /*775875.0*/ -glabel expended_shell_initial_gravity_modifier_non_pistol -.word 0x3e8e38e4 /*0.27777779*/ -) -#else -GLOBAL_ASM( -.late_rodata -glabel D_800543B4 -.word 0x3dccccce /*0.10000001*/ -glabel D_800543B8 -.word 0x3f088888 /*0.5333333*/ -glabel D_800543BC -.word 0x40c90fdb /*6.2831855*/ -glabel D_800543C0 -.word 0x3ec90fdb /*0.39269909*/ -glabel D_800543C4 -.word 0x40c90fdb /*6.2831855*/ -glabel D_800543C8 -.word 0x3ec90fdb /*0.39269909*/ -glabel D_800543CC -.word 0x40c90fdb /*6.2831855*/ -glabel D_800543D0 -.word 0x3ec90fdb /*0.39269909*/ -glabel D_800543D4 -.word 0x49634ea0 /* 931050.0 */ -glabel expended_shell_initial_gravity_modifier_pistol -.word 0x3e8e38e4 /*0.27777779*/ -glabel D_800543DC -.word 0x3fb55555 /*1.4166666*/ -glabel D_800543E0 -.word 0x3fd55555 /*1.6666666*/ -glabel D_800543E4 -.word 0x40c90fdb /*6.2831855*/ -glabel D_800543E8 -.word 0x3ec90fdb /*0.39269909*/ -glabel D_800543EC -.word 0x40c90fdb /*6.2831855*/ -glabel D_800543F0 -.word 0x3ec90fdb /*0.39269909*/ -glabel D_800543F4 -.word 0x40c90fdb /*6.2831855*/ -glabel D_800543F8 -.word 0x3ec90fdb /*0.39269909*/ -glabel D_800543FC -.word 0x49634ea0 /* 931050.0 */ -glabel expended_shell_initial_gravity_modifier_non_pistol -.word 0x3e8e38e4 /*0.27777779*/ -) -#endif - -/** - * Address: 7F068508 - * - * Ejects a spent cartridge casing from the gun in the given hand. - */ -void sub_GAME_7F068508(GUNHAND handnum, f32 floor_y_pos) -{ - CasingRecord *casing; - Mtxf mtx; - ITEM_IDS weaponid; - coord3d *switchdata; - ModelFileHeader *cartridge_header; - coord3d switchpos; - ModelNode *switch0; - coord3d rot; -#if VERSION_EU - Mtxf rotmtx; -#endif - f32 rand; - s32 new_var; /* dead but declared on EU — still reserves its frame slot */ - f32 frac; -#if VERSION_EU - s32 randlimit; -#endif - f32 oldvely; - f32 newvely; -#ifndef VERSION_EU - s32 randlimit; -#endif - s32 handoffset; - u32 randval; -#if VERSION_EU - s32 pad[2]; -#endif - - weaponid = getCurrentPlayerWeaponId(handnum); - cartridge_header = get_ptr_item_statistics(weaponid)->ptr_cartridge_struct; - - // Do not create ejected casings in multiplayer. - if ((cartridge_header == NULL) || (getPlayerCount() >= 2)) - { - return; - } - - handoffset = handnum * sizeof(struct hand); - switch0 = g_CurrentPlayer->copy_of_body_obj_header[handnum].Switches[0]; - - if (switch0 != NULL) - { - switchdata = (coord3d *) switch0->Data; - - switchpos.x = switchdata->x * D_800543B4; - switchpos.y = switchdata->y * D_800543B4; - switchpos.z = switchdata->z * D_800543B4; - - matrix_4x4_set_identity_and_position(&switchpos, &mtx); - matrix_4x4_multiply_in_place(THROWMTX, &mtx); - } - else - { - matrix_4x4_copy(THROWMTX, &mtx); - } - - casing = casingCreate(cartridge_header, &mtx); - - if (casing == NULL) - { - return; - } - - rot = *((coord3d *) (&D_80035EA4)); - casing->floor_y_pos = floor_y_pos; - - if (((((weaponid == ITEM_WPPK) || (weaponid == ITEM_WPPKSIL)) || (weaponid == ITEM_TT33)) || (weaponid == ITEM_SILVERWPPK)) || (weaponid == ITEM_GOLDWPPK)) - { - rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; - newvely = 0.0625f; - casing->vel.x = -(((rand * D_800543B8) * newvely) + D_800543B8); - - rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; - casing->vel.y = ((rand * 2.5f) * 0.0625f) + 2.5f; - casing->vel.z = frac * 0.0f; - - mtx4RotateVecInPlace(THROWMTX, &casing->vel); - - rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; - rot.x = (((rand + rand) * D_800543BC) * newvely) - D_800543C0; - - rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; - rot.y = (((rand + rand) * D_800543C4) * newvely) - D_800543C8; - - rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; - rot.z = (((rand + rand) * D_800543CC) * newvely) - D_800543D0; - -#if VERSION_EU - matrix_4x4_set_rotation_around_xyz(&rot, &rotmtx); - matrix_7f05842c_eu(&rotmtx, casing->rot_velocity_mtx); - if (handoffset); -#else - matrix_4x4_set_rotation_around_xyz(&rot, &casing->rot_velocity_mtx); -#endif - -#if VERSION_EU - randlimit = ((s32) ((randomGetNext() >> 24) * 0x158679)) >> 10; - randlimit = randlimit + 0x158679; - randval = randomGetNext(); - oldvely = casing->vel.y; - frac = ((f32) ((u32) (randval % randlimit))) / D_800543D4; -#else - randlimit = (((s32) ((randomGetNext() >> 24) * 0x158679)) >> 10) + 0x158679; - new_var = randlimit; - randval = randomGetNext(); - oldvely = casing->vel.y; - frac = ((f32) ((u32) (randval % new_var))) / D_800543D4; -#endif - newvely = oldvely - (frac * expended_shell_initial_gravity_modifier_pistol); - - casing->vel.y = newvely; - casing->pos.y += (frac * (oldvely + newvely)) * 0.5f; - casing->pos.x += frac * casing->vel.x; - casing->pos.z += frac * casing->vel.z; - - // Keep the 0 + 1 for matching. - if (g_ClockTimer >= (0 + 1)) - { - casing->vel.x += (THROWPOS(0) - THROWPREV(0)) / g_GlobalTimerDelta; - casing->vel.y += (THROWPOS(1) - THROWPREV(1)) / g_GlobalTimerDelta; - casing->vel.z += (THROWPOS(2) - THROWPREV(2)) / g_GlobalTimerDelta; - } - } - else - { - rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; - casing->vel.x = -(((rand * D_800543DC) * 0.125f) + D_800543DC); - - rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; - casing->vel.y = ((rand * D_800543E0) * 0.125f) + D_800543E0; - casing->vel.z = 0.0f; - - mtx4RotateVecInPlace(THROWMTX, &casing->vel); - - rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; - rot.x = (((rand + rand) * D_800543E4) * 0.0625f) - D_800543E8; - - rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; - rot.y = (((rand + rand) * D_800543EC) * 0.0625f) - D_800543F0; - - rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; - rot.z = (((rand + rand) * D_800543F4) * 0.0625f) - D_800543F8; - -#if VERSION_EU - matrix_4x4_set_rotation_around_xyz(&rot, &rotmtx); - matrix_7f05842c_eu(&rotmtx, casing->rot_velocity_mtx); - if (handoffset); -#else - matrix_4x4_set_rotation_around_xyz(&rot, &casing->rot_velocity_mtx); -#endif - randval = ((s32) ((randomGetNext() >> 24) * 0x158679)) >> 10; -#if VERSION_EU - randval = randval + 0x158679; - randlimit = randomGetNext(); - oldvely = (&casing->vel)->y; - frac = ((f32) ((u32) (randlimit % randval))) / D_800543FC; -#else - randlimit = randval + 0x158679; - randval = randomGetNext(); - oldvely = (&casing->vel)->y; - frac = ((f32) ((u32) (randval % randlimit))) / D_800543FC; -#endif - newvely = (casing->vel.y = oldvely - (frac * expended_shell_initial_gravity_modifier_non_pistol)); - - casing->pos.y += (frac * (oldvely + newvely)) * 0.5f; - casing->pos.x += frac * casing->vel.x; - casing->pos.z += frac * casing->vel.z; - - if (g_ClockTimer > 0) - { - casing->vel.x += (THROWPOS(0) - THROWPREV(0)) / g_GlobalTimerDelta; - casing->vel.y += (THROWPOS(1) - THROWPREV(1)) / g_GlobalTimerDelta; - casing->vel.z += (THROWPOS(2) - THROWPREV(2)) / g_GlobalTimerDelta; - } - } - - if (handoffset); -} - - -extern f32 g_CasingGravity; -extern f32 g_CasingModelScale; -extern f32 g_CasingMinMatrixTranslation; -extern f32 g_CasingMaxMatrixTranslation; - -GLOBAL_ASM( -.late_rodata -glabel g_CasingGravity -.word 0x3e8e38e4 /*0.27777779*/ -glabel g_CasingModelScale -.word 0x3dccccce /*0.10000001*/ -glabel g_CasingMinMatrixTranslation -.word 0xc6ea6000 /*-30000.0*/ -glabel g_CasingMaxMatrixTranslation -.word 0x46ea6000 /*30000.0*/ -) - -void update_bullet_casing(CasingRecord* casing) -{ - f32 new_val_y; - f32 delta; - s32 i; - struct player* current_player; - - delta = g_GlobalTimerDelta; - new_val_y = casing->vel.y - (delta * g_CasingGravity); - - casing->pos.y += delta * 0.5f * (casing->vel.y + new_val_y); - - if (casing->pos.y < casing->floor_y_pos) - { -#if defined(BUGFIX_R1) - if (g_CasingSfxState == 0 && (g_ClockTimer > 0)) -#else - if (g_CasingSfxState == 0) -#endif - { - if ((g_CurrentPlayer->hands[0].weapon_action_state != GUN_ANIM_STATE_FIRE) && (g_CurrentPlayer->hands[1].weapon_action_state != GUN_ANIM_STATE_FIRE)) - { - // Play bullet casing rolling on floor sound - sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, CART_SPENT_SFX, (ALSoundState* ) &g_CasingSfxState); - } - } - - // This casing is removed and not updated anymore - casing->header = NULL; - return; - } - - casing->vel.y = new_val_y; - casing->pos.x += delta * casing->vel.x; - casing->pos.z += delta * casing->vel.z; - - for (i = 0; i < g_ClockTimer; i++) - { -#if defined(VERSION_US) || defined(VERSION_JP) - matrix_4x4_multiply_homogeneous_in_place(&casing->rot_velocity_mtx, &casing->rot_mtx); -#else - matrix_4x4_multiply_homogeneous_in_place_eu(casing->rot_velocity_mtx, casing->rot_mtx); -#endif - } -} - - -void update_bullet_casings(void) -{ - CasingRecord* end = g_Casings + ARRAYCOUNT(g_Casings); - CasingRecord* entry = g_Casings; - - while (entry < end) - { - if (entry->header) - { - update_bullet_casing(entry); - } - - entry++; - } -} - -typedef struct ModelHead { - s16 unk00; - s16 rwdatalen; - void *chr; - ModelFileHeader *obj; - RenderPosView *render_pos; - union ModelRwData **datas; - f32 scale; - Model *attachedto; - ModelNode *attachedto_objinst; -} ModelHead; - -void sub_GAME_7F068EC4(CasingRecord *casing, Gfx **gdl) -{ - Gfx *savedgdl = *gdl; - ModelFileHeader *model_header = casing->header; - RenderPosView *model_matrices = dynAllocate(model_header->numMatrices * sizeof(RenderPosView)); - ModelHead model; - ModelRenderData render_data = *(ModelRenderData *)g_DefaultCasingModelRenderData; - Mtxf casing_model_mtx; - s32 axis_offset; - s32 matrix_translation_in_range = TRUE; - f32 max_matrix_translation; - f32 model_scale_or_min_translation; - u8 *matrix_axis_ptr; - - modelCalculateRwDataLen(model_header); - modelInit((Model *)&model, model_header, NULL); - - model.render_pos = model_matrices; - -#if defined(VERSION_EU) - matrix_4x4_copy_eu(casing->rot_mtx, casing_model_mtx.m); -#else - matrix_4x4_copy(&casing->rot_mtx, &casing_model_mtx); -#endif - - model_scale_or_min_translation = g_CasingModelScale; - matrix_scalar_multiply(model_scale_or_min_translation, &casing_model_mtx); - - matrix_4x4_set_position(&casing->pos, &casing_model_mtx); - - matrix_4x4_multiply_homogeneous( - camGetWorldToScreenMtxf(), - &casing_model_mtx, - (Mtxf *)model.render_pos); - - model_scale_or_min_translation = g_CasingMinMatrixTranslation; - max_matrix_translation = g_CasingMaxMatrixTranslation; - - axis_offset = 0; - matrix_axis_ptr = (u8 *)model.render_pos; - - // Offset 0x30 is m[3][0]; advancing the pointer checks translation X, Y and Z. - while (axis_offset != 12) - { - if (max_matrix_translation < *(f32 *)(matrix_axis_ptr + 0x30)) - { - matrix_translation_in_range = FALSE; - } - else if (*(f32 *)(matrix_axis_ptr + 0x30) < model_scale_or_min_translation) - { - matrix_translation_in_range = FALSE; - } - - axis_offset += 4; - matrix_axis_ptr += 4; - } - - if (matrix_translation_in_range) - { - render_data.zbufferenabled = 0; - render_data.gdl = savedgdl; - render_data.mtxlist = (Mtxf *)model_matrices; - render_data.PropType = PROP_TYPE_WEAPON; - - render_data.envcolour.word = - ((g_CurrentPlayer->tileColor.a | - (g_CurrentPlayer->tileColor.r << 24)) | - (g_CurrentPlayer->tileColor.g << 16)) | - (g_CurrentPlayer->tileColor.b << 8); - - subdraw(&render_data, (Model *)&model); - - *gdl = render_data.gdl; - - bondviewTransformManyPosToViewMatrix(model_matrices, model_header->numMatrices); - } -} - - -// Address: 0x7F06908C -void gunRenderCasings(Gfx **gdl) -{ - CasingRecord* end = g_Casings + ARRAYCOUNT(g_Casings); - CasingRecord* entry = g_Casings; - - while (entry < end) - { - if (entry->header) - { - sub_GAME_7F068EC4(entry, gdl); - } - - entry++; - } -} - - -void gunSetGunAmmoVisible(s32 reason, bool enable) { - - if (enable) - { - g_CurrentPlayer->gunammooff &= ~reason; - return; - } - - g_CurrentPlayer->gunammooff |= reason; -} - - - -void give_cur_player_ammo(s32 ammo_type, s32 ammo_amount) { - enum ITEM_IDS weapon_id; - s32 max_ammo; - - weapon_id = getCurrentPlayerWeaponId(GUNRIGHT); - if ((get_ammo_type_for_weapon(weapon_id) == ammo_type) && (bondwalkItemCheckBitflags(weapon_id, WEAPONSTATBITFLAG_AMMO_CLIP_LIMIT) != 0)) - { - g_CurrentPlayer->hands[0].weapon_ammo_in_magazine += ammo_amount; - if (get_ptr_item_statistics(weapon_id)->MagSize < g_CurrentPlayer->hands[0].weapon_ammo_in_magazine) - { - g_CurrentPlayer->hands[0].weapon_ammo_in_magazine = (s32) get_ptr_item_statistics(weapon_id)->MagSize; - } - g_CurrentPlayer->ammoheldarr[ammo_type] = 0; - return; - } - - max_ammo = ammo_related[ammo_type].MaxAmmo; - if (max_ammo < ammo_amount) - { - g_CurrentPlayer->ammoheldarr[ammo_type] = max_ammo; - return; - } - - g_CurrentPlayer->ammoheldarr[ammo_type] = ammo_amount; -} - - - - -s32 check_cur_player_ammo_amount_in_inventory(AMMOTYPE ammotype) { - return g_CurrentPlayer->ammoheldarr[ammotype]; -} - -s32 currentPlayerGetAmmoCount(AMMOTYPE ammotype) { - - s32 total_ammo = check_cur_player_ammo_amount_in_inventory(ammotype); - - if (get_ammo_type_for_weapon(getCurrentPlayerWeaponId(GUNRIGHT)) == ammotype) { - total_ammo += get_ammo_in_hands_magazine(GUNRIGHT); - } - - if (get_ammo_type_for_weapon(getCurrentPlayerWeaponId(GUNLEFT)) == ammotype) { - total_ammo += get_ammo_in_hands_magazine(GUNLEFT); - } - - return total_ammo; -} - - - -s32 get_max_ammo_for_type(s32 arg0) -{ - return ammo_related[arg0].MaxAmmo; -} - - - - -void set_max_ammo_for_cur_player(void) -{ - s32 ammo_type; - - for (ammo_type = 0; ammo_type < AMMO_RELATED_MAX; ammo_type++) - { - give_cur_player_ammo(ammo_type, ammo_related[ammo_type].MaxAmmo); - } -} - - - -s32 get_ammo_in_hands_magazine(GUNHAND hand) { - return g_CurrentPlayer->hands[hand].weapon_ammo_in_magazine; -} - - - -s32 get_ammo_in_hands_weapon(enum GUNHAND hand) -{ - s32 weapon_id; - s32 ammo_count; - - weapon_id = getCurrentPlayerWeaponId(hand); - ammo_count = get_ammo_count_for_weapon(weapon_id); - - if ((weapon_id == ITEM_SHOTGUN) || (weapon_id == ITEM_AUTOSHOT)) - { - s32 other_weapon_id; - other_weapon_id = getCurrentPlayerWeaponId(1 - hand); - - if ((other_weapon_id == ITEM_SHOTGUN) || (other_weapon_id == ITEM_AUTOSHOT)) - { - return ammo_count - g_CurrentPlayer->hands[1 - hand].numvisibleshells; - } - - /* I don't know why there's an extra return here, but it's needed to match */ - return ammo_count; - } - - return ammo_count; -} - - - -s32 get_ammo_type_for_weapon(ITEM_IDS weapon) { - return get_ptr_item_statistics(weapon)->AmmoType; -} - -s32 get_ammo_count_for_weapon(ITEM_IDS weapon) { - WeaponStats *weaponstats = get_ptr_item_statistics(weapon); - return g_CurrentPlayer->ammoheldarr[weaponstats->AmmoType]; -} - -void add_ammo_to_weapon(ITEM_IDS weapon, s32 ammo) { - give_cur_player_ammo(get_ptr_item_statistics(weapon)->AmmoType, ammo); -} - -s32 get_max_ammo_for_weapon(enum ITEM_IDS weapon) -{ - return ammo_related[get_ptr_item_statistics(weapon)->AmmoType].MaxAmmo; -} - - -Gfx *microcode_generation_ammo_related(Gfx *gdl, struct sImageTableEntry *tconfig, f32 x, f32 y, f32 arg4, s32 arg5, f32 arg6, s32 arg7, s32 red, s32 green, s32 blue, s32 alpha) -{ - f32 xy[2]; - f32 halfed[2]; - - gDPSetColorDither(gdl++, G_CD_DISABLE); - gDPSetTexturePersp(gdl++, G_TP_NONE); - gDPSetAlphaCompare(gdl++, G_AC_NONE); - gDPSetTextureLOD(gdl++, G_TL_TILE); - gDPSetTextureFilter(gdl++, G_TF_POINT); - gDPSetTextureConvert(gdl++, G_TC_FILT); - gDPSetTextureLUT(gdl++, G_TT_NONE); - - xy[0] = ((u32)tconfig->width * 0.5f) - (f32)(tconfig->width / 2); - - if (arg5 != 0) - { - xy[0] = -xy[0]; - } - - xy[0] = xy[0] + x; - - if (0.0f <= y) - { - xy[1] = y - (((f32) ((u32) tconfig->height)) * 0.5f); - } - else - { - xy[1] = -((((f32)((u32)tconfig->height)) * 0.5f) - ((f32)(tconfig->height / 2))); - xy[1] = arg4 + xy[1]; - xy[1] = xy[1] + arg6; - } - - halfed[0] = ((f32) ((u32) tconfig->width)) * 0.5f; - halfed[1] = ((f32) ((u32) tconfig->height)) * 0.5f; - - gDPPipeSync(gdl++); - gDPSetCycleType(gdl++, G_CYC_1CYCLE); - gDPSetRenderMode(gdl++, G_RM_XLU_SURF, G_RM_XLU_SURF2); - gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); - gDPSetPrimColor(gdl++, 0, 0, 0, 0, 0, 0); - gDPFillRectangle(gdl++, ((s32)(xy[0] - halfed[0])) - 1, ((s32)(xy[1] - halfed[1])) - 1, ((s32)(xy[0] + halfed[0])) + 1, ((s32)(xy[1] + halfed[1])) + 1); - - texSelect(&gdl, tconfig, (arg7 != 0) ? (2) : (1), 0, 0); - display_image_at_position(&gdl, xy, halfed, tconfig->width, tconfig->height, 0, 0, 1, red, green, blue, alpha, 0 < tconfig->level, 0); - - gDPPipeSync(gdl++); - gDPSetColorDither(gdl++, G_CD_BAYER); - gDPSetTexturePersp(gdl++, G_TP_PERSP); - gDPSetAlphaCompare(gdl++, G_AC_NONE); - gDPSetTextureLOD(gdl++, G_TL_LOD); - gDPSetTextureFilter(gdl++, G_TF_BILERP); - gDPSetTextureConvert(gdl++, G_TC_FILT); - gDPSetTextureLUT(gdl++, G_TT_NONE); - - return gdl; -} - - -/** - * Address: TODO - * WARNING: This function is missing a "return". This will cause bugs on other compilers. - */ -Gfx *set_rgba_redirect_generate_microcode(Gfx *gdl, sImageTableEntry *tconfig, f32 x, f32 y, f32 arg4, s32 arg5, f32 arg6, s32 arg7) -{ - microcode_generation_ammo_related(gdl, tconfig, x, y, arg4, arg5, arg6, arg7, 0xff, 0xff, 0xff, 0xff); -} - - -/** - * Address: TODO - */ -Gfx *gunDrawHudString(Gfx *gdl, s8 *text, s32 x, s32 halign, s32 y, s32 valign, bool outline) -{ - s32 x1; - s32 y1; - s32 x2; - s32 y2; - s32 textheight; - s32 textwidth; - - x1 = 0; - y1 = 0; - x2 = 0; - y2 = 0; - textwidth = 0; - textheight = 0; - - textMeasure(&textheight, &textwidth, text, ptrFontBankGothicChars, ptrFontBankGothic, 0); - - if (halign == HUDHALIGN_LEFT) { // left - x2 = x + textwidth; - x1 = x; - } else if (halign == HUDHALIGN_RIGHT) { // right - x1 = x - textwidth; - x2 = x; - } else if (halign == HUDHALIGN_MIDDLE) { // middle - x2 = x + textwidth / 2; - x1 = x2 - textwidth; - } - - if (valign == HUDVALIGN_TOP) { // top - y2 = y + textheight; - y1 = y; - } else if (valign == HUDVALIGN_BOTTOM) { // bottom - y1 = y - textheight; - y2 = y; - } else if (valign == HUDVALIGN_MIDDLE) { // middle - y2 = y + textheight / 2; - y1 = y2 - textheight; - } - - gdl = draw_blackbox_to_screen(gdl, &x1, &y1, &x2, &y2); - - if (outline) { - gdl = textRenderOutlined(gdl, &x1, &y1, text, ptrFontBankGothicChars, ptrFontBankGothic, -1, 0x646464FF, (s32) viGetX(), viGetY(), 0, 0); - } else { - gdl = textRender(gdl, &x1, &y1, text, ptrFontBankGothicChars, ptrFontBankGothic, 0xFF00B0, (s32) viGetX(), viGetY(), 0, 0); - } - - return gdl; -} - - -/** - * Address: TODO - */ -Gfx *gunDrawHudInteger(Gfx *gdl, s32 value, s32 x, s32 halign, s32 y, s32 valign, bool outline) -{ - char buffer[12]; - sprintf(buffer, "%d\n", value); - return gunDrawHudString(gdl, buffer, x, halign, y, valign, outline); -} - - -/** - * Draw magazine ammo number, ammo type icon, and total ammo number at the bottom right of the viewport. - * Render an additional ammo counter at the bottom left of the viewport when dual wielding. - */ -Gfx *generate_ammo_total_microcode(Gfx *gdl) -{ - ITEM_IDS weapon_left; - ITEM_IDS weapon_right; - s32 ammotype; - s32 leftx; - s32 rightx; - s32 reserveammo; - s32 magammo; - u32 imageoffset_r; - s32 textwidth_r; - u32 imageoffset_l; - s32 textwidth_l; - - if (g_CurrentPlayer->gunammooff == 0) - { - if (g_CurrentPlayer->mpmenuon == 0) - { - weapon_left = getCurrentPlayerWeaponId(GUNLEFT); - weapon_right = getCurrentPlayerWeaponId(GUNRIGHT); - - if (getPlayerCount() < 3) - { - leftx = 59; - rightx = 59; - } - else if (get_cur_playernum() & 1) - { - leftx = 43; - rightx = 127; - } - else - { - leftx = 59; - rightx = 109; - } - - if (weapon_right != ITEM_UNARMED) - { - ammotype = get_ammo_type_for_weapon(weapon_right); - - if (ammotype != 0 - && g_CurrentPlayer->hands[0].weapon_action_state != GUN_ANIM_STATE_SWITCH_SWAP - && g_CurrentPlayer->hands[0].weapon_action_state != GUN_ANIM_STATE_SWITCH_HOLD - && !bondwalkItemCheckBitflags(weapon_right, WEAPONSTATBITFLAG_HIDE_AMMO_DISPLAY)) - { - imageoffset_r = ammo_related[ammotype].IconImage; - textwidth_r = 5; - - if (imageoffset_r != 0) - { - imageoffset_r += globalbank_rdram_offset; - gdl = set_rgba_redirect_generate_microcode(gdl, (u8 *)imageoffset_r, (getPlayer_c_screenleft() + getPlayer_c_screenwidth()) - (f32)rightx, -1.0f, -#if defined(VERSION_EU) - (viGetViewTop() + viGetViewHeight()) - 30, 0, -#else - (viGetViewTop() + viGetViewHeight()) - 20, 0, -#endif - ammo_related[ammotype].IconYOffset, 1); - textwidth_r = ((u8 *)imageoffset_r)[4]; - } - - gdl = microcode_constructor(gdl); - - if (bondwalkItemCheckBitflags(weapon_right, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) - { - magammo = 0; - reserveammo = g_CurrentPlayer->ammoheldarr[ammotype] + g_CurrentPlayer->hands[0].weapon_ammo_in_magazine; - if (weapon_left == weapon_right) - { - reserveammo += g_CurrentPlayer->hands[1].weapon_ammo_in_magazine; - } - } - else - { - magammo = g_CurrentPlayer->hands[0].weapon_ammo_in_magazine; - reserveammo = g_CurrentPlayer->ammoheldarr[ammotype]; - } - - if (!bondwalkItemCheckBitflags(weapon_right, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) - { - gdl = gunDrawHudInteger(gdl, magammo, (((viGetViewLeft() + viGetViewWidth()) - rightx) - (textwidth_r / 2)) - 4, 0, -#if defined(VERSION_EU) - (viGetViewTop() + viGetViewHeight()) - 28, 2, 1); -#else - (viGetViewTop() + viGetViewHeight()) - 18, 2, 1); -#endif - } - - if (reserveammo > 0 || bondwalkItemCheckBitflags(weapon_right, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) - { - gdl = gunDrawHudInteger(gdl, reserveammo, (((viGetViewLeft() + viGetViewWidth()) - rightx) + ((textwidth_r + 1) / 2)) + 3, 1, -#if defined(VERSION_EU) - (viGetViewTop() + viGetViewHeight()) - 28, 2, 1); -#else - (viGetViewTop() + viGetViewHeight()) - 18, 2, 1); -#endif - } - - gdl = combiner_bayer_lod_perspective(gdl); - } - } - - if (weapon_left != ITEM_UNARMED) - { - ammotype = get_ammo_type_for_weapon(weapon_left); - - if (ammotype != 0 - && g_CurrentPlayer->hands[1].weapon_action_state != GUN_ANIM_STATE_SWITCH_SWAP - && g_CurrentPlayer->hands[1].weapon_action_state != GUN_ANIM_STATE_SWITCH_HOLD - && !bondwalkItemCheckBitflags(weapon_left, WEAPONSTATBITFLAG_HIDE_AMMO_DISPLAY)) - { - imageoffset_l = ammo_related[ammotype].IconImage; - textwidth_l = 5; - - if (imageoffset_l != 0) - { - imageoffset_l += globalbank_rdram_offset; - gdl = set_rgba_redirect_generate_microcode(gdl, (u8 *)imageoffset_l, getPlayer_c_screenleft() + (f32)leftx, -1.0f, -#if defined(VERSION_EU) - (viGetViewTop() + viGetViewHeight()) - 30, 1, -#else - (viGetViewTop() + viGetViewHeight()) - 20, 1, -#endif - ammo_related[ammotype].IconYOffset, 1); - textwidth_l = ((u8 *)imageoffset_l)[4]; - } - - gdl = microcode_constructor(gdl); - - if (bondwalkItemCheckBitflags(weapon_left, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) - { - magammo = 0; - reserveammo = g_CurrentPlayer->ammoheldarr[ammotype] + g_CurrentPlayer->hands[1].weapon_ammo_in_magazine; - if (weapon_left == weapon_right) - { - reserveammo += g_CurrentPlayer->hands[0].weapon_ammo_in_magazine; - } - } - else - { - magammo = g_CurrentPlayer->hands[1].weapon_ammo_in_magazine; - reserveammo = g_CurrentPlayer->ammoheldarr[ammotype]; - } - - if (!bondwalkItemCheckBitflags(weapon_left, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) - { - gdl = gunDrawHudInteger(gdl, magammo, ((viGetViewLeft() + leftx) + (textwidth_l / 2)) + 3, 1, -#if defined(VERSION_EU) - (viGetViewTop() + viGetViewHeight()) - 28, 2, 1); -#else - (viGetViewTop() + viGetViewHeight()) - 18, 2, 1); -#endif - } - - if (reserveammo > 0 || bondwalkItemCheckBitflags(weapon_left, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) - { - gdl = gunDrawHudInteger(gdl, reserveammo, ((viGetViewLeft() + leftx) - ((textwidth_l + 1) / 2)) - 4, 0, -#if defined(VERSION_EU) - (viGetViewTop() + viGetViewHeight()) - 28, 2, 1); -#else - (viGetViewTop() + viGetViewHeight()) - 18, 2, 1); -#endif - } - - gdl = combiner_bayer_lod_perspective(gdl); - } - } - } - } - - return gdl; -} - - -/** - * Address: 7F06A334 - */ -Gfx *gunDrawWatchAmmoDisplay(Gfx *gdl) -{ - ITEM_IDS offhanditem; - ITEM_IDS item; - s32 ammotype; - s32 reserveammo; - s32 magammo; - u32 imageoffset; - s32 textwidth; - s32 pad; - - offhanditem = getCurrentPlayerWeaponId(1); - item = getCurrentPlayerWeaponId(0); - - if (item != ITEM_UNARMED) - { - ammotype = get_ammo_type_for_weapon(item); - - if (ammotype != 0 - && g_CurrentPlayer->hands[GUNRIGHT].weapon_action_state != GUN_ANIM_STATE_SWITCH_SWAP - && g_CurrentPlayer->hands[GUNRIGHT].weapon_action_state != GUN_ANIM_STATE_SWITCH_HOLD - && !bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_HIDE_AMMO_DISPLAY)) - { - imageoffset = ammo_related[ammotype].IconImage; - textwidth = 5; - - get_ptr_item_statistics(item); - - if (imageoffset != 0) - { - imageoffset += globalbank_rdram_offset; - - // Draw the ammo icon -#if defined(VERSION_EU) - gdl = set_rgba_redirect_generate_microcode(gdl, (u8 *)imageoffset, 200.0f, 208.0f, (viGetViewTop() + viGetViewHeight()) - 30, 0, ammo_related[ammotype].IconYOffset, 1); -#else - gdl = set_rgba_redirect_generate_microcode(gdl, (u8 *)imageoffset, 200.0f, 180.0f, (viGetViewTop() + viGetViewHeight()) - 20, 0, ammo_related[ammotype].IconYOffset, 1); -#endif - - textwidth = ((u8 *)imageoffset)[4]; - } - - gdl = microcode_constructor(gdl); - - if (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) - { - magammo = 0; - reserveammo = g_CurrentPlayer->ammoheldarr[ammotype] + g_CurrentPlayer->hands[0].weapon_ammo_in_magazine; - - if (offhanditem == item) - { - reserveammo += g_CurrentPlayer->hands[1].weapon_ammo_in_magazine; - } - } - else - { - magammo = g_CurrentPlayer->hands[0].weapon_ammo_in_magazine; - reserveammo = g_CurrentPlayer->ammoheldarr[ammotype]; - } - - if (!bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) - { - // Draw the magazine ammo count. -#if defined(VERSION_EU) - gdl = gunDrawHudInteger(gdl, magammo, 196 - (textwidth / 2), 0, 205, 2, 0); -#else - gdl = gunDrawHudInteger(gdl, magammo, 196 - (textwidth / 2), 0, 177, 2, 0); -#endif - } - - if (reserveammo > 0 || bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) - { - // Draw the reserve ammo count. -#if defined(VERSION_EU) - gdl = gunDrawHudInteger(gdl, reserveammo, 203 + ((textwidth + 1) / 2), 1, 205, 2, 0); -#else - gdl = gunDrawHudInteger(gdl, reserveammo, 203 + ((textwidth + 1) / 2), 1, 177, 2, 0); -#endif - } - - gdl = combiner_bayer_lod_perspective(gdl); - } - } - - return gdl; -} - - -void gunSetSightVisible(s32 reason, bool visible) -{ - if (visible) - { - g_CurrentPlayer->gunsightmode &= ~reason; - return; - } - - g_CurrentPlayer->gunsightmode |= reason; -} - - -void gunDrawSight(s32 *gdl) { - - s32 sp54; - f32 xypos[2]; - f32 halfedxy[2]; - - if ((g_CurrentPlayer->gunsightmode == 0) && (g_CurrentPlayer->mpmenuon == FALSE)) { - sp54 = *gdl; - texSelect(&sp54, crosshairimage, 4, 0, 0); - - xypos[0] = g_CurrentPlayer->crosshair_angle.f[0]; - xypos[1] = g_CurrentPlayer->crosshair_angle.f[1]; - halfedxy[0] = 16.0f; - halfedxy[1] = 16.0f; - - if (get_screen_ratio() == SCREEN_RATIO_16_9) { - halfedxy[0] = halfedxy[0] * 0.75f; - } -#ifdef VERSION_EU - halfedxy[1] = halfedxy[1] * 1.19047617912f; -#endif - display_image_at_position(&sp54, &xypos, &halfedxy, 0x20, 0x20, 0, 0, 1, 0xFF, 0xFF, 0xFF, 0x6E, (crosshairimage->level > 0), 0); - *gdl = sp54; - } -} - - -void inc_curplayer_hitcount_with_weapon(ITEM_IDS item, SHOT_REGISTER shot_register) { - - if (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_PLAYER_STAT_HIT)) { - g_playerPerm->shot_count[shot_register] = g_playerPerm->shot_count[shot_register]+1; - } -} - - -s32 get_curplayer_shot_register(SHOT_REGISTER shot_register) -{ - return g_playerPerm->shot_count[shot_register]; -} - - -void inc_cur_civilian_casualties(void) -{ - g_playerPerm->killed_civilians++; -} - - -s32 get_civilian_casualties(void) -{ - return g_playerPerm->killed_civilians; -} - - -//D:80053BF8 +const char g_GunHudIntegerFormat[] = "%d\n"; const char aSD[] = "%s: %d\n"; - -void increment_num_kills_display_text_in_MP(void) -{ - s8 buffer[256]; - s32 time_since_kill; - s32 recent_kill_count; - s32 mission_time; - s32 unused; // needed this variable to match - - g_playerPerm->kill_count += 1; - g_CurrentPlayer->kills_this_life += 1; - - if (getPlayerCount() < 2) { return; } - - mission_time = getMissiontimer(); - sprintf(&buffer, aSD, langGet(getStringID(LGUN, GUN_STR_DA_KILLCOUNT)), g_playerPerm->kill_count); // "kill count" - -#if defined(VERSION_US) - hudmsgBottomShow(&buffer); -#elif defined(VERSION_JP) || defined(VERSION_EU) - jp_hudmsgBottomShow(&buffer); -#endif - - if (g_playerPerm->kill_count >= 2) - { - time_since_kill = mission_time - g_CurrentPlayer->last_kill_time[0]; - if (g_playerPerm->max_time_between_kills < time_since_kill) - { - g_playerPerm->max_time_between_kills = time_since_kill; - } - - if (time_since_kill < g_playerPerm->min_time_between_kills) - { - g_playerPerm->min_time_between_kills = time_since_kill; - } - } - - recent_kill_count = 1; - g_CurrentPlayer->last_kill_time[3] = g_CurrentPlayer->last_kill_time[2]; - g_CurrentPlayer->last_kill_time[2] = g_CurrentPlayer->last_kill_time[1]; - g_CurrentPlayer->last_kill_time[1] = g_CurrentPlayer->last_kill_time[0]; - g_CurrentPlayer->last_kill_time[0] = mission_time; - - // I tried to turn this into a loop but it didn't match - if (g_CurrentPlayer->last_kill_time[1] != -1 && (g_CurrentPlayer->last_kill_time[0] - g_CurrentPlayer->last_kill_time[1]) < 0x78) - { - recent_kill_count++; - if ((g_CurrentPlayer->last_kill_time[2] != -1) && ((g_CurrentPlayer->last_kill_time[0] - g_CurrentPlayer->last_kill_time[2]) < 0x78)) - { - recent_kill_count++; - if ((g_CurrentPlayer->last_kill_time[3] != -1) && ((g_CurrentPlayer->last_kill_time[0] - g_CurrentPlayer->last_kill_time[3]) < 0x78)) - { - recent_kill_count++; - } - } - } - - if (g_playerPerm->most_killed_one_time < recent_kill_count) - { - g_playerPerm->most_killed_one_time = recent_kill_count; - } -} - - - -s32 get_curplay_killcount(void) { - return g_playerPerm->kill_count; -} - -void increment_num_times_killed_MwtGC(void){ - g_playerPerm->killed_gg_owner_count++; -} - -s32 get_times_killed_mwtgx(void) { - return g_playerPerm->killed_gg_owner_count; -} - - -void increment_num_deaths(void) -{ - char buffer[256]; - g_CurrentPlayer->deathcount = (s32) (g_CurrentPlayer->deathcount + 1); - if (getPlayerCount() >= 2) - { - if (g_CurrentPlayer->deathcount == 1) - { - sprintf(buffer, langGet(getStringID(LGUN, GUN_STR_DB_DIEDONCE_LF))); //died once - } - else - { - sprintf(buffer, "%s %d %s\n", langGet(getStringID(LGUN, GUN_STR_DC_DIED)), g_CurrentPlayer->deathcount, langGet(getStringID(LGUN, GUN_STR_DD_TIMES))); //died times - } -#if defined(VERSION_JP) || defined(VERSION_EU) - jp_hudmsgBottomShow(buffer); -#else - hudmsgBottomShow(buffer); -#endif - } -} - - -s32 get_curplayer_numdeaths(void) { - return g_CurrentPlayer->deathcount; -} - -//D:80053C0C +const char g_GunDeathCountFormat[] = "%s %d %s\n"; const char aSD_0[] = "%s: %d\n"; -void increment_num_suicides_display_MP(void) { - char buffer[256]; - s32 time_diff; - s32 recent_kill_count; - s32 currentTime; - - g_CurrentPlayer->num_suicides += 1; - if (getPlayerCount() >= 2) { - - currentTime = getMissiontimer(); - - sprintf(&buffer, &aSD_0, langGet(getStringID(LGUN, GUN_STR_DE_SUICIDECOUNT)), g_CurrentPlayer->num_suicides); // "suicide count" - -#if defined(VERSION_JP) || defined(VERSION_EU) - jp_hudmsgBottomShow(&buffer); -#else - hudmsgBottomShow(&buffer); -#endif - - if (g_playerPerm->kill_count >= 2) { - time_diff = currentTime - g_CurrentPlayer->last_kill_time[0]; - if (g_playerPerm->max_time_between_kills < time_diff) { - g_playerPerm->max_time_between_kills = time_diff; - } - if (time_diff < g_playerPerm->min_time_between_kills) { - g_playerPerm->min_time_between_kills = time_diff; - } - } - recent_kill_count = 1; - g_CurrentPlayer->last_kill_time[3] = g_CurrentPlayer->last_kill_time[2]; - g_CurrentPlayer->last_kill_time[2] = g_CurrentPlayer->last_kill_time[1]; - g_CurrentPlayer->last_kill_time[1] = g_CurrentPlayer->last_kill_time[0]; - g_CurrentPlayer->last_kill_time[0] = currentTime; - - if ( g_CurrentPlayer->last_kill_time[1] != -1) { - - if ((g_CurrentPlayer->last_kill_time[0] - g_CurrentPlayer->last_kill_time[1]) < 0x78) { - - recent_kill_count += 1; - - if ((g_CurrentPlayer->last_kill_time[2] != -1) && ((g_CurrentPlayer->last_kill_time[0] - g_CurrentPlayer->last_kill_time[2]) < 0x78)) { - - recent_kill_count += 1; - - if ((g_CurrentPlayer->last_kill_time[3] != -1) && ((g_CurrentPlayer->last_kill_time[0] - g_CurrentPlayer->last_kill_time[3]) < 0x78)) { - recent_kill_count += 1; - } - } - } - } - - if (g_playerPerm->most_killed_one_time < recent_kill_count) { - g_playerPerm->most_killed_one_time = recent_kill_count; - } - } -} - -s32 get_curplayer_numsuicides(void) { - return g_CurrentPlayer->num_suicides; -} diff --git a/src/game/gun_rodata.c b/src/game/gun_rodata.c new file mode 100644 index 00000000..46a69002 --- /dev/null +++ b/src/game/gun_rodata.c @@ -0,0 +1,10 @@ +#include + +/* + * Keep these values as one-element arrays so the linker retains the original order + * of gun.c's literal pool. + */ +const f32 g_GLGrenadeLaunchUnk8C[1] = { 0.3f }; +const f32 g_GLGrenadeLaunchUnk94[1] = { 0.13333333f }; +const f32 g_TankShellSpeed[1] = { 66.666664f }; +const f32 D_80053DDC[1] = { 1.111111f }; diff --git a/src/game/gunfire.c b/src/game/gunfire.c new file mode 100644 index 00000000..e9a970f1 --- /dev/null +++ b/src/game/gunfire.c @@ -0,0 +1,6465 @@ +#include +#include "include/limits.h" +#include +#include +#include +#include +#include +#include "bondview.h" +#include "bondinv.h" +#include "gun.h" +#include "chrobjdata.h" +#include "game/propobj.h" +#include "game/objective_status.h" +#include "quaternion.h" +#include "image_bank.h" +#include "bondwalk2.h" +#include "othermodemicrocode.h" +#include "player.h" +#include "lv.h" +#include "random.h" +#include "math_asinfacosf.h" +#include "loadobjectmodel.h" +#include "objecthandler.h" +#include "image.h" +#include "tex.h" +#include "debugmenu_handler.h" +#include "fr.h" +#include "assets/obseg/text/LgunE.h" +#include "textrelated.h" +#include "chrai.h" +#include "model.h" +#include "options.h" +#include "mpmenu.h" +#include "joy.h" +#include "matrixmath.h" +#include "bondinv.h" +#include "stan.h" +#include "gbi_extension.h" + + +#ifdef REFRESH_PAL +#define THROWN_ITEM_REFRESH_RATE 50 +#define DUAL_WIELD_TRIGGER_SWAP_TICKS 24 +#define DUAL_WIELD_SINGLE_TRIGGER_SWAP_TICKS 36 +#define WATCH_SOUND_DURATION_TICKS 250 +#define GUN_SPRING_DAMP 0.9402999877929688f +#define GUN_SPRING_SCALE 0.05970001220703125f +#else +#define THROWN_ITEM_REFRESH_RATE 60 +#define DUAL_WIELD_TRIGGER_SWAP_TICKS 20 +#define DUAL_WIELD_SINGLE_TRIGGER_SWAP_TICKS 30 +#define WATCH_SOUND_DURATION_TICKS 300 +#define GUN_SPRING_DAMP 0.95f +#define GUN_SPRING_SCALE 0.050000012f +#endif + +extern f32 g_TankShellSpeed; + +extern coord3d D_80035C40; +extern coord3d D_80035C4C; +extern coord3d D_80035C58; +extern coord3d D_80035C64; +extern coord3d D_80035C70; +extern coord3d D_80035C7C; +extern coord3d D_80035C88; +extern Vtx D_80035C98; +extern coord3d D_80035CA8; +extern coord3d D_80035CB4; +extern u32 D_80035CC0; +extern u32 D_80035D00; +extern u32 D_80035D04[]; +extern u32 D_80035EA4; +extern u32 watchControllerButtonBases[]; +extern GunModelFileRecord gitem_structs[]; +extern struct gun_trigger_state g_ZeroTriggerState; +extern Lights1 g_WeaponEnvmapLight; +extern ALSoundState *g_ImpactSfxStates[NUM_IMPACT_SFX_STATES]; +extern struct RicochetSoundsSmall ricochet_sounds_small; +extern struct PunchSounds punch_sounds; +extern struct BulletFleshSounds bullet_flesh_sounds; +extern struct LaserRichochetSounds laser_ricochet_sounds; +extern struct RicochetSoundsLarge ricochet_sounds_large; +extern struct EarWhistleSounds ear_whistle_sounds; +extern struct sfx2 watchlaser_fire_sounds; +extern struct sfx3 knife_throw_sounds; +extern u32 D_80032458; +extern u32 D_80034CA4[]; +extern u32 D_80034E0C[]; +extern Weapon1PTransformKeyframe throwKnifeDrawBackKeyframes[]; +extern Weapon1PTransformKeyframe throwKnifeReleaseKeyframes[]; +extern Weapon1PTransformKeyframe grenadeThrowKeyframes[]; +extern Weapon1PTransformKeyframe timedMineThrowKeyframes[]; +extern Weapon1PTransformKeyframe proxMineThrowKeyframes[]; +extern Weapon1PTransformKeyframe remoteMineThrowKeyframes[]; +extern Weapon1PTransformKeyframe fistMeleeKeyframes1[]; +extern Weapon1PTransformKeyframe fistMeleeKeyframes2[]; +extern Weapon1PTransformKeyframe sniperMeleeKeyframes1[]; +extern Weapon1PTransformKeyframe sniperMeleeKeyframes2[]; +extern Weapon1PTransformKeyframe taserFireKeyFrames[]; +extern Weapon1PTransformKeyframe taserRaiseKeyframes[]; +extern struct ModelSkeleton skeleton_gun_kf7; + +typedef struct ModelHeader { + s16 unk00; + s16 Type; + struct ChrRecord *chr; + ModelFileHeader *obj; + RenderPosView *render_pos; + union ModelRwData **datas; + f32 scale; + struct Model *attachedto; + ModelNode *attachedto_objinst; +} ModelHeader; + +void gunCreateBeamForHand(enum GUNHAND hand); +void bullet_path_from_screen_center(coord3d *arg0, coord3d *arg1, enum GUNHAND arg2); +void gunInitProjectileFromPlayer(ObjectRecord *obj, coord3d *targetpos, Mtxf *arg2, coord3d *velocity, Mtxf *arg4); +s32 gunSample1PTransform(Weapon1PTransformKeyframe *keyframes, f32 time, Mtxf *matrix, GUNHAND hand); +void analyzeGEKey(void); +void give_weapon_case_items(void); +struct ModelFileHeader *get_ptr_weapon_model_header_line(ITEM_IDS weapon); +s32 get_ammo_in_hands_weapon(enum GUNHAND hand); +s32 get_ammo_type_for_weapon(ITEM_IDS weapon); +f32 gunSetHorizontalOffset(GUNHAND hand); +f32 get_value_if_watch_is_on_hand_or_not(GUNHAND hand); +void sub_GAME_7F05DA8C(GUNHAND hand, ITEM_IDS weaponnum_watchmenu); +void sub_GAME_7F05E808(GUNHAND hand); +void sub_GAME_7F05EA94(Model *model, s32 val); +void sub_GAME_7F0649D8(enum GUNHAND hand); +void sub_GAME_7F068508(GUNHAND handnum, f32 floor_y_pos); +Vtx *dynAllocateVertices(s32 count); +Mtx *dynAllocateMatrix(void); +void divide3DCoordinates(coord3d *in, f32 divisor, coord3d *out); + +#if !defined(VERSION_EU) +void sub_GAME_7F05FB00(enum GUNHAND hand) +{ + struct hand* hand_ptr; + ObjectRecord* hand_obj_record; + + hand_ptr = &g_CurrentPlayer->hands[hand]; + hand_obj_record = hand_ptr->rocket; + + if (hand_obj_record != NULL) + { + objFreePermanently(hand_obj_record, 1); + hand_ptr->rocket = NULL; + } +} + + +extern f32 D_80053DDC; + +/* +* Address: 0x7F05FB64 +*/ +void gunFireTankShell(s32 handnum) +{ + WeaponObjRecord *obj; + struct hand *hand; + Mtxf identitymtx; + coord3d velocity; + ObjectRecord *tankobj; + coord3d unscaledvelocity; + Mtxf shellmtx; + coord3d screenpos; + coord3d aimdir; + PropRecord *playerprop; + coord3d *prevplayerpos; + ITEM_IDS weaponid; + coord3d spawnpos; + PropRecord *tankprop; + + hand = &g_CurrentPlayer->hands[handnum]; + + playerprop = getCurrentPlayerProp(); + prevplayerpos = getCurrentPlayerPrevPos(); + weaponid = getCurrentPlayerWeaponId(handnum); + + matrix_4x4_set_identity(&identitymtx); + + if (weaponid == ITEM_TANKSHELLS) + { + tankprop = get_ptr_for_players_tank(); + + if (1); + + if ((tankprop != NULL) && (tankprop->flags & TANK_RUN_STATE_RUNNING)) + { + bondviewSet3dCoord7F07CEB0(&aimdir); + } + else + { + sub_GAME_7F068190(&screenpos, &aimdir); + mtx4RotateVecInPlace(currentPlayerGetViewToWorldMtxf(), &aimdir); + } + + velocity.x = aimdir.x * g_TankShellSpeed; + velocity.y = aimdir.y * g_TankShellSpeed; + velocity.z = aimdir.z * g_TankShellSpeed; + + if (g_ClockTimer > 0) { + velocity.x += (playerprop->pos.x - prevplayerpos->x) / g_GlobalTimerDelta; + velocity.y += (playerprop->pos.y - prevplayerpos->y) / g_GlobalTimerDelta; + velocity.z += (playerprop->pos.z - prevplayerpos->z) / g_GlobalTimerDelta; + } + + if ((tankprop != NULL) && (tankprop->flags & TANK_RUN_STATE_RUNNING)) + { + tankobj = tankprop->obj; + spawnpos.x = tankobj->model->render_pos[4].pos.m[3][0]; + spawnpos.y = tankobj->model->render_pos[4].pos.m[3][1]; + spawnpos.z = tankobj->model->render_pos[4].pos.m[3][2]; + + mtx4TransformVecInPlace(currentPlayerGetViewToWorldMtxf(), &spawnpos); + } + else + { + spawnpos.x = playerprop->pos.x; + spawnpos.y = playerprop->pos.y; + spawnpos.z = playerprop->pos.z; + } + + if ((g_CurrentPlayer && g_CurrentPlayer)); + + setSixExplosionAndSmokeEntries(); + } + else + { + bullet_path_from_screen_center(&screenpos, &aimdir, handnum); + mtx4RotateVecInPlace(currentPlayerGetViewToWorldMtxf(), &aimdir); + + spawnpos.x = hand->field_B58.x; + spawnpos.y = hand->field_B58.y; + spawnpos.z = hand->field_B58.z; + + if (1); + + unscaledvelocity.x = aimdir.x * D_80053DDC; + unscaledvelocity.y = aimdir.y * D_80053DDC; + unscaledvelocity.z = aimdir.z * D_80053DDC; + + velocity.x = unscaledvelocity.x * g_GlobalTimerDelta; + velocity.y = unscaledvelocity.y * g_GlobalTimerDelta; + velocity.z = unscaledvelocity.z * g_GlobalTimerDelta; + + if (g_ClockTimer > 0) + { + velocity.x += (playerprop->pos.x - prevplayerpos->x) / g_GlobalTimerDelta; + velocity.y += (playerprop->pos.y - prevplayerpos->y) / g_GlobalTimerDelta; + velocity.z += (playerprop->pos.z - prevplayerpos->z) / g_GlobalTimerDelta; + } + } + + matrix_4x4_copy(&g_CurrentPlayer->hands[handnum].throw_item_pos_related, &shellmtx); + + shellmtx.m[3][0] = 0.0f; + shellmtx.m[3][1] = 0.0f; + shellmtx.m[3][2] = 0.0f; + + if (hand->rocket != NULL) + { + obj = (WeaponObjRecord *) hand->rocket; + hand->firedrocket = 1; + } + else + { + obj = (WeaponObjRecord *) create_new_item_instance_of_model(PROP_CHRROCKET, ITEM_ROCKETROUND); + } + + if (obj == NULL) + { + return; + } + + obj->timer = -1; + obj->runtime_bitflags &= ~RUNTIMEBITFLAG_OWNER; + obj->runtime_bitflags |= get_cur_playernum() << RUNTIMEBITSHIFT_OWNER; + + gunInitProjectileFromPlayer(obj, &spawnpos, &shellmtx, &velocity, (s32 *) &identitymtx); + + if (obj->runtime_bitflags & RUNTIMEBITFLAG_00000080) + { + obj->projectile->flags |= PROJECTILEFLAG_LAUNCHING; + + if (weaponid != ITEM_TANKSHELLS) + { + obj->projectile->flags |= PROJECTILEFLAG_00000020; + obj->projectile->unkB0 = obj->runtime_pos.y; + obj->projectile->unkB4 = obj->projectile->speed.y; + obj->projectile->unk10.x = unscaledvelocity.x; + obj->projectile->unk10.y = unscaledvelocity.y; + obj->projectile->unk10.z = unscaledvelocity.z; + obj->projectile->refreshrate = THROWN_ITEM_REFRESH_RATE; + + if (obj->projectile->sounds[0] == NULL) + { + sndPlaySfx(g_musicSfxBufferPtr, 1, &obj->projectile->sounds[0]); + } + else if (obj->projectile->sounds[1] == NULL) + { + sndPlaySfx(g_musicSfxBufferPtr, 1, &obj->projectile->sounds[1]); + } + } + } +} + + +/** + * D_80053DDC belongs to gunFireTankShell, but must sit here + * immediately ahead of this function's pool for that function to match. + */ +#endif + +void gunUpdateAndFire(GUNHAND handnum) +{ + Mtxf *rwmtx; + Mtxf gunmtx; + Mtxf flashmtx; + Mtxf flash2mtx; + Mtxf tmpmtx; + ModelFileHeader *mdlhdr; + coord3d gunofs = D_80035C40; + Mtxf rotmtx; + Mtxf aimmtx; + struct hand *hand; + s32 *flashvisptr; + f32 *flashdata; + ModelNode *node; + s32 j; + ITEM_IDS item; + WeaponStats *itemstats; + f32 rndf; + u32 rnd; + f32 stackpad_scale; + coord3d blendedpos; + coord3d blendedlook; + coord3d blendedup; + s32 i; + coord3d trigrot; + coord3d taserrot; + coord3d fistrot; + f32 *cylinderdata; + u8 stackpad1[4]; + ModelNode **hammerdata; + Model *model; + coord3d flashpos; + f32 flashscale; + f32 flashext; + f32 *nodeptr; + f32 *nodepos; + f32 *swdata; + s32 sw6mtxidx; + f32 *hingedata; + f32 *sw7data; + s32 sw7mtxidx; + s32 shellidx; + u8 stackpad2[4]; + + flashvisptr = NULL; + flashdata = NULL; + hand = &g_CurrentPlayer->hands[handnum]; + item = get_item_in_hand_or_watch_menu(handnum); + itemstats = get_ptr_item_statistics(item); + + /** + * When switching from a single weapon to dual wielding, both gun models interpolate a little to the sides of the screen + * over a period of 4 seconds. And when switching back to a single weapon that weapon moves back more towards the + * center of the screen. + */ + if (handnum == GUNRIGHT) + { + if (bondwalkItemCheckBitflags(get_item_in_hand_or_watch_menu(1), WEAPONSTATBITFLAG_SHOW_FIRST_PERSON) != 0) + { + hand->field_A34 += (2.0f * g_GlobalTimerDelta) / 240.0f; + + if (hand->field_A34 > 2.0f) + { + hand->field_A34 = 2.0f; + } + } + else + { + hand->field_A34 -= (2.0f * g_GlobalTimerDelta) / 240.0f; + + if (hand->field_A34 < 0.0f) + { + hand->field_A34 = 0.0f; + } + } + } + else if (bondwalkItemCheckBitflags(get_item_in_hand_or_watch_menu(0), WEAPONSTATBITFLAG_SHOW_FIRST_PERSON) != 0) + { + hand->field_A34 -= (2.0f * g_GlobalTimerDelta) / 240.0f; + + if (hand->field_A34 < (-2.0f)) + { + hand->field_A34 = -2.0f; + } + } + else + { + hand->field_A34 += (2.0f * g_GlobalTimerDelta) / 240.0f; + + if (hand->field_A34 > 0.0f) + { + hand->field_A34 = 0.0f; + } + } + + /** + * Gun sway system. This moves the held weapons in figure-eight pattern which becomes bigger depending how fast the player is moving. + */ + blendedpos = D_80035C4C; + blendedlook = D_80035C58; + blendedup = D_80035C64; + + i = hand->curblendpos; + + coord3dCatmullRomInterp(&hand->blendpos[(i + 3) % 4], &hand->blendpos[i], &hand->blendpos[(i + 1) % 4], &hand->blendpos[(i + 2) % 4], hand->dampt, &blendedpos); + coord3dCatmullRomInterp(&hand->blendlook[(i + 3) % 4], &hand->blendlook[i], &hand->blendlook[(i + 1) % 4], &hand->blendlook[(i + 2) % 4], hand->dampt, &blendedlook); + coord3dCatmullRomInterp(&hand->blendup[(i + 3) % 4], &hand->blendup[i], &hand->blendup[(i + 1) % 4], &hand->blendup[(i + 2) % 4], hand->dampt, &blendedup); + + blendedpos.x *= g_CurrentPlayer->gunposamplitude; + blendedpos.y *= g_CurrentPlayer->gunposamplitude; + blendedpos.z *= g_CurrentPlayer->gunposamplitude; + blendedpos.x += hand->weapon_theta_displacement; + blendedpos.y += hand->weapon_verta_displacement; + blendedpos.x += sub_GAME_7F05DCB8(handnum); + + j = 0; + + if (g_ClockTimer > 0) + { + do + { + j += 1; + hand->spring_pos_x = (GUN_SPRING_DAMP * hand->spring_pos_x) + ((f32 *) (&blendedpos))[0]; + hand->spring_pos_y = (GUN_SPRING_DAMP * hand->spring_pos_y) + ((f32 *) (&blendedpos))[1]; + hand->spring_pos_z = (GUN_SPRING_DAMP * hand->spring_pos_z) + ((f32 *) (&blendedpos))[2]; + hand->spring_look_x = (GUN_SPRING_DAMP * hand->spring_look_x) + ((f32 *) (&blendedlook))[0]; + hand->spring_look_y = (GUN_SPRING_DAMP * hand->spring_look_y) + ((f32 *) (&blendedlook))[1]; + hand->spring_look_z = (GUN_SPRING_DAMP * hand->spring_look_z) + ((f32 *) (&blendedlook))[2]; + hand->spring_up_x = (GUN_SPRING_DAMP * hand->spring_up_x) + ((f32 *) (&blendedup))[0]; + hand->spring_up_y = (GUN_SPRING_DAMP * hand->spring_up_y) + ((f32 *) (&blendedup))[1]; + hand->spring_up_z = (GUN_SPRING_DAMP * hand->spring_up_z) + ((f32 *) (&blendedup))[2]; + } + while (j < g_ClockTimer); + } + + hand->sway_pos_x = hand->spring_pos_x * GUN_SPRING_SCALE; + hand->sway_pos_y = hand->spring_pos_y * GUN_SPRING_SCALE; + hand->sway_pos_z = hand->spring_pos_z * GUN_SPRING_SCALE; + hand->sway_look_x = hand->spring_look_x * GUN_SPRING_SCALE; + hand->sway_look_y = hand->spring_look_y * GUN_SPRING_SCALE; + hand->sway_look_z = hand->spring_look_z * GUN_SPRING_SCALE; + hand->sway_up_x = hand->spring_up_x * GUN_SPRING_SCALE; + hand->sway_up_y = hand->spring_up_y * GUN_SPRING_SCALE; + hand->sway_up_z = hand->spring_up_z * GUN_SPRING_SCALE; + + // Offset the weapon to the right or left side of the screen depending on which hand it's in. + if (handnum == GUNRIGHT) + { + gunofs.x = (gunSetHorizontalOffset(handnum) + hand->sway_pos_x) + (*hand).gunofs2_x; + } + else + { + gunofs.x = (gunSetHorizontalOffset(handnum) + hand->sway_pos_x) - hand->gunofs2_x; + } + + gunofs.y = hand->gunofs2_y + (itemstats->PosY + hand->sway_pos_y); + gunofs.z = hand->gunofs2_z + (itemstats->PosZ + hand->sway_pos_z); + + if (((item == ITEM_ROCKETLAUNCH) || (item == ITEM_TRIGGER)) || (item == ITEM_WATCHLASER)) + { + gunofs.y += g_CurrentPlayer->ducking_height_offset / (-100.0f); + gunofs.z += (3.0f * g_CurrentPlayer->ducking_height_offset) / (-100.0f); + + if ((item == ITEM_ROCKETLAUNCH) && (((cur_player_get_screen_setting() == SCREEN_SIZE_WIDESCREEN) || (cur_player_get_screen_setting() == SCREEN_SIZE_CINEMA)) || (get_screen_ratio() == SCREEN_RATIO_16_9))) + { + gunofs.y -= 3.0f; + } + } + else if (item == ITEM_TASER) + { + gunofs.y += (2.5f * g_CurrentPlayer->ducking_height_offset) / (-100.0f); + gunofs.z += (7.5f * g_CurrentPlayer->ducking_height_offset) / (-100.0f); + } + else + { + gunofs.y += (5.0f * g_CurrentPlayer->ducking_height_offset) / (-100.0f); + gunofs.z += (15.0f * g_CurrentPlayer->ducking_height_offset) / (-100.0f); + } + + if ((hand->weapon_firing_status != 0) && (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_00000020) != 0)) + { + if (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_00000040) != 0) + { + rnd = randomGetNext(); + rndf = (f32) ((u32) rnd); + gunofs.x += 0.3f - ((rndf * (1.0f / M_U32_MAX_VALUE_F)) * 0.6f); + } + + rnd = randomGetNext(); + rndf = (f32) ((u32) rnd); + gunofs.y += 0.3f - ((rndf * (1.0f / M_U32_MAX_VALUE_F)) * 0.6f); + rnd = randomGetNext(); + rndf = (f32) ((u32) rnd); + gunofs.z += 0.3f - ((rndf * (1.0f / M_U32_MAX_VALUE_F)) * 0.6f); + } + + gunofs.x += (((g_CurrentPlayer->field_FFC.x - getPlayer_c_screenleft()) - (getPlayer_c_screenwidth() * 0.5f)) * itemstats->PlayZ) / (getPlayer_c_screenwidth() * 0.5f); + + if ((g_CurrentPlayer->field_FFC.y - getPlayer_c_screentop()) > (getPlayer_c_screenheight() * 0.5f)) + { + gunofs.y -= (((g_CurrentPlayer->field_FFC.y - getPlayer_c_screentop()) - (getPlayer_c_screenheight() * 0.5f)) * itemstats->PlayY) / (getPlayer_c_screenheight() * 0.5f); + } + else + { + gunofs.y -= (((g_CurrentPlayer->field_FFC.y - getPlayer_c_screentop()) - (getPlayer_c_screenheight() * 0.5f)) * itemstats->PlayX) / (getPlayer_c_screenheight() * 0.5f); + } + + sub_GAME_7F05C614(); + matrix_4x4_set_identity(&rotmtx); + + if ((item == ITEM_TRIGGER) || (item == ITEM_WATCHLASER)) + { + trigrot = D_80035C70; + matrix_4x4_set_rotation_around_xyz(&trigrot, &tmpmtx); + matrix_4x4_multiply_homogeneous_in_place(&tmpmtx, &rotmtx); + } + else if (item == ITEM_TASER) + { + taserrot = D_80035C7C; + matrix_4x4_set_rotation_around_xyz(&taserrot, &tmpmtx); + matrix_4x4_multiply_homogeneous_in_place(&tmpmtx, &rotmtx); + } + else if ((item == ITEM_FIST) && (g_CurrentPlayer->cur_item_weapon_getname == ITEM_SNIPERRIFLE)) + { + fistrot = D_80035C88; + matrix_4x4_set_rotation_around_xyz(&fistrot, &tmpmtx); + matrix_4x4_multiply_homogeneous_in_place(&tmpmtx, &rotmtx); + gunofs.x += -2.5f; + gunofs.y += 27.8f; + gunofs.z += 2.0f; + } + + if (hand->field_92C != 0) + { + gunofs.x += hand->field_8EC.m[3][0]; + gunofs.y += hand->field_8EC.m[3][1]; + gunofs.z += hand->field_8EC.m[3][2]; + matrix_4x4_multiply_homogeneous_in_place(&hand->field_8EC, &rotmtx); + rotmtx.m[3][0] = 0.0f; + rotmtx.m[3][1] = 0.0f; + rotmtx.m[3][2] = 0.0f; + } + else + { + hand->field_8E8 = 0.0f; + hand->field_8DC = (-0.0f) + 0.0f; + hand->field_8E0 = 0.0f; + hand->field_8E4 = (-0.0f) + 0.0f; + } + + matrix_4x4_set_basis_and_position_target(&tmpmtx, 0.0f, 0.0f, 0.0f, hand->sway_look_x, hand->sway_look_y, hand->sway_look_z, hand->sway_up_x, hand->sway_up_y, hand->sway_up_z); + matrix_4x4_multiply_homogeneous_in_place(&tmpmtx, &rotmtx); + matrix_4x4_align(&tmpmtx, 0.0f, gunofs.x - hand->field_A38, gunofs.y - hand->field_A3C, gunofs.z - hand->field_A40); + matrix_4x4_multiply_homogeneous_in_place(&tmpmtx, &rotmtx); + matrix_4x4_copy(&rotmtx, &gunmtx); + matrix_4x4_set_position(&gunofs, &gunmtx); + matrix_4x4_copy(&gunmtx, &hand->gunmtx_camspace); + matrix_4x4_copy(&hand->throw_item_pos_related, &hand->throw_item_pos_related_prev); + matrix_4x4_multiply_homogeneous(currentPlayerGetViewToWorldMtxf(), &hand->gunmtx_camspace, &hand->throw_item_pos_related); + hand->field_87F = 1; + + if (((((((get_ptr_weapon_model_header_line(item) == 0) || (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_SHOW_FIRST_PERSON) == 0)) || (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_HIDE_FIRST_PERSON_HAND) != 0)) + || (hand->weapon_action_state == GUN_ANIM_STATE_SWITCH_SWAP)) || (hand->weapon_action_state == GUN_ANIM_STATE_SWITCH_HOLD)) || (Gun_hand_without_item(handnum) == 0)) || (get_itemtype_in_hand(handnum) == 0)) + { + hand->field_87F = 0; + } + + if ((hand->weapon_ammo_in_magazine <= 0) && (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_SINGLE_USE_RELOAD) != 0)) + { + hand->field_87F = 0; + } + + if (hand->field_87F != 0) + { + mdlhdr = &g_CurrentPlayer->copy_of_body_obj_header[handnum]; + rwmtx = (Mtxf *) dynAllocate(mdlhdr->numMatrices * ((s32) (sizeof(Mtxf)))); + j = 0; + + if (mdlhdr->numMatrices > 0) + { + do + { + matrix_4x4_set_identity((Mtxf *) (((u8 *) rwmtx) + (j * ((s32) (sizeof(Mtxf)))))); + j += 1; + } + while (j < mdlhdr->numMatrices); + } + + modelCalculateRwDataLen(mdlhdr); +#ifdef DEBUG + /** + * The model's runtime data is written into hand->modeldatas, which is a + * fixed run of 32 words (modeldatas .. field_C04, ending at volley). + */ + if (mdlhdr->numRecords >= 32) + { + osSyncPrintf("Increase GUNSAVESIZE to %d!!! ", mdlhdr->numRecords); + } +#endif + model = (Model *) (&hand->field_B68); + + if (mdlhdr->Switches); + + modelInit(model, mdlhdr, (s32 *) (&hand->modeldatas)); + sub_GAME_7F05E978(model, 1); + sub_GAME_7F05EA94(model, hand->field_87E); + node = mdlhdr->Switches[1]; + + if (node != NULL) + { + if (&node->Data->Switch); + + flashvisptr = ((s32 *) (&hand->modeldatas)) + node->Data->Switch.RwDataIndex; + } + + if (mdlhdr->Switches[3] != NULL) + { + flashdata = (f32 *) mdlhdr->Switches[3]->Data; + } + + hand->mtxlist = rwmtx; + + if ((bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_MIRROR_DUAL) != 0) && (handnum == GUNLEFT)) + { + matrix_column_1_scalar_multiply(-1.0f, gunmtx.m[0]); + } + + matrix_scalar_multiply(IDO_POINT_ONE, gunmtx.m[0]); + matrix_4x4_copy(&gunmtx, rwmtx); + + if (mdlhdr->Skeleton == (&skeleton_gun_revolver)) + { + swdata = (f32 *) mdlhdr->Switches[4]; + + if (swdata != NULL) + { + rndf = 0.0f; + cylinderdata = (f32 *) ((ModelNode *) swdata)->Data; + + if (item == ITEM_RUGER) + { + if (hand->weapon_action_state == 1) + { +#if defined(VERSION_EU) + rndf = (((hand->field_890 - (hand->weapon_ammo_in_magazine * 5)) + 0x19) * M_TAU_F) / 30.0f; +#else + rndf = (((hand->field_890 - (hand->weapon_ammo_in_magazine * 6)) + 0x1E) * M_TAU_F) / 36.0f; +#endif + } + else + { + rndf = ((6 - hand->weapon_ammo_in_magazine) * M_TAU_F) / 6.0f; + } + } + else if (hand->weapon_action_state == 1) + { +#if defined(VERSION_EU) + if (hand->field_890 < 5) + { + rndf = (hand->field_890 * M_TAU_F) / 30.0f; + } +#else + if (hand->field_890 < 6) + { + rndf = (hand->field_890 * M_TAU_F) / 36.0f; + } +#endif + } + + matrix_4x4_set_rotation_around_z(rndf, &tmpmtx); + matrix_4x4_set_position((coord3d *) cylinderdata, &tmpmtx); + matrix_4x4_multiply(&gunmtx, &tmpmtx, &rwmtx[3]); + } + + swdata = (f32 *) mdlhdr->Switches[5]; + + if (swdata != NULL) + { + hammerdata = (ModelNode **) ((ModelNode *) swdata)->Data; + + if (hand->weapon_action_state == 1) + { +#if defined(VERSION_EU) + if (hand->field_890 < 2) + { + rndf = (2.0f * ((-((f32) hand->field_890)) * DegToRad(30.0f))) / 5.0f; + } + else + { + rndf = (2.0f * ((-((f32) (5 - hand->field_890))) * DegToRad(30.0f))) / 5.0f; + } +#else + if (hand->field_890 < 3) + { + rndf = (2.0f * ((-((f32) hand->field_890)) * DegToRad(30.0f))) / 6.0f; + } + else + { + rndf = (2.0f * ((-((f32) (6 - hand->field_890))) * DegToRad(30.0f))) / 6.0f; + } +#endif + matrix_4x4_set_rotation_around_x(rndf, &tmpmtx); + matrix_4x4_set_position((coord3d *) hammerdata, &tmpmtx); + } + else + { + matrix_4x4_set_identity_and_position((coord3d *) hammerdata, &tmpmtx); + } + + matrix_4x4_multiply(&gunmtx, &tmpmtx, &rwmtx[4]); + } + } + + if (flashvisptr != NULL) + { + *flashvisptr = 0; + } + + if (flashdata != NULL) + { + rnd = randomGetNext(); + rndf = (f32) ((u32) rnd); + flashscale = ((rndf * (1.0f / M_U32_MAX_VALUE_F)) * 0.25f) + 1.0f; + flashext = itemstats->MuzzleFlashExtension; + + if (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_00000001) != 0) + { + rnd = randomGetNext(); + rndf = (f32) ((u32) rnd); + matrix_4x4_set_rotation_around_z((rndf * (1.0f / M_U32_MAX_VALUE_F)) * M_TAU_F, &flashmtx); + matrix_4x4_set_position((coord3d *) flashdata, &flashmtx); + } + else + { + matrix_4x4_set_identity_and_position((coord3d *) flashdata, &flashmtx); + } + + matrix_scalar_multiply(flashscale, flashmtx.m[0]); + matrix_column_3_scalar_multiply(flashext, flashmtx.m[0]); + matrix_4x4_multiply_in_place(&gunmtx, &flashmtx); + matrix_4x4_copy(&flashmtx, &rwmtx[1]); + + hand->field_B58.x = flashmtx.m[3][0]; + hand->field_B58.y = flashmtx.m[3][1]; + hand->field_B58.z = flashmtx.m[3][2]; + mtx4TransformVecInPlace(currentPlayerGetViewToWorldMtxf(), &hand->field_B58); + hand->field_B64 = -flashmtx.m[3][2]; + + if (hand->field_87D != 0) + { + if (flashvisptr != NULL) + { + *flashvisptr = 1; + } + + nodeptr = (f32 *) mdlhdr->Switches[2]; + + if (nodeptr != NULL) + { + nodepos = (f32 *) ((ModelNode *) nodeptr)->Data; + flashpos.x = (((((f32 *) nodepos)[0] * flashmtx.m[0][0]) + (((f32 *) nodepos)[1] * flashmtx.m[1][0])) + (((f32 *) nodepos)[2] * flashmtx.m[2][0])) + flashmtx.m[3][0]; + flashpos.y = (((((f32 *) nodepos)[0] * flashmtx.m[0][1]) + (((f32 *) nodepos)[1] * flashmtx.m[1][1])) + (((f32 *) nodepos)[2] * flashmtx.m[2][1])) + flashmtx.m[3][1]; + flashpos.z = (((((f32 *) nodepos)[0] * flashmtx.m[0][2]) + (((f32 *) nodepos)[1] * flashmtx.m[1][2])) + (((f32 *) nodepos)[2] * flashmtx.m[2][2])) + flashmtx.m[3][2]; + + matrix_4x4_align(&flash2mtx, (randomGetNext() * (1.0f / M_U32_MAX_VALUE_F)) * M_TAU_F, -flashpos.x, -flashpos.y, -flashpos.z); + matrix_scalar_multiply(IDO_POINT_ONE * flashscale, flash2mtx.m[0]); + matrix_4x4_set_rotation_axis_angle(&aimmtx, 0, gunofs.x - hand->field_A38, gunofs.y - hand->field_A3C, gunofs.z - hand->field_A40); + matrix_4x4_multiply_in_place(&aimmtx, &flash2mtx); + matrix_row_3_scalar_multiply(flashext, flash2mtx.m[0]); + matrix_4x4_multiply_in_place(&rotmtx, &flash2mtx); + matrix_4x4_set_position(&flashpos, &flash2mtx); + matrix_4x4_copy(&flash2mtx, &rwmtx[2]); + } + + if (mdlhdr->Skeleton == (&skeleton_gun_kf7)) + { + nodeptr = (f32 *) mdlhdr->Switches[4]; + + if (nodeptr != NULL) + { + nodepos = (f32 *) ((ModelNode *) nodeptr)->Data; + flashpos.x = (((((f32 *) nodepos)[0] * flashmtx.m[0][0]) + (((f32 *) nodepos)[1] * flashmtx.m[1][0])) + (((f32 *) nodepos)[2] * flashmtx.m[2][0])) + flashmtx.m[3][0]; + flashpos.y = (((((f32 *) nodepos)[0] * flashmtx.m[0][1]) + (((f32 *) nodepos)[1] * flashmtx.m[1][1])) + (((f32 *) nodepos)[2] * flashmtx.m[2][1])) + flashmtx.m[3][1]; + flashpos.z = (((((f32 *) nodepos)[0] * flashmtx.m[0][2]) + (((f32 *) nodepos)[1] * flashmtx.m[1][2])) + (((f32 *) nodepos)[2] * flashmtx.m[2][2])) + flashmtx.m[3][2]; + ((f32 *) stackpad2)[-8] = IDO_POINT_ONE * flashscale; + matrix_4x4_align(&flash2mtx, (randomGetNext() * (1.0f / M_U32_MAX_VALUE_F)) * M_TAU_F, -flashpos.x, -flashpos.y, -flashpos.z); + matrix_scalar_multiply(((f32 *) stackpad2)[-8], flash2mtx.m[0]); + matrix_4x4_set_rotation_axis_angle(&aimmtx, 0, gunofs.x - hand->field_A38, gunofs.y - hand->field_A3C, gunofs.z - hand->field_A40); + matrix_4x4_multiply_in_place(&aimmtx, &flash2mtx); + matrix_row_3_scalar_multiply(flashext, flash2mtx.m[0]); + matrix_4x4_multiply_in_place(&rotmtx, &flash2mtx); + matrix_4x4_set_position(&flashpos, &flash2mtx); + matrix_4x4_copy(&flash2mtx, &rwmtx[3]); + } + } + } + } + else + { + hand->field_B58.x = hand->throw_item_pos_related.m[3][0]; + hand->field_B58.y = hand->throw_item_pos_related.m[3][1]; + hand->field_B58.z = hand->throw_item_pos_related.m[3][2]; + hand->field_B64 = -hand->gunmtx_camspace.m[3][2]; + } + + node = mdlhdr->Switches[6]; + + if (node != NULL) + { + swdata = (f32 *) node->Data; + sw6mtxidx = modelFindNodeMtxIndex(node, 0); + sub_GAME_7F05E6B4(handnum, hand->weapon_hold_time); + + if ((mdlhdr->numSwitches >= 0x1D) && (mdlhdr->Switches[28] != NULL)) + { + hingedata = (f32 *) mdlhdr->Switches[28]->Data; + guRotateF(tmpmtx.m, (((hand->field_A84 + M_TAU_F) - get_value_if_watch_is_on_hand_or_not(handnum)) * 360.0f) / M_TAU_F, hingedata[0] - hingedata[3], hingedata[1] - hingedata[4], hingedata[2] - hingedata[5]); + matrix_4x4_set_position((coord3d *) swdata, &tmpmtx); + } + else + { + matrix_4x4_set_position_and_rotation_around_y(swdata, hand->field_A84, &tmpmtx); + } + + matrix_4x4_multiply_homogeneous(&gunmtx, &tmpmtx, &rwmtx[sw6mtxidx]); + } + + if (mdlhdr->numSwitches >= 0x1E) + { + bondviewSelectCuff(model, mdlhdr, 0x1D); + } + + node = mdlhdr->Switches[7]; + + if (node != NULL) + { + sw7data = (f32 *) node->Data; + sw7mtxidx = modelFindNodeMtxIndex(node, 0); + sub_GAME_7F05E83C(handnum); + matrix_4x4_set_identity_and_position((coord3d *) sw7data, &tmpmtx); + tmpmtx.m[3][2] -= hand->field_A88; + matrix_4x4_multiply(&gunmtx, &tmpmtx, &rwmtx[sw7mtxidx]); + } + + shellidx = 0; + + /** + * For the shotguns, show or hide the shells in the shell holder based on how much ammunition is in the player's reserve. + */ + if (mdlhdr->numSwitches >= 0x13) + { + do + { + if (mdlhdr->Switches[18 + shellidx] != 0) + { + nodeptr = (f32 *) modelGetNodeRwData(model, mdlhdr->Switches[18 + shellidx]); + + if (nodeptr != NULL) + { + *((s32 *) nodeptr) = hand->numvisibleshells >= (5 - shellidx); + } + } + + if (mdlhdr->Switches[23 + shellidx] != 0) + { + nodeptr = (f32 *) modelGetNodeRwData(model, mdlhdr->Switches[23 + shellidx]); + + if (nodeptr != NULL) + { + *((s32 *) nodeptr) = hand->numvisibleshells >= (5 - shellidx); + } + } + + shellidx += 1; + } + while (shellidx != 5); + } + + modelUpdateNodeRelations(model); + + if (hand->weapon_firing_status != 0) + { + switch (item) + { + case ITEM_WPPK: + case ITEM_WPPKSIL: + case ITEM_TT33: + case ITEM_SKORPION: + case ITEM_AK47: + case ITEM_UZI: + case ITEM_MP5K: + case ITEM_MP5KSIL: + case ITEM_SPECTRE: + case ITEM_M16: + case ITEM_FNP90: + case ITEM_SNIPERRIFLE: + case ITEM_RUGER: + case ITEM_GOLDENGUN: + case ITEM_SILVERWPPK: + case ITEM_GOLDWPPK: + gunCreateBeamForHand(handnum); + hand->field_8A0 = hand->field_8A0 + 1; + break; + case ITEM_LASER: + case ITEM_WATCHLASER: +#if defined(VERSION_JP) || defined(VERSION_EU) + hand->field_8A0 = hand->field_8A0 + 1; +#endif + gunCreateBeamForHand(handnum); + break; + } + } + } + + if (item == ITEM_ROCKETLAUNCH) + { + gunUpdateAttachedRocket(handnum); + } + + if (hand->weapon_firing_status != 0) + { + sub_GAME_7F068508(handnum, bondviewGetPlayerStanHeight(g_CurrentPlayer)); + + if (item == ITEM_GRENADELAUNCH) + { + gunSpawnGLGrenade(handnum); + return; + } + + if (item == ITEM_GRENADE) + { + generate_player_thrown_grenade(handnum); + return; + } + + if (item == ITEM_ROCKETLAUNCH) + { + gunFireTankShell(handnum); + return; + } + + if (item == ITEM_THROWKNIFE) + { + generate_player_thrown_knife(handnum); + return; + } + + if ((((((((item == ITEM_REMOTEMINE) || (item == ITEM_PROXIMITYMINE)) || (item == ITEM_TIMEDMINE)) || (item == ITEM_BOMBCASE)) || (item == ITEM_BUG)) || (item == ITEM_MICROCAMERA)) || (item == ITEM_GOLDENEYEKEY)) || (item == ITEM_PLASTIQUE)) + { + generate_player_thrown_object(handnum); + return; + } + + if (item == ITEM_FLAREPISTOL) + { + gunSpawnGLGrenade(handnum); + return; + } + + if (item == ITEM_PITONGUN) + { + gunSpawnGLGrenade(handnum); + } + } +} + + +void gunUpdateAndFireBothHands(void) +{ + gunUpdateAndFire(GUNRIGHT); + gunUpdateAndFire(GUNLEFT); +} + + +/** + * @param arg0: + * @param item: + * @param arg2: + * @param arg3: + * + * Address 0x7F061948. + * + * This function adjusts the length of the bullet beam that's rendered on screen. + * This function is used for both player and guard beams. + * + * The watch laser has a very short beam, in accordance with its range. + * The laser also has a shortened one, but it appears this is to avoid graphical glitches. + * Other weapons have their bullet beam capped at 10000 max length, otherwise if the player + * fires into the void, there may be graphical glitches with the beam. + * +*/ +void CapBeamLengthAndDecideIfRendered(struct BeamRecord *arg0, ITEM_IDS item, coord3d *arg2, coord3d *arg3) +{ + f32 phi_f12_2; + + //arg0->pos.x = arg2->x; + //arg0->pos.y = arg2->y; + //arg0->pos.z = arg2->z; + + //arg0->delta.x = arg3->x - arg2->x; + //arg0->delta.y = arg3->y - arg2->y; + //arg0->delta.z = arg3->z - arg2->z; + + //phi_f12_2 = sqrtf((arg0->delta.f[0] * arg0->delta.f[0]) + (arg0->delta.f[1] * arg0->delta.f[1]) + (arg0->delta.f[2] * arg0->delta.f[2])); + + //arg0->delta.x *= 1.0f / phi_f12_2; + //arg0->delta.y *= 1.0f / phi_f12_2; + //arg0->delta.z *= 1.0f / phi_f12_2; + + + arg0->pos.f[0] = arg2->f[0]; + arg0->pos.f[1] = arg2->f[1]; + arg0->pos.f[2] = arg2->f[2]; + + arg0->delta.f[0] = arg3->x - arg2->x; + arg0->delta.f[1] = arg3->f[1] - arg2->f[1]; + arg0->delta.f[2] = arg3->f[2] - arg2->f[2]; + + phi_f12_2 = sqrtf((arg0->delta.f[0] * arg0->delta.f[0]) + (arg0->delta.f[1] * arg0->delta.f[1]) + (arg0->delta.f[2] * arg0->delta.f[2])); + + arg0->delta.f[0] *= 1.0f / phi_f12_2; + arg0->delta.f[1] *= 1.0f / phi_f12_2; + arg0->delta.f[2] *= 1.0f / phi_f12_2; + + if (item == ITEM_WATCHLASER) + { + if (phi_f12_2 > 300.0f) + { + phi_f12_2 = 300.0f; + } + } + else + { + if (phi_f12_2 > 10000.0f) + { + phi_f12_2 = 10000.0f; + } + } + + arg0->unk00 = 0; + arg0->item_id = (s8) item; + arg0->unk1c = phi_f12_2; + + if (phi_f12_2 < 500.0f) + { + phi_f12_2 = 500.0f; + } + + if (item == ITEM_LASER) + { + arg0->unk20 = 0.25f * phi_f12_2; + arg0->unk24 = 0.6f * phi_f12_2; + + if (arg0->unk24 > 3000.0f) + { + arg0->unk24 = 3000.0f; + } + + // Laser beams are rendered more often than other normal weapons + arg0->unk28 = (-0.1f - ((f32) (u32)randomGetNext() * (1.0f / UINT_MAX) * 0.3f)) * phi_f12_2; + } + else if (item == ITEM_WATCHLASER) + { + arg0->unk24 = phi_f12_2; + arg0->unk20 = 2.0f * phi_f12_2; + + if (phi_f12_2 > 3000.0f) + { + arg0->unk24 = 3000.0f; + } + + // Always render the beam for the watch laser + arg0->unk28 = 0.0f; + } + else + { + arg0->unk20 = 0.2f * phi_f12_2; + arg0->unk24 = arg0->unk20; + + if (arg0->unk20 > 3000.0f) + { + arg0->unk24 = 3000.0f; + } + + // Decide if a beam should be rendered for normal weapon bullets + arg0->unk28 = ((2.0f * ((f32) (u32)randomGetNext() * (1.0f / UINT_MAX))) - 1.0f) * arg0->unk20; + } + + if (arg0->unk1c <= arg0->unk28) + { + // No beam will be rendered + arg0->unk00 = -1; + } +} + + +void gunCreateBeamForHand(enum GUNHAND hand) +{ + coord3d *field_2A18; + Mtxf *player_matrix; + struct hand *hand_ptr; + f32 val; + struct ChrRecord *chr; + f32 diff1_z; + f32 diff1_y; + f32 diff1_x; + f32 diff2_z; + f32 diff2_y; + f32 diff2_x; + BeamRecord *weapon_beam; + + hand_ptr = &g_CurrentPlayer->hands[hand]; + player_matrix = camGetWorldToScreenMtxf(); + + val = -((((hand_ptr->item_related.x * player_matrix->m[0][2]) + (hand_ptr->item_related.y * player_matrix->m[1][2])) + (hand_ptr->item_related.z * player_matrix->m[2][2])) + player_matrix->m[3][2]); + + if (val < hand_ptr->field_B64) + { + return; + } + + weapon_beam = &hand_ptr->weapon_beam; + + CapBeamLengthAndDecideIfRendered(weapon_beam, getCurrentPlayerWeaponId(hand), &hand_ptr->field_B58, &hand_ptr->item_related); + + if ((g_CurrentPlayer->prop->chr == NULL) || (getPlayerCount() < 2)) + { + return; + } + + chr = g_CurrentPlayer->prop->chr; + + diff1_x = hand_ptr->item_related.x - g_CurrentPlayer->field_2A18[hand].x; + diff1_y = hand_ptr->item_related.y - g_CurrentPlayer->field_2A18[hand].y; + diff1_z = hand_ptr->item_related.z - g_CurrentPlayer->field_2A18[hand].z; + guNormalize(&diff1_x, &diff1_y, &diff1_z); + + diff2_x = hand_ptr->item_related.x - hand_ptr->field_B58.x; + diff2_y = hand_ptr->item_related.y - hand_ptr->field_B58.y; + diff2_z = hand_ptr->item_related.z - hand_ptr->field_B58.z; + guNormalize(&diff2_x, &diff2_y, &diff2_z); + + val = acosf( + + (diff2_z * diff1_z) + + ((diff1_x * diff2_x) + + (diff1_y * diff2_y))); + + if (val > 0.08726647f) + { + return; + } + + CapBeamLengthAndDecideIfRendered(&chr->beams[hand], getCurrentPlayerWeaponId(hand), &g_CurrentPlayer->field_2A18[hand], &hand_ptr->item_related); +} + + +Gfx *sub_GAME_7F061E18(Gfx *gdl, BeamRecord *flash, s32 arg2) +{ + f32 posz; + Mtx *mtx; + Mtxf mtxf; + Vtx templatevtx; + coord3d pos; + coord3d *playerpos; + f32 radius; + f32 pad_after_radius[2]; + f32 startoffset; + coord3d up; + coord3d right; + coord3d flareoffset; + coord3d extraorigin; + f32 extra_scale; + struct sImageTableEntry *image; + f32 d; + Mtxf *worldtoscreen; + coord3d tmp; + coord3d divout; + f32 divin[2]; + f32 f14; + f32 f16; + f32 f18; + f32 dist_to_start; + Vtx *vtx; + f32 dist; + Gfx *cmd; + + if (flash->unk00 >= 0) + { + templatevtx = D_80035C98; + playerpos = bondviewGetCurrentPlayersPosition(); + startoffset = flash->unk28; + dist = flash->unk24; + flareoffset = D_80035CA8; + extraorigin = D_80035CB4; + extra_scale = 1.4142f; // ~√2 + image = flareimage3; + worldtoscreen = camGetWorldToScreenMtxf(); + + if (flash->item_id == ITEM_LASER) + { + radius = 50.0f; + image = flareimage4; + } + else if (flash->item_id == ITEM_WATCHLASER) + { + radius = 10.0f; + image = flareimage4; + templatevtx.v.cn[3] = (randomGetNext() % 50) + 150; + + if ((randomGetNext() % 5) == 0) + { + templatevtx.v.cn[0] = (templatevtx.v.cn[1] = 255 - (randomGetNext() % 100)); + } + } + else + { + radius = 30.0f; + } + + pos.f[0] = flash->pos.f[0]; + pos.f[1] = flash->pos.f[1]; + pos.f[2] = flash->pos.f[2]; + + if (startoffset > 0.0f) + { + pos.f[0] += startoffset * flash->delta.f[0]; + pos.f[1] += startoffset * flash->delta.f[1]; + pos.f[2] += startoffset * flash->delta.f[2]; + } + else + { + dist += startoffset; + startoffset = 0.0f; + } + + if (flash->unk1c < (startoffset + dist)) + { + dist = flash->unk1c - startoffset; + } + + right.f[0] = (flash->delta.f[1] * (playerpos->f[2] - (pos.f[2] + (dist * flash->delta.f[2])))) - (flash->delta.f[2] * (playerpos->f[1] - (pos.f[1] + (dist * flash->delta.f[1])))); + right.f[1] = (flash->delta.f[2] * (playerpos->f[0] - (pos.f[0] + (dist * flash->delta.f[0])))) - (flash->delta.f[0] * (playerpos->f[2] - (pos.f[2] + (dist * flash->delta.f[2])))); + right.f[2] = (flash->delta.f[0] * (playerpos->f[1] - (pos.f[1] + (dist * flash->delta.f[1])))) - (flash->delta.f[1] * (playerpos->f[0] - (pos.f[0] + (dist * flash->delta.f[0])))); + + if (((right.f[0] != 0.0f) || (right.f[1] != 0.0f)) || (right.f[2] != 0.0f)) + { + guNormalize(&right.f[0], &right.f[1], &right.f[2]); + right.f[0] *= radius; + right.f[1] *= radius; + right.f[2] *= radius; + } + else + { + right.f[0] = 0.0f; + right.f[1] = radius; + right.f[2] = 0.0f; + } + + up.f[0] = (flash->delta.f[1] * right.f[2]) - (flash->delta.f[2] * right.f[1]); + up.f[1] = (flash->delta.f[2] * right.f[0]) - (flash->delta.f[0] * right.f[2]); + up.f[2] = (flash->delta.f[0] * right.f[1]) - (flash->delta.f[1] * right.f[0]); + + guNormalize(&up.f[0], &up.f[1], &up.f[2]); + + up.f[0] *= radius; + up.f[1] *= radius; + up.f[2] *= radius; + + if (flash->item_id == ITEM_LASER) + { + vtx = dynAllocateVertices(8); + } + else + { + vtx = dynAllocateVertices(4); + } + + mtx = dynAllocateMatrix(); + + matrix_4x4_set_identity_and_position(&pos, &mtxf); + matrix_scalar_multiply(0.1f, (f32 *)&mtxf); + matrix_4x4_multiply_homogeneous_in_place(worldtoscreen, &mtxf); + matrix_4x4_f32_to_s32(&mtxf, (Mtxf *)mtx); + + vtx[0] = templatevtx; + vtx[1] = templatevtx; + vtx[2] = templatevtx; + vtx[3] = templatevtx; + + if (flash->item_id == ITEM_LASER) + { + vtx[4] = templatevtx; + vtx[5] = templatevtx; + vtx[6] = templatevtx; + vtx[7] = templatevtx; + } + + if (flash->item_id == ITEM_WATCHLASER) + { + tmp.f[0] = pos.f[0] + flash->delta.f[0] * dist; + tmp.f[1] = pos.f[1] + flash->delta.f[1] * dist; + tmp.f[2] = pos.f[2] + flash->delta.f[2] * dist; + + mtx4TransformVecInPlace(worldtoscreen, &tmp); + + divin[0] = divin[1] = radius / 10.0f; + + dist_to_start = -tmp.f[2]; + divide3DCoordinates((coord3d *)divin, dist_to_start, &divout); + + if (divout.f[0] < 2.0f) + { + tmp.f[0] *= divout.f[0] * 0.5f; + tmp.f[1] *= divout.f[0] * 0.5f; + tmp.f[2] *= divout.f[0] * 0.5f; + } + + mtx4TransformVecInPlace(currentPlayerGetViewToWorldMtxf(), &tmp); + + tmp.f[0] -= pos.f[0]; + tmp.f[1] -= pos.f[1]; + tmp.f[2] -= pos.f[2]; + + flareoffset.x = tmp.f[0] * 10.0f; + flareoffset.y = tmp.f[1] * 10.0f; + flareoffset.z = tmp.f[2] * 10.0f; + } + else + { + flareoffset.x = flash->delta.f[0] * (dist * 10.0f); + flareoffset.y = flash->delta.f[1] * (dist * 10.0f); + flareoffset.z = flash->delta.f[2] * (dist * 10.0f); + } + + vtx[0].v.ob[0] = right.f[0]; + vtx[0].v.ob[1] = right.f[1]; + vtx[0].v.ob[2] = right.f[2]; + vtx[0].v.tc[0] = image->width << 5; + vtx[0].v.tc[1] = 0; + + vtx[1].v.ob[0] = -right.f[0]; + vtx[1].v.ob[1] = -right.f[1]; + vtx[1].v.ob[2] = -right.f[2]; + vtx[1].v.tc[0] = 0; + vtx[1].v.tc[1] = 0; + + vtx[2].v.ob[0] = flareoffset.f[0] + (right.f[0] * 0.9f); + vtx[2].v.ob[1] = flareoffset.f[1] + (right.f[1] * 0.9f); + vtx[2].v.ob[2] = flareoffset.f[2] + (right.f[2] * 0.9f); + vtx[2].v.tc[0] = image->width << 5; + vtx[2].v.tc[1] = image->height << 5; + + vtx[3].v.ob[0] = flareoffset.f[0] - (right.f[0] * 0.9f); + vtx[3].v.ob[1] = flareoffset.f[1] - (right.f[1] * 0.9f); + vtx[3].v.ob[2] = flareoffset.f[2] - (right.f[2] * 0.9f); + vtx[3].v.tc[0] = 0; + vtx[3].v.tc[1] = image->height << 5; + + if (flash->item_id == ITEM_LASER) + { + f14 = playerpos->f[0] - pos.f[0]; + f16 = playerpos->f[1] - pos.f[1]; + f18 = playerpos->f[2] - pos.f[2]; + + dist_to_start = (f14 * f14) + (f16 * f16) + (f18 * f18); + + f14 = playerpos->f[0] - (pos.f[0] + (flash->delta.f[0] * dist)); + f16 = playerpos->f[1] - (pos.f[1] + (flash->delta.f[1] * dist)); + f18 = playerpos->f[2] - (pos.f[2] + (flash->delta.f[2] * dist)); + + d = (f14 * f14) + (f16 * f16) + (f18 * f18); + + if (d < dist_to_start) + { + extraorigin.f[0] = flareoffset.f[0]; + extraorigin.f[1] = flareoffset.f[1]; + extraorigin.f[2] = flareoffset.f[2]; + extra_scale *= 0.9f; + } + + vtx[4].v.ob[0] = extraorigin.f[0] + (up.f[0] * extra_scale); + vtx[4].v.ob[1] = extraorigin.f[1] + (up.f[1] * extra_scale); + vtx[4].v.ob[2] = extraorigin.f[2] + (up.f[2] * extra_scale); + vtx[4].v.tc[0] = flareimage5->width << 5; + vtx[4].v.tc[1] = flareimage5->height << 5; + + vtx[5].v.ob[0] = extraorigin.f[0] - (up.f[0] * extra_scale); + vtx[5].v.ob[1] = extraorigin.f[1] - (up.f[1] * extra_scale); + vtx[5].v.ob[2] = extraorigin.f[2] - (up.f[2] * extra_scale); + vtx[5].v.tc[0] = 0; + vtx[5].v.tc[1] = 0; + + vtx[6].v.ob[0] = extraorigin.f[0] + (right.f[0] * extra_scale); + vtx[6].v.ob[1] = extraorigin.f[1] + (right.f[1] * extra_scale); + vtx[6].v.ob[2] = extraorigin.f[2] + (right.f[2] * extra_scale); + vtx[6].v.tc[0] = 0; + vtx[6].v.tc[1] = flareimage5->height << 5; + + vtx[7].v.ob[0] = extraorigin.f[0] - (right.f[0] * extra_scale); + vtx[7].v.ob[1] = extraorigin.f[1] - (right.f[1] * extra_scale); + vtx[7].v.ob[2] = extraorigin.f[2] - (right.f[2] * extra_scale); + vtx[7].v.tc[0] = flareimage5->width << 5; + vtx[7].v.tc[1] = 0; + } + + gSPClearGeometryMode(gdl++, G_CULL_BACK); + + // Ideally this should be something like gSPMatrix(gdl++ or cmd++, osVirtualToPhysical(mtx), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH) but I can't get these or similar forms to match + { + cmd = gdl++; + cmd->words.w0 = _SHIFTL(G_MTX, 24, 8) + | _SHIFTL(G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH, 16, 8) + | _SHIFTL(sizeof(Mtx), 0, 16); + cmd->words.w1 = osVirtualToPhysical(mtx); + } + + if (flash->item_id == ITEM_LASER) + { + texSelect(&gdl, flareimage5, 4, arg2, 2); + + gSPVertex(gdl++, osVirtualToPhysical(vtx), 8, 0); + + gSP4Triangles(gdl++, 4, 5, 6, 4, 5, 7, 0, 0, 0, 0, 0, 0); + + texSelect(&gdl, image, 4, arg2, 2); + + gSP4Triangles(gdl++, 0, 2, 3, 0, 3, 1, 0, 0, 0, 0, 0, 0); + } + else + { + texSelect(&gdl, image, 4, arg2, 2); + + gSPVertex(gdl++, osVirtualToPhysical(vtx), 4, 0); + + gSP4Triangles(gdl++, 0, 2, 3, 0, 3, 1, 0, 0, 0, 0, 0, 0); + } + } + + return gdl; +} + + +/* +* Address: 0x7F062B00 +*/ +void gunAdvanceBeamTimer(BeamRecord* beam) +{ + if (beam->unk00 >= 0) + { + if (g_ClockTimer < 3) + { +#ifdef VERSION_US + beam->unk28 += beam->unk20 * g_GlobalTimerDelta; +#else + beam->unk28 += beam->unk20 * g_JP_GlobalTimerDelta; +#endif + } + else + { + beam->unk28 += beam->unk20 * (2.0f + ((f32) randomGetNext() * 2.3283064e-10f * 0.5f)); + } + + if (beam->unk1c <= beam->unk28) + { + beam->unk00 = -1; + return; + } + + beam->unk00++; + } +} + +// Address: 0x7F062BE4 +void gunRenderFirstPersonGunModels(Gfx **gdlptr) +{ + Gfx *gdl = *gdlptr; + ModelRenderData renderdata; + s32 handnum; + Model *model; + + renderdata = *(ModelRenderData *)&D_80035CC0; + + for (handnum = 0; handnum != 2; handnum++) + { + struct hand *handptr = &g_CurrentPlayer->hands[handnum]; + s32 item = get_item_in_hand_or_watch_menu(handnum); + + if (handptr->field_87F == 0) + { + continue; + } + + if (item != ITEM_WATCHLASER) + { + gdl = sub_GAME_7F061E18(gdl, &handptr->weapon_beam, 0); + } + + if (item == ITEM_GOLDENGUN || item == ITEM_RUGER || item == ITEM_KNIFE || item == ITEM_THROWKNIFE || item == ITEM_SILVERWPPK || item == ITEM_GOLDWPPK) + { + gSPSetLights1(gdl++, g_WeaponEnvmapLight); + gSPLookAt(gdl++, sub_GAME_7F078474()); + } + + gSPPerspNormalize(gdl++, matrix_4x4_calc_depth_scale(0.0f, 300.0f)); + + if ((*(Model *)&handptr->field_B68).obj->numSwitches >= 0x11 && (*(Model *)&handptr->field_B68).obj->Switches[16] != NULL) + { + union ModelRwData *rwdata; + model = (Model *)&handptr->field_B68; + rwdata = modelGetNodeRwData(model, (*(Model *)&handptr->field_B68).obj->Switches[17]); + + if (rwdata != NULL) + { + rwdata->Raw.unk00 = 1; + } + + if (item == ITEM_ROCKETLAUNCH) + { + save_img_index_to_obj_ani_slot(&g_UnknownAnimController, crosshairimage); + gdl = process_monitor_animation_microcode(model, (*(Model *)&handptr->field_B68).obj->Switches[16], &g_UnknownAnimController, gdl, 0, 4); + } + else + { + gdl = process_monitor_animation_microcode(model, (*(Model *)&handptr->field_B68).obj->Switches[16], &g_TaserAnimController, gdl, 0, 1); + } + } + + renderdata.gdl = gdl; + renderdata.PropType = 4; + renderdata.envcolour.word = g_CurrentPlayer->tileColor.a + | ((u32)g_CurrentPlayer->tileColor.r << 24) + | ((u32)g_CurrentPlayer->tileColor.g << 16) + | ((u32)g_CurrentPlayer->tileColor.b << 8); + renderdata.zbufferenabled = 0; + + matrix_4x4_7F058C64(); + + if (item == ITEM_ROCKETLAUNCH && handptr->rocket != NULL) + { + model = handptr->rocket->model; + + subdraw(&renderdata, model); + bondviewTransformManyPosToViewMatrix(model->render_pos, model->obj->numMatrices); + + if (handptr->firedrocket != 0) + { + handptr->rocket = NULL; + } + } + + if (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_MIRROR_DUAL) != 0) + { + gSPClearGeometryMode(renderdata.gdl++, G_CULL_BOTH); + + if (handnum == 0) + { + renderdata.cullmode = 3; + } + else + { + renderdata.cullmode = 2; + } + } + + subdraw(&renderdata, (Model *)&handptr->field_B68); + gdl = renderdata.gdl; + + if (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_MIRROR_DUAL) != 0) + { + gSPClearGeometryMode(gdl++, G_CULL_BOTH); + } + + bondviewTransformManyPosToViewMatrix((*(Model *)&handptr->field_B68).render_pos, (*(Model *)&handptr->field_B68).obj->numMatrices); + matrix_4x4_7F058C88(); + + gSPPerspNormalize(gdl++, viGetPerspNorm()); + + if (item == ITEM_WATCHLASER) + { + gdl = sub_GAME_7F061E18(gdl, &handptr->weapon_beam, 0); + } + } + + *gdlptr = gdl; +} + + +Gfx *set_enviro_fog_for_items_in_solo_watch_menu(Gfx *gdl, ITEM_IDS itemid, Mtxf *mtx, s32 arg3, s32 arg4) +{ + ModelRenderData renderdata = *((ModelRenderData *) (&D_80035D00)); + ModelHeader model; + u8 spb8[0x80]; + s32 padb4; + Mtxf sp74; + Mtxf *matrices; + union ModelRwData *rwdata; + s32 i; + s32 j; + ModelFileHeader *bodymodel; + + if ((itemid == ITEM_TRIGGER) || (itemid == ITEM_WATCHLASER)) + { + itemid = ITEM_WATCHMAGNETATTRACT; + } + + sub_GAME_7F05DA8C(GUNRIGHT, itemid); + + if ((!Gun_hand_without_item(GUNRIGHT)) || (!get_itemtype_in_hand(GUNRIGHT))) + { + return gdl; + } + + bodymodel = &g_CurrentPlayer->copy_of_body_obj_header[GUNRIGHT]; + + if (!get_ptr_weapon_model_header_line(itemid)) + { + goto earlyreturn; + } + + if (bondwalkItemCheckBitflags(itemid, WEAPONSTATBITFLAG_HIDE_FIRST_PERSON_MENU)) + { + goto earlyreturn; + } + + matrices = dynAllocate(bodymodel->numMatrices << 6); + + for (i = 0; i < bodymodel->numMatrices; i++) + { + matrix_4x4_set_identity(&matrices[i]); + } + + i = 0; + ((Model *) &model)->render_pos = matrices; + modelCalculateRwDataLen(bodymodel); + modelInit((Model *) &model, bodymodel, spb8); + sub_GAME_7F05E978((Model *) &model, 0); + sub_GAME_7F05EA94((Model *) &model, 1); + + if (bodymodel->Switches[1] != NULL) + { + rwdata = modelGetNodeRwData((Model *) &model, bodymodel->Switches[1]); + + if (rwdata != 0) + { + rwdata->Raw.unk00 = 0; + } + } + + matrix_4x4_copy(mtx, matrices); + + if (bodymodel->Skeleton == (&skeleton_gun_revolver)) + { + if (bodymodel->Switches[4] != NULL) + { + matrix_4x4_set_identity_and_position((coord3d *) bodymodel->Switches[4]->Data, &sp74); + matrix_4x4_multiply(mtx, &sp74, &matrices[3]); + } + if (bodymodel->Switches[5] != NULL) + { + matrix_4x4_set_identity_and_position((coord3d *) bodymodel->Switches[5]->Data, &sp74); + matrix_4x4_multiply(mtx, &sp74, &matrices[4]); + } + } + + if (bodymodel->Switches[6] != NULL) + { + coord3d *pos; + s32 index; + + pos = (coord3d *) bodymodel->Switches[6]->Data; + index = modelFindNodeMtxIndex(bodymodel->Switches[6], 0); + matrix_4x4_set_identity_and_position(pos, &sp74); + matrix_4x4_multiply(mtx, &sp74, &matrices[index]); + } + + if (bodymodel->Switches[7] != NULL) + { + coord3d *pos; + s32 index; + u8 pad[8]; + + pos = (coord3d *) bodymodel->Switches[7]->Data; + index = modelFindNodeMtxIndex(bodymodel->Switches[7], 0); + matrix_4x4_set_identity_and_position(pos, &sp74); + matrix_4x4_multiply(mtx, &sp74, &matrices[index]); + } + + if (bodymodel->numSwitches >= 19) + { + for (j = 0; j != 20; j += 4) + { + if ((*((ModelNode **) ((((u8 *) bodymodel->Switches) + j) + 0x48))) != NULL) + { + rwdata = modelGetNodeRwData((Model *) &model, *((ModelNode **) ((((u8 *) bodymodel->Switches) + j) + 0x48))); + + if (rwdata != NULL) + { + rwdata->Raw.unk00 = 1; + } + } + + if ((*((ModelNode **) ((((u8 *) bodymodel->Switches) + j) + 0x5c))) != NULL) + { + rwdata = modelGetNodeRwData((Model *) &model, *((ModelNode **) ((((u8 *) bodymodel->Switches) + j) + 0x5c))); + + if (rwdata != NULL) + { + rwdata->Raw.unk00 = 1; + } + } + } + } + + modelUpdateNodeRelations((Model *) &model); + + if ((((((itemid == ITEM_GOLDENGUN) || (itemid == ITEM_RUGER)) || (itemid == ITEM_KNIFE)) || (itemid == ITEM_THROWKNIFE)) || (itemid == ITEM_SILVERWPPK)) || (itemid == ITEM_GOLDWPPK)) + { + gSPSetLights1(gdl++, g_WeaponEnvmapLight); + gSPLookAt(gdl++, sub_GAME_7F078474()); + } + + if (bodymodel->numSwitches >= 17) + { + if (bodymodel->Switches[16] != NULL) + { + rwdata = modelGetNodeRwData((Model *) &model, bodymodel->Switches[17]); + + if (rwdata != 0) + { + rwdata->Raw.unk00 = 0; + } + } + } + + renderdata.gdl = gdl; + + if (arg3 >= 0xff) + { + renderdata.PropType = PROP_TYPE_WEAPON; + renderdata.envcolour.word = arg4; + } + else + { + renderdata.PropType = PROP_TYPE_PLAYER; + renderdata.envcolour.word = arg3; + renderdata.fogcolour.word = arg4; + } + + renderdata.zbufferenabled = FALSE; + subdraw(&renderdata, (Model *) &model); + gdl = renderdata.gdl; + matrix_4x4_7F058C64(); + j = 0; + + if (bodymodel->numMatrices > 0) + { + do + { + matrix_4x4_copy((Mtxf *) (((u8 *) ((Model *) &model)->render_pos) + j), &sp74); + matrix_4x4_f32_to_s32(&sp74, (Mtxf *) ((i << 6) + (u8 *) ((Model *) &model)->render_pos)); + i++; + j += 0x40; + } + while (i < bodymodel->numMatrices); + } + + matrix_4x4_7F058C88(); + +earlyreturn: + return gdl; + +} + + +void sub_GAME_7F0634D8(s32 arg0, s32 arg1, s32 arg2, s32 arg3) +{ + set_enviro_fog_for_items_in_solo_watch_menu(arg0, arg1, arg2, arg3, -256); +} + + +// Unreferenced +void sub_GAME_7F0634FC(s32 arg0, s32 arg1, s32 arg2) +{ + sub_GAME_7F0634D8(arg0, arg1, arg2, 0xFF); +} + + +void sub_GAME_7F06351C(struct coord3d* arg0, Mtxf* arg1, Mtxf* arg2, Mtxf* arg3, struct coord3d* arg4, Mtxf* arg5, Mtxf* arg6) +{ + Mtxf sp20; + + matrix_4x4_set_identity_and_position(arg0, arg6); + matrix_4x4_multiply_in_place(arg1, arg6); + matrix_4x4_multiply_in_place(arg2, arg6); + matrix_4x4_multiply_in_place(arg3, arg6); + matrix_4x4_set_identity_and_position(arg4, &sp20); + matrix_4x4_multiply_in_place(&sp20, arg6); + matrix_4x4_multiply_in_place(arg5, arg6); +} + + +/** + * Address: 7F06359C + */ +Gfx* watchRenderController(Gfx* gdl, Mtxf* basemtx, s32 envcolour, bool animatebuttons, WatchContButtonPositions* buttonpositions, s8* contpadnum) +{ + ModelRenderData renderdata; + struct ModelHeader modelstack; + s32 i; + s32 j; + s32 offset; + f32 angle; + u32 rwdata[26]; + u32 pad2; + Mtxf sp41c; + Mtxf sp3dc; + struct ModelFileHeader* objheader; + struct coord3d* position; + Mtxf* matrices; + ModelNode* node; + Mtxf sp38c; + Mtxf sp34c; + Mtxf sp30c; + Mtxf sp2cc; + Mtxf sp28c; + Mtxf sp24c; + Mtxf sp20c; + Mtxf sp1cc; + struct coord3d coord_node2; + struct coord3d coord_node11_pos; + struct coord3d coord_node11_base; + struct coord3d coord_node4_pos; + struct coord3d coord_node4_base; + struct coord3d coord_node5_pos; + struct coord3d coord_node5_base; + struct coord3d coord_node6_pos; + struct coord3d coord_node6_base; + struct coord3d coord_node7_pos; + struct coord3d coord_node7_base; + struct coord3d coord_node9_pos; + struct coord3d coord_node9_base; + struct coord3d coord_node8_pos; + struct coord3d coord_node8_base; + struct coord3d coord_node10_pos; + struct coord3d coord_node10_base; + struct coord3d coord_node3_pos; + Mtxf spb4; + struct coord3d coord_node3_base; + struct coord3d coord_node1_pos; + struct coord3d coord_node1_base; + struct coord3d coord_node12_pos; + struct coord3d coord_node12_base; + + renderdata = *(ModelRenderData *)((u8 *)D_80035D04 + 0x3c); + + sub_GAME_7F05DA8C(GUNRIGHT, 0x55); + + if (!(Gun_hand_without_item(GUNRIGHT) && get_itemtype_in_hand(GUNRIGHT))) + { + return gdl; + } + + objheader = g_CurrentPlayer->copy_of_body_obj_header; + matrices = dynAllocate(objheader->numMatrices * (sizeof(Mtxf))); + modelCalculateRwDataLen(objheader); + + if (objheader); + + modelInit(&modelstack, objheader, rwdata); + modelstack.render_pos = (RenderPosView*) matrices; + matrix_4x4_copy(basemtx, &matrices[0]); + + for (i = 1; i < 13; i++) + { + position = objheader->Switches[i]->Data; + + // Update joy stick position and rotation. + if (i == 2) + { + angle = ((((-(f32) joyGetStickX(*contpadnum)) * M_TAU_F) * 0.6f)) / 360.0f; + matrix_4x4_set_rotation_around_z(angle, &sp41c); + angle = ((((-(f32) joyGetStickY(*contpadnum)) * M_TAU_F) * 0.6f)) / 360.0f; + matrix_4x4_set_rotation_around_x(angle, &sp3dc); + matrix_4x4_multiply_in_place(&sp3dc, &sp41c); + matrix_4x4_set_position(position, &sp41c); + } + else + { + matrix_4x4_set_identity_and_position(position, &sp41c); + } + + matrix_4x4_multiply(basemtx, &sp41c, &matrices[i]); + } + + modelUpdateNodeRelations(&modelstack); + renderdata.gdl = gdl; + + if (envcolour >= 0xff) + { + renderdata.PropType = PROP_TYPE_OBJ; + } + else + { + renderdata.PropType = PROP_TYPE_PLAYER; + renderdata.envcolour.word = envcolour; + renderdata.fogcolour.word = 0xFFFFFF00; + } + + renderdata.zbufferenabled = TRUE; + subdraw(&renderdata, &modelstack); + gdl = renderdata.gdl; + matrix_4x4_7F058C64(); + + for (i = 0; i < objheader->numMatrices; i++) + { + matrix_4x4_copy((u32)modelstack.render_pos + i * sizeof(Mtxf), &sp41c); + matrix_4x4_f32_to_s32(&sp41c, &modelstack.render_pos[i]); + } + + matrix_4x4_7F058C88(); + + if (animatebuttons) + { + node = objheader->Switches[13]; + + if (node) + { + *((s32*) modelGetNodeRwData(&modelstack, node)) = 0; + } + + matrices = dynAllocate(objheader->numMatrices * (sizeof(Mtxf))); + modelstack.render_pos = (RenderPosView*) matrices; + + // Update the positions and/or rotations of the free floating buttons on the sides of the screen. + for (i = 0; i < 13; i++) + { + matrix_4x4_set_lookat_target(&sp20c, -5.0f, 2000.0f, -168.0f, -5.0f, 0.0f, -168.0f, 0.0f, 0.0f, -1.0f); + matrix_4x4_set_lookat_target(&sp38c, -5.0f, 2000.0f, -168.0f, -5.0f, 0.0f, -168.0f, 0.0f, 0.0f, -1.0f); + matrix_4x4_set_identity(&sp24c); + matrix_4x4_set_identity(&sp1cc); + matrix_4x4_copy(&sp1cc, &sp2cc); + + // Joy stick + if (i == 2) + { + coord_node2 = buttonpositions->joystick; + matrix_4x4_set_identity_and_position(&coord_node2, &sp34c); + angle = ((((-(f32) joyGetStickX(*contpadnum)) * M_TAU_F) * 0.6f)) / 360.0f; + matrix_4x4_set_rotation_around_z(angle, &sp41c); + angle = ((((-(f32) joyGetStickY(*contpadnum)) * M_TAU_F) * 0.6f)) / 360.0f; + matrix_4x4_set_rotation_around_x(angle, &sp3dc); + matrix_4x4_multiply_in_place(&sp3dc, &sp41c); + matrix_4x4_multiply_in_place(&sp34c, &sp41c); + matrix_4x4_multiply(&sp20c, &sp41c, &sp30c); + matrix_4x4_copy(&sp30c, &matrices[i]); + } + // R + else if (i == 11) + { + coord_node11_base = ((struct coord3d *)watchControllerButtonBases)[5]; + coord_node11_pos = buttonpositions->r; + + if (joyGetButtons(*contpadnum, R_TRIG)) + { + matrix_4x4_set_rotation_around_y(-0.17453294f, &sp24c); + } + + matrix_4x4_set_rotation_around_x(1.0471976f, &sp28c); + sub_GAME_7F06351C(&coord_node11_base, &sp24c, &sp28c, &sp1cc, &coord_node11_pos, &sp20c, &sp38c); + matrix_4x4_copy(&sp38c, &matrices[i]); + } + // C-Up + else if (i == 4) + { + coord_node4_base = ((struct coord3d *)watchControllerButtonBases)[6]; + coord_node4_pos = buttonpositions->cUp; + + if (joyGetButtons(*contpadnum, U_CBUTTONS)) + { + coord_node4_base.y += -10.0f; + } + + matrix_4x4_set_rotation_around_x(-1.0471976f, &sp28c); + sub_GAME_7F06351C(&coord_node4_base, &sp24c, &sp28c, &sp1cc, &coord_node4_pos, &sp20c, &sp38c); + matrix_4x4_copy(&sp38c, &matrices[i]); + } + // C-Down + else if (i == 5) + { + coord_node5_base = ((struct coord3d *)watchControllerButtonBases)[7]; + coord_node5_pos = buttonpositions->cDown; + + if (joyGetButtons(*contpadnum, D_CBUTTONS)) + { + coord_node5_base.y += -10.0f; + } + + matrix_4x4_set_rotation_around_x(-1.0471976f, &sp28c); + sub_GAME_7F06351C(&coord_node5_base, &sp24c, &sp28c, &sp1cc, &coord_node5_pos, &sp20c, &sp38c); + matrix_4x4_copy(&sp38c, &matrices[i]); + } + // C-Left + else if (i == 6) + { + coord_node6_base = ((struct coord3d *)watchControllerButtonBases)[8]; + coord_node6_pos = buttonpositions->cLeft; + + if (joyGetButtons(*contpadnum, L_CBUTTONS)) + { + coord_node6_base.y += -10.0f; + } + + matrix_4x4_set_rotation_around_x(-1.0471976f, &sp28c); + sub_GAME_7F06351C(&coord_node6_base, &sp24c, &sp28c, &sp1cc, &coord_node6_pos, &sp20c, &sp38c); + matrix_4x4_copy(&sp38c, &matrices[i]); + } + // C-Right + else if (i == 7) + { + coord_node7_base = ((struct coord3d *)watchControllerButtonBases)[9]; + coord_node7_pos = buttonpositions->cRight; + + if (joyGetButtons(*contpadnum, R_CBUTTONS)) + { + coord_node7_base.y += -10.0f; + } + + matrix_4x4_set_rotation_around_x(-1.0471976f, &sp28c); + sub_GAME_7F06351C(&coord_node7_base, &sp24c, &sp28c, &sp1cc, &coord_node7_pos, &sp20c, &sp38c); + matrix_4x4_copy(&sp38c, &matrices[i]); + } + // B + else if (i == 9) + { + coord_node9_base = ((struct coord3d *)watchControllerButtonBases)[10]; + coord_node9_pos = buttonpositions->b; + + if (joyGetButtons(*contpadnum, B_BUTTON)) + { + coord_node9_base.y += -10.0f; + } + + matrix_4x4_set_rotation_around_x(-1.0471976, &sp28c); + sub_GAME_7F06351C(&coord_node9_base, &sp24c, &sp28c, &sp1cc, &coord_node9_pos, &sp20c, &sp38c); + matrix_4x4_copy(&sp38c, &matrices[i]); + } + // A + else if (i == 8) + { + coord_node8_base = ((struct coord3d *)watchControllerButtonBases)[11]; + coord_node8_pos = buttonpositions->a; + + if (joyGetButtons(*contpadnum, A_BUTTON)) + { + coord_node8_base.y += -10.0f; + } + + matrix_4x4_set_rotation_around_x(-1.0471976f, &sp28c); + sub_GAME_7F06351C(&coord_node8_base, &sp24c, &sp28c, &sp1cc, &coord_node8_pos, &sp20c, &sp38c); + matrix_4x4_copy(&sp38c, &matrices[i]); + } + // L + else if (i == 10) + { + coord_node10_base = ((struct coord3d *)watchControllerButtonBases)[12]; + coord_node10_pos = buttonpositions->l; + + if (joyGetButtons(*contpadnum, L_TRIG)) + { + matrix_4x4_set_rotation_around_y(0.17453294f, &sp24c); + } + + matrix_4x4_set_rotation_around_x(1.0471976f, &sp28c); + sub_GAME_7F06351C(&coord_node10_base, &sp24c, &sp28c, &sp1cc, &coord_node10_pos, &sp20c, &sp38c); + matrix_4x4_copy(&sp38c, &matrices[i]); + } + // D-pad + else if (i == 3) + { + coord_node3_base = ((struct coord3d *)watchControllerButtonBases)[13]; + coord_node3_pos = buttonpositions->dPad; + matrix_4x4_set_identity(&spb4); + + if (joyGetButtons(*contpadnum, U_JPAD)) + { + matrix_4x4_set_rotation_around_x(-0.17453294f, &sp24c); + } + else if (joyGetButtons(*contpadnum, D_JPAD)) + { + matrix_4x4_set_rotation_around_x(0.17453294f, &sp24c); + } + + if (joyGetButtons(*contpadnum, L_JPAD)) + { + matrix_4x4_set_rotation_around_z(0.17453294f, &spb4); + } + else if (joyGetButtons(*contpadnum, R_JPAD)) + { + matrix_4x4_set_rotation_around_z(-0.17453294f, &spb4); + } + + matrix_4x4_multiply_in_place(&spb4, &sp24c); + matrix_4x4_set_rotation_around_x(-0.89759791f, &sp28c); + sub_GAME_7F06351C(&coord_node3_base, &sp24c, &sp28c, &sp1cc, &coord_node3_pos, &sp20c, &sp38c); + matrix_4x4_copy(&sp38c, &matrices[i]); + } + // Start + else if (i == 1) + { + coord_node1_base = ((struct coord3d *)watchControllerButtonBases)[14]; + coord_node1_pos = buttonpositions->start; + + if (joyGetButtons(*contpadnum, START_BUTTON)) + { + coord_node1_base.y += -10.0f; + } + + matrix_4x4_set_rotation_around_x(-1.0471976f, &sp28c); + sub_GAME_7F06351C(&coord_node1_base, &sp24c, &sp28c, &sp1cc, &coord_node1_pos, &sp20c, &sp38c); + matrix_4x4_copy(&sp38c, &matrices[i]); + } + // Z + else if (i == 12) + { + coord_node12_base = ((struct coord3d *)watchControllerButtonBases)[15]; + coord_node12_pos = buttonpositions->z; + + if (joyGetButtons(*contpadnum, Z_TRIG)) + { + matrix_4x4_set_rotation_around_x(-0.17453294f, &sp24c); + } + + matrix_4x4_set_rotation_around_z(M_PI_F, &sp28c); + sub_GAME_7F06351C(&coord_node12_base, &sp24c, &sp28c, &sp1cc, &coord_node12_pos, &sp20c, &sp38c); + matrix_4x4_copy(&sp38c, &matrices[i]); + } + else + { + matrix_4x4_copy(basemtx, &matrices[i]); + } + } + + modelUpdateNodeRelations(&modelstack); + renderdata.gdl = gdl; + subdraw(&renderdata, &modelstack); + gdl = renderdata.gdl; + matrix_4x4_7F058C64(); + + for (i = 0; i < objheader->numMatrices; i++) + { + matrix_4x4_copy((u32)modelstack.render_pos + i * sizeof(Mtxf), &sp41c); + matrix_4x4_f32_to_s32(&sp41c, &modelstack.render_pos[i]); + } + + matrix_4x4_7F058C88(); + } + + return gdl; +} + + +/** + * Address: 7F064364 + */ +Gfx *watchRenderControllerOpaque(Gfx *gdl, Mtxf *basemtx, bool animatebuttons, WatchContButtonPositions *buttonpositions, s8 *contpadnum) +{ + return watchRenderController(gdl, basemtx, 0xff, animatebuttons, buttonpositions, contpadnum); +} + + +/** + * Address: 7F0643A0 + */ +ALSoundState* gunGetFreeSfxState(void) +{ + s32 i; + + for (i = 0; i < NUM_IMPACT_SFX_STATES; i++) + { + if (g_ImpactSfxStates[i] == NULL) + { + return &g_ImpactSfxStates[i]; + } + } + + return NULL; +} + + +void recall_joy2_hits_edit_detail_edit_flag(enum ITEM_IDS item, PropRecord* prop, s32 texture_index) +{ + s32 sp6C; + u32 rnd1; + u32 rnd2; + ALSoundState* sound_state; + struct RicochetSoundsSmall ricochet_sounds_small_copy; + struct PunchSounds punch_sounds_copy; + struct BulletFleshSounds bullet_flesh_sounds_copy; + u32 sfx_index; + + sp6C = sub_GAME_7F0539E4(&prop->pos); + + rnd1 = randomGetNext(); + rnd2 = randomGetNext(); + + D_800483C4 = texture_index; + + if (get_debug_joy2hitsedit_flag() == 0) + { + get_debug_joy2detailedit_flag(); + } + + if ((item == ITEM_REMOTEMINE) + || (item == ITEM_PROXIMITYMINE) + || (item == ITEM_TIMEDMINE) + || (item == ITEM_BOMBCASE) + || (item == ITEM_BUG) + || (item == ITEM_MICROCAMERA) + || (item == ITEM_PLASTIQUE) + || (item == ITEM_WATCHLASER) + || (item == ITEM_WATCHMAGNETATTRACT)) + { + return; + } + +#ifdef BUGFIX_R1 + if (g_ClockTimer <= 0) { return; } +#endif + + sound_state = gunGetFreeSfxState(); + if (sound_state != NULL) + { + if ((prop->type != PROP_TYPE_CHR) && (prop->type != PROP_TYPE_VIEWER)) + { + if (item == ITEM_LASER) + { + sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, RICO_LASER1_SFX, sound_state); + } + else + { + ricochet_sounds_small_copy = ricochet_sounds_small; + sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, ricochet_sounds_small_copy.arr[rnd1 % 20], sound_state); + } + + if (sound_state->link.next != NULL) + { + sndCreatePostEvent((ALSoundState* ) sound_state->link.next, 8, sp6C); + } + } + else + { + if (item == ITEM_KNIFE) + { + sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, HIT_BULLET_SNOW_SFX, sound_state); + } + else if (item == ITEM_FIST) + { + punch_sounds_copy = punch_sounds; + sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, punch_sounds_copy.arr[rnd1 % 3], sound_state); + } + else + { + bullet_flesh_sounds_copy = bullet_flesh_sounds; + sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, bullet_flesh_sounds_copy.arr[rnd1 % 2], sound_state); + } + + if (sound_state->link.next != NULL) { + sndCreatePostEvent((ALSoundState* ) sound_state->link.next, 8, sp6C); + } + } + } + + sound_state = gunGetFreeSfxState(); + if ((sound_state != NULL) && (texture_index >= 0)) + { + if (g_HitTypeSounds[g_Textures[texture_index].hitSound] != NULL) + { + if (g_HitTypeSounds[g_Textures[texture_index].hitSound]->sfx_len > 0) + { + sfx_index = rnd2 % g_HitTypeSounds[g_Textures[texture_index].hitSound]->sfx_len; + sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, g_HitTypeSounds[g_Textures[texture_index].hitSound]->sfx[sfx_index], sound_state); + } + + if (sound_state->link.next != NULL) + { + chrobjSndCreatePostEventDefault((ALSoundState* ) sound_state->link.next, &prop->pos); + } + } + } +#ifdef DEBUG + osSyncPrintf("Shot prop: hittype %d\n", g_Textures[texture_index].hitSound); +#endif +#ifdef ENABLE_LOG + osSyncPrintf("Shot prop: %S\n", HIT_TYPE_ToString[g_Textures[texture_index].hitSound]); +#endif +} + + +void sub_GAME_7F064720(coord3d* pos) +{ + ALSoundState* sound; + ALLink* link; + +#ifdef BUGFIX_R1 + if (g_ClockTimer <= 0) { return; } +#endif + + sound = gunGetFreeSfxState(); + + if (sound != NULL) + { + sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, HIT_BULLET_GLASS_SFX, sound); + + link = sound->link.next; + if (link != NULL) + { + chrobjSndCreatePostEventDefault((ALSoundState* ) link, pos); + } + } +} + + +void recall_joy2_hits_edit_flag(enum ITEM_IDS item, coord3d* arg1, s32 texture_index) +{ + ALSoundState *sound_state; + u32 rnd1; + u32 rnd2; + struct LaserRichochetSounds laser_copied; + struct RicochetSoundsLarge rico_copied; + u32 sfx_index; + struct image_sound *img_sound; + + rnd1 = randomGetNext(); + rnd2 = randomGetNext(); + + D_800483C4 = texture_index; + get_debug_joy2hitsedit_flag(); + +#ifdef BUGFIX_R1 + if (g_ClockTimer <= 0) { return; } +#endif + + sound_state = gunGetFreeSfxState(); + if (sound_state != NULL) + { + if (item != ITEM_WATCHLASER) + { + if (item == ITEM_LASER) + { + laser_copied = laser_ricochet_sounds; + sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, laser_copied.arr[rnd1 % 2], sound_state); + } + else + { + rico_copied = ricochet_sounds_large; + sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, rico_copied.arr[rnd1 % 36], sound_state); + } + } + + if (sound_state->link.next != NULL) + { + chrobjSndCreatePostEventDefault((ALSoundState* ) sound_state->link.next, arg1); + } + } + + sound_state = gunGetFreeSfxState(); + if ((sound_state != NULL) && (texture_index >= 0)) + { + img_sound = g_HitTypeSounds[g_Textures[texture_index].hitSound]; + if (img_sound->sfx_len > 0) + { + if (img_sound != NULL) + { + sfx_index = rnd2 % img_sound->sfx_len; + sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, img_sound->sfx[sfx_index], sound_state); + } + + if (sound_state->link.next != NULL) + { + chrobjSndCreatePostEventDefault((ALSoundState* ) sound_state->link.next, arg1); + } + } + } +} + + +void sub_GAME_7F064934(ITEM_IDS item) +{ + struct EarWhistleSounds copied; + +#ifdef BUGFIX_R1 + if (g_ClockTimer <= 0) { return; } +#endif + if ((item != ITEM_LASER) && (item != ITEM_WATCHLASER)) + { + copied = ear_whistle_sounds; + sndPlaySfx((struct ALBankAlt_s*) g_musicSfxBufferPtr, copied.arr[randomGetNext() % 5], 0); + } +} + + +f32 sub_GAME_7F0649AC(s32 param_1) +{ + f32 fVar1; + + fVar1 = -60.0f; + if (param_1 == 0x19) { + fVar1 -= 20.0f; + } + return fVar1; +} + + + +void sub_GAME_7F0649D8(enum GUNHAND hand) +{ + struct hand* hand_ptr; + enum ITEM_IDS item_id; + s32 ammo_in_magazine; + s32 ammo_in_hands; + WeaponStats* item_stats; + s32 magsize; + s32 ammo_total; + + hand_ptr = &g_CurrentPlayer->hands[hand]; + item_id = getCurrentPlayerWeaponId(hand); + ammo_in_magazine = hand_ptr->weapon_ammo_in_magazine; + ammo_in_hands = get_ammo_in_hands_weapon(hand); + item_stats = get_ptr_item_statistics(item_id); + ammo_total = ammo_in_hands + ammo_in_magazine; + + hand_ptr->weapon_ammo_in_magazine = (ammo_total >= item_stats->MagSize) + ? item_stats->MagSize + : ammo_total; + + g_CurrentPlayer->ammoheldarr[item_stats->AmmoType] = (bondwalkItemCheckBitflags(item_id, WEAPONSTATBITFLAG_AMMO_CLIP_LIMIT) != 0) + ? 0 + : (g_CurrentPlayer->ammoheldarr[item_stats->AmmoType] - hand_ptr->weapon_ammo_in_magazine) + ammo_in_magazine; + + if (item_id == ITEM_ROCKETLAUNCH) + { + currentPlayerCreateRocket(hand); + return; + } + + if ((item_id == ITEM_SHOTGUN) || (item_id == ITEM_AUTOSHOT)) + { + ammo_in_hands = get_ammo_in_hands_weapon(hand); + if (ammo_in_hands >= 5) + { + hand_ptr->numvisibleshells = 5; + return; + } + hand_ptr->numvisibleshells = ammo_in_hands; + } +} + +#if defined(VERSION_US) || defined(VERSION_JP) + #define WEAPON_1P_ANIM_TIME(x) ((f32)(x)) + #define WHEN_1_CASE_GRENADELAUNCH_FLD890 6 + #define WHEN_1_CASE_GRENADE_FLD890 0xf0 + #define WHEN_D_FLD890 0x14 + #define WHEN_5_SP188_INIT 0x10 + #define WHEN_5_SP188_MULTI 0xc + #define WHEN_5_FLD8B0_SP 0x11 + #define WHEN_5_FLD8B0_MULTI 0xd + #define WHEN_8_SP178_INIT 0x17 + #define WHEN_8_SP178_MULTI 0xc + #define WHEN_A_FLD890 0x10 + #define WHEN_A_FLD8B0 0x11 + #define WHEN_C_FLD890 0x17 + #define WHEN_E_FLD890 0x10 + #define WHEN_10_FLD890 0x17 + #define WHEN_11_FLD890_1 0x10 + #define WHEN_11_FLD890_2 0x18 + #define WHEN_1E_FLD890 0x1e +#endif +#if defined(VERSION_EU) + #define WEAPON_1P_ANIM_TIME(x) ((f32)(x)) * 60.0f / 50.0f + #define WHEN_1_CASE_GRENADELAUNCH_FLD890 5 + #define WHEN_1_CASE_GRENADE_FLD890 0xc8 + #define WHEN_D_FLD890 0x10 + #define WHEN_5_SP188_INIT 0xd + #define WHEN_5_SP188_MULTI 0xa + #define WHEN_5_FLD8B0_SP 0xe + #define WHEN_5_FLD8B0_MULTI 0xa + #define WHEN_8_SP178_INIT 0x13 + #define WHEN_8_SP178_MULTI 0xa + #define WHEN_A_FLD890 0xd + #define WHEN_A_FLD8B0 0xe + #define WHEN_C_FLD890 0x13 + #define WHEN_E_FLD890 0xd + #define WHEN_10_FLD890 0x13 + #define WHEN_11_FLD890_1 0xd + #define WHEN_11_FLD890_2 0x14 + #define WHEN_1E_FLD890 0x19 +#endif + + +/** + * Address: 7F064B28 + */ +void gunTickHandState(enum GUNHAND hand, s32 triggerOn) +{ +#if defined(VERSION_US) + s32 stack1; + s32 stack2; + s32 sp1C4; + s32 stack3; + struct hand *sp1BC; + s32 stack4; + s32 sp1B4; + struct sfx2 sp1B0; + s32 stack5; + struct WeaponStats *weapon_stats; + s32 sp1A4; + s32 sp1A0; + f32 sp19C; + f32 sp198; + s32 stack7; + f32 sp190; + f32 sp18C; + s32 sp188; + f32 sp184; + s32 stack8; + s32 stack9; + s32 sp178; + f32 sp174; + s32 stack10; + s32 stack11; + Mtxf sp12C; + f32 sp128; + s32 stack12; + Mtxf spE4; + f32 tempf; + struct hand *handptr; + Mtxf sp9C; + f32 sp98; + f32 sp94; + enum ITEM_IDS temp_v0_3; + f32 sp8C; + f32 sp88; + enum ITEM_IDS var_s1; + struct sfx3 sp7C; + struct PropRecord *temp_v0_8; + Weapon1PTransformKeyframe *sp74; + f32 temp_f0_2; + u32 var_a0_2; + f32 temp_v1_9; + struct hand *temp_v1_5; + f32 un_f32_num = 0.0f; + f32 un_f32_div_1 = 16.0f; + f32 un_f32_div_2 = 23.0f; + s32 stack14; + s32 stack15; +#endif +#if defined(VERSION_JP) + s32 stack1; + s32 stack2; + s32 sp1C4; + s32 stack3; + struct hand *sp1BC; + s32 stack4; + s32 sp1B4; + struct sfx2 sp1B0; + s32 stack5; + struct WeaponStats *weapon_stats; + s32 sp1A4; + s32 sp1A0; + f32 sp19C; + s32 stat_2; + s32 stat_3; + s32 stat_4; + f32 sp198; + s32 stack14; + f32 sp190; + f32 sp18C; + s32 sp188; + f32 sp184; + s32 stack7; + s32 stack8; + s32 sp178; + f32 sp174; + s32 stack9; + s32 stack10; + Mtxf sp12C; + f32 sp128; + s32 stack11; + Mtxf spE4; + s32 stack12; + f32 tempf; + Mtxf sp9C; + f32 sp98; + f32 sp94; + struct hand *handptr; + f32 sp8C; + f32 sp88; + enum ITEM_IDS temp_v0_3; + struct sfx3 sp7C; + enum ITEM_IDS var_s1; + Weapon1PTransformKeyframe *sp74; + struct PropRecord *temp_v0_8; + f32 temp_f0_2; + u32 var_a0_2; + f32 temp_v1_9; + struct hand *temp_v1_5; + f32 un_f32_num = 0.0f; + f32 un_f32_div_1 = 16.0f; + f32 un_f32_div_2 = 23.0f; + s32 stack15; +#endif +#if defined(VERSION_EU) + s32 stack1; + s32 stack2; + s32 sp1C4; + s32 stack3; + struct hand *sp1BC; + s32 stack4; + s32 sp1B4; + struct sfx2 sp1B0; + s32 stack5; + struct WeaponStats *weapon_stats; + s32 sp1A4; + s32 sp1A0; + f32 sp19C; + s32 stat_2; + s32 stat_3; + s32 stat_4; + f32 sp198; + s32 stack14; + f32 sp190; + f32 sp18C; + s32 sp188; + f32 sp184; + s32 stack7; + s32 stack8; + s32 sp178; + f32 sp174; + s32 stack9; + s32 stack10; + Mtxf sp12C; + f32 sp128; + s32 stack11; + Mtxf spE4; + s32 stack12; + f32 tempf; + Mtxf sp9C; + f32 sp98; + f32 sp94; + struct hand *handptr; + f32 sp8C; + f32 sp88; + enum ITEM_IDS temp_v0_3; + struct sfx3 sp7C; + enum ITEM_IDS var_s1; + Weapon1PTransformKeyframe *sp74; + struct PropRecord *temp_v0_8; + f32 temp_f0_2; + u32 var_a0_2; + f32 temp_v1_9; + struct hand *temp_v1_5; + f32 un_f32_num = 0.0f; + f32 un_f32_div_1 = 13.0f; + f32 un_f32_div_2 = 19.0f; + s32 stack15; +#endif + + handptr = &g_CurrentPlayer->hands[hand]; + var_s1 = get_item_in_hand_or_watch_menu(hand); + sp1C4 = get_ammo_type_for_weapon(var_s1); + + handptr->field_884 = handptr->weapon_hold_time; + handptr->weapon_hold_time = triggerOn; + + if (triggerOn == 0) + { + handptr->field_888 = 1; + } + + handptr->weapon_firing_status = 0; + handptr->field_87D = 0; + + if (g_ClockTimer > 0) + { + handptr->field_890 += g_ClockTimer; + handptr->field_88C += 1; + } + + handptr->field_92C = 0; + + if (handptr->weapon_action_state == GUN_ANIM_STATE_IDLE) + { +#if defined(VERSION_JP) || defined(VERSION_EU) + if ((var_s1 == ITEM_LASER) && (handptr->field_888 != 0)) + { + handptr->field_8A0 = 0; + } +#endif + if ( + (handptr->weapon_hold_time != 0) + && (var_s1 != ITEM_UNARMED) + && (((bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_CLICKY) != 0)) || (handptr->weapon_ammo_in_magazine > 0)) +#if defined(VERSION_JP) || defined(VERSION_EU) + && ((var_s1 != ITEM_LASER) || (handptr->field_8A0 < 0xC8)) +#endif + ) + { + handptr->weapon_action_state = GUN_ANIM_STATE_TRIGGER_PRESS; + handptr->field_890 = 0; + handptr->field_88C = 0; + handptr->field_888 = 0; + } + else + { + if (handptr->weapon_current_animation != 0) + { + handptr->weapon_action_state = handptr->weapon_current_animation; + handptr->field_890 = 0; + handptr->field_88C = 0; + } + } + + handptr->weapon_current_animation = 0; + + if ((handptr->weapon_action_state == GUN_ANIM_STATE_IDLE) + && (handptr->weapon_ammo_in_magazine == 0) + && (sp1C4 != 0)) + { + if ((lvlGetControlsLockedFlag() == 0) && (g_CurrentPlayer->mpmenuon == 0)) + { + /** + * D_80032458 is always 0 so this branch can never execute. + */ + if ((D_80032458 != 0) && (sp1C4 == 1) && (g_CurrentPlayer->ammoheldarr[sp1C4] <= 0)) + { + g_CurrentPlayer->ammoheldarr[sp1C4] = 1; + } + + if (get_ammo_in_hands_weapon(hand) > 0) + { + handptr->weapon_action_state = GUN_ANIM_STATE_RELOAD_START; + handptr->field_890 = 0; + handptr->field_88C = 0; + } + else + { + if (g_CurrentPlayer->trigger_released != 0) + { + temp_v0_3 = get_item_in_hand_or_watch_menu(1 - hand); + + sp1BC = (g_CurrentPlayer->hands - hand) + 1; + + if ((sp1BC->weapon_action_state == GUN_ANIM_STATE_IDLE) + && (sp1BC->weapon_current_animation == 0) + && ( + (temp_v0_3 == ITEM_UNARMED) + || ((sp1BC->weapon_ammo_in_magazine == 0) + && ((get_ammo_type_for_weapon(temp_v0_3) != 0)) + && ((get_ammo_in_hands_weapon(1 - hand) <= 0))))) + { + autoadvance_on_deplete_all_ammo(); + + handptr->field_88C = 0; + handptr->field_890 = 0; + handptr->weapon_action_state = handptr->weapon_current_animation; + handptr->weapon_current_animation = 0; + + sp1BC->field_88C = 0; + sp1BC->field_890 = 0; + sp1BC->weapon_action_state = sp1BC->weapon_current_animation; + sp1BC->weapon_current_animation = 0; + } + } + } + } + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_TRIGGER_PRESS) + { + switch (var_s1) + { + case ITEM_RUGER: + case ITEM_GRENADELAUNCH: + if (handptr->field_890 >= WHEN_1_CASE_GRENADELAUNCH_FLD890) + { + handptr->weapon_action_state = GUN_ANIM_STATE_FIRE; + handptr->field_890 = 0; + handptr->field_88C = 0; + } + break; + case ITEM_CAMERA: + if (handptr->field_88C == 0) + { + currentPlayerSetFadeColour(0, 0, 0, 1.0f); + } + else if (handptr->field_890 > 0) + { + currentPlayerAdjustFade(8.0f, 0, 0, 0, 0.0f); + handptr->weapon_action_state = GUN_ANIM_STATE_FIRE; + handptr->field_890 = 0; + handptr->field_88C = 0; + } + break; + case ITEM_WPPK: + case ITEM_WPPKSIL: + case ITEM_TT33: + case ITEM_SKORPION: + case ITEM_AK47: + case ITEM_UZI: + case ITEM_MP5K: + case ITEM_MP5KSIL: + case ITEM_SPECTRE: + case ITEM_M16: + case ITEM_FNP90: + case ITEM_SHOTGUN: + case ITEM_AUTOSHOT: + case ITEM_SNIPERRIFLE: + case ITEM_GOLDENGUN: + case ITEM_SILVERWPPK: + case ITEM_GOLDWPPK: + case ITEM_LASER: + case ITEM_WATCHLASER: + case ITEM_ROCKETLAUNCH: + case ITEM_TRIGGER: + case ITEM_TANKSHELLS: + case ITEM_FLAREPISTOL: + case ITEM_PITONGUN: + case ITEM_WATCHMAGNETATTRACT: + handptr->weapon_action_state = GUN_ANIM_STATE_FIRE; + handptr->field_890 = 0; + handptr->field_88C = 0; + break; + case ITEM_TIMEDMINE: + case ITEM_PROXIMITYMINE: + case ITEM_REMOTEMINE: + case ITEM_BOMBCASE: + case ITEM_PLASTIQUE: + case ITEM_BUG: + case ITEM_MICROCAMERA: + case ITEM_GOLDENEYEKEY: + handptr->weapon_action_state = GUN_ANIM_STATE_MINE_PLACE; + handptr->field_890 = 0; + handptr->field_88C = 0; + break; + case ITEM_KNIFE: + if (!(randomGetNext() & 1)) + { + handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH1_BEGIN; + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH2_BEGIN; + } + handptr->field_890 = 0; + handptr->field_88C = 0; + break; + case ITEM_GRENADE: + if ((handptr->field_888 != 0) || (handptr->field_890 >= WHEN_1_CASE_GRENADE_FLD890)) + { + g_CurrentPlayer->last_z_trigger_timer = handptr->field_890; + handptr->weapon_action_state = GUN_ANIM_STATE_GRENADE_THROW; + handptr->field_88C = 0; + handptr->field_890 = 0; + } + break; + case ITEM_FIST: + if (!(randomGetNext() & 1)) + { + handptr->weapon_action_state = GUN_ANIM_STATE_PUNCH1_STRIKE; + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_PUNCH2_STRIKE; + } + handptr->field_890 = 0; + handptr->field_88C = 0; + break; + case ITEM_THROWKNIFE: + handptr->weapon_action_state = GUN_ANIM_STATE_THROWKNIFE_DRAW; + handptr->field_890 = 0; + handptr->field_88C = 0; + break; + case ITEM_TASER: + tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); + if (gunSample1PTransform(taserFireKeyFrames, tempf, &handptr->field_8EC, hand) != 0) + { + handptr->field_92C = 1; + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_FIRE; + handptr->field_890 = 0; + handptr->field_88C = 0; + } + break; + case ITEM_BUNGEE: + case ITEM_DOORDECODER: + case ITEM_BOMBDEFUSER: + case ITEM_LOCKEXPLODER: + case ITEM_DOOREXPLODER: + case ITEM_WEAPONCASE: + case ITEM_SAFECRACKERCASE: + case ITEM_KEYANALYSERCASE: + case ITEM_BUGDETECTOR: + case ITEM_EXPLOSIVEFLOPPY: + case ITEM_POLARIZEDGLASSES: + case ITEM_DARKGLASSES: + case ITEM_CREDITCARD: + case ITEM_GASKEYRING: + case ITEM_DATATHIEF: + case ITEM_WATCHIDENTIFIER: + case ITEM_WATCHCOMMUNICATOR: + case ITEM_WATCHGEIGERCOUNTER: + case ITEM_WATCHMAGNETREPEL: + case ITEM_DATTAPE: + case ITEM_KEYCARD: + case ITEM_KEYYALE: + case ITEM_KEYBOLT: + handptr->weapon_action_state = GUN_ANIM_STATE_USE_ITEM; + handptr->field_890 = 0; + handptr->field_88C = 0; + break; + case ITEM_SUIT_LF_HAND: + case ITEM_JOYPAD: + case ITEM_ROCKETROUND: + case ITEM_GRENADEROUND: + case ITEM_TOKEN: + default: + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0; + handptr->field_88C = 0; + break; + } + + handptr->volley = 0; + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_FIRE) + { + if ((get_ammo_type_for_weapon(var_s1) == 0) || (handptr->weapon_ammo_in_magazine > 0)) + { + switch (var_s1) + { + case ITEM_CAMERA: + case ITEM_WATCHMAGNETATTRACT: + if (handptr->field_88C == 0) + { + handptr->weapon_firing_status = (lvlGetControlsLockedFlag() == 0) && (g_CurrentPlayer->mpmenuon == 0); + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL1; + handptr->field_890 = 0; + handptr->field_88C = 0; + } + break; + case ITEM_WPPK: + case ITEM_WPPKSIL: + case ITEM_TT33: + case ITEM_SHOTGUN: + case ITEM_AUTOSHOT: + case ITEM_SNIPERRIFLE: + case ITEM_RUGER: + case ITEM_GOLDENGUN: + case ITEM_SILVERWPPK: + case ITEM_GOLDWPPK: + case ITEM_LASER: + case ITEM_WATCHLASER: + case ITEM_GRENADELAUNCH: + case ITEM_ROCKETLAUNCH: + case ITEM_TRIGGER: + case ITEM_TANKSHELLS: + case ITEM_FLAREPISTOL: + case ITEM_PITONGUN: + if (handptr->field_88C == 0) + { + if ((getPlayerCount() == 1) || ((checkGamePaused() == 0) && (g_CurrentPlayer->mpmenuon == 0))) + { + handptr->field_87D = 1; + } + + handptr->weapon_firing_status = (lvlGetControlsLockedFlag() == 0) && (g_CurrentPlayer->mpmenuon == 0); + + sub_GAME_7F05E808(hand); + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL1; + handptr->field_890 = 0; + handptr->field_88C = 0; + } + break; + case ITEM_SKORPION: + case ITEM_AK47: + case ITEM_UZI: + case ITEM_MP5K: + case ITEM_MP5KSIL: + case ITEM_SPECTRE: + case ITEM_M16: + case ITEM_FNP90: + if ((handptr->field_88C == 0) + || (handptr->weapon_hold_time != 0) + || ((bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_BURST_FIRE) != 0) + && (currentPlayerGetIsAiming() == 0) + && (((s32) handptr->volley % 3) != 0))) + { + if (((s32) handptr->field_88C % bondwalkItemGetAutomaticFiringRate(var_s1)) == 0) + { + if ((getPlayerCount() == 1) || ((checkGamePaused() == 0) && (g_CurrentPlayer->mpmenuon == 0))) + { + handptr->field_87D = 1; + } + + handptr->weapon_firing_status = (lvlGetControlsLockedFlag() == 0) + && (g_CurrentPlayer->mpmenuon == 0); + } + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL1; + handptr->field_890 = 0; + handptr->field_88C = 0; + } + break; + case ITEM_KNIFE: + if ((handptr->field_88C == 0) || (handptr->weapon_hold_time != 0)) + { + handptr->weapon_firing_status = 0; + handptr->field_87D = handptr->weapon_firing_status; + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL1; + handptr->field_890 = 0; + handptr->field_88C = 0; + } + break; + case ITEM_TASER: + if ((handptr->field_88C == 0) || (handptr->weapon_hold_time != 0)) + { + gunSample1PTransform(taserRaiseKeyframes, 0.0f, &handptr->field_8EC, hand); + + handptr->weapon_firing_status = 0; + handptr->field_92C = 1; + handptr->field_87D = handptr->weapon_firing_status; + + if (handptr->field_88C == 0) + { + handptr->weapon_firing_status = (lvlGetControlsLockedFlag() == 0) + && (g_CurrentPlayer->mpmenuon == 0); + } + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL1; + handptr->field_890 = 0; + handptr->field_88C = 0; + } + break; + } + + if (handptr->weapon_firing_status != 0) + { + if (var_s1 != ITEM_CAMERA) + { + joyRumblePakStart(get_cur_playernum(), 0.1f); + + if (cur_player_get_control_type() >= 4) + { + joyRumblePakStart(get_cur_playernum() + getPlayerCount(), 0.1f); + } + } + + handptr->weapon_ammo_in_magazine -= 1; + handptr->volley += 1; + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_FIRE) + { + sp1B4 = 0; + + if (bondwalkItemGetSoundTriggerRate(var_s1) > 0) + { + if ((g_CurrentPlayer->hands[1 - hand].field_A50 != g_GlobalTimer) + && (handptr->field_A4C < g_GlobalTimer)) + { + handptr->field_A4C = bondwalkItemGetSoundTriggerRate(var_s1) + g_GlobalTimer; + sp1B4 = 1; + } + } + else if (handptr->weapon_firing_status != 0) + { + sp1B4 = 1; + } + + if ((getPlayerCount() == 1) || ((checkGamePaused() == 0) && (g_CurrentPlayer->mpmenuon == 0))) + { + if (sp1B4 != 0) + { + if ((handptr->audioHandle != NULL) && (sndGetPlayingState(handptr->audioHandle) != 0)) + { + sndDeactivate(handptr->audioHandle); + } + + if (((struct ALSoundState *)handptr->field_A48 != 0) + && (sndGetPlayingState((struct ALSoundState *) handptr->field_A48) != 0)) + { + sndDeactivate((struct ALSoundState *) handptr->field_A48); + } + + if (bondwalkItemGetSound(var_s1) != 0) + { + if (handptr->audioHandle == NULL) + { + sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, bondwalkItemGetSound(var_s1), (struct ALSoundState *) &handptr->audioHandle); + } + else if ((struct ALSoundState *)handptr->field_A48 == 0) + { + sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, bondwalkItemGetSound(var_s1), (struct ALSoundState *) &handptr->field_A48); + } + + handptr->field_A50 = g_GlobalTimer; + } + } + + if (var_s1 == ITEM_WATCHLASER) + { + sp1B0 = watchlaser_fire_sounds; + sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, sp1B0.half[randomGetNext() & 1], NULL); + } + } + } + } + else if (handptr->field_88C > 0) + { + handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL1; + handptr->field_890 = 0; + handptr->field_88C = 0; + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_DRY_FIRE; + handptr->field_890 = 0; + handptr->field_88C = 0; + + if ((getPlayerCount() == 1) +#if defined(VERSION_JP) || defined(VERSION_EU) + || ((checkGamePaused() == 0) && (g_CurrentPlayer->mpmenuon == 0)) +#else + || (checkGamePaused() == 0) +#endif + ) + { + sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, EMPTY_GUN_FIRE_SFX, NULL); + } + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_RECOIL1) + { + if (var_s1 == ITEM_TASER) + { + tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); + if (gunSample1PTransform(taserRaiseKeyframes, tempf, &handptr->field_8EC, hand) != 0) + { + handptr->field_92C = 1; + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + else + { + weapon_stats = get_ptr_item_statistics(var_s1); + +#if defined(VERSION_US) + sp1A4 = weapon_stats->b44[0]; + sp1A0 = weapon_stats->b44[1]; +#endif +#if defined(VERSION_JP) + sp1A4 = weapon_stats->b44[0]; + sp1A0 = weapon_stats->b44[1]; + stat_2 = weapon_stats->b44[2]; + stat_3 = weapon_stats->b44[3]; + stat_4 = weapon_stats->SingleFiringRate; +#endif +#if defined(VERSION_EU) + sp1A4 = ((s32)weapon_stats->b44[0] * 50) / 60; + sp1A0 = ((s32)weapon_stats->b44[1] * 50) / 60; + stat_2 = ((s32)weapon_stats->b44[2] * 50) / 60; + stat_3 = ((s32)weapon_stats->b44[3] * 50) / 60; + stat_4 = weapon_stats->SingleFiringRate * 50 / 60; +#endif + + if (( + (handptr->field_888 != 0) + && (handptr->field_890 >= (sp1A4 + sp1A0)) + ) + || + ( + ((weapon_stats->SingleFiringRate >= 0)) + && (handptr->field_888 == 0) +#if defined(VERSION_US) + && (handptr->field_890 >= (sp1A4 + sp1A0 + weapon_stats->SingleFiringRate)) +#endif +#if defined(VERSION_JP) || defined(VERSION_EU) + && (handptr->field_890 >= (sp1A4 + sp1A0 + stat_4)) +#endif + ) + ) + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + else if ( + (handptr->field_888 != 0) + && (handptr->weapon_hold_time != 0) + +#if defined(VERSION_US) + && (handptr->field_890 >= weapon_stats->b44[2]) +#endif +#if defined(VERSION_JP) || defined(VERSION_EU) + && (handptr->field_890 >= stat_2) +#endif + + && (weapon_stats->b44[3] >= 0) + +#if defined(VERSION_US) + // HACK: registers are swapped + // addu a1, v1, a0 + && (handptr->field_890 + weapon_stats->b44[3] < (0,sp1A4) + sp1A0) + && (handptr->field_890 + weapon_stats->b44[3] >= (s32)weapon_stats->b44[2]) +#endif +#if defined(VERSION_JP) || defined(VERSION_EU) + && (handptr->field_890 + stat_3 < sp1A4 + sp1A0) + && (handptr->field_890 + stat_3 >= (s32)stat_2) +#endif + ) + { + handptr->weapon_action_state = GUN_ANIM_STATE_RECOIL2; + handptr->field_890 = 0; + handptr->field_88C = 0; +#if defined(VERSION_US) + handptr->field_8A8 = weapon_stats->b44[3]; +#endif +#if defined(VERSION_JP) || defined(VERSION_EU) + handptr->field_8A8 = stat_3; +#endif + } + else if (handptr->field_890 < sp1A4 + sp1A0) + { + sp198 = weapon_stats->RecoilBack; + sp19C = weapon_stats->RecoilUp; + + if (handptr->field_890 == 0) + { + handptr->field_8C8 = handptr->field_8E8; + handptr->field_8BC = handptr->field_8DC; + handptr->field_8C0 = handptr->field_8E0; + handptr->field_8C4 = handptr->field_8E4; + } + + if (handptr->field_890 < sp1A4) + { + handptr->field_8D8 = M_TAU_F - ((sp19C * M_TAU_F) / 360.0f); + + handptr->field_8CC = ((gunSetHorizontalOffset(hand) - handptr->field_A38) * sp198) / 1000.0f; + handptr->field_8D0 = 0; + handptr->field_8D4 = ((weapon_stats->PosZ - handptr->field_A40) * sp198) / 1000.0f; + + sp190 = sinf(((f32) handptr->field_890 * M_PI_2F) / (f32) sp1A4); + } + else + { + handptr->field_8D8 = M_TAU_F - ((sp19C * M_TAU_F) / 360.0f); + + handptr->field_8CC = ((gunSetHorizontalOffset(hand) - handptr->field_A38) * sp198) / 1000.0f; + handptr->field_8D0 = 0; + handptr->field_8D4 = ((weapon_stats->PosZ - handptr->field_A40) * sp198) / 1000.0f; + + sp190 = (cosf(((f32) (handptr->field_890 - sp1A4) * M_PI_F) / (f32) sp1A0) * 0.5f) + 0.5f; + } + + temp_f0_2 = sub_GAME_7F06D0CC(handptr->field_8C8, handptr->field_8D8, sp190); + + handptr->field_8E8 = temp_f0_2; + handptr->field_92C = 1; + handptr->field_8DC = ((handptr->field_8CC - handptr->field_8BC) * sp190) + handptr->field_8BC; + handptr->field_8E0 = ((handptr->field_8D0 - handptr->field_8C0) * sp190) + handptr->field_8C0; + handptr->field_8E4 = ((handptr->field_8D4 - handptr->field_8C4) * sp190) + handptr->field_8C4; + + matrix_4x4_set_rotation_around_x(temp_f0_2, &handptr->field_8EC); + matrix_4x4_set_position((struct coord3d *)&handptr->field_8DC, &handptr->field_8EC); + } + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_RECOIL2) + { + if (handptr->field_890 == 0) + { + handptr->field_8C8 = handptr->field_8E8; + handptr->field_8BC = handptr->field_8DC; + handptr->field_8C0 = handptr->field_8E0; + handptr->field_8C4 = handptr->field_8E4; + handptr->field_8D8 = 0.0f; + handptr->field_8CC = 0.0f; + handptr->field_8D0 = 0.0f; + handptr->field_8D4 = 0.0f; + } + + if (handptr->field_890 < handptr->field_8A8) + { + sp18C = (cosf(((f32) (handptr->field_8A8 - handptr->field_890) * M_PI_2F) / (f32) handptr->field_8A8) * 0.5f) + 0.5f; + + temp_f0_2 = sub_GAME_7F06D0CC(handptr->field_8C8, handptr->field_8D8, sp18C); + + handptr->field_8E8 = temp_f0_2; + handptr->field_92C = 1; + handptr->field_8DC = ((handptr->field_8CC - handptr->field_8BC) * sp18C) + handptr->field_8BC; + handptr->field_8E0 = ((handptr->field_8D0 - handptr->field_8C0) * sp18C) + handptr->field_8C0; + handptr->field_8E4 = ((handptr->field_8D4 - handptr->field_8C4) * sp18C) + handptr->field_8C4; + + matrix_4x4_set_rotation_around_x(temp_f0_2, &handptr->field_8EC); + matrix_4x4_set_position((struct coord3d *)&handptr->field_8DC, &handptr->field_8EC); + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_DRY_FIRE) + { + if (handptr->field_88C == 0) + { + sub_GAME_7F05E808(hand); + } + + if ((handptr->field_888 != 0) || ((handptr->field_888 == 0) && (handptr->field_890 >= WHEN_D_FLD890))) + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + + sp188 = WHEN_5_SP188_INIT; + if (handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_LOWER) + { + if (getPlayerCount() >= 2) + { + sp188 = WHEN_5_SP188_MULTI; + } + + if (handptr->field_88C == 0) + { + if (getPlayerCount() == 1) + { + handptr->field_8B0 = WHEN_5_FLD8B0_SP; + } + else + { + handptr->field_8B0 = WHEN_5_FLD8B0_MULTI; + } + } + + if (handptr->field_890 >= sp188) + { + g_CurrentPlayer->ammoheldarr[get_ammo_type_for_weapon(var_s1)] += handptr->weapon_ammo_in_magazine; + handptr->weapon_ammo_in_magazine = 0; + + if (getPlayerCount() >= 2) + { + sub_GAME_7F09B368(hand); + } + + sub_GAME_7F05FB00(hand); + + handptr->weapon_action_state = GUN_ANIM_STATE_SWITCH_SWAP; + + if (bondinvItemAvailable(ITEM_SNIPERRIFLE) != 0) + { + g_CurrentPlayer->cur_item_weapon_getname = ITEM_SNIPERRIFLE; + } + else + { + g_CurrentPlayer->cur_item_weapon_getname = ITEM_FIST; + } + } + else + { + sp184 = ((f32) handptr->field_890 * M_LN2F) / (f32) sp188; + handptr->field_92C = 1; + + matrix_4x4_set_rotation_around_x(sp184, &handptr->field_8EC); + + handptr->field_8EC.m[3][0] = 0.0f; + handptr->field_8EC.m[3][1] = (1.0f - cosf(sp184)) * -60.0f; + handptr->field_8EC.m[3][2] = sinf(sp184) * 15.0f; + } + } + + if ((handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_SWAP) || (handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_HOLD)) + { + if ((handptr->weapon_animation_trigger == 0) || (handptr->field_890 >= handptr->field_8B0)) + { + if (handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_SWAP) + { + temp_v1_5 = (g_CurrentPlayer->hands - hand) + 1; + + if ((temp_v1_5->weapon_action_state != GUN_ANIM_STATE_SWITCH_SWAP) && (temp_v1_5->weapon_action_state != GUN_ANIM_STATE_SWITCH_LOWER)) + { + if ( + (temp_v1_5->weapon_current_animation != 5) + && (temp_v1_5->weapon_action_state != GUN_ANIM_STATE_WATCH_LOWER) + && (temp_v1_5->weapon_action_state != GUN_ANIM_STATE_WATCH_SWAP) + && (temp_v1_5->weapon_action_state != GUN_ANIM_STATE_WATCH_RAISE) + && (temp_v1_5->weapon_current_animation != 0xE)) + { + if (hand == GUNRIGHT) + { + if (bondinvItemAvailableForHand(handptr->weapon_next_weapon, getCurrentPlayerWeaponId(GUNLEFT)) == 0) + { + currentPlayerEquipWeaponWrapper(GUNLEFT, 0); + } + } + else if (bondinvItemAvailableForHand(getCurrentPlayerWeaponId(GUNRIGHT), handptr->weapon_next_weapon) == 0) + { + handptr->weapon_next_weapon = ITEM_UNARMED; + } + } + } + currentPlayerUnEquipWeaponWrapper(hand, handptr->weapon_next_weapon); + var_s1 = get_item_in_hand_or_watch_menu(hand); + handptr->weapon_action_state = GUN_ANIM_STATE_SWITCH_HOLD; + } + else if (Gun_hand_without_item(hand) != 0) + { + handptr->weapon_action_state = GUN_ANIM_STATE_SWITCH_RAISE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + + if ((handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_SWAP) || (handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_HOLD)) + { + handptr->field_92C = 1; + matrix_4x4_set_rotation_around_x(M_LN2F, &handptr->field_8EC); + handptr->field_8EC.m[3][0] = 0.0f; + handptr->field_8EC.m[3][1] = (1.0f - cosf(M_LN2F)) * -60.0f; + handptr->field_8EC.m[3][2] = sinf(M_LN2F) * 15.0f; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_SWITCH_RAISE) + { + sp178 = WHEN_8_SP178_INIT; + + if (getPlayerCount() >= 2) + { + sp178 = WHEN_8_SP178_MULTI; + } + + if (handptr->field_88C == 0) + { + if (getPlayerCount() >= 2) + { + sub_GAME_7F09B398(hand); + } + + sub_GAME_7F0649D8(hand); + + g_CurrentPlayer->trigger_released = 0; + + if ((g_ClockTimer > 0) + && (g_CurrentPlayer->cameramode != CAMERAMODE_INTRO) + && (Gun_hand_without_item(hand) != 0) + && (g_PlayerInvincible == FALSE) +#if defined(VERSION_JP) || defined(VERSION_EU) + && (g_CurrentPlayer->bonddead == 0) +#endif + ) + { + switch (var_s1) + { + case ITEM_LASER: + sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, PICKUP_LASER_SFX, NULL); + break; + + case ITEM_KNIFE: + case ITEM_THROWKNIFE: + sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, PICKUP_KNIFE_SFX, NULL); + break; + + case ITEM_TIMEDMINE: + case ITEM_PROXIMITYMINE: + case ITEM_REMOTEMINE: + sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, PICKUP_MINE_SFX, NULL); + break; + + case ITEM_UNARMED: + case ITEM_FIST: + case ITEM_WATCHLASER: + case ITEM_GRENADE: + case ITEM_TRIGGER: + case ITEM_TASER: + case ITEM_TANKSHELLS: + case ITEM_BOMBCASE: + case ITEM_PLASTIQUE: + case ITEM_CAMERA: + case ITEM_BUG: + case ITEM_MICROCAMERA: + case ITEM_WATCHMAGNETATTRACT: + case ITEM_GOLDENEYEKEY: + case ITEM_TOKEN: + break; + + default: + sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, PICKUP_GUN_SFX, NULL); + break; + } + } + } + + if ((handptr->field_890 >= sp178) + || (get_ptr_weapon_model_header_line(var_s1) == NULL) + || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_SHOW_FIRST_PERSON) == 0) + || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_HIDE_FIRST_PERSON_HAND) != 0)) + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + else + { + sp174 = ((f32) (sp178 - handptr->field_890) * M_LN2F) / (f32) sp178; + handptr->field_92C = 1; + matrix_4x4_set_rotation_around_x(sp174, &handptr->field_8EC); + handptr->field_8EC.m[3][0] = 0.0f; + handptr->field_8EC.m[3][1] = (1.0f - cosf(sp174)) * -60.0f; + handptr->field_8EC.m[3][2] = sinf(sp174) * 15.0f; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_RELOAD_START) + { + if (((handptr->weapon_ammo_in_magazine < get_ptr_item_statistics(var_s1)->MagSize) + || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_AMMO_CLIP_LIMIT) != 0)) + && ((get_ammo_in_hands_weapon(hand) > 0))) + { + handptr->weapon_action_state = GUN_ANIM_STATE_RELOAD_LOWER; + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_RELOAD_LOWER) + { + if ((handptr->field_890 >= WHEN_A_FLD890) || (handptr->field_87F == 0)) + { + handptr->weapon_action_state = GUN_ANIM_STATE_RELOAD_SWAP; + handptr->field_8B0 = WHEN_A_FLD8B0; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + else + { + sp128 = ((f32) handptr->field_890 * M_LN2F) / un_f32_div_1; + handptr->field_92C = 1; + + if (hand == GUNRIGHT) + { + matrix_4x4_set_rotation_around_z((un_f32_num / un_f32_div_1), &handptr->field_8EC); + } + else + { + matrix_4x4_set_rotation_around_z(-(un_f32_num / un_f32_div_1), &handptr->field_8EC); + } + + matrix_4x4_set_rotation_around_x(sp128, &sp12C); + matrix_4x4_multiply_in_place(&sp12C, &handptr->field_8EC); + sinf((un_f32_num / un_f32_div_1)); + handptr->field_8EC.m[3][0] = 0.0f; + handptr->field_8EC.m[3][1] = sub_GAME_7F0649AC(var_s1) * (1.0f - cosf(sp128)); + handptr->field_8EC.m[3][2] = sinf(sp128) * 15.0f; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_RELOAD_SWAP) + { + if ((handptr->field_88C == 0) +#if defined(VERSION_JP) || defined(VERSION_EU) + && (g_ClockTimer > 0) +#endif + && (g_CurrentPlayer->cameramode != CAMERAMODE_INTRO) + && (Gun_hand_without_item(hand) != 0) + && (g_PlayerInvincible == FALSE) +#if defined(VERSION_JP) || defined(VERSION_EU) + && (g_CurrentPlayer->bonddead == 0) +#endif + ) + { + switch (var_s1) + { + case ITEM_UNARMED: + case ITEM_FIST: + case ITEM_KNIFE: + case ITEM_THROWKNIFE: + case ITEM_LASER: + case ITEM_WATCHLASER: + case ITEM_GRENADE: + case ITEM_TIMEDMINE: + case ITEM_PROXIMITYMINE: + case ITEM_REMOTEMINE: + case ITEM_TRIGGER: + case ITEM_TASER: + case ITEM_TANKSHELLS: + case ITEM_BOMBCASE: + case ITEM_PLASTIQUE: + case ITEM_CAMERA: + case ITEM_BUG: + case ITEM_MICROCAMERA: + case ITEM_WATCHMAGNETATTRACT: + case ITEM_GOLDENEYEKEY: + case ITEM_TOKEN: + break; + default: + case ITEM_WPPK: + case ITEM_WPPKSIL: + case ITEM_TT33: + case ITEM_SKORPION: + case ITEM_AK47: + case ITEM_UZI: + case ITEM_MP5K: + case ITEM_MP5KSIL: + case ITEM_SPECTRE: + case ITEM_M16: + case ITEM_FNP90: + case ITEM_SHOTGUN: + case ITEM_AUTOSHOT: + case ITEM_SNIPERRIFLE: + case ITEM_RUGER: + case ITEM_GOLDENGUN: + case ITEM_SILVERWPPK: + case ITEM_GOLDWPPK: + case ITEM_GRENADELAUNCH: + case ITEM_ROCKETLAUNCH: + case ITEM_FLAREPISTOL: + case ITEM_PITONGUN: + case ITEM_BUNGEE: + case ITEM_DOORDECODER: + case ITEM_BOMBDEFUSER: + case ITEM_LOCKEXPLODER: + case ITEM_DOOREXPLODER: + case ITEM_BRIEFCASE: + case ITEM_WEAPONCASE: + case ITEM_SAFECRACKERCASE: + case ITEM_KEYANALYSERCASE: + case ITEM_BUGDETECTOR: + case ITEM_EXPLOSIVEFLOPPY: + case ITEM_POLARIZEDGLASSES: + case ITEM_DARKGLASSES: + case ITEM_CREDITCARD: + case ITEM_GASKEYRING: + case ITEM_DATATHIEF: + case ITEM_WATCHIDENTIFIER: + case ITEM_WATCHCOMMUNICATOR: + case ITEM_WATCHGEIGERCOUNTER: + case ITEM_WATCHMAGNETREPEL: + sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, GUN_RIFLECOCK_SFX, NULL); + break; + } + } + + if ((handptr->field_890 >= handptr->field_8B0) && !(((handptr->field_88C < 2)))) + { + handptr->weapon_action_state = GUN_ANIM_STATE_RELOAD_RAISE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + else + { + handptr->field_92C = 1; + + if (hand == GUNRIGHT) + { + matrix_4x4_set_rotation_around_z(un_f32_num, &handptr->field_8EC); + } + else + { + matrix_4x4_set_rotation_around_z(-un_f32_num, &handptr->field_8EC); + } + + matrix_4x4_set_rotation_around_x(M_LN2F, &spE4); + matrix_4x4_multiply_in_place(&spE4, &handptr->field_8EC); + sinf(un_f32_num); + handptr->field_8EC.m[3][0] = 0.0f; + handptr->field_8EC.m[3][1] = sub_GAME_7F0649AC(var_s1) * (1.0f - cosf(M_LN2F)); + handptr->field_8EC.m[3][2] = sinf(M_LN2F) * 15.0f; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_RELOAD_RAISE) + { + if (handptr->field_88C == 0) + { + sub_GAME_7F0649D8(hand); + g_CurrentPlayer->trigger_released = 0; + } + + if ((handptr->field_890 >= WHEN_C_FLD890) + || (get_ptr_weapon_model_header_line(var_s1) == NULL) + || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_SHOW_FIRST_PERSON) == 0) + || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_HIDE_FIRST_PERSON_HAND) != 0)) + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + else + { + sp98 = ((f32) (WHEN_C_FLD890 - handptr->field_890) * M_LN2F) / un_f32_div_2; + handptr->field_92C = 1; + + if (hand == GUNRIGHT) + { + matrix_4x4_set_rotation_around_z((un_f32_num / un_f32_div_2), &handptr->field_8EC); + } + else + { + matrix_4x4_set_rotation_around_z(-(un_f32_num / un_f32_div_2), &handptr->field_8EC); + } + + matrix_4x4_set_rotation_around_x(sp98, &sp9C); + matrix_4x4_multiply_in_place(&sp9C, &handptr->field_8EC); + sinf(un_f32_num / un_f32_div_2); + handptr->field_8EC.m[3][0] = 0.0f; + handptr->field_8EC.m[3][1] = sub_GAME_7F0649AC(var_s1) * (1.0f - cosf(sp98)); + handptr->field_8EC.m[3][2] = sinf(sp98) * 15.0f; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_WATCH_LOWER) + { + if ((handptr->field_890 >= WHEN_E_FLD890) || (handptr->field_87F == 0)) + { + handptr->weapon_action_state = GUN_ANIM_STATE_WATCH_SWAP; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + else + { + sp94 = ((f32) handptr->field_890 * M_LN2F) / un_f32_div_1; + handptr->field_92C = 1; + + matrix_4x4_set_rotation_around_x(sp94, &handptr->field_8EC); + handptr->field_8EC.m[3][0] = 0.0f; + handptr->field_8EC.m[3][1] = (1.0f - cosf(sp94)) * -60.0f; + handptr->field_8EC.m[3][2] = sinf(sp94) * 15.0f; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_WATCH_SWAP) + { + if ((handptr->field_88C == 0) || (Gun_hand_without_item(hand) == 0)) + { + sub_GAME_7F05DA8C(hand, handptr->weapon_next_weapon); + var_s1 = get_item_in_hand_or_watch_menu(hand); + } + + if (Gun_hand_without_item(hand) != 0) + { + handptr->weapon_action_state = GUN_ANIM_STATE_WATCH_RAISE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + else + { + handptr->field_92C = 1; + matrix_4x4_set_rotation_around_x(M_LN2F, &handptr->field_8EC); + handptr->field_8EC.m[3][0] = 0.0f; + handptr->field_8EC.m[3][1] = (1.0f - cosf(M_LN2F)) * -60.0f; + handptr->field_8EC.m[3][2] = sinf(M_LN2F) * 15.0f; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_WATCH_RAISE) + { + if ((handptr->field_88C == 0) && (var_s1 < 0x21)) + { + if (getPlayerCount() >= 2) + { + sub_GAME_7F09B398(hand); + } + sub_GAME_7F0649D8(hand); + g_CurrentPlayer->trigger_released = 0; + } + + if ((handptr->field_890 >= WHEN_10_FLD890) + || (get_ptr_weapon_model_header_line(var_s1) == NULL) + || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_SHOW_FIRST_PERSON) == 0) + || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_HIDE_FIRST_PERSON_HAND) != 0)) + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + else + { + sp8C = ((f32) (WHEN_10_FLD890 - handptr->field_890) * M_LN2F) / un_f32_div_2; + handptr->field_92C = 1; + matrix_4x4_set_rotation_around_x(sp8C, &handptr->field_8EC); + handptr->field_8EC.m[3][0] = 0.0f; + handptr->field_8EC.m[3][1] = (1.0f - cosf(sp8C)) * -60.0f; + handptr->field_8EC.m[3][2] = sinf(sp8C) * 15.0f; + } + } + + if ((handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_BEGIN) + || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_STRIKE) + || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_RECOVER) + || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH2_BEGIN) + || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH2_STRIKE) + || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH2_RECOVER)) + { + sp88 = WEAPON_1P_ANIM_TIME(handptr->field_890); + + if (((handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_BEGIN) + || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH2_BEGIN)) + && (handptr->field_890 >= WHEN_11_FLD890_1)) + { + sp7C = knife_throw_sounds; + sndPlaySfx((struct ALBankAlt_s *) g_musicSfxBufferPtr, sp7C.half[randomGetNext() % 3U], NULL); + + + if (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_BEGIN) + { + handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH1_STRIKE; + handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH1_STRIKE; + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH2_STRIKE; + handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH2_STRIKE; + } + } + + if ((handptr->weapon_action_state != GUN_ANIM_STATE_KNIFE_SLASH1_RECOVER) + && (handptr->weapon_action_state != GUN_ANIM_STATE_KNIFE_SLASH2_RECOVER) + && (handptr->field_890 >= WHEN_11_FLD890_2)) + { + handptr->weapon_firing_status = 1; + if ((handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_BEGIN) || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_STRIKE)) + { + handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH1_RECOVER; + handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH1_RECOVER; + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH2_RECOVER; + handptr->weapon_action_state = GUN_ANIM_STATE_KNIFE_SLASH2_RECOVER; + } + } + + if ((handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_BEGIN) + || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_STRIKE) + || (handptr->weapon_action_state == GUN_ANIM_STATE_KNIFE_SLASH1_RECOVER)) + { + var_a0_2 = D_80034CA4; + } + else + { + var_a0_2 = D_80034E0C; + } + + if (gunSample1PTransform(var_a0_2, sp88, &handptr->field_8EC, hand) != 0) + { + handptr->field_92C = 1; + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + + if ((handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH1_STRIKE) + || (handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH1_RECOVER) + || (handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH2_STRIKE) + || (handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH2_RECOVER)) + { + temp_v1_9 = WEAPON_1P_ANIM_TIME(handptr->field_890); + + if ((handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH1_STRIKE) || (handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH1_RECOVER)) + { + if (g_CurrentPlayer->cur_item_weapon_getname == ITEM_SNIPERRIFLE) + { + sp74 = sniperMeleeKeyframes1; + } + else + { + sp74 = fistMeleeKeyframes1; + } + + if ((handptr->weapon_action_state != GUN_ANIM_STATE_PUNCH1_RECOVER) && (handptr->field_890 >= WHEN_1E_FLD890)) + { + handptr->weapon_firing_status = 1; + handptr->weapon_action_state = GUN_ANIM_STATE_PUNCH1_RECOVER; + } + } + else if ((handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH2_STRIKE) || (handptr->weapon_action_state == GUN_ANIM_STATE_PUNCH2_RECOVER)) + { + if (g_CurrentPlayer->cur_item_weapon_getname == ITEM_SNIPERRIFLE) + { + sp74 = sniperMeleeKeyframes2; + } + else + { + sp74 = fistMeleeKeyframes2; + } + + if ((handptr->weapon_action_state != GUN_ANIM_STATE_PUNCH2_RECOVER) && (handptr->field_890 >= WHEN_1E_FLD890)) + { + handptr->weapon_firing_status = 1; + handptr->weapon_action_state = GUN_ANIM_STATE_PUNCH2_RECOVER; + } + } + + if (gunSample1PTransform(sp74, temp_v1_9, &handptr->field_8EC, hand) != 0) + { + handptr->field_92C = 1; + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_GRENADE_THROW) + { + if (handptr->weapon_ammo_in_magazine > 0) + { + tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); + if (gunSample1PTransform(grenadeThrowKeyframes, tempf, &handptr->field_8EC, hand) != 0) + { + handptr->field_92C = 1; + } + else + { + handptr->field_87E = 0; + handptr->weapon_firing_status = 1; + handptr->weapon_ammo_in_magazine -= 1; + handptr->weapon_action_state = GUN_ANIM_STATE_GRENADE_RECOVER; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_GRENADE_RECOVER) + { + tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); + if (gunSample1PTransform(timedMineThrowKeyframes, tempf, &handptr->field_8EC, hand) != 0) + { + handptr->field_92C = 1; + } + else + { + handptr->field_87E = 1; + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_THROWKNIFE_DRAW) + { + if (handptr->weapon_ammo_in_magazine > 0) + { + if (handptr->field_888 != 0) + { + handptr->weapon_action_state = GUN_ANIM_STATE_THROWKNIFE_THROW; + } + else + { + tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); + if (gunSample1PTransform(throwKnifeDrawBackKeyframes, tempf, &handptr->field_8EC, hand) != 0) + { + handptr->field_92C = 1; + } + else if (gunSample1PTransform(throwKnifeReleaseKeyframes, 0.0f, &handptr->field_8EC, hand) != 0) + { + handptr->field_92C = 1; + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_THROWKNIFE_THROW; + } + } + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_THROWKNIFE_THROW) + { + if (handptr->weapon_ammo_in_magazine > 0) + { + tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); + if (gunSample1PTransform(throwKnifeDrawBackKeyframes, tempf, &handptr->field_8EC, hand) != 0) + { + handptr->field_92C = 1; + } + else + { + handptr->field_87E = 0; + handptr->weapon_firing_status = 1; + handptr->weapon_ammo_in_magazine -= 1; + handptr->weapon_action_state = GUN_ANIM_STATE_THROWKNIFE_RECOVER; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_THROWKNIFE_RECOVER) + { + tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); + if (gunSample1PTransform(throwKnifeReleaseKeyframes, tempf, &handptr->field_8EC, hand) != 0) + { + handptr->field_92C = 1; + } + else + { + handptr->field_87E = 1; + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_MINE_PLACE) + { + if ((handptr->weapon_ammo_in_magazine > 0) || (bondwalkItemCheckBitflags(var_s1, WEAPONSTATBITFLAG_CLICKY) != 0)) + { + tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); + + if (gunSample1PTransform(proxMineThrowKeyframes, tempf, &handptr->field_8EC, hand) != 0) + { + handptr->field_92C = 1; + } + else + { + handptr->field_87E = 0; + handptr->weapon_firing_status = 1; + handptr->weapon_ammo_in_magazine -= 1; + handptr->weapon_action_state = GUN_ANIM_STATE_MINE_RECOVER; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + else + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_MINE_RECOVER) + { + tempf = WEAPON_1P_ANIM_TIME(handptr->field_890); + if (gunSample1PTransform(remoteMineThrowKeyframes, tempf, &handptr->field_8EC, hand) != 0) + { + handptr->field_92C = 1; + } + else + { + handptr->field_87E = 1; + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } + + if (handptr->weapon_action_state == GUN_ANIM_STATE_USE_ITEM) + { + if (var_s1 == ITEM_KEYANALYSERCASE) + { + if (handptr->field_88C == 0) + { + analyzeGEKey(); + } + } + else if (var_s1 == ITEM_WEAPONCASE) + { + if (handptr->field_88C == 0) + { + give_weapon_case_items(); + } + } + else if ((var_s1 == ITEM_BOMBDEFUSER) + || (var_s1 == ITEM_DATATHIEF) + || (var_s1 == ITEM_DOORDECODER) + || (var_s1 == ITEM_EXPLOSIVEFLOPPY) + || (var_s1 == ITEM_DATTAPE)) + { + if (handptr->field_88C == 0) + { + temp_v0_8 = propFindForInteract(); + + if (temp_v0_8 != NULL) + { + temp_v0_8->obj->state |= 0x40; + } + } + } + else if ((var_s1 != ITEM_POLARIZEDGLASSES) + && (var_s1 != ITEM_DARKGLASSES) + && (var_s1 != ITEM_WATCHGEIGERCOUNTER) + && (var_s1 != ITEM_WATCHMAGNETREPEL) + && (var_s1 != ITEM_KEYCARD) + && (var_s1 != ITEM_KEYYALE) + && (var_s1 != ITEM_KEYBOLT) + && (var_s1 != ITEM_SAFECRACKERCASE) + && (var_s1 != ITEM_LOCKEXPLODER) + && (var_s1 != ITEM_DOOREXPLODER) + && (var_s1 != ITEM_CREDITCARD) + && (var_s1 != ITEM_GASKEYRING) + && (var_s1 == ITEM_BUNGEE)) + { + // removed + } + else if (var_s1 == ITEM_PITONGUN + || var_s1 == ITEM_GASKEYRING + || var_s1 == ITEM_BUNGEE) + { + // removed + } + + if (handptr->field_888 != 0) + { + handptr->weapon_action_state = GUN_ANIM_STATE_IDLE; + handptr->field_890 = 0.0f; + handptr->field_88C = 0; + } + } +} + +#undef WEAPON_1P_ANIM_TIME +#undef WHEN_1_CASE_GRENADELAUNCH_FLD890 +#undef WHEN_1_CASE_GRENADE_FLD890 +#undef WHEN_D_FLD890 +#undef WHEN_5_SP188_INIT +#undef WHEN_5_SP188_MULTI +#undef WHEN_5_FLD8B0_SP +#undef WHEN_5_FLD8B0_MULTI +#undef WHEN_8_SP178_INIT +#undef WHEN_8_SP178_MULTI +#undef WHEN_A_FLD890 +#undef WHEN_A_FLD8B0 +#undef WHEN_C_FLD890 +#undef WHEN_E_FLD890 +#undef WHEN_10_FLD890 +#undef WHEN_11_FLD890_1 +#undef WHEN_11_FLD890_2 +#undef WHEN_1E_FLD890 + + +void analyzeGEKey(void) +{ + if (bondinvHasGEKey()) + { + HUDMESSAGEBOTTOM(langGet(getStringID(LGUN, GUN_STR_D8_ANALYZINGTHEGOLDENEYEKEY_LF))); //Analyzing the GoldenEye key... + g_CurrentPlayer->copiedgoldeneye = TRUE; + sndPlaySfx(g_musicSfxBufferPtr, KEY_ANALYSER_SFX, 0x0); + currentPlayerEquipWeaponWrapper(GUNRIGHT, ITEM_GOLDENEYEKEY); + currentPlayerEquipWeaponWrapper(GUNLEFT, ITEM_UNARMED); + } + else + { + HUDMESSAGEBOTTOM(langGet(getStringID(LGUN, GUN_STR_D9_YOUDONOTHAVETHEGOLDENEYEKEY_LF))); //You do not have the GoldenEye key. + sub_GAME_7F05D690(); + } + return; +} + + +s32 get_keyanalyzer_flag(void) +{ + return g_CurrentPlayer->copiedgoldeneye; +} + + +void give_weapon_case_items(void) +{ + add_ammo_to_inventory(AMMO_KNIFE, 2, 0, 1); + add_ammo_to_inventory(AMMO_GRENADE, 2, 0, 1); + bondinvAddInvItem(ITEM_SNIPERRIFLE); + set_sound_effect_for_weapontype_collection(ITEM_SNIPERRIFLE); + display_text_for_weapon_in_lower_left_corner(ITEM_SNIPERRIFLE); + give_cur_player_ammo(sniperrifle_stats.AmmoType, check_cur_player_ammo_amount_in_inventory(sniperrifle_stats.AmmoType) + sniperrifle_stats.MagSize); + bondinvRemoveItemByID(ITEM_WEAPONCASE); + currentPlayerEquipWeaponWrapper(GUNRIGHT,ITEM_SNIPERRIFLE); + currentPlayerEquipWeaponWrapper(GUNLEFT,ITEM_UNARMED); +} + + +f32 get_vertical_position_solo_watch_menu_main_page_for_item(ITEM_IDS item) +{ + return gitem_structs[item].watch_pos_x; +} + + +f32 get_lateral_position_solo_watch_menu_main_page_for_item(ITEM_IDS item) +{ + return gitem_structs[item].watch_pos_y; +} + + +f32 get_depth_on_solo_watch_menu_page_for_item(ITEM_IDS item) +{ + return gitem_structs[item].watch_pos_z; +} + + +f32 get_xrotation_solo_watch_menu_for_item(ITEM_IDS item) + +{ + return gitem_structs[item].x_rotation; +} + + +f32 get_yrotation_solo_watch_menu_for_item(ITEM_IDS item) +{ + return gitem_structs[item].y_rotation; +} + + +f32 get_45_degree_angle(s32 unk) { + return 45.0f; +} + + +u16 *get_ptr_first_title_line_item(ITEM_IDS item) +{ + return langGet(gitem_structs[item].upper_watch_text); +} + + +u16 *get_ptr_second_title_line_item(ITEM_IDS item) +{ + return langGet(gitem_structs[item].lower_watch_text); +} + + +u16 *get_ptr_short_watch_text_for_item(ITEM_IDS item) +{ + return langGet(gitem_structs[item].watch_equipment_text); +} + + +u16 *get_ptr_long_watch_text_for_item(ITEM_IDS item) +{ + return langGet(gitem_structs[item].weapon_of_choice_text); +} + + +f32 get_45_degree_angle_0(s32 unk) +{ + return 45.0f; +} + + +f32 get_horizontal_offset_on_solo_watch_menu_for_item(ITEM_IDS item) +{ + return gitem_structs[item].equip_watch_x; +} + + +f32 get_vertical_offset_on_solo_watch_menu_for_item(ITEM_IDS item) +{ + return gitem_structs[item].equip_watch_y; +} + + +f32 get_depth_offset_solo_watch_menu_inventory_page_for_item(ITEM_IDS item) +{ + return gitem_structs[item].equip_watch_z; +} + + +f32 getCurrentPlayerNoise(GUNHAND hand) +{ + return g_CurrentPlayer->hands[hand].noise; +} + + +void gunTickNoise(void) +{ + enum ITEM_IDS weapon_id_right; + enum ITEM_IDS weapon_id_left; + s32 unused2; + f32 noise_reduction; + WeaponStats *item_right_stats; + WeaponStats *item_left_stats; + f32 noise_reduction_max; + s32 unused; + + weapon_id_right = getCurrentPlayerWeaponId(GUNRIGHT); + weapon_id_left = getCurrentPlayerWeaponId(GUNLEFT); + item_right_stats = get_ptr_item_statistics(weapon_id_right); + item_left_stats = get_ptr_item_statistics(weapon_id_left); + + if (weapon_id_right != ITEM_UNARMED && get_hands_firing_status(GUNRIGHT)) + { + g_CurrentPlayer->hands[GUNRIGHT].noise += item_right_stats->NoiseIncreasePerShot; + + if (item_right_stats->LoudnessMax < g_CurrentPlayer->hands[GUNRIGHT].noise) + { + g_CurrentPlayer->hands[GUNRIGHT].noise = item_right_stats->LoudnessMax; + } + } + + if (weapon_id_left != ITEM_UNARMED && get_hands_firing_status(GUNLEFT)) + { + g_CurrentPlayer->hands[GUNLEFT].noise += item_left_stats->NoiseIncreasePerShot; + + if (item_left_stats->LoudnessMax < g_CurrentPlayer->hands[GUNLEFT].noise) + { + g_CurrentPlayer->hands[GUNLEFT].noise = item_left_stats->LoudnessMax; + } + } + + noise_reduction = (item_right_stats->NoiseIncreasePerShot * g_GlobalTimerDelta) / (item_right_stats->NoiseDecayLinearTime * 60.0f); + noise_reduction_max = ((g_CurrentPlayer->hands[GUNRIGHT].noise - item_right_stats->LoudnessMin) * g_GlobalTimerDelta) / (item_right_stats->NoiseDecayScaledTime * 60.0f); + + if (noise_reduction < noise_reduction_max) + { + noise_reduction = noise_reduction_max; + } + + g_CurrentPlayer->hands[GUNRIGHT].noise -= noise_reduction; + + if (g_CurrentPlayer->hands[GUNRIGHT].noise < item_right_stats->LoudnessMin) + { + g_CurrentPlayer->hands[GUNRIGHT].noise = item_right_stats->LoudnessMin; + } + + noise_reduction = (item_left_stats->NoiseIncreasePerShot * g_GlobalTimerDelta) / (item_left_stats->NoiseDecayLinearTime * 60.0f); + noise_reduction_max = ((g_CurrentPlayer->hands[GUNLEFT].noise - item_left_stats->LoudnessMin) * g_GlobalTimerDelta) / (item_left_stats->NoiseDecayScaledTime * 60.0f); + + if (noise_reduction < noise_reduction_max) + { + noise_reduction = noise_reduction_max; + } + + g_CurrentPlayer->hands[GUNLEFT].noise -= noise_reduction; + + if (g_CurrentPlayer->hands[GUNLEFT].noise < item_left_stats->LoudnessMin) + { + g_CurrentPlayer->hands[GUNLEFT].noise = item_left_stats->LoudnessMin; + } +} + + +/** + * Returns true if the hand has a melee weapon or has ammo in the magazine. + */ +s32 gunCanUseWeapon(enum GUNHAND hand) +{ + return (get_ammo_type_for_weapon(getCurrentPlayerWeaponId(hand)) == 0) + || (g_CurrentPlayer->hands[hand].weapon_ammo_in_magazine > 0); +} + + +/** + * US address 7F067420. + * Perfect Dark method bgunTickGameplay. + * + * Handles logic for single gun and dual wield trigger presses. + * Calls updates to first person gun animations, gun model loading, noise to AI, and updating color from collision tiles. + * Also handles the Watch Magnet Attract hum noise. +*/ +void gunTickGameplay(s32 triggerOn) +{ + struct gun_trigger_state trigger_state; + enum ITEM_IDS weapon_id_right; + enum ITEM_IDS weapon_id_left; + enum GUNHAND hand = GUNLEFT; + struct rgba_u8 weapon_color; + + trigger_state = g_ZeroTriggerState; + + // Save previous trigger state. + g_CurrentPlayer->prev_trigger_down = g_CurrentPlayer->trigger_down; + + // Save raw trigger state. + g_CurrentPlayer->trigger_down = triggerOn; + + if ((g_CurrentPlayer->trigger_down == 0) && (g_CurrentPlayer->prev_trigger_down != 0)) + { + g_CurrentPlayer->trigger_released = 1; + } + + // Z button pressed this frame. + if (g_CurrentPlayer->trigger_down != 0) + { + weapon_id_right = getCurrentPlayerWeaponId(GUNRIGHT); + weapon_id_left = getCurrentPlayerWeaponId(GUNLEFT); + + g_CurrentPlayer->z_trigger_timer += g_ClockTimer; + + // Dual wielding. + if ((weapon_id_right != ITEM_UNARMED) && (weapon_id_left != ITEM_UNARMED)) + { + // Both guns prefer to take turns firing in dual wield. + if ((bondwalkItemCheckBitflags(weapon_id_right, WEAPONSTATBITFLAG_DUAL_WIELD_ALTERNATING_FIRE) != 0) && (bondwalkItemCheckBitflags(weapon_id_left, WEAPONSTATBITFLAG_DUAL_WIELD_ALTERNATING_FIRE) != 0)) + { + // Trigger has been held longer than 20 ticks on NTSC (24 on PAL). + if (g_CurrentPlayer->z_trigger_timer > DUAL_WIELD_TRIGGER_SWAP_TICKS) + { + // 'hand' still has its default value here, which behaves like trigger-on. + trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = hand; + + // If the gun in the other hand is usable or has been held for any amount of time, depress its trigger as well. + if (gunCanUseWeapon(1 - g_CurrentPlayer->current_trigger_hand) || g_CurrentPlayer->hands[1 - g_CurrentPlayer->current_trigger_hand].weapon_hold_time) + { + trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 1; + } + } + // Z has been held for less than or equal to 20 ticks on NTSC (24 on PAL). + else + { + if ((g_CurrentPlayer->prev_trigger_down == 0) && + ((gunCanUseWeapon(1 - g_CurrentPlayer->current_trigger_hand) != 0) || (gunCanUseWeapon(g_CurrentPlayer->current_trigger_hand) == 0))) + { + g_CurrentPlayer->current_trigger_hand = 1 - g_CurrentPlayer->current_trigger_hand; + } + + trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = 1; + trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 0; + } + } + /** + * One gun prefers to take turns firing in dual wield. + * This doesn't happen much in the vanilla US version with the notable + * exception of equipping Xenia's RC-P90 and Grenade Launcher in Jungle + */ + else if ((bondwalkItemCheckBitflags(weapon_id_right, WEAPONSTATBITFLAG_DUAL_WIELD_ALTERNATING_FIRE) != 0) || (bondwalkItemCheckBitflags(weapon_id_left, WEAPONSTATBITFLAG_DUAL_WIELD_ALTERNATING_FIRE) != 0)) + { + // Z has been held more than 30 ticks on NTSC (36 for PAL), depress trigger on both guns. + if (g_CurrentPlayer->z_trigger_timer > DUAL_WIELD_SINGLE_TRIGGER_SWAP_TICKS) + { + trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = hand; + + if ((gunCanUseWeapon(1 - g_CurrentPlayer->current_trigger_hand) != 0) || g_CurrentPlayer->hands[1 - g_CurrentPlayer->current_trigger_hand].weapon_hold_time != 0) + { + trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 1; + } + } + // Before the hold threshold (30 ticks NTSC or 36 PAL), prefer the hand whose weapon uses alternating dual wield fire. + else + { + hand = bondwalkItemCheckBitflags(weapon_id_right, WEAPONSTATBITFLAG_DUAL_WIELD_ALTERNATING_FIRE) ? GUNRIGHT : GUNLEFT; + + if (gunCanUseWeapon(hand) != 0 || g_CurrentPlayer->hands[hand].weapon_hold_time != 0) + { + g_CurrentPlayer->current_trigger_hand = hand; + } + else + { + if ((gunCanUseWeapon(1 - hand) != 0) || g_CurrentPlayer->hands[1 - hand].weapon_hold_time != 0) + { + g_CurrentPlayer->current_trigger_hand = 1 - hand; + } + else + { + g_CurrentPlayer->current_trigger_hand = 1 - g_CurrentPlayer->current_trigger_hand; + } + } + + trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = 1; + trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 0; + } + } + /** + * Neither weapon uses alternating dual wield fire. + * Once the hold threshold is exceeded, allow the off-hand to become active too. + */ + else if (g_CurrentPlayer->z_trigger_timer > DUAL_WIELD_SINGLE_TRIGGER_SWAP_TICKS) + { + trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = hand; + + if (gunCanUseWeapon(1 - g_CurrentPlayer->current_trigger_hand) || g_CurrentPlayer->hands[1 - g_CurrentPlayer->current_trigger_hand].weapon_hold_time) + { + trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 1; + } + } + /** + * Neither weapon uses alternating dual wield fire. + * On a fresh Z press, switch lead hands if the other hand is usable or the current hand cannot be used. + * The lead hand continues being the lead hand. + */ + else + { + if ((g_CurrentPlayer->prev_trigger_down == 0) && + ((gunCanUseWeapon(1 - g_CurrentPlayer->current_trigger_hand) != 0) || (gunCanUseWeapon(g_CurrentPlayer->current_trigger_hand) == 0))) + { + g_CurrentPlayer->current_trigger_hand = 1 - g_CurrentPlayer->current_trigger_hand; + } + + trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = 1; + trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 0; + } + } + // Not dual wielding. + else + { + if ((getCurrentPlayerWeaponId(g_CurrentPlayer->current_trigger_hand) == ITEM_UNARMED) && (getCurrentPlayerWeaponId(1 - g_CurrentPlayer->current_trigger_hand) != ITEM_UNARMED)) + { + g_CurrentPlayer->current_trigger_hand = 1 - g_CurrentPlayer->current_trigger_hand; + } + + trigger_state.triggerOn[g_CurrentPlayer->current_trigger_hand] = 1; + trigger_state.triggerOn[1 - g_CurrentPlayer->current_trigger_hand] = 0; + } + } + // Z button not pressed. Reset the trigger timer. + else + { + g_CurrentPlayer->z_trigger_timer = 0; + } + + gunTickHandState(0, trigger_state.triggerOn[0]); // Right hand + gunTickHandState(1, trigger_state.triggerOn[1]); // Left hand + used_to_load_1st_person_model_on_demand(0); + used_to_load_1st_person_model_on_demand(1); + gunTickNoise(); + + if (g_CurrentPlayer->resetshadecol) + { + set_color_shading_from_tile(getCurrentPlayerProp(), (struct rgba_u8 *) &g_CurrentPlayer->tileColor); + g_CurrentPlayer->resetshadecol = FALSE; + } + else + { + set_color_shading_from_tile(getCurrentPlayerProp(), &weapon_color); + update_color_shading(&g_CurrentPlayer->tileColor, &weapon_color); + } + + bondinvIncrementHeldTime(getCurrentPlayerWeaponId(GUNRIGHT), getCurrentPlayerWeaponId(GUNLEFT)); + + if(1); + + if (g_CurrentPlayer->magnetattracttime >= 0) + { + struct hand *hand_right = &g_CurrentPlayer->hands[0]; + + g_CurrentPlayer->magnetattracttime += g_ClockTimer; + + if (g_CurrentPlayer->magnetattracttime < WATCH_SOUND_DURATION_TICKS) + { + // Start or restart the hum sound if needed + if (hand_right->audioHandle == NULL + || sndGetPlayingState((struct ALSoundState *) hand_right->audioHandle) == 0) + { + if (lvlGetControlsLockedFlag() == 0) + { + sndPlaySfx( + (struct ALBankAlt_s *) g_musicSfxBufferPtr, + MAGNETIC_HUM_SFX, + (struct ALSoundState *) &hand_right->audioHandle); + } + } + } + else + { + g_CurrentPlayer->magnetattracttime = -1; + + if (hand_right->audioHandle != NULL) + { + if (sndGetPlayingState((struct ALSoundState *) hand_right->audioHandle) != 0) + { + sndDeactivate((struct ALSoundState *) hand_right->audioHandle); + } + } + } + } +} + + +void gunSetAimType(s32 param_1) +{ + g_CurrentPlayer->aimtype = param_1; +} + + +void sub_GAME_7F067AB4(coord3d *param_1) +{ + g_CurrentPlayer->hands[GUNRIGHT].field_A38 = sub_GAME_7F05DCB8(GUNRIGHT) + param_1->x; + g_CurrentPlayer->hands[GUNRIGHT].field_A3C = param_1->y; + g_CurrentPlayer->hands[GUNRIGHT].field_A40 = param_1->z; + + g_CurrentPlayer->hands[GUNLEFT].field_A38 = sub_GAME_7F05DCB8(GUNLEFT) + param_1->x; + g_CurrentPlayer->hands[GUNLEFT].field_A3C = param_1->y; + g_CurrentPlayer->hands[GUNLEFT].field_A40 = param_1->z; + +} + + +void gunSetTracerTarget(coord3d* pos) +{ + g_CurrentPlayer->hands[GUNLEFT].item_related.x = g_CurrentPlayer->hands[GUNRIGHT].item_related.x = pos->x; + g_CurrentPlayer->hands[GUNLEFT].item_related.y = g_CurrentPlayer->hands[GUNRIGHT].item_related.y = pos->y; + g_CurrentPlayer->hands[GUNLEFT].item_related.z = g_CurrentPlayer->hands[GUNRIGHT].item_related.z = pos->z; +} + + +void caclulate_gun_crosshair_position_rotation(f32 turn_x, f32 turn_y, f32 guncrossdamp, f32 gunaimdamp) +{ + s32 i; + f32 screen_width; + f32 screen_height; + coord3d coords; + + screen_width = getPlayer_c_screenwidth(); + screen_height = getPlayer_c_screenheight(); + + if (guncrossdamp != g_CurrentPlayer->guncrossdamp) + { + g_CurrentPlayer->crosshair_x_pos = (g_CurrentPlayer->crosshair_x_pos * (1.0f - g_CurrentPlayer->guncrossdamp)) / (1.0f - guncrossdamp); + g_CurrentPlayer->crosshair_y_pos = (g_CurrentPlayer->crosshair_y_pos * (1.0f - g_CurrentPlayer->guncrossdamp)) / (1.0f - guncrossdamp); + g_CurrentPlayer->guncrossdamp = guncrossdamp; + } + + if (gunaimdamp != g_CurrentPlayer->gunaimdamp) + { + g_CurrentPlayer->gun_azimuth_angle = (g_CurrentPlayer->gun_azimuth_angle * (1.0f - g_CurrentPlayer->gunaimdamp)) / (1.0f - gunaimdamp); + g_CurrentPlayer->gun_azimuth_turning = (g_CurrentPlayer->gun_azimuth_turning * (1.0f - g_CurrentPlayer->gunaimdamp)) / (1.0f - gunaimdamp); + g_CurrentPlayer->gunaimdamp = gunaimdamp; + } + + for (i = 0; i < g_ClockTimer; i++) + { + g_CurrentPlayer->crosshair_x_pos = (g_CurrentPlayer->crosshair_x_pos * guncrossdamp) + turn_x; + g_CurrentPlayer->crosshair_y_pos = (g_CurrentPlayer->crosshair_y_pos * guncrossdamp) + turn_y; + } + + g_CurrentPlayer->crosshair_angle.f[0] = (g_CurrentPlayer->crosshair_x_pos * (1.0f - guncrossdamp) * screen_width * 0.5f) + (screen_width * 0.5f); + g_CurrentPlayer->crosshair_angle.f[1] = (g_CurrentPlayer->crosshair_y_pos * (1.0f - guncrossdamp) * screen_height * 0.5f) + (screen_height * 0.5f); + + if (g_CurrentPlayer->crosshair_angle.f[0] < 3.0f) + { + g_CurrentPlayer->crosshair_angle.f[0] = 3.0f; + } + else if ((screen_width - 4.0f) < g_CurrentPlayer->crosshair_angle.f[0]) + { + g_CurrentPlayer->crosshair_angle.f[0] = screen_width - 4.0f; + } + + if (g_CurrentPlayer->crosshair_angle.f[1] < 3.0f) + { + g_CurrentPlayer->crosshair_angle.f[1] = 3.0f; + } + else if ((screen_height - 4.0f) < g_CurrentPlayer->crosshair_angle.f[1]) + { + g_CurrentPlayer->crosshair_angle.f[1] = (screen_height - 4.0f); + } + + g_CurrentPlayer->crosshair_angle.f[0] += getPlayer_c_screenleft(); + g_CurrentPlayer->crosshair_angle.f[1] += getPlayer_c_screentop(); + + for (i = 0; i < g_ClockTimer; i++) + { + g_CurrentPlayer->gun_azimuth_angle = (g_CurrentPlayer->gun_azimuth_angle * gunaimdamp) + turn_x; + g_CurrentPlayer->gun_azimuth_turning = (g_CurrentPlayer->gun_azimuth_turning * gunaimdamp) + turn_y; + } + + g_CurrentPlayer->field_FFC.x = (g_CurrentPlayer->gun_azimuth_angle * (1.0f - gunaimdamp) * screen_width * 0.5f) + (screen_width * 0.5f); + g_CurrentPlayer->field_FFC.y = (g_CurrentPlayer->gun_azimuth_turning * (1.0f - gunaimdamp) * screen_height * 0.5f) + (screen_height * 0.5f); + + g_CurrentPlayer->field_FFC.x += getPlayer_c_screenleft(); + g_CurrentPlayer->field_FFC.y += getPlayer_c_screentop(); + + transformAndNormalizeByLength2Dto3D(&g_CurrentPlayer->field_FFC, &coords, 1000.0f); + sub_GAME_7F067AB4(&coords); +} + + +void sub_GAME_7F067F58(f32 turn_x, f32 turn_y, f32 max_aim_lock_speed) +{ + f32 aim_lock_speed; + +#if defined(VERSION_US) || defined(VERSION_JP) + aim_lock_speed = get_ptr_item_statistics(getCurrentPlayerWeaponId(GUNRIGHT))->AimLockSpeed; +#elif defined(VERSION_EU) + aim_lock_speed = get_ptr_item_statistics(getCurrentPlayerWeaponId(GUNRIGHT))->CrosshairSpeed; +#endif + + if (aim_lock_speed < max_aim_lock_speed) + { + aim_lock_speed = max_aim_lock_speed; + } + + caclulate_gun_crosshair_position_rotation(turn_x, turn_y, max_aim_lock_speed, aim_lock_speed); +} + + +void sub_GAME_7F067FBC(f32 turn_x, f32 turn_y) +{ + WeaponStats * item_stats; + f32 guncrossdamp; + f32 gunaimdamp; + + item_stats = get_ptr_item_statistics(getCurrentPlayerWeaponId(GUNRIGHT)); + +#if defined(VERSION_US) + guncrossdamp = item_stats->CrosshairSpeed; + gunaimdamp = item_stats->AimLockSpeed; +#elif defined(VERSION_EU) + guncrossdamp = 0.7651f; + gunaimdamp = item_stats->CrosshairSpeed; +#elif defined(VERSION_JP) + guncrossdamp = 0.8f; + gunaimdamp = item_stats->AimLockSpeed; +#endif + + caclulate_gun_crosshair_position_rotation(turn_x, turn_y, guncrossdamp, gunaimdamp); +} + + +/* +* Address: 0x7f068008 +*/ +void get_bullet_angle(f32* horizontal_angle, f32* vertical_angle) { + *horizontal_angle = g_CurrentPlayer->crosshair_angle.f[0]; + *vertical_angle = g_CurrentPlayer->crosshair_angle.f[1]; +} + + +void sub_GAME_7F06802C(void) +{ + coord3d coord; + f32 tmp; + + tmp = getPlayer_c_screenleft() + (getPlayer_c_screenwidth() * 0.5f); + g_CurrentPlayer->crosshair_angle.x = tmp; + g_CurrentPlayer->field_FFC.x = tmp; + + tmp = getPlayer_c_screentop() + (getPlayer_c_screenheight() * 0.5f); + g_CurrentPlayer->crosshair_angle.y = tmp; + g_CurrentPlayer->field_FFC.y = tmp; + + transformAndNormalizeByLength2Dto3D((coord2d *) &g_CurrentPlayer->field_FFC, &coord, 1000.0f); + sub_GAME_7F067AB4(&coord); +} + + +void sub_GAME_7F0680D4(coord3d * coord) +{ + coord3d tmp; + + g_CurrentPlayer->field_1010.x = coord->x; + g_CurrentPlayer->field_1010.y = coord->y; + g_CurrentPlayer->field_1010.z = coord->z; + matrix_4x4_set_rotation_around_xyz(coord->f, &g_CurrentPlayer->field_101C); + + tmp.x = g_CurrentPlayer->field_101C.m[2][0] * 1000.0f; + tmp.y = g_CurrentPlayer->field_101C.m[2][1] * 1000.0f; + tmp.z = g_CurrentPlayer->field_101C.m[2][2] * 1000.0f; + transform3Dto2DCoords(&tmp, (coord3d* ) &g_CurrentPlayer->crosshair_angle); + + g_CurrentPlayer->field_FFC.x = g_CurrentPlayer->crosshair_angle.x; + g_CurrentPlayer->field_FFC.y = g_CurrentPlayer->crosshair_angle.y; + + sub_GAME_7F067AB4(&tmp); +} + +extern const f32 g_GunScreenAspectRatio; + + +/** + * Address 0x7F068190. +*/ +#if !defined(VERSION_US) +void sub_GAME_7F068190(coord3d *zeropos, coord3d *vec) +{ + zeropos->x = 0.0f; + zeropos->y = 0.0f; + zeropos->z = 0.0f; + + transformAndNormalizeByLength2Dto3D(&g_CurrentPlayer->crosshair_angle, vec, 1.0f); +} + + +/* +* Address: 0x7f0681cc +* This function computes the angle the player's bullets are fired at +*/ +void bullet_path_from_screen_center(coord3d* arg0, coord3d* result, enum GUNHAND arg2) +{ + coord2d crosspos; + s32 unused; + f32 inaccuracy; + f32 scaledspread; + f32 randfactor; + + inaccuracy = get_ptr_item_statistics(getCurrentPlayerWeaponId(arg2))->Inaccuracy; + if ((bondwalkItemCheckBitflags(get_item_in_hand_or_watch_menu(arg2), WEAPONSTATBITFLAG_FIRST_SHOT_ACCURACY) != 0) && (g_CurrentPlayer->hands[arg2].volley == 1)) + { + // Single shots are four times more accurate + inaccuracy *= 0.25f; + } + + scaledspread = (120.0f * inaccuracy) / viGetFovY(); + + randfactor = (RANDOMFRAC() - 0.5f) * RANDOMFRAC(); + crosspos.x = g_CurrentPlayer->crosshair_angle.f[0] + randfactor * scaledspread * getPlayer_c_screenwidth() * g_GunScreenAspectRatio + / (getPlayer_c_perspaspect() * 320.0f); + + randfactor = (RANDOMFRAC() - 0.5f) * RANDOMFRAC(); + crosspos.y = g_CurrentPlayer->crosshair_angle.f[1] + randfactor * scaledspread * getPlayer_c_screenheight() + / (PAL ? (f32)(SCREEN_HEIGHT_272) : (f32)(SCREEN_HEIGHT_240)); + + arg0->x = 0.0f; + arg0->y = 0.0f; + arg0->z = 0.0f; + + // Result is a normalized vector describing the path the bullet will follow + // Can be used to compute x,y,z displacement off the center of the screen if done for a projectile + transformAndNormalizeByLength2Dto3D(&crosspos, result, 1.0f); +} + + +/* +* Address: 0x7f068420 +*/ +CasingRecord* casingCreate(ModelFileHeader* header, Mtxf* mtx) +{ + CasingRecord* entry = g_Casings; + CasingRecord* end = g_Casings + ARRAYCOUNT(g_Casings); + + while (entry < end && entry->header != NULL) + { + entry++; + } + + if (entry < end) + { + entry->header = header; + + entry->pos.x = mtx->m[3][0]; + entry->pos.y = mtx->m[3][1]; + entry->pos.z = mtx->m[3][2]; +#if VERSION_EU + matrix_7f05842c_eu(mtx, entry->rot_mtx); +#else + entry->rot_mtx.m[0][0] = mtx->m[0][0]; + entry->rot_mtx.m[0][1] = mtx->m[0][1]; + entry->rot_mtx.m[0][2] = mtx->m[0][2]; + entry->rot_mtx.m[0][3] = 0.0f; + + entry->rot_mtx.m[1][0] = mtx->m[1][0]; + entry->rot_mtx.m[1][1] = mtx->m[1][1]; + entry->rot_mtx.m[1][2] = mtx->m[1][2]; + entry->rot_mtx.m[1][3] = 0.0f; + + entry->rot_mtx.m[2][0] = mtx->m[2][0]; + entry->rot_mtx.m[2][1] = mtx->m[2][1]; + entry->rot_mtx.m[2][2] = mtx->m[2][2]; + entry->rot_mtx.m[2][3] = 0.0f; + + entry->rot_mtx.m[3][0] = 0.0f; + entry->rot_mtx.m[3][1] = 0.0f; + entry->rot_mtx.m[3][2] = 0.0f; + entry->rot_mtx.m[3][3] = 1.0f; +#endif + return entry; + } + + return NULL; +} +#endif + + +#if VERSION_EU +#define THROWMTX_OFFSET 0xAD0 +#define THROWPOS_OFFSET 0xB00 +#define THROWPOS_PREV_OFFSET 0xB40 +#else +#define THROWMTX_OFFSET 0xAD8 +#define THROWPOS_OFFSET 0xB08 +#define THROWPOS_PREV_OFFSET 0xB48 +#endif + +#define THROWMTX ((Mtxf *) ((u8 *) g_CurrentPlayer + handoffset + THROWMTX_OFFSET)) +#define THROWPOS(k) (((f32 *) ((u8 *) g_CurrentPlayer + handoffset + THROWPOS_OFFSET))[k]) +#define THROWPREV(k) (((f32 *) ((u8 *) g_CurrentPlayer + handoffset + THROWPOS_PREV_OFFSET))[k]) + +extern const f32 g_CasingSwitchScale; +extern const f32 g_PistolCasingHorizontalSpeed; +extern const f32 g_PistolCasingRotationScaleX; +extern const f32 g_PistolCasingRotationOffsetX; +extern const f32 g_PistolCasingRotationScaleY; +extern const f32 g_PistolCasingRotationOffsetY; +extern const f32 g_PistolCasingRotationScaleZ; +extern const f32 g_PistolCasingRotationOffsetZ; +extern const f32 g_PistolCasingRandomDivisor; +extern const f32 g_PistolCasingGravity; +extern const f32 g_RifleCasingHorizontalSpeed; +extern const f32 g_RifleCasingVerticalSpeed; +extern const f32 g_RifleCasingRotationScaleX; +extern const f32 g_RifleCasingRotationOffsetX; +extern const f32 g_RifleCasingRotationScaleY; +extern const f32 g_RifleCasingRotationOffsetY; +extern const f32 g_RifleCasingRotationScaleZ; +extern const f32 g_RifleCasingRotationOffsetZ; +extern const f32 g_RifleCasingRandomDivisor; +extern const f32 g_RifleCasingGravity; + + +/** + * Address: 7F068508 + * + * Ejects a spent cartridge casing from the gun in the given hand. + */ +#if defined(VERSION_EU) +void sub_GAME_7F068508(GUNHAND handnum, f32 floor_y_pos) +{ + CasingRecord *casing; + Mtxf mtx; + ITEM_IDS weaponid; + coord3d *switchdata; + ModelFileHeader *cartridge_header; + coord3d switchpos; + ModelNode *switch0; + coord3d rot; +#if VERSION_EU + Mtxf rotmtx; +#endif + f32 rand; + s32 new_var; /* dead but declared on EU — still reserves its frame slot */ + f32 frac; +#if VERSION_EU + s32 randlimit; +#endif + f32 oldvely; + f32 newvely; +#ifndef VERSION_EU + s32 randlimit; +#endif + s32 handoffset; + u32 randval; +#if VERSION_EU + s32 pad[2]; +#endif + + weaponid = getCurrentPlayerWeaponId(handnum); + cartridge_header = get_ptr_item_statistics(weaponid)->ptr_cartridge_struct; + + // Do not create ejected casings in multiplayer. + if ((cartridge_header == NULL) || (getPlayerCount() >= 2)) + { + return; + } + + handoffset = handnum * sizeof(struct hand); + switch0 = g_CurrentPlayer->copy_of_body_obj_header[handnum].Switches[0]; + + if (switch0 != NULL) + { + switchdata = (coord3d *) switch0->Data; + + switchpos.x = switchdata->x * g_CasingSwitchScale; + switchpos.y = switchdata->y * g_CasingSwitchScale; + switchpos.z = switchdata->z * g_CasingSwitchScale; + + matrix_4x4_set_identity_and_position(&switchpos, &mtx); + matrix_4x4_multiply_in_place(THROWMTX, &mtx); + } + else + { + matrix_4x4_copy(THROWMTX, &mtx); + } + + casing = casingCreate(cartridge_header, &mtx); + + if (casing == NULL) + { + return; + } + + rot = *((coord3d *) (&D_80035EA4)); + casing->floor_y_pos = floor_y_pos; + + if (((((weaponid == ITEM_WPPK) || (weaponid == ITEM_WPPKSIL)) || (weaponid == ITEM_TT33)) || (weaponid == ITEM_SILVERWPPK)) || (weaponid == ITEM_GOLDWPPK)) + { + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + newvely = 0.0625f; + casing->vel.x = -(((rand * g_PistolCasingHorizontalSpeed) * newvely) + g_PistolCasingHorizontalSpeed); + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + casing->vel.y = ((rand * 2.5f) * 0.0625f) + 2.5f; + casing->vel.z = frac * 0.0f; + + mtx4RotateVecInPlace(THROWMTX, &casing->vel); + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + rot.x = (((rand + rand) * g_PistolCasingRotationScaleX) * newvely) - g_PistolCasingRotationOffsetX; + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + rot.y = (((rand + rand) * g_PistolCasingRotationScaleY) * newvely) - g_PistolCasingRotationOffsetY; + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + rot.z = (((rand + rand) * g_PistolCasingRotationScaleZ) * newvely) - g_PistolCasingRotationOffsetZ; + +#if VERSION_EU + matrix_4x4_set_rotation_around_xyz(&rot, &rotmtx); + matrix_7f05842c_eu(&rotmtx, casing->rot_velocity_mtx); + if (handoffset); +#else + matrix_4x4_set_rotation_around_xyz(&rot, &casing->rot_velocity_mtx); +#endif + +#if VERSION_EU + randlimit = ((s32) ((randomGetNext() >> 24) * 0x158679)) >> 10; + randlimit = randlimit + 0x158679; + randval = randomGetNext(); + oldvely = casing->vel.y; + frac = ((f32) ((u32) (randval % randlimit))) / g_PistolCasingRandomDivisor; +#else + randlimit = (((s32) ((randomGetNext() >> 24) * 0x158679)) >> 10) + 0x158679; + new_var = randlimit; + randval = randomGetNext(); + oldvely = casing->vel.y; + frac = ((f32) ((u32) (randval % new_var))) / g_PistolCasingRandomDivisor; +#endif + newvely = oldvely - (frac * g_PistolCasingGravity); + + casing->vel.y = newvely; + casing->pos.y += (frac * (oldvely + newvely)) * 0.5f; + casing->pos.x += frac * casing->vel.x; + casing->pos.z += frac * casing->vel.z; + + // Keep the 0 + 1 for matching. + if (g_ClockTimer >= (0 + 1)) + { + casing->vel.x += (THROWPOS(0) - THROWPREV(0)) / g_GlobalTimerDelta; + casing->vel.y += (THROWPOS(1) - THROWPREV(1)) / g_GlobalTimerDelta; + casing->vel.z += (THROWPOS(2) - THROWPREV(2)) / g_GlobalTimerDelta; + } + } + else + { + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + casing->vel.x = -(((rand * g_RifleCasingHorizontalSpeed) * 0.125f) + g_RifleCasingHorizontalSpeed); + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + casing->vel.y = ((rand * g_RifleCasingVerticalSpeed) * 0.125f) + g_RifleCasingVerticalSpeed; + casing->vel.z = 0.0f; + + mtx4RotateVecInPlace(THROWMTX, &casing->vel); + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + rot.x = (((rand + rand) * g_RifleCasingRotationScaleX) * 0.0625f) - g_RifleCasingRotationOffsetX; + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + rot.y = (((rand + rand) * g_RifleCasingRotationScaleY) * 0.0625f) - g_RifleCasingRotationOffsetY; + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + rot.z = (((rand + rand) * g_RifleCasingRotationScaleZ) * 0.0625f) - g_RifleCasingRotationOffsetZ; + +#if VERSION_EU + matrix_4x4_set_rotation_around_xyz(&rot, &rotmtx); + matrix_7f05842c_eu(&rotmtx, casing->rot_velocity_mtx); + if (handoffset); +#else + matrix_4x4_set_rotation_around_xyz(&rot, &casing->rot_velocity_mtx); +#endif + randval = ((s32) ((randomGetNext() >> 24) * 0x158679)) >> 10; +#if VERSION_EU + randval = randval + 0x158679; + randlimit = randomGetNext(); + oldvely = (&casing->vel)->y; + frac = ((f32) ((u32) (randlimit % randval))) / g_RifleCasingRandomDivisor; +#else + randlimit = randval + 0x158679; + randval = randomGetNext(); + oldvely = (&casing->vel)->y; + frac = ((f32) ((u32) (randval % randlimit))) / g_RifleCasingRandomDivisor; +#endif + newvely = (casing->vel.y = oldvely - (frac * g_RifleCasingGravity)); + + casing->pos.y += (frac * (oldvely + newvely)) * 0.5f; + casing->pos.x += frac * casing->vel.x; + casing->pos.z += frac * casing->vel.z; + + if (g_ClockTimer > 0) + { + casing->vel.x += (THROWPOS(0) - THROWPREV(0)) / g_GlobalTimerDelta; + casing->vel.y += (THROWPOS(1) - THROWPREV(1)) / g_GlobalTimerDelta; + casing->vel.z += (THROWPOS(2) - THROWPREV(2)) / g_GlobalTimerDelta; + } + } + + if (handoffset); +} +#endif + + + +/* ===== merged from gun2.c ===== */ + +#if VERSION_EU +extern const f32 g_GunSightAspectRatio; +#endif +extern ALSoundState *g_CasingSfxState; +extern u32 g_DefaultCasingModelRenderData[]; + +#define AMMO_RELATED_MAX 30 +extern AmmoStats ammo_related[AMMO_RELATED_MAX]; +extern const char g_GunHudIntegerFormat[]; +extern const char aSD[]; +extern const char g_GunDeathCountFormat[]; +extern const char aSD_0[]; + + +#if defined(VERSION_US) +/** + * Address 0x7F068190. +*/ +void sub_GAME_7F068190(coord3d *zeropos, coord3d *vec) +{ + zeropos->x = 0.0f; + zeropos->y = 0.0f; + zeropos->z = 0.0f; + + transformAndNormalizeByLength2Dto3D(&g_CurrentPlayer->crosshair_angle, vec, 1.0f); +} + + +/* +* Address: 0x7f0681cc +* This function computes the angle the player's bullets are fired at +*/ +void bullet_path_from_screen_center(coord3d* arg0, coord3d* result, enum GUNHAND arg2) +{ + coord2d crosspos; + s32 unused; + f32 inaccuracy; + f32 scaledspread; + f32 randfactor; + + inaccuracy = get_ptr_item_statistics(getCurrentPlayerWeaponId(arg2))->Inaccuracy; + if ((bondwalkItemCheckBitflags(get_item_in_hand_or_watch_menu(arg2), WEAPONSTATBITFLAG_FIRST_SHOT_ACCURACY) != 0) && (g_CurrentPlayer->hands[arg2].volley == 1)) + { + // Single shots are four times more accurate + inaccuracy *= 0.25f; + } + + scaledspread = (120.0f * inaccuracy) / viGetFovY(); + + randfactor = (RANDOMFRAC() - 0.5f) * RANDOMFRAC(); + crosspos.x = g_CurrentPlayer->crosshair_angle.f[0] + randfactor * scaledspread * getPlayer_c_screenwidth() * g_GunScreenAspectRatio + / (getPlayer_c_perspaspect() * 320.0f); + + randfactor = (RANDOMFRAC() - 0.5f) * RANDOMFRAC(); + crosspos.y = g_CurrentPlayer->crosshair_angle.f[1] + randfactor * scaledspread * getPlayer_c_screenheight() + / (PAL ? (f32)(SCREEN_HEIGHT_272) : (f32)(SCREEN_HEIGHT_240)); + + arg0->x = 0.0f; + arg0->y = 0.0f; + arg0->z = 0.0f; + + // Result is a normalized vector describing the path the bullet will follow + // Can be used to compute x,y,z displacement off the center of the screen if done for a projectile + transformAndNormalizeByLength2Dto3D(&crosspos, result, 1.0f); +} + + +/* +* Address: 0x7f068420 +*/ +CasingRecord* casingCreate(ModelFileHeader* header, Mtxf* mtx) +{ + CasingRecord* entry = g_Casings; + CasingRecord* end = g_Casings + ARRAYCOUNT(g_Casings); + + while (entry < end && entry->header != NULL) + { + entry++; + } + + if (entry < end) + { + entry->header = header; + + entry->pos.x = mtx->m[3][0]; + entry->pos.y = mtx->m[3][1]; + entry->pos.z = mtx->m[3][2]; +#if VERSION_EU + matrix_7f05842c_eu(mtx, entry->rot_mtx); +#else + entry->rot_mtx.m[0][0] = mtx->m[0][0]; + entry->rot_mtx.m[0][1] = mtx->m[0][1]; + entry->rot_mtx.m[0][2] = mtx->m[0][2]; + entry->rot_mtx.m[0][3] = 0.0f; + + entry->rot_mtx.m[1][0] = mtx->m[1][0]; + entry->rot_mtx.m[1][1] = mtx->m[1][1]; + entry->rot_mtx.m[1][2] = mtx->m[1][2]; + entry->rot_mtx.m[1][3] = 0.0f; + + entry->rot_mtx.m[2][0] = mtx->m[2][0]; + entry->rot_mtx.m[2][1] = mtx->m[2][1]; + entry->rot_mtx.m[2][2] = mtx->m[2][2]; + entry->rot_mtx.m[2][3] = 0.0f; + + entry->rot_mtx.m[3][0] = 0.0f; + entry->rot_mtx.m[3][1] = 0.0f; + entry->rot_mtx.m[3][2] = 0.0f; + entry->rot_mtx.m[3][3] = 1.0f; +#endif + return entry; + } + + return NULL; +} +#endif + + +#if VERSION_EU +#else +#endif + + + + +/** + * Address: 7F068508 + * + * Ejects a spent cartridge casing from the gun in the given hand. + */ +#if !defined(VERSION_EU) +void sub_GAME_7F068508(GUNHAND handnum, f32 floor_y_pos) +{ + CasingRecord *casing; + Mtxf mtx; + ITEM_IDS weaponid; + coord3d *switchdata; + ModelFileHeader *cartridge_header; + coord3d switchpos; + ModelNode *switch0; + coord3d rot; +#if VERSION_EU + Mtxf rotmtx; +#endif + f32 rand; + s32 new_var; /* dead but declared on EU — still reserves its frame slot */ + f32 frac; +#if VERSION_EU + s32 randlimit; +#endif + f32 oldvely; + f32 newvely; +#ifndef VERSION_EU + s32 randlimit; +#endif + s32 handoffset; + u32 randval; +#if VERSION_EU + s32 pad[2]; +#endif + + weaponid = getCurrentPlayerWeaponId(handnum); + cartridge_header = get_ptr_item_statistics(weaponid)->ptr_cartridge_struct; + + // Do not create ejected casings in multiplayer. + if ((cartridge_header == NULL) || (getPlayerCount() >= 2)) + { + return; + } + + handoffset = handnum * sizeof(struct hand); + switch0 = g_CurrentPlayer->copy_of_body_obj_header[handnum].Switches[0]; + + if (switch0 != NULL) + { + switchdata = (coord3d *) switch0->Data; + + switchpos.x = switchdata->x * g_CasingSwitchScale; + switchpos.y = switchdata->y * g_CasingSwitchScale; + switchpos.z = switchdata->z * g_CasingSwitchScale; + + matrix_4x4_set_identity_and_position(&switchpos, &mtx); + matrix_4x4_multiply_in_place(THROWMTX, &mtx); + } + else + { + matrix_4x4_copy(THROWMTX, &mtx); + } + + casing = casingCreate(cartridge_header, &mtx); + + if (casing == NULL) + { + return; + } + + rot = *((coord3d *) (&D_80035EA4)); + casing->floor_y_pos = floor_y_pos; + + if (((((weaponid == ITEM_WPPK) || (weaponid == ITEM_WPPKSIL)) || (weaponid == ITEM_TT33)) || (weaponid == ITEM_SILVERWPPK)) || (weaponid == ITEM_GOLDWPPK)) + { + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + newvely = 0.0625f; + casing->vel.x = -(((rand * g_PistolCasingHorizontalSpeed) * newvely) + g_PistolCasingHorizontalSpeed); + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + casing->vel.y = ((rand * 2.5f) * 0.0625f) + 2.5f; + casing->vel.z = frac * 0.0f; + + mtx4RotateVecInPlace(THROWMTX, &casing->vel); + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + rot.x = (((rand + rand) * g_PistolCasingRotationScaleX) * newvely) - g_PistolCasingRotationOffsetX; + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + rot.y = (((rand + rand) * g_PistolCasingRotationScaleY) * newvely) - g_PistolCasingRotationOffsetY; + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + rot.z = (((rand + rand) * g_PistolCasingRotationScaleZ) * newvely) - g_PistolCasingRotationOffsetZ; + +#if VERSION_EU + matrix_4x4_set_rotation_around_xyz(&rot, &rotmtx); + matrix_7f05842c_eu(&rotmtx, casing->rot_velocity_mtx); + if (handoffset); +#else + matrix_4x4_set_rotation_around_xyz(&rot, &casing->rot_velocity_mtx); +#endif + +#if VERSION_EU + randlimit = ((s32) ((randomGetNext() >> 24) * 0x158679)) >> 10; + randlimit = randlimit + 0x158679; + randval = randomGetNext(); + oldvely = casing->vel.y; + frac = ((f32) ((u32) (randval % randlimit))) / g_PistolCasingRandomDivisor; +#else + randlimit = (((s32) ((randomGetNext() >> 24) * 0x158679)) >> 10) + 0x158679; + new_var = randlimit; + randval = randomGetNext(); + oldvely = casing->vel.y; + frac = ((f32) ((u32) (randval % new_var))) / g_PistolCasingRandomDivisor; +#endif + newvely = oldvely - (frac * g_PistolCasingGravity); + + casing->vel.y = newvely; + casing->pos.y += (frac * (oldvely + newvely)) * 0.5f; + casing->pos.x += frac * casing->vel.x; + casing->pos.z += frac * casing->vel.z; + + // Keep the 0 + 1 for matching. + if (g_ClockTimer >= (0 + 1)) + { + casing->vel.x += (THROWPOS(0) - THROWPREV(0)) / g_GlobalTimerDelta; + casing->vel.y += (THROWPOS(1) - THROWPREV(1)) / g_GlobalTimerDelta; + casing->vel.z += (THROWPOS(2) - THROWPREV(2)) / g_GlobalTimerDelta; + } + } + else + { + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + casing->vel.x = -(((rand * g_RifleCasingHorizontalSpeed) * 0.125f) + g_RifleCasingHorizontalSpeed); + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + casing->vel.y = ((rand * g_RifleCasingVerticalSpeed) * 0.125f) + g_RifleCasingVerticalSpeed; + casing->vel.z = 0.0f; + + mtx4RotateVecInPlace(THROWMTX, &casing->vel); + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + rot.x = (((rand + rand) * g_RifleCasingRotationScaleX) * 0.0625f) - g_RifleCasingRotationOffsetX; + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + rot.y = (((rand + rand) * g_RifleCasingRotationScaleY) * 0.0625f) - g_RifleCasingRotationOffsetY; + + rand = ((f32) ((u32) randomGetNext())) * 2.3283064e-10f; + rot.z = (((rand + rand) * g_RifleCasingRotationScaleZ) * 0.0625f) - g_RifleCasingRotationOffsetZ; + +#if VERSION_EU + matrix_4x4_set_rotation_around_xyz(&rot, &rotmtx); + matrix_7f05842c_eu(&rotmtx, casing->rot_velocity_mtx); + if (handoffset); +#else + matrix_4x4_set_rotation_around_xyz(&rot, &casing->rot_velocity_mtx); +#endif + randval = ((s32) ((randomGetNext() >> 24) * 0x158679)) >> 10; +#if VERSION_EU + randval = randval + 0x158679; + randlimit = randomGetNext(); + oldvely = (&casing->vel)->y; + frac = ((f32) ((u32) (randlimit % randval))) / g_RifleCasingRandomDivisor; +#else + randlimit = randval + 0x158679; + randval = randomGetNext(); + oldvely = (&casing->vel)->y; + frac = ((f32) ((u32) (randval % randlimit))) / g_RifleCasingRandomDivisor; +#endif + newvely = (casing->vel.y = oldvely - (frac * g_RifleCasingGravity)); + + casing->pos.y += (frac * (oldvely + newvely)) * 0.5f; + casing->pos.x += frac * casing->vel.x; + casing->pos.z += frac * casing->vel.z; + + if (g_ClockTimer > 0) + { + casing->vel.x += (THROWPOS(0) - THROWPREV(0)) / g_GlobalTimerDelta; + casing->vel.y += (THROWPOS(1) - THROWPREV(1)) / g_GlobalTimerDelta; + casing->vel.z += (THROWPOS(2) - THROWPREV(2)) / g_GlobalTimerDelta; + } + } + + if (handoffset); +} +#endif + + +extern const f32 g_CasingGravity; +extern const f32 g_CasingModelScale; +extern const f32 g_CasingMinMatrixTranslation; +extern const f32 g_CasingMaxMatrixTranslation; + +void update_bullet_casing(CasingRecord* casing) +{ + f32 new_val_y; + f32 delta; + s32 i; + struct player* current_player; + + delta = g_GlobalTimerDelta; + new_val_y = casing->vel.y - (delta * g_CasingGravity); + + casing->pos.y += delta * 0.5f * (casing->vel.y + new_val_y); + + if (casing->pos.y < casing->floor_y_pos) + { +#if defined(BUGFIX_R1) + if (g_CasingSfxState == 0 && (g_ClockTimer > 0)) +#else + if (g_CasingSfxState == 0) +#endif + { + if ((g_CurrentPlayer->hands[0].weapon_action_state != GUN_ANIM_STATE_FIRE) && (g_CurrentPlayer->hands[1].weapon_action_state != GUN_ANIM_STATE_FIRE)) + { + // Play bullet casing rolling on floor sound + sndPlaySfx((struct ALBankAlt_s* ) g_musicSfxBufferPtr, CART_SPENT_SFX, (ALSoundState* ) &g_CasingSfxState); + } + } + + // This casing is removed and not updated anymore + casing->header = NULL; + return; + } + + casing->vel.y = new_val_y; + casing->pos.x += delta * casing->vel.x; + casing->pos.z += delta * casing->vel.z; + + for (i = 0; i < g_ClockTimer; i++) + { +#if defined(VERSION_US) || defined(VERSION_JP) + matrix_4x4_multiply_homogeneous_in_place(&casing->rot_velocity_mtx, &casing->rot_mtx); +#else + matrix_4x4_multiply_homogeneous_in_place_eu(casing->rot_velocity_mtx, casing->rot_mtx); +#endif + } +} + + +void update_bullet_casings(void) +{ + CasingRecord* end = g_Casings + ARRAYCOUNT(g_Casings); + CasingRecord* entry = g_Casings; + + while (entry < end) + { + if (entry->header) + { + update_bullet_casing(entry); + } + + entry++; + } +} + +typedef struct ModelHead { + s16 unk00; + s16 rwdatalen; + void *chr; + ModelFileHeader *obj; + RenderPosView *render_pos; + union ModelRwData **datas; + f32 scale; + Model *attachedto; + ModelNode *attachedto_objinst; +} ModelHead; + +void sub_GAME_7F068EC4(CasingRecord *casing, Gfx **gdl) +{ + Gfx *savedgdl = *gdl; + ModelFileHeader *model_header = casing->header; + RenderPosView *model_matrices = dynAllocate(model_header->numMatrices * sizeof(RenderPosView)); + ModelHead model; + ModelRenderData render_data = *(ModelRenderData *)g_DefaultCasingModelRenderData; + Mtxf casing_model_mtx; + s32 axis_offset; + s32 matrix_translation_in_range = TRUE; + f32 max_matrix_translation; + f32 model_scale_or_min_translation; + u8 *matrix_axis_ptr; + + modelCalculateRwDataLen(model_header); + modelInit((Model *)&model, model_header, NULL); + + model.render_pos = model_matrices; + +#if defined(VERSION_EU) + matrix_4x4_copy_eu(casing->rot_mtx, casing_model_mtx.m); +#else + matrix_4x4_copy(&casing->rot_mtx, &casing_model_mtx); +#endif + + model_scale_or_min_translation = g_CasingModelScale; + matrix_scalar_multiply(model_scale_or_min_translation, &casing_model_mtx); + + matrix_4x4_set_position(&casing->pos, &casing_model_mtx); + + matrix_4x4_multiply_homogeneous( + camGetWorldToScreenMtxf(), + &casing_model_mtx, + (Mtxf *)model.render_pos); + + model_scale_or_min_translation = g_CasingMinMatrixTranslation; + max_matrix_translation = g_CasingMaxMatrixTranslation; + + axis_offset = 0; + matrix_axis_ptr = (u8 *)model.render_pos; + + // Offset 0x30 is m[3][0]; advancing the pointer checks translation X, Y and Z. + while (axis_offset != 12) + { + if (max_matrix_translation < *(f32 *)(matrix_axis_ptr + 0x30)) + { + matrix_translation_in_range = FALSE; + } + else if (*(f32 *)(matrix_axis_ptr + 0x30) < model_scale_or_min_translation) + { + matrix_translation_in_range = FALSE; + } + + axis_offset += 4; + matrix_axis_ptr += 4; + } + + if (matrix_translation_in_range) + { + render_data.zbufferenabled = 0; + render_data.gdl = savedgdl; + render_data.mtxlist = (Mtxf *)model_matrices; + render_data.PropType = PROP_TYPE_WEAPON; + + render_data.envcolour.word = + ((g_CurrentPlayer->tileColor.a | + (g_CurrentPlayer->tileColor.r << 24)) | + (g_CurrentPlayer->tileColor.g << 16)) | + (g_CurrentPlayer->tileColor.b << 8); + + subdraw(&render_data, (Model *)&model); + + *gdl = render_data.gdl; + + bondviewTransformManyPosToViewMatrix(model_matrices, model_header->numMatrices); + } +} + + +// Address: 0x7F06908C +void gunRenderCasings(Gfx **gdl) +{ + CasingRecord* end = g_Casings + ARRAYCOUNT(g_Casings); + CasingRecord* entry = g_Casings; + + while (entry < end) + { + if (entry->header) + { + sub_GAME_7F068EC4(entry, gdl); + } + + entry++; + } +} + + +void gunSetGunAmmoVisible(s32 reason, bool enable) { + + if (enable) + { + g_CurrentPlayer->gunammooff &= ~reason; + return; + } + + g_CurrentPlayer->gunammooff |= reason; +} + + + +void give_cur_player_ammo(s32 ammo_type, s32 ammo_amount) { + enum ITEM_IDS weapon_id; + s32 max_ammo; + + weapon_id = getCurrentPlayerWeaponId(GUNRIGHT); + if ((get_ammo_type_for_weapon(weapon_id) == ammo_type) && (bondwalkItemCheckBitflags(weapon_id, WEAPONSTATBITFLAG_AMMO_CLIP_LIMIT) != 0)) + { + g_CurrentPlayer->hands[0].weapon_ammo_in_magazine += ammo_amount; + if (get_ptr_item_statistics(weapon_id)->MagSize < g_CurrentPlayer->hands[0].weapon_ammo_in_magazine) + { + g_CurrentPlayer->hands[0].weapon_ammo_in_magazine = (s32) get_ptr_item_statistics(weapon_id)->MagSize; + } + g_CurrentPlayer->ammoheldarr[ammo_type] = 0; + return; + } + + max_ammo = ammo_related[ammo_type].MaxAmmo; + if (max_ammo < ammo_amount) + { + g_CurrentPlayer->ammoheldarr[ammo_type] = max_ammo; + return; + } + + g_CurrentPlayer->ammoheldarr[ammo_type] = ammo_amount; +} + + + + +s32 check_cur_player_ammo_amount_in_inventory(AMMOTYPE ammotype) { + return g_CurrentPlayer->ammoheldarr[ammotype]; +} + +s32 currentPlayerGetAmmoCount(AMMOTYPE ammotype) { + + s32 total_ammo = check_cur_player_ammo_amount_in_inventory(ammotype); + + if (get_ammo_type_for_weapon(getCurrentPlayerWeaponId(GUNRIGHT)) == ammotype) { + total_ammo += get_ammo_in_hands_magazine(GUNRIGHT); + } + + if (get_ammo_type_for_weapon(getCurrentPlayerWeaponId(GUNLEFT)) == ammotype) { + total_ammo += get_ammo_in_hands_magazine(GUNLEFT); + } + + return total_ammo; +} + + + +s32 get_max_ammo_for_type(s32 arg0) +{ + return ammo_related[arg0].MaxAmmo; +} + + + + +void set_max_ammo_for_cur_player(void) +{ + s32 ammo_type; + + for (ammo_type = 0; ammo_type < AMMO_RELATED_MAX; ammo_type++) + { + give_cur_player_ammo(ammo_type, ammo_related[ammo_type].MaxAmmo); + } +} + + + +s32 get_ammo_in_hands_magazine(GUNHAND hand) { + return g_CurrentPlayer->hands[hand].weapon_ammo_in_magazine; +} + + + +s32 get_ammo_in_hands_weapon(enum GUNHAND hand) +{ + s32 weapon_id; + s32 ammo_count; + + weapon_id = getCurrentPlayerWeaponId(hand); + ammo_count = get_ammo_count_for_weapon(weapon_id); + + if ((weapon_id == ITEM_SHOTGUN) || (weapon_id == ITEM_AUTOSHOT)) + { + s32 other_weapon_id; + other_weapon_id = getCurrentPlayerWeaponId(1 - hand); + + if ((other_weapon_id == ITEM_SHOTGUN) || (other_weapon_id == ITEM_AUTOSHOT)) + { + return ammo_count - g_CurrentPlayer->hands[1 - hand].numvisibleshells; + } + + /* I don't know why there's an extra return here, but it's needed to match */ + return ammo_count; + } + + return ammo_count; +} + + + +s32 get_ammo_type_for_weapon(ITEM_IDS weapon) { + return get_ptr_item_statistics(weapon)->AmmoType; +} + +s32 get_ammo_count_for_weapon(ITEM_IDS weapon) { + WeaponStats *weaponstats = get_ptr_item_statistics(weapon); + return g_CurrentPlayer->ammoheldarr[weaponstats->AmmoType]; +} + +void add_ammo_to_weapon(ITEM_IDS weapon, s32 ammo) { + give_cur_player_ammo(get_ptr_item_statistics(weapon)->AmmoType, ammo); +} + +s32 get_max_ammo_for_weapon(enum ITEM_IDS weapon) +{ + return ammo_related[get_ptr_item_statistics(weapon)->AmmoType].MaxAmmo; +} + + +Gfx *microcode_generation_ammo_related(Gfx *gdl, struct sImageTableEntry *tconfig, f32 x, f32 y, f32 arg4, s32 arg5, f32 arg6, s32 arg7, s32 red, s32 green, s32 blue, s32 alpha) +{ + f32 xy[2]; + f32 halfed[2]; + + gDPSetColorDither(gdl++, G_CD_DISABLE); + gDPSetTexturePersp(gdl++, G_TP_NONE); + gDPSetAlphaCompare(gdl++, G_AC_NONE); + gDPSetTextureLOD(gdl++, G_TL_TILE); + gDPSetTextureFilter(gdl++, G_TF_POINT); + gDPSetTextureConvert(gdl++, G_TC_FILT); + gDPSetTextureLUT(gdl++, G_TT_NONE); + + xy[0] = ((u32)tconfig->width * 0.5f) - (f32)(tconfig->width / 2); + + if (arg5 != 0) + { + xy[0] = -xy[0]; + } + + xy[0] = xy[0] + x; + + if (0.0f <= y) + { + xy[1] = y - (((f32) ((u32) tconfig->height)) * 0.5f); + } + else + { + xy[1] = -((((f32)((u32)tconfig->height)) * 0.5f) - ((f32)(tconfig->height / 2))); + xy[1] = arg4 + xy[1]; + xy[1] = xy[1] + arg6; + } + + halfed[0] = ((f32) ((u32) tconfig->width)) * 0.5f; + halfed[1] = ((f32) ((u32) tconfig->height)) * 0.5f; + + gDPPipeSync(gdl++); + gDPSetCycleType(gdl++, G_CYC_1CYCLE); + gDPSetRenderMode(gdl++, G_RM_XLU_SURF, G_RM_XLU_SURF2); + gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); + gDPSetPrimColor(gdl++, 0, 0, 0, 0, 0, 0); + gDPFillRectangle(gdl++, ((s32)(xy[0] - halfed[0])) - 1, ((s32)(xy[1] - halfed[1])) - 1, ((s32)(xy[0] + halfed[0])) + 1, ((s32)(xy[1] + halfed[1])) + 1); + + texSelect(&gdl, tconfig, (arg7 != 0) ? (2) : (1), 0, 0); + display_image_at_position(&gdl, xy, halfed, tconfig->width, tconfig->height, 0, 0, 1, red, green, blue, alpha, 0 < tconfig->level, 0); + + gDPPipeSync(gdl++); + gDPSetColorDither(gdl++, G_CD_BAYER); + gDPSetTexturePersp(gdl++, G_TP_PERSP); + gDPSetAlphaCompare(gdl++, G_AC_NONE); + gDPSetTextureLOD(gdl++, G_TL_LOD); + gDPSetTextureFilter(gdl++, G_TF_BILERP); + gDPSetTextureConvert(gdl++, G_TC_FILT); + gDPSetTextureLUT(gdl++, G_TT_NONE); + + return gdl; +} + + +/** + * Address: TODO + * WARNING: This function is missing a "return". This will cause bugs on other compilers. + */ +Gfx *set_rgba_redirect_generate_microcode(Gfx *gdl, sImageTableEntry *tconfig, f32 x, f32 y, f32 arg4, s32 arg5, f32 arg6, s32 arg7) +{ + microcode_generation_ammo_related(gdl, tconfig, x, y, arg4, arg5, arg6, arg7, 0xff, 0xff, 0xff, 0xff); +} + + +/** + * Address: TODO + */ +Gfx *gunDrawHudString(Gfx *gdl, s8 *text, s32 x, s32 halign, s32 y, s32 valign, bool outline) +{ + s32 x1; + s32 y1; + s32 x2; + s32 y2; + s32 textheight; + s32 textwidth; + + x1 = 0; + y1 = 0; + x2 = 0; + y2 = 0; + textwidth = 0; + textheight = 0; + + textMeasure(&textheight, &textwidth, text, ptrFontBankGothicChars, ptrFontBankGothic, 0); + + if (halign == HUDHALIGN_LEFT) { // left + x2 = x + textwidth; + x1 = x; + } else if (halign == HUDHALIGN_RIGHT) { // right + x1 = x - textwidth; + x2 = x; + } else if (halign == HUDHALIGN_MIDDLE) { // middle + x2 = x + textwidth / 2; + x1 = x2 - textwidth; + } + + if (valign == HUDVALIGN_TOP) { // top + y2 = y + textheight; + y1 = y; + } else if (valign == HUDVALIGN_BOTTOM) { // bottom + y1 = y - textheight; + y2 = y; + } else if (valign == HUDVALIGN_MIDDLE) { // middle + y2 = y + textheight / 2; + y1 = y2 - textheight; + } + + gdl = draw_blackbox_to_screen(gdl, &x1, &y1, &x2, &y2); + + if (outline) { + gdl = textRenderOutlined(gdl, &x1, &y1, text, ptrFontBankGothicChars, ptrFontBankGothic, -1, 0x646464FF, (s32) viGetX(), viGetY(), 0, 0); + } else { + gdl = textRender(gdl, &x1, &y1, text, ptrFontBankGothicChars, ptrFontBankGothic, 0xFF00B0, (s32) viGetX(), viGetY(), 0, 0); + } + + return gdl; +} + + +/** + * Address: TODO + */ +Gfx *gunDrawHudInteger(Gfx *gdl, s32 value, s32 x, s32 halign, s32 y, s32 valign, bool outline) +{ + char buffer[12]; + sprintf(buffer, g_GunHudIntegerFormat, value); + return gunDrawHudString(gdl, buffer, x, halign, y, valign, outline); +} + + +/** + * Draw magazine ammo number, ammo type icon, and total ammo number at the bottom right of the viewport. + * Render an additional ammo counter at the bottom left of the viewport when dual wielding. + */ +Gfx *generate_ammo_total_microcode(Gfx *gdl) +{ + ITEM_IDS weapon_left; + ITEM_IDS weapon_right; + s32 ammotype; + s32 leftx; + s32 rightx; + s32 reserveammo; + s32 magammo; + u32 imageoffset_r; + s32 textwidth_r; + u32 imageoffset_l; + s32 textwidth_l; + + if (g_CurrentPlayer->gunammooff == 0) + { + if (g_CurrentPlayer->mpmenuon == 0) + { + weapon_left = getCurrentPlayerWeaponId(GUNLEFT); + weapon_right = getCurrentPlayerWeaponId(GUNRIGHT); + + if (getPlayerCount() < 3) + { + leftx = 59; + rightx = 59; + } + else if (get_cur_playernum() & 1) + { + leftx = 43; + rightx = 127; + } + else + { + leftx = 59; + rightx = 109; + } + + if (weapon_right != ITEM_UNARMED) + { + ammotype = get_ammo_type_for_weapon(weapon_right); + + if (ammotype != 0 + && g_CurrentPlayer->hands[0].weapon_action_state != GUN_ANIM_STATE_SWITCH_SWAP + && g_CurrentPlayer->hands[0].weapon_action_state != GUN_ANIM_STATE_SWITCH_HOLD + && !bondwalkItemCheckBitflags(weapon_right, WEAPONSTATBITFLAG_HIDE_AMMO_DISPLAY)) + { + imageoffset_r = ammo_related[ammotype].IconImage; + textwidth_r = 5; + + if (imageoffset_r != 0) + { + imageoffset_r += globalbank_rdram_offset; + gdl = set_rgba_redirect_generate_microcode(gdl, (u8 *)imageoffset_r, (getPlayer_c_screenleft() + getPlayer_c_screenwidth()) - (f32)rightx, -1.0f, +#if defined(VERSION_EU) + (viGetViewTop() + viGetViewHeight()) - 30, 0, +#else + (viGetViewTop() + viGetViewHeight()) - 20, 0, +#endif + ammo_related[ammotype].IconYOffset, 1); + textwidth_r = ((u8 *)imageoffset_r)[4]; + } + + gdl = microcode_constructor(gdl); + + if (bondwalkItemCheckBitflags(weapon_right, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) + { + magammo = 0; + reserveammo = g_CurrentPlayer->ammoheldarr[ammotype] + g_CurrentPlayer->hands[0].weapon_ammo_in_magazine; + if (weapon_left == weapon_right) + { + reserveammo += g_CurrentPlayer->hands[1].weapon_ammo_in_magazine; + } + } + else + { + magammo = g_CurrentPlayer->hands[0].weapon_ammo_in_magazine; + reserveammo = g_CurrentPlayer->ammoheldarr[ammotype]; + } + + if (!bondwalkItemCheckBitflags(weapon_right, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) + { + gdl = gunDrawHudInteger(gdl, magammo, (((viGetViewLeft() + viGetViewWidth()) - rightx) - (textwidth_r / 2)) - 4, 0, +#if defined(VERSION_EU) + (viGetViewTop() + viGetViewHeight()) - 28, 2, 1); +#else + (viGetViewTop() + viGetViewHeight()) - 18, 2, 1); +#endif + } + + if (reserveammo > 0 || bondwalkItemCheckBitflags(weapon_right, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) + { + gdl = gunDrawHudInteger(gdl, reserveammo, (((viGetViewLeft() + viGetViewWidth()) - rightx) + ((textwidth_r + 1) / 2)) + 3, 1, +#if defined(VERSION_EU) + (viGetViewTop() + viGetViewHeight()) - 28, 2, 1); +#else + (viGetViewTop() + viGetViewHeight()) - 18, 2, 1); +#endif + } + + gdl = combiner_bayer_lod_perspective(gdl); + } + } + + if (weapon_left != ITEM_UNARMED) + { + ammotype = get_ammo_type_for_weapon(weapon_left); + + if (ammotype != 0 + && g_CurrentPlayer->hands[1].weapon_action_state != GUN_ANIM_STATE_SWITCH_SWAP + && g_CurrentPlayer->hands[1].weapon_action_state != GUN_ANIM_STATE_SWITCH_HOLD + && !bondwalkItemCheckBitflags(weapon_left, WEAPONSTATBITFLAG_HIDE_AMMO_DISPLAY)) + { + imageoffset_l = ammo_related[ammotype].IconImage; + textwidth_l = 5; + + if (imageoffset_l != 0) + { + imageoffset_l += globalbank_rdram_offset; + gdl = set_rgba_redirect_generate_microcode(gdl, (u8 *)imageoffset_l, getPlayer_c_screenleft() + (f32)leftx, -1.0f, +#if defined(VERSION_EU) + (viGetViewTop() + viGetViewHeight()) - 30, 1, +#else + (viGetViewTop() + viGetViewHeight()) - 20, 1, +#endif + ammo_related[ammotype].IconYOffset, 1); + textwidth_l = ((u8 *)imageoffset_l)[4]; + } + + gdl = microcode_constructor(gdl); + + if (bondwalkItemCheckBitflags(weapon_left, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) + { + magammo = 0; + reserveammo = g_CurrentPlayer->ammoheldarr[ammotype] + g_CurrentPlayer->hands[1].weapon_ammo_in_magazine; + if (weapon_left == weapon_right) + { + reserveammo += g_CurrentPlayer->hands[0].weapon_ammo_in_magazine; + } + } + else + { + magammo = g_CurrentPlayer->hands[1].weapon_ammo_in_magazine; + reserveammo = g_CurrentPlayer->ammoheldarr[ammotype]; + } + + if (!bondwalkItemCheckBitflags(weapon_left, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) + { + gdl = gunDrawHudInteger(gdl, magammo, ((viGetViewLeft() + leftx) + (textwidth_l / 2)) + 3, 1, +#if defined(VERSION_EU) + (viGetViewTop() + viGetViewHeight()) - 28, 2, 1); +#else + (viGetViewTop() + viGetViewHeight()) - 18, 2, 1); +#endif + } + + if (reserveammo > 0 || bondwalkItemCheckBitflags(weapon_left, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) + { + gdl = gunDrawHudInteger(gdl, reserveammo, ((viGetViewLeft() + leftx) - ((textwidth_l + 1) / 2)) - 4, 0, +#if defined(VERSION_EU) + (viGetViewTop() + viGetViewHeight()) - 28, 2, 1); +#else + (viGetViewTop() + viGetViewHeight()) - 18, 2, 1); +#endif + } + + gdl = combiner_bayer_lod_perspective(gdl); + } + } + } + } + + return gdl; +} + + +/** + * Address: 7F06A334 + */ +Gfx *gunDrawWatchAmmoDisplay(Gfx *gdl) +{ + ITEM_IDS offhanditem; + ITEM_IDS item; + s32 ammotype; + s32 reserveammo; + s32 magammo; + u32 imageoffset; + s32 textwidth; + s32 pad; + + offhanditem = getCurrentPlayerWeaponId(1); + item = getCurrentPlayerWeaponId(0); + + if (item != ITEM_UNARMED) + { + ammotype = get_ammo_type_for_weapon(item); + + if (ammotype != 0 + && g_CurrentPlayer->hands[GUNRIGHT].weapon_action_state != GUN_ANIM_STATE_SWITCH_SWAP + && g_CurrentPlayer->hands[GUNRIGHT].weapon_action_state != GUN_ANIM_STATE_SWITCH_HOLD + && !bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_HIDE_AMMO_DISPLAY)) + { + imageoffset = ammo_related[ammotype].IconImage; + textwidth = 5; + + get_ptr_item_statistics(item); + + if (imageoffset != 0) + { + imageoffset += globalbank_rdram_offset; + + // Draw the ammo icon +#if defined(VERSION_EU) + gdl = set_rgba_redirect_generate_microcode(gdl, (u8 *)imageoffset, 200.0f, 208.0f, (viGetViewTop() + viGetViewHeight()) - 30, 0, ammo_related[ammotype].IconYOffset, 1); +#else + gdl = set_rgba_redirect_generate_microcode(gdl, (u8 *)imageoffset, 200.0f, 180.0f, (viGetViewTop() + viGetViewHeight()) - 20, 0, ammo_related[ammotype].IconYOffset, 1); +#endif + + textwidth = ((u8 *)imageoffset)[4]; + } + + gdl = microcode_constructor(gdl); + + if (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) + { + magammo = 0; + reserveammo = g_CurrentPlayer->ammoheldarr[ammotype] + g_CurrentPlayer->hands[0].weapon_ammo_in_magazine; + + if (offhanditem == item) + { + reserveammo += g_CurrentPlayer->hands[1].weapon_ammo_in_magazine; + } + } + else + { + magammo = g_CurrentPlayer->hands[0].weapon_ammo_in_magazine; + reserveammo = g_CurrentPlayer->ammoheldarr[ammotype]; + } + + if (!bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) + { + // Draw the magazine ammo count. +#if defined(VERSION_EU) + gdl = gunDrawHudInteger(gdl, magammo, 196 - (textwidth / 2), 0, 205, 2, 0); +#else + gdl = gunDrawHudInteger(gdl, magammo, 196 - (textwidth / 2), 0, 177, 2, 0); +#endif + } + + if (reserveammo > 0 || bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_NO_CLIP_RELOADS)) + { + // Draw the reserve ammo count. +#if defined(VERSION_EU) + gdl = gunDrawHudInteger(gdl, reserveammo, 203 + ((textwidth + 1) / 2), 1, 205, 2, 0); +#else + gdl = gunDrawHudInteger(gdl, reserveammo, 203 + ((textwidth + 1) / 2), 1, 177, 2, 0); +#endif + } + + gdl = combiner_bayer_lod_perspective(gdl); + } + } + + return gdl; +} + + +void gunSetSightVisible(s32 reason, bool visible) +{ + if (visible) + { + g_CurrentPlayer->gunsightmode &= ~reason; + return; + } + + g_CurrentPlayer->gunsightmode |= reason; +} + + +void gunDrawSight(s32 *gdl) { + + s32 sp54; + f32 xypos[2]; + f32 halfedxy[2]; + + if ((g_CurrentPlayer->gunsightmode == 0) && (g_CurrentPlayer->mpmenuon == FALSE)) { + sp54 = *gdl; + texSelect(&sp54, crosshairimage, 4, 0, 0); + + xypos[0] = g_CurrentPlayer->crosshair_angle.f[0]; + xypos[1] = g_CurrentPlayer->crosshair_angle.f[1]; + halfedxy[0] = 16.0f; + halfedxy[1] = 16.0f; + + if (get_screen_ratio() == SCREEN_RATIO_16_9) { + halfedxy[0] = halfedxy[0] * 0.75f; + } +#ifdef VERSION_EU + halfedxy[1] = halfedxy[1] * g_GunSightAspectRatio; +#endif + display_image_at_position(&sp54, &xypos, &halfedxy, 0x20, 0x20, 0, 0, 1, 0xFF, 0xFF, 0xFF, 0x6E, (crosshairimage->level > 0), 0); + *gdl = sp54; + } +} + + +void inc_curplayer_hitcount_with_weapon(ITEM_IDS item, SHOT_REGISTER shot_register) { + + if (bondwalkItemCheckBitflags(item, WEAPONSTATBITFLAG_PLAYER_STAT_HIT)) { + g_playerPerm->shot_count[shot_register] = g_playerPerm->shot_count[shot_register]+1; + } +} + + +s32 get_curplayer_shot_register(SHOT_REGISTER shot_register) +{ + return g_playerPerm->shot_count[shot_register]; +} + + +void inc_cur_civilian_casualties(void) +{ + g_playerPerm->killed_civilians++; +} + + +s32 get_civilian_casualties(void) +{ + return g_playerPerm->killed_civilians; +} + + +void increment_num_kills_display_text_in_MP(void) +{ + s8 buffer[256]; + s32 time_since_kill; + s32 recent_kill_count; + s32 mission_time; + s32 unused; // needed this variable to match + + g_playerPerm->kill_count += 1; + g_CurrentPlayer->kills_this_life += 1; + + if (getPlayerCount() < 2) { return; } + + mission_time = getMissiontimer(); + sprintf(&buffer, aSD, langGet(getStringID(LGUN, GUN_STR_DA_KILLCOUNT)), g_playerPerm->kill_count); // "kill count" + +#if defined(VERSION_US) + hudmsgBottomShow(&buffer); +#elif defined(VERSION_JP) || defined(VERSION_EU) + jp_hudmsgBottomShow(&buffer); +#endif + + if (g_playerPerm->kill_count >= 2) + { + time_since_kill = mission_time - g_CurrentPlayer->last_kill_time[0]; + if (g_playerPerm->max_time_between_kills < time_since_kill) + { + g_playerPerm->max_time_between_kills = time_since_kill; + } + + if (time_since_kill < g_playerPerm->min_time_between_kills) + { + g_playerPerm->min_time_between_kills = time_since_kill; + } + } + + recent_kill_count = 1; + g_CurrentPlayer->last_kill_time[3] = g_CurrentPlayer->last_kill_time[2]; + g_CurrentPlayer->last_kill_time[2] = g_CurrentPlayer->last_kill_time[1]; + g_CurrentPlayer->last_kill_time[1] = g_CurrentPlayer->last_kill_time[0]; + g_CurrentPlayer->last_kill_time[0] = mission_time; + + // I tried to turn this into a loop but it didn't match + if (g_CurrentPlayer->last_kill_time[1] != -1 && (g_CurrentPlayer->last_kill_time[0] - g_CurrentPlayer->last_kill_time[1]) < 0x78) + { + recent_kill_count++; + if ((g_CurrentPlayer->last_kill_time[2] != -1) && ((g_CurrentPlayer->last_kill_time[0] - g_CurrentPlayer->last_kill_time[2]) < 0x78)) + { + recent_kill_count++; + if ((g_CurrentPlayer->last_kill_time[3] != -1) && ((g_CurrentPlayer->last_kill_time[0] - g_CurrentPlayer->last_kill_time[3]) < 0x78)) + { + recent_kill_count++; + } + } + } + + if (g_playerPerm->most_killed_one_time < recent_kill_count) + { + g_playerPerm->most_killed_one_time = recent_kill_count; + } +} + + + +s32 get_curplay_killcount(void) { + return g_playerPerm->kill_count; +} + +void increment_num_times_killed_MwtGC(void){ + g_playerPerm->killed_gg_owner_count++; +} + +s32 get_times_killed_mwtgx(void) { + return g_playerPerm->killed_gg_owner_count; +} + + +void increment_num_deaths(void) +{ + char buffer[256]; + g_CurrentPlayer->deathcount = (s32) (g_CurrentPlayer->deathcount + 1); + if (getPlayerCount() >= 2) + { + if (g_CurrentPlayer->deathcount == 1) + { + sprintf(buffer, langGet(getStringID(LGUN, GUN_STR_DB_DIEDONCE_LF))); //died once + } + else + { + sprintf(buffer, g_GunDeathCountFormat, langGet(getStringID(LGUN, GUN_STR_DC_DIED)), g_CurrentPlayer->deathcount, langGet(getStringID(LGUN, GUN_STR_DD_TIMES))); //died times + } +#if defined(VERSION_JP) || defined(VERSION_EU) + jp_hudmsgBottomShow(buffer); +#else + hudmsgBottomShow(buffer); +#endif + } +} + + +s32 get_curplayer_numdeaths(void) { + return g_CurrentPlayer->deathcount; +} + +void increment_num_suicides_display_MP(void) { + char buffer[256]; + s32 time_diff; + s32 recent_kill_count; + s32 currentTime; + + g_CurrentPlayer->num_suicides += 1; + if (getPlayerCount() >= 2) { + + currentTime = getMissiontimer(); + + sprintf(&buffer, &aSD_0, langGet(getStringID(LGUN, GUN_STR_DE_SUICIDECOUNT)), g_CurrentPlayer->num_suicides); // "suicide count" + +#if defined(VERSION_JP) || defined(VERSION_EU) + jp_hudmsgBottomShow(&buffer); +#else + hudmsgBottomShow(&buffer); +#endif + + if (g_playerPerm->kill_count >= 2) { + time_diff = currentTime - g_CurrentPlayer->last_kill_time[0]; + if (g_playerPerm->max_time_between_kills < time_diff) { + g_playerPerm->max_time_between_kills = time_diff; + } + if (time_diff < g_playerPerm->min_time_between_kills) { + g_playerPerm->min_time_between_kills = time_diff; + } + } + recent_kill_count = 1; + g_CurrentPlayer->last_kill_time[3] = g_CurrentPlayer->last_kill_time[2]; + g_CurrentPlayer->last_kill_time[2] = g_CurrentPlayer->last_kill_time[1]; + g_CurrentPlayer->last_kill_time[1] = g_CurrentPlayer->last_kill_time[0]; + g_CurrentPlayer->last_kill_time[0] = currentTime; + + if ( g_CurrentPlayer->last_kill_time[1] != -1) { + + if ((g_CurrentPlayer->last_kill_time[0] - g_CurrentPlayer->last_kill_time[1]) < 0x78) { + + recent_kill_count += 1; + + if ((g_CurrentPlayer->last_kill_time[2] != -1) && ((g_CurrentPlayer->last_kill_time[0] - g_CurrentPlayer->last_kill_time[2]) < 0x78)) { + + recent_kill_count += 1; + + if ((g_CurrentPlayer->last_kill_time[3] != -1) && ((g_CurrentPlayer->last_kill_time[0] - g_CurrentPlayer->last_kill_time[3]) < 0x78)) { + recent_kill_count += 1; + } + } + } + } + + if (g_playerPerm->most_killed_one_time < recent_kill_count) { + g_playerPerm->most_killed_one_time = recent_kill_count; + } + } +} + +s32 get_curplayer_numsuicides(void) { + return g_CurrentPlayer->num_suicides; +} + +/* + * IDO emits scalar const objects to .data. The linker keeps this block directly + * after gunfire's .rodata so these values retain their original ROM layout. + */ +#if VERSION_EU +const f32 g_GunScreenAspectRatio = 20.0f / 17.0f; +#else +const f32 g_GunScreenAspectRatio = 4.0f / 3.0f; +#endif +const f32 g_CasingSwitchScale = 0.10000001f; +const f32 g_PistolCasingHorizontalSpeed = 0.5333333f; +const f32 g_PistolCasingRotationScaleX = M_TAU_F; +const f32 g_PistolCasingRotationOffsetX = M_PI_F / 8.0f; +const f32 g_PistolCasingRotationScaleY = M_TAU_F; +const f32 g_PistolCasingRotationOffsetY = M_PI_F / 8.0f; +const f32 g_PistolCasingRotationScaleZ = M_TAU_F; +const f32 g_PistolCasingRotationOffsetZ = M_PI_F / 8.0f; +#if VERSION_EU +const f32 g_PistolCasingRandomDivisor = 931050.0f; +#else +const f32 g_PistolCasingRandomDivisor = 775875.0f; +#endif +const f32 g_PistolCasingGravity = 0.2777778f; +const f32 g_RifleCasingHorizontalSpeed = 1.4166666f; +const f32 g_RifleCasingVerticalSpeed = 1.6666666f; +const f32 g_RifleCasingRotationScaleX = M_TAU_F; +const f32 g_RifleCasingRotationOffsetX = M_PI_F / 8.0f; +const f32 g_RifleCasingRotationScaleY = M_TAU_F; +const f32 g_RifleCasingRotationOffsetY = M_PI_F / 8.0f; +const f32 g_RifleCasingRotationScaleZ = M_TAU_F; +const f32 g_RifleCasingRotationOffsetZ = M_PI_F / 8.0f; +#if VERSION_EU +const f32 g_RifleCasingRandomDivisor = 931050.0f; +#else +const f32 g_RifleCasingRandomDivisor = 775875.0f; +#endif +const f32 g_RifleCasingGravity = 0.2777778f; +const f32 g_CasingGravity = 0.2777778f; +const f32 g_CasingModelScale = 0.10000001f; +const f32 g_CasingMinMatrixTranslation = -30000.0f; +const f32 g_CasingMaxMatrixTranslation = 30000.0f; +#if VERSION_EU +const f32 g_GunSightAspectRatio = 25.0f / 21.0f; +#endif diff --git a/src/game/initpathtablelinks.c b/src/game/initpathtablelinks.c index 50ece1d0..9f9f4973 100644 --- a/src/game/initpathtablelinks.c +++ b/src/game/initpathtablelinks.c @@ -459,4 +459,4 @@ void init_path_table_links(void) } } -} \ No newline at end of file +} diff --git a/src/game/line_tri_intersect.c b/src/game/line_tri_intersect.c index 4d6fb248..7fab119d 100644 --- a/src/game/line_tri_intersect.c +++ b/src/game/line_tri_intersect.c @@ -173,4 +173,4 @@ bool intersectRayTriangle(Vertex *vertex0, Vertex *vertex1, Vertex *vertex2, coo // The line reached the triangle's plane outside the triangle's three edges. return FALSE; -} \ No newline at end of file +} diff --git a/tools/__pycache__/diff_settings.cpython-312.pyc b/tools/__pycache__/diff_settings.cpython-312.pyc deleted file mode 100644 index cae2a5485bfabf8d061d190ee7423142776206c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 464 zcmZuu%SyvQ6rDV3+G-ROr8^4>62ztpZ7CF&UDmw_CCyCI(WDb*5->%uf(!q^U(j!H z)4D3z`U66CU5IyLyYs@Fd(O<6d*|_CnpFhxbMtsRhx{eQI+PX3rR5c2^o*`is#vP4 zt}T$Y)ySKFF69AXwF?|;!1RKZfNd1az-3!X`N?=lr;1w zd&7hV*iLMpG@I?!YAH?IS*#?aoQ_aVb1h#3oP3BtzI^9F*%F&+D& z5v5tliJ~CoCX|uyCTxHyTGURay_e2h-(MV@0&72AEox`$sblM{GdsGN_GX)hpL#uq qEvRoPMG;;B!M7!B0W8a1I6@MTOTGiLXd%DlTT>JzS9PUTcz*$%(0p(J diff --git a/tools/asm-processor/LICENSE b/tools/asm-processor/LICENSE deleted file mode 100644 index cf1ab25d..00000000 --- a/tools/asm-processor/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/tools/asm-processor/README.md b/tools/asm-processor/README.md deleted file mode 100644 index 89a0b665..00000000 --- a/tools/asm-processor/README.md +++ /dev/null @@ -1,139 +0,0 @@ -# asm-processor - -Pre-process .c files and post-process .o files to enable embedding MIPS assembly into IDO-compiled C. - -This repository contains both the original Python implementation and rewrite in Rust that is designed to be 1:1 behavorially equivalent with the existing Python version, but faster. - -## Installation - -Most projects traditionally have included the `asm-processor` repo as a [submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules), [subrepo](https://github.com/ingydotnet/git-subrepo), or plain copy inside their project. -This is recommended, as it ensures consistency for all project users. - -### Rust -After vendoring this repo into your repository, you will want to add a step to your project setup procedure that builds the asm-processor binary with the [Rust toolchain](https://www.rust-lang.org/tools/install). -Presuming this repo is available at `tools/asm-processor/`, the following command can be run to build the project: - -``` -cargo build --release --manifest-path tools/asm-processor/rust/Cargo.toml -``` - -This will generate the executable at `tools/asm-processor/rust/target/release/asm-processor`. The build system for your project can then be configured to run `asm-processor` from this location. - -If you prefer not to build the project yourself or require downstream users to do so, we also provide release binaries that can either be downloaded at build time or included directly in your project's repo. - -### Python -Simply vendor this repo into your repository as described above and use `build.py`. - - -## Usage - -The Python `build.py` script and Rust `asm-processor` binary accept the same syntax and command line flags. If using the Rust implementation, substitute `build.py` with `asm-processor` in the below guide. - -Let's say you have a file compiled with `-g` on the IDO compiler, that looks like this: -```c -float func4(void) { - "func4"; - return 0.2f; -} -``` - -This script enables replacing it by: -```asm -GLOBAL_ASM( -.rdata -.word 0x66756e63 # func -.word 0x34000000 # 4\0\0\0 - -.late_rodata -glabel rv -.word 0x3e4ccccd # 0.2f - -.text -glabel func4 -lui $at, %hi(rv) -jr $ra -lwc1 $f0, %lo(rv)($at) -jr $ra -nop -jr $ra -nop -) -``` - -To compile the file, run `build.py $CC -- $AS $ASFLAGS -- $CFLAGS -o out.o in.c`, where $CC points to an IDO binary (5.3/7.1 and recomp/qemu all supported), $AS is e.g. `mips-linux-gnu-as`, $ASFLAGS e.g. `-march=vr4300 -mabi=32` and $CFLAGS e.g. `-Wab,-r4300_mul -non_shared -G 0 -Xcpluscomm -g`. - -In addition to an .o file, asm-processor also generates a .d file with Makefile dependencies for .s files referenced by the input .c file. -This functionality can be disabled by passing the `--no-dep-file` flag. - -Reading assembly from file is also supported, by either `GLOBAL_ASM("file.s")` or `#pragma GLOBAL_ASM("file.s")`. - -For compatibility with common GCC macros, `INCLUDE_ASM("folder", functionname);` and `INCLUDE_RODATA("folder", functionname);` are also allowed, and equivalent to `GLOBAL_ASM("folder/functionname.s")`. - -### What is supported? - -`.text`, `.data`, `.bss` and `.rodata` sections, `.word`/`.incbin`, `.ascii`/`.asciz`, and `-g`, `-g3`, `-O1`, `-O2`, `-framepointer` and `-mips1`/`-mips2` flags to the IDO compiler. - -### What is not supported? - -* complicated assembly (.ifdef, macro declarations/calls other than `glabel`, pseudo-instructions that expand to several real instructions) -* non-IDO compilers -* `-O3` (due to function reordering) - -C `#ifdef`s only work outside of `GLOBAL_ASM` calls, but is otherwise able to replace `.ifdef`. - -### What's up with "late rodata"? - -The IDO compiler emits rodata in two passes: first array/string contents, then large literals/switch jump tables. - -Data declared within `.rdata`/`.section .rodata` will end up in the first half, and `.late_rodata`/`.section .late_rodata` in the second half. - -### How does it work? - -It's a bit of a hack! -The basic idea is replace `GLOBAL_ASM` blocks with dummy C functions/global vars of the same sections sizes as the assembly. -Then the C file gets compiled, and the dummy contents overwritten with the injected assembly. - -To accomplish this, asm-processor has logic for guessing the size of assembly contents -(which assumes the assembly isn't too complicated, e.g. no macros), -and for emitting C code of exact sizes for a bunch of different IDO compiler flags. - -The assembler code is padded with nops to line it up with its correct position in the C; -this allows C and asm ELF files to be merged easily without having to fix up e.g. symbol addresses. - -The most difficult part is `late_rodata`, which is hard to create programmatically. -asm-processor does that by emitting code that uses dummy float literals/double literals/jump tables, -assembles the late_rodata at another location of the .rodata section, then overwrites the dummy rodata. -This does require some movement of symbols and relocations, and quite a bit of care in what code to -emit and how to preserve .double alignment. - -It's worth noting some alternative ways in which asm-processor would have been implemented: -- One idea to get rid of the C/asm size estimations is to emit arbitrary code, and then move code, -symbols and relocations to the correct place after the sizes are known. -Given the machinery for `late_rodata` this wouldn't have been too difficult, and it would have the upside of improved portability. -There is a big downside, however: using dummy code of incorrect size throws off alignment and can introduce unintended padding. -Fixing this would require running multiple passes of asm-processor, with one compile per `ASM_GLOBAL`. -- Another idea is to run the compiler with -S to emit assembly, modify the emitted assembly, then run the assembler -(which in IDO's case may perform additional instruction reordering etc.). -This option has not been investigated in much detail, and would perhaps be superior to the current implementation. -It does have a few unknowns to it, e.g. instruction encoding differences between GNU `as` and IDO's assembler, -how to avoid reordering the injected assembly, and how .rodata/.late_rodata are implemented. - -### Testing - -There are a few tests to ensure you don't break anything when hacking on asm-processor: `./run-tests.sh` should exit without output if they pass, or else output a diff from previous to new version. - -Tests need the environment variable `MIPS_CC` set to point to the IDO 7.1 compiler, with Pascal support enabled. - -For example if asm-processor is cloned in the same directory as [ido static recomp](https://github.com/decompals/ido-static-recomp) and the working directory is asm-processor, tests can be run using: - -```sh -MIPS_CC=../ido-static-recomp/build/7.1/out/cc ./run-tests.sh -``` - -Or using qemu-irix (don't forget `chmod u+x qemu-irix`) to emulate IDO: - -```sh -MIPS_CC='./qemu-irix -silent -L ../ido-static-recomp/ido/7.1/ ../ido-static-recomp/ido/7.1/usr/bin/cc' ./run-tests.sh -``` - -To skip running Pascal tests, remove the `tests/*.p` glob from `run-tests.sh`. diff --git a/tools/asm-processor/add-test.sh b/tools/asm-processor/add-test.sh deleted file mode 100755 index 7aef817f..00000000 --- a/tools/asm-processor/add-test.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -WD=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) - -for A in "$@"; do - OBJDUMPFLAGS="-srt" - "$WD/compile-test.sh" "$A" python && mips-linux-gnu-objdump $OBJDUMPFLAGS "${A%.*}.o" > "${A%.*}.objdump" -done diff --git a/tools/asm-processor/asm_processor.py b/tools/asm-processor/asm_processor.py deleted file mode 100644 index b30ede30..00000000 --- a/tools/asm-processor/asm_processor.py +++ /dev/null @@ -1,1652 +0,0 @@ -#!/usr/bin/env python3 -import argparse -from collections import namedtuple -from io import StringIO -import os -from pathlib import Path -import re -import struct -import sys -import tempfile - -MAX_FN_SIZE = 100 -SLOW_CHECKS = False - -EI_NIDENT = 16 -EI_CLASS = 4 -EI_DATA = 5 -EI_VERSION = 6 -EI_OSABI = 7 -EI_ABIVERSION = 8 -STN_UNDEF = 0 - -SHN_UNDEF = 0 -SHN_ABS = 0xfff1 -SHN_COMMON = 0xfff2 -SHN_XINDEX = 0xffff -SHN_LORESERVE = 0xff00 - -STT_NOTYPE = 0 -STT_OBJECT = 1 -STT_FUNC = 2 -STT_SECTION = 3 -STT_FILE = 4 -STT_COMMON = 5 -STT_TLS = 6 - -STB_LOCAL = 0 -STB_GLOBAL = 1 -STB_WEAK = 2 - -STV_DEFAULT = 0 -STV_INTERNAL = 1 -STV_HIDDEN = 2 -STV_PROTECTED = 3 - -SHT_NULL = 0 -SHT_PROGBITS = 1 -SHT_SYMTAB = 2 -SHT_STRTAB = 3 -SHT_RELA = 4 -SHT_HASH = 5 -SHT_DYNAMIC = 6 -SHT_NOTE = 7 -SHT_NOBITS = 8 -SHT_REL = 9 -SHT_SHLIB = 10 -SHT_DYNSYM = 11 -SHT_INIT_ARRAY = 14 -SHT_FINI_ARRAY = 15 -SHT_PREINIT_ARRAY = 16 -SHT_GROUP = 17 -SHT_SYMTAB_SHNDX = 18 -SHT_MIPS_GPTAB = 0x70000003 -SHT_MIPS_DEBUG = 0x70000005 -SHT_MIPS_REGINFO = 0x70000006 -SHT_MIPS_OPTIONS = 0x7000000d - -SHF_WRITE = 0x1 -SHF_ALLOC = 0x2 -SHF_EXECINSTR = 0x4 -SHF_MERGE = 0x10 -SHF_STRINGS = 0x20 -SHF_INFO_LINK = 0x40 -SHF_LINK_ORDER = 0x80 -SHF_OS_NONCONFORMING = 0x100 -SHF_GROUP = 0x200 -SHF_TLS = 0x400 - -R_MIPS_32 = 2 -R_MIPS_26 = 4 -R_MIPS_HI16 = 5 -R_MIPS_LO16 = 6 - -MIPS_DEBUG_ST_STATIC = 2 -MIPS_DEBUG_ST_PROC = 6 -MIPS_DEBUG_ST_BLOCK = 7 -MIPS_DEBUG_ST_END = 8 -MIPS_DEBUG_ST_FILE = 11 -MIPS_DEBUG_ST_STATIC_PROC = 14 -MIPS_DEBUG_ST_STRUCT = 26 -MIPS_DEBUG_ST_UNION = 27 -MIPS_DEBUG_ST_ENUM = 28 - - -class ElfFormat: - def __init__(self, is_big_endian): - self.is_big_endian = is_big_endian - self.struct_char = ">" if is_big_endian else "<" - - def pack(self, fmt, *args): - return struct.pack(self.struct_char + fmt, *args) - - def unpack(self, fmt, data): - return struct.unpack(self.struct_char + fmt, data) - - -class ElfHeader: - """ - typedef struct { - unsigned char e_ident[EI_NIDENT]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; - } Elf32_Ehdr; - """ - - def __init__(self, data): - self.e_ident = data[:EI_NIDENT] - assert self.e_ident[EI_CLASS] == 1 # 32-bit - self.fmt = ElfFormat(is_big_endian=(self.e_ident[EI_DATA] == 2)) - self.e_type, self.e_machine, self.e_version, self.e_entry, self.e_phoff, self.e_shoff, self.e_flags, self.e_ehsize, self.e_phentsize, self.e_phnum, self.e_shentsize, self.e_shnum, self.e_shstrndx = self.fmt.unpack('HHIIIIIHHHHHH', data[EI_NIDENT:]) - assert self.e_type == 1 # relocatable - assert self.e_machine == 8 # MIPS I Architecture - assert self.e_phoff == 0 # no program header - assert self.e_shoff != 0 # section header - assert self.e_shstrndx != SHN_UNDEF - - def to_bin(self): - return self.e_ident + self.fmt.pack('HHIIIIIHHHHHH', self.e_type, - self.e_machine, self.e_version, self.e_entry, self.e_phoff, - self.e_shoff, self.e_flags, self.e_ehsize, self.e_phentsize, - self.e_phnum, self.e_shentsize, self.e_shnum, self.e_shstrndx) - - -class Symbol: - """ - typedef struct { - Elf32_Word st_name; - Elf32_Addr st_value; - Elf32_Word st_size; - unsigned char st_info; - unsigned char st_other; - Elf32_Half st_shndx; - } Elf32_Sym; - """ - - def __init__(self, fmt, data, strtab, name=None): - self.fmt = fmt - self.st_name, self.st_value, self.st_size, st_info, self.st_other, self.st_shndx = fmt.unpack('IIIBBH', data) - assert self.st_shndx != SHN_XINDEX, "too many sections (SHN_XINDEX not supported)" - self.st_bind = st_info >> 4 - self.st_type = st_info & 0xf - self.name = name if name is not None else strtab.lookup_str(self.st_name) - self.st_visibility = self.st_other & 3 - - @staticmethod - def from_parts(fmt, st_name, st_value, st_size, st_info, st_other, st_shndx, strtab, name): - header = fmt.pack('IIIBBH', st_name, st_value, st_size, st_info, st_other, st_shndx) - return Symbol(fmt, header, strtab, name) - - def to_bin(self): - st_info = (self.st_bind << 4) | self.st_type - return self.fmt.pack('IIIBBH', self.st_name, self.st_value, self.st_size, st_info, self.st_other, self.st_shndx) - - -class Relocation: - def __init__(self, fmt, data, sh_type): - self.fmt = fmt - self.sh_type = sh_type - if sh_type == SHT_REL: - self.r_offset, r_info = fmt.unpack('II', data) - else: - self.r_offset, r_info, self.r_addend = fmt.unpack('III', data) - self.sym_index = r_info >> 8 - self.rel_type = r_info & 0xff - - def to_bin(self): - r_info = (self.sym_index << 8) | self.rel_type - if self.sh_type == SHT_REL: - return self.fmt.pack('II', self.r_offset, r_info) - else: - return self.fmt.pack('III', self.r_offset, r_info, self.r_addend) - - -class Section: - """ - typedef struct { - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; - } Elf32_Shdr; - """ - - def __init__(self, fmt, header, data, index): - self.fmt = fmt - self.sh_name, self.sh_type, self.sh_flags, self.sh_addr, self.sh_offset, self.sh_size, self.sh_link, self.sh_info, self.sh_addralign, self.sh_entsize = fmt.unpack('IIIIIIIIII', header) - assert not self.sh_flags & SHF_LINK_ORDER - if self.sh_entsize != 0: - assert self.sh_size % self.sh_entsize == 0 - if self.sh_type == SHT_NOBITS: - self.data = b'' - else: - self.data = data[self.sh_offset:self.sh_offset + self.sh_size] - self.index = index - self.relocated_by = [] - - @staticmethod - def from_parts(fmt, sh_name, sh_type, sh_flags, sh_link, sh_info, sh_addralign, sh_entsize, data, index): - header = fmt.pack('IIIIIIIIII', sh_name, sh_type, sh_flags, 0, 0, len(data), sh_link, sh_info, sh_addralign, sh_entsize) - return Section(fmt, header, data, index) - - def lookup_str(self, index): - assert self.sh_type == SHT_STRTAB - to = self.data.find(b'\0', index) - assert to != -1 - return self.data[index:to].decode('latin1') - - def add_str(self, string): - assert self.sh_type == SHT_STRTAB - ret = len(self.data) - self.data += string.encode('latin1') + b'\0' - return ret - - def is_rel(self): - return self.sh_type == SHT_REL or self.sh_type == SHT_RELA - - def header_to_bin(self): - if self.sh_type != SHT_NOBITS: - self.sh_size = len(self.data) - return self.fmt.pack('IIIIIIIIII', self.sh_name, self.sh_type, self.sh_flags, self.sh_addr, self.sh_offset, self.sh_size, self.sh_link, self.sh_info, self.sh_addralign, self.sh_entsize) - - def init_relocs(self): - assert self.is_rel() - entries = [] - for i in range(0, self.sh_size, self.sh_entsize): - entries.append(Relocation(self.fmt, self.data[i:i+self.sh_entsize], self.sh_type)) - self.relocations = entries - - def relocate_mdebug(self, original_offset): - assert self.sh_type == SHT_MIPS_DEBUG - new_data = bytearray(self.data) - shift_by = self.sh_offset - original_offset - - # Update the file-relative offsets in the Symbolic HDRR - hdrr_magic, hdrr_vstamp, hdrr_ilineMax, hdrr_cbLine, \ - hdrr_cbLineOffset, hdrr_idnMax, hdrr_cbDnOffset, hdrr_ipdMax, \ - hdrr_cbPdOffset, hdrr_isymMax, hdrr_cbSymOffset, hdrr_ioptMax, \ - hdrr_cbOptOffset, hdrr_iauxMax, hdrr_cbAuxOffset, hdrr_issMax, \ - hdrr_cbSsOffset, hdrr_issExtMax, hdrr_cbSsExtOffset, hdrr_ifdMax, \ - hdrr_cbFdOffset, hdrr_crfd, hdrr_cbRfdOffset, hdrr_iextMax, \ - hdrr_cbExtOffset = self.fmt.unpack("HHIIIIIIIIIIIIIIIIIIIIIII", self.data[0:0x60]) - - assert hdrr_magic == 0x7009, "Invalid magic value for .mdebug symbolic header" - - if hdrr_cbLine: hdrr_cbLineOffset += shift_by - if hdrr_idnMax: hdrr_cbDnOffset += shift_by - if hdrr_ipdMax: hdrr_cbPdOffset += shift_by - if hdrr_isymMax: hdrr_cbSymOffset += shift_by - if hdrr_ioptMax: hdrr_cbOptOffset += shift_by - if hdrr_iauxMax: hdrr_cbAuxOffset += shift_by - if hdrr_issMax: hdrr_cbSsOffset += shift_by - if hdrr_issExtMax: hdrr_cbSsExtOffset += shift_by - if hdrr_ifdMax: hdrr_cbFdOffset += shift_by - if hdrr_crfd: hdrr_cbRfdOffset += shift_by - if hdrr_iextMax: hdrr_cbExtOffset += shift_by - - new_data[0:0x60] = self.fmt.pack("HHIIIIIIIIIIIIIIIIIIIIIII", hdrr_magic, hdrr_vstamp, hdrr_ilineMax, hdrr_cbLine, \ - hdrr_cbLineOffset, hdrr_idnMax, hdrr_cbDnOffset, hdrr_ipdMax, \ - hdrr_cbPdOffset, hdrr_isymMax, hdrr_cbSymOffset, hdrr_ioptMax, \ - hdrr_cbOptOffset, hdrr_iauxMax, hdrr_cbAuxOffset, hdrr_issMax, \ - hdrr_cbSsOffset, hdrr_issExtMax, hdrr_cbSsExtOffset, hdrr_ifdMax, \ - hdrr_cbFdOffset, hdrr_crfd, hdrr_cbRfdOffset, hdrr_iextMax, \ - hdrr_cbExtOffset) - - self.data = bytes(new_data) - -class ElfFile: - def __init__(self, data): - self.data = data - assert data[:4] == b'\x7fELF', "not an ELF file" - - self.elf_header = ElfHeader(data[0:52]) - self.fmt = self.elf_header.fmt - - offset, size = self.elf_header.e_shoff, self.elf_header.e_shentsize - null_section = Section(self.fmt, data[offset:offset + size], data, 0) - num_sections = self.elf_header.e_shnum or null_section.sh_size - - self.sections = [null_section] - for i in range(1, num_sections): - ind = offset + i * size - self.sections.append(Section(self.fmt, data[ind:ind + size], data, i)) - - symtab = None - for s in self.sections: - if s.sh_type == SHT_SYMTAB: - assert not symtab - symtab = s - assert symtab is not None - self.symtab = symtab - self.sym_strtab = self.sections[symtab.sh_link] - self.symbol_entries = ElfFile.init_symbols(symtab, self.sym_strtab) - - shstr = self.sections[self.elf_header.e_shstrndx] - for s in self.sections: - s.name = shstr.lookup_str(s.sh_name) - if s.is_rel(): - self.sections[s.sh_info].relocated_by.append(s) - s.init_relocs() - - @staticmethod - def init_symbols(symtab, strtab): - assert symtab.sh_type == SHT_SYMTAB - assert symtab.sh_entsize == 16 - syms = [] - for i in range(0, symtab.sh_size, symtab.sh_entsize): - syms.append(Symbol(symtab.fmt, symtab.data[i:i+symtab.sh_entsize], strtab)) - return syms - - def find_symbol(self, name): - for s in self.symbol_entries: - if s.name == name: - return (s.st_shndx, s.st_value) - return None - - def find_symbol_in_section(self, name, section): - pos = self.find_symbol(name) - assert pos is not None - assert pos[0] == section.index - return pos[1] - - def find_section(self, name): - for s in self.sections: - if s.name == name: - return s - return None - - def add_section(self, name, sh_type, sh_flags, sh_link, sh_info, sh_addralign, sh_entsize, data): - shstr = self.sections[self.elf_header.e_shstrndx] - sh_name = shstr.add_str(name) - s = Section.from_parts(self.fmt, sh_name=sh_name, sh_type=sh_type, - sh_flags=sh_flags, sh_link=sh_link, sh_info=sh_info, - sh_addralign=sh_addralign, sh_entsize=sh_entsize, data=data, - index=len(self.sections)) - self.sections.append(s) - s.name = name - return s - - def drop_mdebug_gptab(self): - # We can only drop sections at the end, since otherwise section - # references might be wrong. Luckily, these sections typically are. - while self.sections[-1].sh_type in [SHT_MIPS_DEBUG, SHT_MIPS_GPTAB]: - self.sections.pop() - - def write(self, filename): - outfile = open(filename, 'wb') - outidx = 0 - def write_out(data): - nonlocal outidx - outfile.write(data) - outidx += len(data) - def pad_out(align): - if align and outidx % align: - write_out(b'\0' * (align - outidx % align)) - - self.elf_header.e_shnum = len(self.sections) - write_out(self.elf_header.to_bin()) - - for s in self.sections: - if s.sh_type != SHT_NOBITS and s.sh_type != SHT_NULL: - pad_out(s.sh_addralign) - old_offset = s.sh_offset - s.sh_offset = outidx - if s.sh_type == SHT_MIPS_DEBUG and s.sh_offset != old_offset: - # The .mdebug section has moved, relocate offsets - s.relocate_mdebug(old_offset) - write_out(s.data) - - pad_out(4) - self.elf_header.e_shoff = outidx - for s in self.sections: - write_out(s.header_to_bin()) - - outfile.seek(0) - outfile.write(self.elf_header.to_bin()) - outfile.close() - - -def is_temp_name(name): - return name.startswith('_asmpp_') - - -# https://stackoverflow.com/a/241506 -def re_comment_replacer(match): - s = match.group(0) - if s[0] in "/#": - return " " - else: - return s - - -re_comment_or_string = re.compile( - r'#.*|/\*.*?\*/|"(?:\\.|[^\\"])*"' -) - - -class Failure(Exception): - def __init__(self, message): - self.message = message - - def __str__(self): - return self.message - - -class GlobalState: - def __init__(self, min_instr_count, skip_instr_count, use_jtbl_for_rodata, prelude_if_late_rodata, mips1, pascal): - # A value that hopefully never appears as a 32-bit rodata constant (or we - # miscompile late rodata). Increases by 1 in each step. - self.late_rodata_hex = 0xE0123456 - self.valuectr = 0 - self.namectr = 0 - self.min_instr_count = min_instr_count - self.skip_instr_count = skip_instr_count - self.use_jtbl_for_rodata = use_jtbl_for_rodata - self.prelude_if_late_rodata = prelude_if_late_rodata - self.mips1 = mips1 - self.pascal = pascal - - def next_late_rodata_hex(self): - dummy_bytes = struct.pack('>I', self.late_rodata_hex) - if (self.late_rodata_hex & 0xffff) == 0: - # Avoid lui - self.late_rodata_hex += 1 - self.late_rodata_hex += 1 - return dummy_bytes - - def make_name(self, cat): - self.namectr += 1 - return '_asmpp_{}{}'.format(cat, self.namectr) - - def func_prologue(self, name): - if self.pascal: - return " ".join([ - "procedure {}();".format(name), - "type", - " pi = ^integer;", - " pf = ^single;", - " pd = ^double;", - "var", - " vi: pi;", - " vf: pf;", - " vd: pd;", - "begin", - " vi := vi;", - " vf := vf;", - " vd := vd;", - ]) - else: - return 'void {}(void) {{'.format(name) - - def func_epilogue(self): - if self.pascal: - return "end;" - else: - return "}" - - def pascal_assignment(self, tp, val): - self.valuectr += 1 - address = (8 * self.valuectr) & 0x7FFF - return 'v{} := p{}({}); v{}^ := {};'.format(tp, tp, address, tp, val) - -Function = namedtuple('Function', ['text_glabels', 'asm_conts', 'late_rodata_dummy_bytes', 'jtbl_rodata_size', 'late_rodata_asm_conts', 'late_rodata_carrier', 'fn_desc', 'data']) - - -class GlobalAsmBlock: - def __init__(self, fn_desc): - self.fn_desc = fn_desc - self.cur_section = '.text' - self.asm_conts = [] - self.late_rodata_asm_conts = [] - self.late_rodata_alignment = 0 - self.late_rodata_alignment_from_content = False - self.text_glabels = [] - self.fn_section_sizes = { - '.text': 0, - '.data': 0, - '.bss': 0, - '.rodata': 0, - '.late_rodata': 0, - } - self.fn_ins_inds = [] - self.glued_line = '' - self.num_lines = 0 - - def fail(self, message, line=None): - context = self.fn_desc - if line: - context += ", at line \"" + line + "\"" - raise Failure(message + "\nwithin " + context) - - def count_quoted_size(self, line, z, real_line, output_enc): - line = line.encode(output_enc).decode('latin1') - in_quote = False - has_comma = True - num_parts = 0 - ret = 0 - i = 0 - digits = "0123456789" # 0-7 would be more sane, but this matches GNU as - while i < len(line): - c = line[i] - i += 1 - if not in_quote: - if c == '"': - in_quote = True - if z and not has_comma: - self.fail(".asciiz with glued strings is not supported due to GNU as version diffs") - num_parts += 1 - elif c == ',': - has_comma = True - else: - if c == '"': - in_quote = False - has_comma = False - continue - ret += 1 - if c != '\\': - continue - if i == len(line): - self.fail("backslash at end of line not supported", real_line) - c = line[i] - i += 1 - # (if c is in "bfnrtv", we have a real escaped literal) - if c == 'x': - # hex literal, consume any number of hex chars, possibly none - while i < len(line) and line[i] in digits + "abcdefABCDEF": - i += 1 - elif c in digits: - # octal literal, consume up to two more digits - it = 0 - while i < len(line) and line[i] in digits and it < 2: - i += 1 - it += 1 - - if in_quote: - self.fail("unterminated string literal", real_line) - if num_parts == 0: - self.fail(".ascii with no string", real_line) - return ret + num_parts if z else ret - - def align2(self): - while self.fn_section_sizes[self.cur_section] % 2 != 0: - self.fn_section_sizes[self.cur_section] += 1 - - def align4(self): - while self.fn_section_sizes[self.cur_section] % 4 != 0: - self.fn_section_sizes[self.cur_section] += 1 - - def add_sized(self, size, line): - if self.cur_section in ['.text', '.late_rodata']: - if size % 4 != 0: - self.fail("size must be a multiple of 4", line) - if size < 0: - self.fail("size cannot be negative", line) - self.fn_section_sizes[self.cur_section] += size - if self.cur_section == '.text': - if not self.text_glabels: - self.fail(".text block without an initial glabel", line) - self.fn_ins_inds.append((self.num_lines - 1, size // 4)) - - def process_line(self, line, output_enc): - self.num_lines += 1 - if line.endswith('\\'): - self.glued_line += line[:-1] - return - line = self.glued_line + line - self.glued_line = '' - - real_line = line - line = re.sub(re_comment_or_string, re_comment_replacer, line) - line = line.strip() - line = re.sub(r'^[a-zA-Z0-9_]+:\s*', '', line) - changed_section = False - emitting_double = False - if (line.startswith('glabel ') or line.startswith('jlabel ')) and self.cur_section == '.text': - self.text_glabels.append(line.split()[1]) - if not line: - pass # empty line - elif line.startswith('glabel ') or line.startswith('dlabel ') or line.startswith('jlabel ') or line.startswith('endlabel ') or (' ' not in line and line.endswith(':')): - pass # label - elif line.startswith('.section') or line in ['.text', '.data', '.rdata', '.rodata', '.bss', '.late_rodata']: - # section change - self.cur_section = '.rodata' if line == '.rdata' else line.split(',')[0].split()[-1] - if self.cur_section not in ['.data', '.text', '.rodata', '.late_rodata', '.bss']: - self.fail("unrecognized .section directive", real_line) - changed_section = True - elif line.startswith('.late_rodata_alignment'): - if self.cur_section != '.late_rodata': - self.fail(".late_rodata_alignment must occur within .late_rodata section", real_line) - value = int(line.split()[1]) - if value not in [4, 8]: - self.fail(".late_rodata_alignment argument must be 4 or 8", real_line) - if self.late_rodata_alignment and self.late_rodata_alignment != value: - self.fail(".late_rodata_alignment alignment assumption conflicts with earlier .double directive. Make sure to provide explicit alignment padding.") - self.late_rodata_alignment = value - changed_section = True - elif line.startswith('.incbin'): - self.add_sized(int(line.split(',')[-1].strip(), 0), real_line) - elif line.startswith('.word') or line.startswith('.gpword') or line.startswith('.float'): - self.align4() - self.add_sized(4 * len(line.split(',')), real_line) - elif line.startswith('.double'): - self.align4() - if self.cur_section == '.late_rodata': - align8 = self.fn_section_sizes[self.cur_section] % 8 - # Automatically set late_rodata_alignment, so the generated C code uses doubles. - # This gives us correct alignment for the transferred doubles even when the - # late_rodata_alignment is wrong, e.g. for non-matching compilation. - if not self.late_rodata_alignment: - self.late_rodata_alignment = 8 - align8 - self.late_rodata_alignment_from_content = True - elif self.late_rodata_alignment != 8 - align8: - if self.late_rodata_alignment_from_content: - self.fail("found two .double directives with different start addresses mod 8. Make sure to provide explicit alignment padding.", real_line) - else: - self.fail(".double at address that is not 0 mod 8 (based on .late_rodata_alignment assumption). Make sure to provide explicit alignment padding.", real_line) - self.add_sized(8 * len(line.split(',')), real_line) - emitting_double = True - elif line.startswith('.space'): - self.add_sized(int(line.split()[1], 0), real_line) - elif line.startswith('.balign'): - align = int(line.split()[1]) - if align != 4: - self.fail("only .balign 4 is supported", real_line) - self.align4() - elif line.startswith('.align'): - align = int(line.split()[1]) - if align != 2: - self.fail("only .align 2 is supported", real_line) - self.align4() - elif line.startswith('.asci'): - z = (line.startswith('.asciz') or line.startswith('.asciiz')) - self.add_sized(self.count_quoted_size(line, z, real_line, output_enc), real_line) - elif line.startswith('.byte'): - self.add_sized(len(line.split(',')), real_line) - elif line.startswith('.half') or line.startswith('.hword') or line.startswith(".short"): - self.align2() - self.add_sized(2*len(line.split(',')), real_line) - elif line.startswith('.size'): - pass - elif line.startswith('.'): - # .macro, ... - self.fail("asm directive not supported", real_line) - else: - # Unfortunately, macros are hard to support for .rodata -- - # we don't know how how space they will expand to before - # running the assembler, but we need that information to - # construct the C code. So if we need that we'll either - # need to run the assembler twice (at least in some rare - # cases), or change how this program is invoked. - # Similarly, we can't currently deal with pseudo-instructions - # that expand to several real instructions. - if self.cur_section != '.text': - self.fail("instruction or macro call in non-.text section? not supported", real_line) - self.add_sized(4, real_line) - if self.cur_section == '.late_rodata': - if not changed_section: - if emitting_double: - self.late_rodata_asm_conts.append(".align 0") - self.late_rodata_asm_conts.append(real_line) - if emitting_double: - self.late_rodata_asm_conts.append(".align 2") - else: - self.asm_conts.append(real_line) - - def finish(self, state): - src = [''] * (self.num_lines + 1) - late_rodata_dummy_bytes = [] - jtbl_rodata_size = 0 - late_rodata_fn_output = [] - - num_instr = self.fn_section_sizes['.text'] // 4 - - if self.fn_section_sizes['.late_rodata'] > 0: - # Generate late rodata by emitting unique float constants. - # This requires 3 instructions for each 4 bytes of rodata. - # If we know alignment, we can use doubles, which give 3 - # instructions for 8 bytes of rodata. - size = self.fn_section_sizes['.late_rodata'] // 4 - skip_next = False - needs_double = (self.late_rodata_alignment != 0) - extra_mips1_nop = False - if state.pascal: - jtbl_size = 9 if state.mips1 else 8 - jtbl_min_rodata_size = 2 - else: - jtbl_size = 11 if state.mips1 else 9 - jtbl_min_rodata_size = 5 - for i in range(size): - if skip_next: - skip_next = False - continue - # Jump tables give 9 instructions (11 with -mips1) for >= 5 words of rodata, - # and should be emitted when: - # - -O2 or -O2 -g3 are used, which give the right codegen - # - we have emitted our first .float/.double (to ensure that we find the - # created rodata in the binary) - # - we have emitted our first .double, if any (to ensure alignment of doubles - # in shifted rodata sections) - # - we have at least 5 words of rodata left to emit (otherwise IDO does not - # generate a jump table) - # - we have at least 10 more instructions to go in this function (otherwise our - # function size computation will be wrong since the delay slot goes unused) - if (not needs_double and state.use_jtbl_for_rodata and i >= 1 and - size - i >= jtbl_min_rodata_size and - num_instr - len(late_rodata_fn_output) >= jtbl_size + 1): - if state.pascal: - cases = "\n".join("{}: ;".format(case) for case in range(size - i)) - line = "case 0 of " + cases + " otherwise end;" - else: - cases = " ".join("case {}:".format(case) for case in range(size - i)) - line = "switch (*(volatile int*)0) { " + cases + " ; }" - late_rodata_fn_output.append(line) - late_rodata_fn_output.extend([""] * (jtbl_size - 1)) - jtbl_rodata_size = (size - i) * 4 - extra_mips1_nop = i != 2 - break - dummy_bytes = state.next_late_rodata_hex() - late_rodata_dummy_bytes.append(dummy_bytes) - if self.late_rodata_alignment == 4 * ((i + 1) % 2 + 1) and i + 1 < size: - dummy_bytes2 = state.next_late_rodata_hex() - late_rodata_dummy_bytes.append(dummy_bytes2) - fval, = struct.unpack('>d', dummy_bytes + dummy_bytes2) - if state.pascal: - line = state.pascal_assignment('d', fval) - else: - line = '*(volatile double*)0 = {};'.format(fval) - late_rodata_fn_output.append(line) - skip_next = True - needs_double = False - if state.mips1: - # mips1 does not have ldc1/sdc1 - late_rodata_fn_output.append('') - late_rodata_fn_output.append('') - extra_mips1_nop = False - else: - fval, = struct.unpack('>f', dummy_bytes) - if state.pascal: - line = state.pascal_assignment('f', fval) - else: - line = '*(volatile float*)0 = {}f;'.format(fval) - late_rodata_fn_output.append(line) - extra_mips1_nop = True - late_rodata_fn_output.append('') - late_rodata_fn_output.append('') - if state.mips1 and extra_mips1_nop: - late_rodata_fn_output.append('') - - text_name = None - late_rodata_carrier = None - if self.fn_section_sizes['.text'] == 0 and late_rodata_fn_output: - # Keep the dummy constants at this point in the compiler's rodata - # stream. The generated function is removed again in fixup_objfile. - late_rodata_carrier = state.make_name('late_rodata_carrier') - src[0] = ' '.join( - [state.func_prologue(late_rodata_carrier)] + - late_rodata_fn_output + - [state.func_epilogue()] - ) - elif self.fn_section_sizes['.text'] > 0: - text_name = state.make_name('func') - src[0] = state.func_prologue(text_name) - src[self.num_lines] = state.func_epilogue() - instr_count = self.fn_section_sizes['.text'] // 4 - if instr_count < state.min_instr_count: - self.fail("too short .text block") - tot_emitted = 0 - tot_skipped = 0 - fn_emitted = 0 - fn_skipped = 0 - skipping = True - rodata_stack = late_rodata_fn_output[::-1] - for (line, count) in self.fn_ins_inds: - for _ in range(count): - if (fn_emitted > MAX_FN_SIZE and instr_count - tot_emitted > state.min_instr_count and - (not rodata_stack or rodata_stack[-1])): - # Don't let functions become too large. When a function reaches 284 - # instructions, and -O2 -framepointer flags are passed, the IRIX - # compiler decides it is a great idea to start optimizing more. - # Also, Pascal cannot handle too large functions before it runs out - # of unique statements to write. - fn_emitted = 0 - fn_skipped = 0 - skipping = True - src[line] += (' ' + state.func_epilogue() + ' ' + - state.func_prologue(state.make_name('large_func')) + ' ') - if ( - skipping and - fn_skipped < state.skip_instr_count + - (state.prelude_if_late_rodata if rodata_stack else 0) - ): - fn_skipped += 1 - tot_skipped += 1 - else: - skipping = False - if rodata_stack: - src[line] += rodata_stack.pop() - elif state.pascal: - src[line] += state.pascal_assignment('i', '0') - else: - src[line] += '*(volatile int*)0 = 0;' - tot_emitted += 1 - fn_emitted += 1 - if rodata_stack: - size = len(late_rodata_fn_output) // 3 - available = instr_count - tot_skipped - self.fail( - "late rodata to text ratio is too high: {} / {} must be <= 1/3\n" - "add .late_rodata_alignment (4|8) to the .late_rodata " - "block to double the allowed ratio." - .format(size, available)) - - rodata_name = None - if self.fn_section_sizes['.rodata'] > 0: - if state.pascal: - self.fail(".rodata isn't supported with Pascal for now") - rodata_name = state.make_name('rodata') - src[self.num_lines] += ' const char {}[{}] = {{1}};'.format(rodata_name, self.fn_section_sizes['.rodata']) - - data_name = None - if self.fn_section_sizes['.data'] > 0: - data_name = state.make_name('data') - if state.pascal: - line = ' var {}: packed array[1..{}] of char := [otherwise: 0];'.format(data_name, self.fn_section_sizes['.data']) - else: - line = ' char {}[{}] = {{1}};'.format(data_name, self.fn_section_sizes['.data']) - src[self.num_lines] += line - - bss_name = None - if self.fn_section_sizes['.bss'] > 0: - if state.pascal: - self.fail(".bss isn't supported with Pascal") - bss_name = state.make_name('bss') - src[self.num_lines] += ' char {}[{}];'.format(bss_name, self.fn_section_sizes['.bss']) - - fn = Function( - text_glabels=self.text_glabels, - asm_conts=self.asm_conts, - late_rodata_dummy_bytes=late_rodata_dummy_bytes, - jtbl_rodata_size=jtbl_rodata_size, - late_rodata_asm_conts=self.late_rodata_asm_conts, - late_rodata_carrier=late_rodata_carrier, - fn_desc=self.fn_desc, - data={ - '.text': (text_name, self.fn_section_sizes['.text']), - '.data': (data_name, self.fn_section_sizes['.data']), - '.rodata': (rodata_name, self.fn_section_sizes['.rodata']), - '.bss': (bss_name, self.fn_section_sizes['.bss']), - }) - return src, fn - -cutscene_data_regexpr = re.compile(r"CutsceneData (.|\n)*\[\] = {") -float_regexpr = re.compile(r"[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?f") - -def repl_float_hex(m): - return str(struct.unpack(">I", struct.pack(">f", float(m.group(0).strip().rstrip("f"))))[0]) - -Opts = namedtuple('Opts', ['opt', 'framepointer', 'mips1', 'kpic', 'pascal', 'input_enc', 'output_enc', 'encode_cutscene_data_floats']) - -def parse_source(f, opts, out_dependencies, print_source=None): - if opts.opt in ['O1', 'O2']: - if opts.framepointer: - min_instr_count = 6 - skip_instr_count = 5 - else: - min_instr_count = 2 - skip_instr_count = 1 - elif opts.opt == 'O0': - if opts.framepointer: - min_instr_count = 8 - skip_instr_count = 8 - else: - min_instr_count = 4 - skip_instr_count = 4 - elif opts.opt == 'g': - if opts.framepointer: - min_instr_count = 7 - skip_instr_count = 7 - else: - min_instr_count = 4 - skip_instr_count = 4 - elif opts.opt == 'g3': - if opts.framepointer: - min_instr_count = 4 - skip_instr_count = 4 - else: - min_instr_count = 2 - skip_instr_count = 2 - else: - raise Failure("must pass one of -g, -O0, -O1, -O2, -O2 -g3") - prelude_if_late_rodata = 0 - if opts.kpic: - # Without optimizations, the PIC prelude always takes up 3 instructions. - # With optimizations, the prelude is optimized out if there's no late rodata. - if opts.opt in ('g3', 'O2'): - prelude_if_late_rodata = 3 - else: - min_instr_count += 3 - skip_instr_count += 3 - - use_jtbl_for_rodata = False - if opts.opt in ['O2', 'g3'] and not opts.framepointer and not opts.kpic: - use_jtbl_for_rodata = True - - state = GlobalState(min_instr_count, skip_instr_count, use_jtbl_for_rodata, prelude_if_late_rodata, opts.mips1, opts.pascal) - output_enc = opts.output_enc - - global_asm = None - asm_functions = [] - base_fname = f.name - output_lines = [ - '#line 1 "' + base_fname + '"' - ] - - is_cutscene_data = False - is_early_include = False - - for line_no, raw_line in enumerate(f, 1): - raw_line = raw_line.rstrip() - line = raw_line.lstrip() - - # Print exactly one output line per source line, to make compiler - # errors have correct line numbers. These will be overridden with - # reasonable content further down. - output_lines.append('') - - if global_asm is not None: - if line.startswith(')'): - src, fn = global_asm.finish(state) - if state.pascal: - # Pascal has a 1600-character line length limit, so some - # of the lines we emit may be broken up. Correct for that - # using a #line directive. - src[-1] += '\n#line ' + str(line_no + 1) - for i, line2 in enumerate(src): - output_lines[start_index + i] = line2 - asm_functions.append(fn) - global_asm = None - else: - global_asm.process_line(raw_line, output_enc) - elif line in ("GLOBAL_ASM(", "#pragma GLOBAL_ASM("): - global_asm = GlobalAsmBlock("GLOBAL_ASM block at line " + str(line_no)) - start_index = len(output_lines) - elif ( - (line.startswith('GLOBAL_ASM("') or line.startswith('#pragma GLOBAL_ASM("')) - and line.endswith('")') - ) or ( - (line.startswith('INCLUDE_ASM("') or line.startswith('INCLUDE_RODATA("')) - and '",' in line - and line.endswith(");") - ): - prologue = [] - if line.startswith("INCLUDE_"): - # INCLUDE_ASM("path/to", functionname); - before, after = line.split('",', 1) - fname = before[before.index("(") + 2 :] + "/" + after.strip()[:-2] + ".s" - if line.startswith("INCLUDE_RODATA"): - prologue = [".section .rodata"] - else: - # GLOBAL_ASM("path/to/file.s") - fname = line[line.index("(") + 2 : -2] - ext_global_asm = GlobalAsmBlock(fname) - for line2 in prologue: - ext_global_asm.process_line(line2, output_enc) - try: - f = open(fname, encoding=opts.input_enc) - except FileNotFoundError: - # The GLOBAL_ASM block might be surrounded by an ifdef, so it's - # not clear whether a missing file actually represents a compile - # error. Pass the responsibility for determining that on to the - # compiler by emitting a bad include directive. (IDO treats - # #error as a warning for some reason.) - output_lines[-1] = '#include "GLOBAL_ASM:' + fname + '"' - continue - with f: - for line2 in f: - ext_global_asm.process_line(line2.rstrip(), output_enc) - src, fn = ext_global_asm.finish(state) - if state.pascal: - # Pascal has a 1600-character line length limit, so avoid putting - # everything on the same line. - src.append('#line ' + str(line_no + 1)) - output_lines[-1] = '\n'.join(src) - else: - output_lines[-1] = ''.join(src) - asm_functions.append(fn) - out_dependencies.append(fname) - elif line == '#pragma asmproc recurse': - # C includes qualified as - # #pragma asmproc recurse - # #include "file.c" - # will be processed recursively when encountered - is_early_include = True - elif is_early_include: - # Previous line was a #pragma asmproc recurse - is_early_include = False - if not line.startswith("#include "): - raise Failure("#pragma asmproc recurse must be followed by an #include") - fpath = os.path.dirname(base_fname) - fname = os.path.join(fpath, line[line.index(' ') + 2 : -1]) - out_dependencies.append(fname) - include_src = StringIO() - with open(fname, encoding=opts.input_enc) as include_file: - parse_source(include_file, opts, out_dependencies, include_src) - include_src.write('#line ' + str(line_no + 1) + ' "' + base_fname + '"') - output_lines[-1] = include_src.getvalue() - include_src.close() - else: - if opts.encode_cutscene_data_floats: - # This is a hack to replace all floating-point numbers in an array of a particular type - # (in this case CutsceneData) with their corresponding IEEE-754 hexadecimal representation - if cutscene_data_regexpr.search(line) is not None: - is_cutscene_data = True - elif line.endswith("};"): - is_cutscene_data = False - if is_cutscene_data: - raw_line = re.sub(float_regexpr, repl_float_hex, raw_line) - output_lines[-1] = raw_line - - if print_source: - if isinstance(print_source, StringIO): - for line in output_lines: - print_source.write(line + '\n') - else: - newline_encoded = "\n".encode(output_enc) - for line in output_lines: - try: - line_encoded = line.encode(output_enc) - except UnicodeEncodeError: - print("Failed to encode a line to", output_enc) - print("The line:", line) - print("The line, utf-8-encoded:", line.encode("utf-8")) - raise - print_source.write(line_encoded) - print_source.write(newline_encoded) - print_source.flush() - - return asm_functions - -def fixup_objfile(objfile_name, functions, asm_prelude, assembler, output_enc, drop_mdebug_gptab, convert_statics): - SECTIONS = ['.data', '.text', '.rodata', '.bss'] - - with open(objfile_name, 'rb') as f: - objfile = ElfFile(f.read()) - fmt = objfile.fmt - - prev_locs = { - '.text': 0, - '.data': 0, - '.rodata': 0, - '.bss': 0, - } - to_copy = { - '.text': [], - '.data': [], - '.rodata': [], - '.bss': [], - } - asm = [] - all_late_rodata_dummy_bytes = [] - all_jtbl_rodata_size = [] - late_rodata_asm = [] - late_rodata_source_name_start = None - late_rodata_source_name_end = None - - late_rodata_carrier_ranges = [] - omitted_late_rodata_carriers = set() - text_section = objfile.find_section('.text') - for function in functions: - if function.late_rodata_carrier is None: - continue - carrier = next( - (symbol for symbol in objfile.symbol_entries - if symbol.name == function.late_rodata_carrier), - None) - if carrier is None: - # The surrounding preprocessor condition omitted this block. - omitted_late_rodata_carriers.add(function.late_rodata_carrier) - continue - if carrier.st_shndx != text_section.index or carrier.st_size == 0: - raise Failure("could not determine generated late rodata carrier size, " + function.fn_desc) - late_rodata_carrier_ranges.append( - (carrier.st_value, carrier.st_value + carrier.st_size)) - - # Generate an assembly file with all the assembly we need to fill in. For - # simplicity we pad with nops/.space so that addresses match exactly, so we - # don't have to fix up relocations/symbol references. - all_text_glabels = set() - func_sizes = {} - for function in functions: - if function.late_rodata_carrier in omitted_late_rodata_carriers: - continue - ifdefed = False - for sectype, (temp_name, size) in function.data.items(): - if temp_name is None: - continue - assert size > 0 - loc = objfile.find_symbol(temp_name) - if loc is None: - ifdefed = True - break - loc = loc[1] - prev_loc = prev_locs[sectype] - if loc < prev_loc: - # If the dummy C generates too little asm, and we have two - # consecutive GLOBAL_ASM blocks, we detect that error here. - # On the other hand, if it generates too much, we don't have - # a good way of discovering that error: it's indistinguishable - # from a static symbol occurring after the GLOBAL_ASM block. - raise Failure("Wrongly computed size for section {} (diff {}). This is an asm-processor bug!".format(sectype, prev_loc- loc)) - if loc != prev_loc: - asm.append('.section ' + sectype) - if sectype == '.text': - for i in range((loc - prev_loc) // 4): - asm.append('nop') - else: - asm.append('.space {}'.format(loc - prev_loc)) - to_copy[sectype].append((loc, size, temp_name, function.fn_desc)) - if function.text_glabels and sectype == '.text': - func_sizes[function.text_glabels[0]] = size - prev_locs[sectype] = loc + size - if not ifdefed: - all_text_glabels.update(function.text_glabels) - all_late_rodata_dummy_bytes.append(function.late_rodata_dummy_bytes) - all_jtbl_rodata_size.append(function.jtbl_rodata_size) - late_rodata_asm.append(function.late_rodata_asm_conts) - for sectype, (temp_name, size) in function.data.items(): - if temp_name is not None: - asm.append('.section ' + sectype) - asm.append('glabel ' + temp_name + '_asm_start') - asm.append('.text') - for line in function.asm_conts: - asm.append(line) - for sectype, (temp_name, size) in function.data.items(): - if temp_name is not None: - asm.append('.section ' + sectype) - asm.append('glabel ' + temp_name + '_asm_end') - if any(late_rodata_asm): - late_rodata_source_name_start = '_asmpp_late_rodata_start' - late_rodata_source_name_end = '_asmpp_late_rodata_end' - asm.append('.section .late_rodata') - # Put some padding at the start to avoid conflating symbols with - # references to the whole section. - asm.append('.word 0, 0') - asm.append('glabel {}'.format(late_rodata_source_name_start)) - for conts in late_rodata_asm: - asm.extend(conts) - asm.append('glabel {}'.format(late_rodata_source_name_end)) - - o_file = tempfile.NamedTemporaryFile(prefix='asm-processor', suffix='.o', delete=False) - o_name = o_file.name - o_file.close() - s_file = tempfile.NamedTemporaryFile(prefix='asm-processor', suffix='.s', delete=False) - s_name = s_file.name - try: - s_file.write(asm_prelude + b'\n') - for line in asm: - s_file.write(line.encode(output_enc) + b'\n') - s_file.close() - ret = os.system(assembler + " " + s_name + " -o " + o_name) - if ret != 0: - raise Failure("failed to assemble") - with open(o_name, 'rb') as f: - asm_objfile = ElfFile(f.read()) - - # Remove clutter from objdump output for tests, and make the tests - # portable by avoiding absolute paths. Outside of tests .mdebug is - # useful for showing source together with asm, though. - mdebug_section = objfile.find_section('.mdebug') - if drop_mdebug_gptab: - objfile.drop_mdebug_gptab() - - # Unify reginfo sections - target_reginfo = objfile.find_section('.reginfo') - if target_reginfo is not None: - source_reginfo_data = list(asm_objfile.find_section('.reginfo').data) - data = list(target_reginfo.data) - for i in range(20): - data[i] |= source_reginfo_data[i] - target_reginfo.data = bytes(data) - - # Move over section contents - modified_text_positions = set() - jtbl_rodata_positions = set() - last_rodata_pos = 0 - for sectype in SECTIONS: - if not to_copy[sectype]: - continue - source = asm_objfile.find_section(sectype) - assert source is not None, "didn't find source section: " + sectype - for (pos, count, temp_name, fn_desc) in to_copy[sectype]: - loc1 = asm_objfile.find_symbol_in_section(temp_name + '_asm_start', source) - loc2 = asm_objfile.find_symbol_in_section(temp_name + '_asm_end', source) - assert loc1 == pos, "assembly and C files don't line up for section " + sectype + ", " + fn_desc - if loc2 - loc1 != count: - raise Failure("incorrectly computed size for section " + sectype + ", " + fn_desc + ". If using .double, make sure to provide explicit alignment padding.") - if sectype == '.bss': - continue - target = objfile.find_section(sectype) - assert target is not None, "missing target section of type " + sectype - data = list(target.data) - for (pos, count, _, _) in to_copy[sectype]: - data[pos:pos + count] = source.data[pos:pos + count] - if sectype == '.text': - assert count % 4 == 0 - assert pos % 4 == 0 - for i in range(count // 4): - modified_text_positions.add(pos + 4 * i) - elif sectype == '.rodata': - last_rodata_pos = pos + count - target.data = bytes(data) - - # Move over late rodata. This is heuristic, sadly, since I can't think - # of another way of doing it. - moved_late_rodata = {} - if any(all_late_rodata_dummy_bytes) or any(all_jtbl_rodata_size): - source = asm_objfile.find_section('.late_rodata') - target = objfile.find_section('.rodata') - source_pos = asm_objfile.find_symbol_in_section(late_rodata_source_name_start, source) - source_end = asm_objfile.find_symbol_in_section(late_rodata_source_name_end, source) - if source_end - source_pos != sum(map(len, all_late_rodata_dummy_bytes)) * 4 + sum(all_jtbl_rodata_size): - raise Failure("computed wrong size of .late_rodata") - new_data = list(target.data) - for dummy_bytes_list, jtbl_rodata_size in zip(all_late_rodata_dummy_bytes, all_jtbl_rodata_size): - for index, dummy_bytes in enumerate(dummy_bytes_list): - if not fmt.is_big_endian: - dummy_bytes = dummy_bytes[::-1] - pos = target.data.index(dummy_bytes, last_rodata_pos) - # This check is nice, but makes time complexity worse for large files: - if SLOW_CHECKS and target.data.find(dummy_bytes, pos + 4) != -1: - raise Failure("multiple occurrences of late_rodata hex magic. Change asm-processor to use something better than 0xE0123456!") - if index == 0 and len(dummy_bytes_list) > 1 and target.data[pos+4:pos+8] == b'\0\0\0\0': - # Ugly hack to handle double alignment for non-matching builds. - # We were told by .late_rodata_alignment (or deduced from a .double) - # that a function's late_rodata started out 4 (mod 8), and emitted - # a float and then a double. But it was actually 0 (mod 8), so our - # double was moved by 4 bytes. To make them adjacent to keep jump - # tables correct, move the float by 4 bytes as well. - new_data[pos:pos+4] = b'\0\0\0\0' - pos += 4 - new_data[pos:pos+4] = source.data[source_pos:source_pos+4] - moved_late_rodata[source_pos] = pos - last_rodata_pos = pos + 4 - source_pos += 4 - if jtbl_rodata_size > 0: - assert dummy_bytes_list, "should always have dummy bytes before jtbl data" - pos = last_rodata_pos - new_data[pos : pos + jtbl_rodata_size] = \ - source.data[source_pos : source_pos + jtbl_rodata_size] - for i in range(0, jtbl_rodata_size, 4): - moved_late_rodata[source_pos + i] = pos + i - jtbl_rodata_positions.add(pos + i) - last_rodata_pos += jtbl_rodata_size - source_pos += jtbl_rodata_size - target.data = bytes(new_data) - - # Merge strtab data. - strtab_adj = len(objfile.sym_strtab.data) - objfile.sym_strtab.data += asm_objfile.sym_strtab.data - - # Find relocated symbols - relocated_symbols = set() - for sectype in SECTIONS + ['.late_rodata']: - sec = asm_objfile.find_section(sectype) - if sec is None: - continue - for reltab in sec.relocated_by: - for rel in reltab.relocations: - relocated_symbols.add(asm_objfile.symbol_entries[rel.sym_index]) - - # Move over symbols, deleting the temporary function labels. - # Skip over new local symbols that aren't relocated against, to - # avoid conflicts. - empty_symbol = objfile.symbol_entries[0] - new_syms = [s for s in objfile.symbol_entries[1:] if not is_temp_name(s.name)] - - for i, s in enumerate(asm_objfile.symbol_entries): - is_local = (i < asm_objfile.symtab.sh_info) - if is_local and s not in relocated_symbols: - continue - if is_temp_name(s.name): - assert s not in relocated_symbols - continue - if s.st_shndx not in [SHN_UNDEF, SHN_ABS]: - section_name = asm_objfile.sections[s.st_shndx].name - target_section_name = section_name - if section_name == ".late_rodata": - target_section_name = ".rodata" - elif section_name not in SECTIONS: - raise Failure("generated assembly .o must only have symbols for .text, .data, .rodata, .late_rodata, ABS and UNDEF, but found " + section_name) - objfile_section = objfile.find_section(target_section_name) - if objfile_section is None: - raise Failure("generated assembly .o has section that real objfile lacks: " + target_section_name) - s.st_shndx = objfile_section.index - # glabel's aren't marked as functions, making objdump output confusing. Fix that. - if s.name in all_text_glabels: - s.st_type = STT_FUNC - if s.name in func_sizes: - s.st_size = func_sizes[s.name] - if section_name == '.late_rodata': - if s.st_value == 0: - # This must be a symbol corresponding to the whole .late_rodata - # section, being referred to from a relocation. - # Moving local symbols is tricky, because it requires fixing up - # lo16/hi16 relocation references to .late_rodata+. - # Just disallow it for now. - raise Failure("local symbols in .late_rodata are not allowed") - s.st_value = moved_late_rodata[s.st_value] - s.st_name += strtab_adj - new_syms.append(s) - make_statics_global = convert_statics in ("global", "global-with-filename") - - # Add static symbols from .mdebug, so they can be referred to from GLOBAL_ASM - if mdebug_section and convert_statics != "no": - static_name_count = {} - strtab_index = len(objfile.sym_strtab.data) - new_strtab_data = [] - ifd_max, cb_fd_offset = fmt.unpack('II', mdebug_section.data[18*4 : 20*4]) - cb_sym_offset, = fmt.unpack('I', mdebug_section.data[9*4 : 10*4]) - cb_ss_offset, = fmt.unpack('I', mdebug_section.data[15*4 : 16*4]) - for i in range(ifd_max): - offset = cb_fd_offset + 18*4*i - iss_base, _, isym_base, csym = fmt.unpack('IIII', objfile.data[offset + 2*4 : offset + 6*4]) - scope_level = 0 - for j in range(csym): - offset2 = cb_sym_offset + 12 * (isym_base + j) - iss, value, st_sc_index = fmt.unpack('III', objfile.data[offset2 : offset2 + 12]) - st = (st_sc_index >> 26) - sc = (st_sc_index >> 21) & 0x1f - if st in (MIPS_DEBUG_ST_STATIC, MIPS_DEBUG_ST_STATIC_PROC): - symbol_name_offset = cb_ss_offset + iss_base + iss - symbol_name_offset_end = objfile.data.find(b'\0', symbol_name_offset) - assert symbol_name_offset_end != -1 - symbol_name = objfile.data[symbol_name_offset : symbol_name_offset_end] - if scope_level > 1: - # For in-function statics, append an increasing counter to - # the name, to avoid duplicate conflicting symbols. - count = static_name_count.get(symbol_name, 0) + 1 - static_name_count[symbol_name] = count - symbol_name += b":" + str(count).encode("utf-8") - emitted_symbol_name = symbol_name - if convert_statics == "global-with-filename": - # Change the emitted symbol name to include the filename, - # but don't let that affect deduplication logic (we still - # want to be able to reference statics from GLOBAL_ASM). - emitted_symbol_name = objfile_name.encode("utf-8") + b":" + symbol_name - section_name = {1: '.text', 2: '.data', 3: '.bss', 15: '.rodata'}[sc] - section = objfile.find_section(section_name) - symtype = STT_FUNC if sc == 1 else STT_OBJECT - binding = STB_GLOBAL if make_statics_global else STB_LOCAL - sym = Symbol.from_parts( - fmt, - st_name=strtab_index, - st_value=value, - st_size=0, - st_info=(binding << 4 | symtype), - st_other=STV_DEFAULT, - st_shndx=section.index, - strtab=objfile.sym_strtab, - name=symbol_name.decode('latin1')) - strtab_index += len(emitted_symbol_name) + 1 - new_strtab_data.append(emitted_symbol_name + b'\0') - new_syms.append(sym) - if st in ( - MIPS_DEBUG_ST_FILE, - MIPS_DEBUG_ST_STRUCT, - MIPS_DEBUG_ST_UNION, - MIPS_DEBUG_ST_ENUM, - MIPS_DEBUG_ST_BLOCK, - MIPS_DEBUG_ST_PROC, - MIPS_DEBUG_ST_STATIC_PROC, - ): - scope_level += 1 - if st == MIPS_DEBUG_ST_END: - scope_level -= 1 - assert scope_level == 0 - objfile.sym_strtab.data += b''.join(new_strtab_data) - - # Get rid of duplicate symbols, favoring ones that are not UNDEF. - # Skip this for unnamed local symbols though. - new_syms.sort(key=lambda s: 0 if s.st_shndx != SHN_UNDEF else 1) - old_syms = [] - newer_syms = [] - name_to_sym = {} - for s in new_syms: - if s.name == "_gp_disp": - s.st_type = STT_OBJECT - if s.st_bind == STB_LOCAL and s.st_shndx == SHN_UNDEF: - raise Failure("local symbol \"" + s.name + "\" is undefined") - if not s.name: - if s.st_bind != STB_LOCAL: - raise Failure("global symbol with no name") - newer_syms.append(s) - else: - existing = name_to_sym.get(s.name) - if not existing: - name_to_sym[s.name] = s - newer_syms.append(s) - elif s.st_shndx != SHN_UNDEF and not ( - existing.st_shndx == s.st_shndx and existing.st_value == s.st_value - ): - raise Failure("symbol \"" + s.name + "\" defined twice") - else: - s.replace_by = existing - old_syms.append(s) - new_syms = newer_syms - - # Put local symbols in front, with the initial dummy entry first, and - # _gp_disp at the end if it exists. - new_syms.insert(0, empty_symbol) - new_syms.sort(key=lambda s: (s.st_bind != STB_LOCAL, s.name == "_gp_disp")) - num_local_syms = sum(1 for s in new_syms if s.st_bind == STB_LOCAL) - - for i, s in enumerate(new_syms): - s.new_index = i - for s in old_syms: - s.new_index = s.replace_by.new_index - objfile.symtab.data = b''.join(s.to_bin() for s in new_syms) - objfile.symtab.sh_info = num_local_syms - - # Fix up relocation symbol references - for sectype in SECTIONS: - target = objfile.find_section(sectype) - - if target is not None: - # fixup relocation symbol indices, since we butchered them above - for reltab in target.relocated_by: - nrels = [] - for rel in reltab.relocations: - if (sectype == '.text' and rel.r_offset in modified_text_positions or - sectype == '.rodata' and rel.r_offset in jtbl_rodata_positions): - # don't include relocations for late_rodata dummy code - continue - rel.sym_index = objfile.symbol_entries[rel.sym_index].new_index - nrels.append(rel) - reltab.relocations = nrels - reltab.data = b''.join(rel.to_bin() for rel in nrels) - - # Move over relocations - for sectype in SECTIONS + ['.late_rodata']: - source = asm_objfile.find_section(sectype) - if source is None or not source.data: - continue - - target_sectype = '.rodata' if sectype == '.late_rodata' else sectype - target = objfile.find_section(target_sectype) - assert target is not None, target_sectype - for reltab in source.relocated_by: - for rel in reltab.relocations: - rel.sym_index = asm_objfile.symbol_entries[rel.sym_index].new_index - if sectype == '.late_rodata': - rel.r_offset = moved_late_rodata[rel.r_offset] - new_data = b''.join(rel.to_bin() for rel in reltab.relocations) - prefix, sh_entsize = ('.rel', 8) if reltab.sh_type == SHT_REL else ('.rela', 12) - target_reltab = objfile.find_section(prefix + target_sectype) - if not target_reltab: - target_reltab = objfile.add_section(prefix + target_sectype, - sh_type=reltab.sh_type, sh_flags=0, - sh_link=objfile.symtab.index, sh_info=target.index, - sh_addralign=4, sh_entsize=sh_entsize, data=b'') - target.relocated_by.append(target_reltab) - target_reltab.relocations = [] - target_reltab.relocations.extend(reltab.relocations) - target_reltab.data += new_data - - # Data-only .late_rodata blocks use temporary C functions to make IDO - # emit their dummy constants at the right point in .rodata. Remove - # those functions and close the gaps in later text symbols and - # relocation offsets. - if late_rodata_carrier_ranges: - ranges = sorted(late_rodata_carrier_ranges) - for (_, end), (next_start, _) in zip(ranges, ranges[1:]): - if end > next_start: - raise Failure("overlapping generated late rodata carriers") - - def removed_before(pos): - return sum(end - start for start, end in ranges if end <= pos) - - def inside_carrier(pos): - return any(start <= pos < end for start, end in ranges) - - new_text = bytearray() - cursor = 0 - for start, end in ranges: - new_text.extend(text_section.data[cursor:start]) - cursor = end - new_text.extend(text_section.data[cursor:]) - text_section.data = bytes(new_text) - - # REL relocations store their addends in section contents. Adjust - # section-relative text pointers (most notably jump tables) before - # shifting the symbols they are based on. - for target_section in objfile.sections: - section_data = bytearray(target_section.data) - changed = False - for reltab in target_section.relocated_by: - for rel in reltab.relocations: - symbol = new_syms[rel.sym_index] - if symbol.st_shndx != text_section.index or \ - rel.rel_type != R_MIPS_32: - continue - addend, = fmt.unpack( - 'I', section_data[rel.r_offset:rel.r_offset + 4]) - target = symbol.st_value + addend - addend -= ( - removed_before(target) - - removed_before(symbol.st_value) - ) - section_data[rel.r_offset:rel.r_offset + 4] = \ - fmt.pack('I', addend) - changed = True - if changed: - target_section.data = bytes(section_data) - - for symbol in new_syms: - if symbol.st_shndx != text_section.index: - continue - if symbol.st_type == STT_SECTION and symbol.st_value == 0: - continue - elif not inside_carrier(symbol.st_value): - symbol.st_value -= removed_before(symbol.st_value) - - text_end = max( - (symbol.st_value + symbol.st_size - for symbol in new_syms - if symbol.st_shndx == text_section.index and - symbol.st_type != STT_SECTION), - default=0 - ) - aligned_text_end = ( - (text_end + text_section.sh_addralign - 1) // - text_section.sh_addralign * text_section.sh_addralign - ) - text_section.data = text_section.data[:aligned_text_end] - text_section.data += b'\0' * (aligned_text_end - len(text_section.data)) - for symbol in new_syms: - if symbol.st_shndx == text_section.index and \ - symbol.st_type == STT_SECTION and symbol.st_value == 0: - symbol.st_size = len(text_section.data) - - for reltab in text_section.relocated_by: - relocations = [] - for rel in reltab.relocations: - if inside_carrier(rel.r_offset): - continue - rel.r_offset -= removed_before(rel.r_offset) - relocations.append(rel) - reltab.relocations = relocations - reltab.data = b''.join(rel.to_bin() for rel in relocations) - - objfile.symtab.data = b''.join(symbol.to_bin() for symbol in new_syms) - - objfile.write(objfile_name) - finally: - s_file.close() - os.remove(s_name) - try: - os.remove(o_name) - except: - pass - -def run_wrapped(argv, outfile, functions): - dir_path = Path(__file__).resolve().parent - parser = argparse.ArgumentParser(description="Pre-process .c files and post-process .o files to enable embedding assembly into C.") - parser.add_argument('filename', help="path to .c code") - parser.add_argument('--post-process', dest='objfile', help="path to .o file to post-process") - parser.add_argument('--assembler', dest='assembler', help="assembler command (e.g. \"mips-linux-gnu-as -march=vr4300 -mabi=32\")") - parser.add_argument('--asm-prelude', dest='asm_prelude', type=Path, default=dir_path / "prelude.inc", help="path to a file containing a prelude to the assembly file (with .set and .macro directives, e.g.)") - parser.add_argument('--input-enc', default='latin1', help="input encoding (default: %(default)s)") - parser.add_argument('--output-enc', default='latin1', help="output encoding (default: %(default)s)") - parser.add_argument('--drop-mdebug-gptab', dest='drop_mdebug_gptab', action='store_true', help="drop mdebug and gptab sections") - parser.add_argument('--convert-statics', dest='convert_statics', choices=["no", "local", "global", "global-with-filename"], default="local", help="change static symbol visibility (default: %(default)s)") - parser.add_argument('--force', dest='force', action='store_true', help="force processing of files without GLOBAL_ASM blocks") - parser.add_argument('--keep-preprocessed', dest='keep_output_dir', type=Path, help="emit temporary files to this directory (build.py only)") - parser.add_argument('--no-dep-file', action='store_true', help="don't generate a .d make dependency file (build.py only)") - parser.add_argument('--encode-cutscene-data-floats', dest='encode_cutscene_data_floats', action='store_true', default=False, help="Replace floats with their encoded hexadecimal representation in CutsceneData data") - parser.add_argument('-framepointer', dest='framepointer', action='store_true') - parser.add_argument('-mips1', dest='mips1', action='store_true') - parser.add_argument('-g3', dest='g3', action='store_true') - parser.add_argument('-KPIC', dest='kpic', action='store_true') - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-O0', dest='opt', action='store_const', const='O0') - group.add_argument('-O1', dest='opt', action='store_const', const='O1') - group.add_argument('-O2', dest='opt', action='store_const', const='O2') - group.add_argument('-g', dest='opt', action='store_const', const='g') - args = parser.parse_args(argv) - opt = args.opt - pascal = any(args.filename.endswith(ext) for ext in (".p", ".pas", ".pp")) - if args.g3: - if opt != 'O2': - raise Failure("-g3 is only supported together with -O2") - opt = 'g3' - if args.mips1 and (opt not in ('O1', 'O2') or args.framepointer): - raise Failure("-mips1 is only supported together with -O1 or -O2") - if pascal and opt not in ('O1', 'O2', 'g3'): - raise Failure("Pascal is only supported together with -O1, -O2 or -O2 -g3") - opts = Opts(opt, args.framepointer, args.mips1, args.kpic, pascal, args.input_enc, args.output_enc, args.encode_cutscene_data_floats) - - if args.objfile is None: - with open(args.filename, encoding=args.input_enc) as f: - deps = [] - functions = parse_source(f, opts, out_dependencies=deps, print_source=outfile) - return functions, deps, args.keep_output_dir - else: - if args.assembler is None: - raise Failure("must pass assembler command") - if functions is None: - with open(args.filename, encoding=args.input_enc) as f: - functions = parse_source(f, opts, out_dependencies=[]) - if not functions and not args.force: - return - asm_prelude = b'' - if args.asm_prelude: - with open(args.asm_prelude, 'rb') as f: - asm_prelude = f.read() - fixup_objfile(args.objfile, functions, asm_prelude, args.assembler, args.output_enc, args.drop_mdebug_gptab, args.convert_statics) - -def run(argv, outfile=sys.stdout.buffer, functions=None): - try: - return run_wrapped(argv, outfile, functions) - except Failure as e: - print("Error:", e, file=sys.stderr) - sys.exit(1) - -if __name__ == "__main__": - run(sys.argv[1:]) diff --git a/tools/asm-processor/build.py b/tools/asm-processor/build.py deleted file mode 100644 index 79583e2f..00000000 --- a/tools/asm-processor/build.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env python3 -import sys -from pathlib import Path -import shlex -import subprocess -import tempfile -import uuid -import asm_processor - -# Preprocessed files are temporary. For debugging purposes, you can set this -# variable or pass --keep-preprocessed path/to/dir/ to keep a copy. -keep_output_dir = None -# keep_output_dir = Path("./asm_processor_preprocessed") - -progname = sys.argv[0] -all_args = sys.argv[1:] - -i = 0 -asmproc_flags = [] -while i < len(all_args): - arg = all_args[i] - if arg == "--": - i += 1 - break - if not arg.startswith("-"): - break - i += 1 - asmproc_flags.append(arg) - if arg in ("--input-enc", "--output-enc", "--asm-prelude", "--convert-statics", "--keep-preprocessed", "--no-dep-file") and i < len(all_args): - asmproc_flags.append(all_args[i]) - i += 1 - -sep0 = i -try: - sep1 = all_args.index("--", sep0) - sep2 = all_args.index("--", sep1 + 1) -except ValueError: - print(f"Usage: {progname} [options] -- -- ") - sys.exit(1) - -compiler = all_args[sep0:sep1] -assembler_args = all_args[sep1 + 1 : sep2] -compile_args = all_args[sep2 + 1 :] - -assembler_sh = " ".join(shlex.quote(x) for x in assembler_args) - - -def fail_parse(msg): - print(f"Failed to parse compiler flags: {msg}") - sys.exit(1) - -try: - out_ind = compile_args.index("-o") -except ValueError: - fail_parse("missing -o argument") - -try: - out_file = Path(compile_args[out_ind + 1]) -except IndexError: - fail_parse("missing argument after -o") - -del compile_args[out_ind + 1] -del compile_args[out_ind] - -try: - in_file = Path(compile_args[-1]) -except IndexError: - fail_parse("missing input file argument") - -del compile_args[-1] - - -in_dir = in_file.resolve().parent -opt_flags = [ - x for x in compile_args if x in {"-g3", "-g", "-O0", "-O1", "-O2", "-framepointer", "-KPIC"} -] -if "-mips2" not in compile_args: - opt_flags.append("-mips1") - -asmproc_flags += opt_flags + [str(in_file)] - -# Drop .mdebug and .gptab sections from resulting binaries. This makes -# resulting .o files much smaller and speeds up builds, but loses line -# number debug data. -# asmproc_flags += ["--drop-mdebug-gptab"] - -# Convert encoding before compiling. -# asmproc_flags += ["--input-enc", "utf-8", "--output-enc", "euc-jp"] - -with tempfile.TemporaryDirectory(prefix="asm_processor") as tmpdirname: - tmpdir_path = Path(tmpdirname) - preprocessed_filename = "preprocessed_" + uuid.uuid4().hex + in_file.suffix - preprocessed_path = tmpdir_path / preprocessed_filename - - with preprocessed_path.open("wb") as outfile: - functions, deps, keep_output_dir2 = asm_processor.run(asmproc_flags, outfile=outfile) - - keep_output_dir = keep_output_dir or keep_output_dir2 - if keep_output_dir: - import shutil - - keep_output_dir.mkdir(parents=True, exist_ok=True) - - shutil.copy( - preprocessed_path, - keep_output_dir / (in_file.stem + "_" + preprocessed_filename), - ) - - compile_cmdline = ( - compiler - + compile_args - + ["-I", str(in_dir), "-o", str(out_file), str(preprocessed_path)] - ) - - try: - subprocess.check_call(compile_cmdline) - except subprocess.CalledProcessError as e: - print("Failed to compile file " + str(in_file) + ". Command line:") - print() - print(" ".join(shlex.quote(x) for x in compile_cmdline)) - print() - sys.exit(55) - - asm_processor.run( - asmproc_flags - + [ - "--post-process", - str(out_file), - "--assembler", - assembler_sh, - ], - functions=functions, - ) - - deps_file = out_file.with_suffix(".asmproc.d") - if deps and "--no-dep-file" not in asmproc_flags: - with deps_file.open("w") as f: - f.write(str(out_file) + ": " + " \\\n ".join(deps) + "\n") - for dep in deps: - f.write("\n" + dep + ":\n") - else: - try: - deps_file.unlink() - except OSError: - pass diff --git a/tools/asm-processor/compile-test.sh b/tools/asm-processor/compile-test.sh deleted file mode 100755 index 3039f8a8..00000000 --- a/tools/asm-processor/compile-test.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -set -o pipefail -INPUT=$(readlink -f "$1") - -cd -- "$(dirname -- "${BASH_SOURCE[0]}")" -WD=$(pwd) -INPUT=${INPUT#"$WD"/} - -OUTPUT="${INPUT%.*}.o" -rm -f "$OUTPUT" - -CC="$MIPS_CC" # ido 7.1 via recomp or qemu-irix -AS="mips-linux-gnu-as" -ASFLAGS="-march=vr4300 -mabi=32" -OPTFLAGS=$(grep 'COMPILE-FLAGS: ' $INPUT | sed 's#^.*COMPILE-FLAGS: ##' | sed 's#}$##') -ASMPFLAGS=$(grep 'ASMP-FLAGS: ' $INPUT | sed 's#^.*ASMP-FLAGS: ##' | sed 's#}$##') -ISET=$(grep 'COMPILE-ISET: ' $INPUT | sed 's#^.*COMPILE-ISET: ##' | sed 's#}$##') -if [[ -z "$OPTFLAGS" ]]; then - OPTFLAGS="-g" -fi -CFLAGS="-Wab,-r4300_mul -G 0 -Xcpluscomm -fullwarn -wlint -woff 819,820,852,821 -signed -c" -if [[ -z "$ISET" ]]; then - CFLAGS="$CFLAGS -mips2" -fi -if [[ "$OPTFLAGS" != *-KPIC* ]]; then - CFLAGS="$CFLAGS -non_shared" -fi - -set -e - -if [[ "$2" == "python" ]]; then - PROG="python3 ./build.py" -elif [[ "$2" == "rust-release" ]]; then - PROG="./rust/target/release/asm-processor" -elif [[ "$2" == "rust-debug" ]]; then - PROG="./rust/target/debug/asm-processor" -else - echo "Usage: $0 input.c (python|rust-release|rust-debug)" -fi - -$PROG --drop-mdebug-gptab $ASMPFLAGS $CC -- $AS $ASFLAGS -- $CFLAGS $OPTFLAGS $ISET -o "$OUTPUT" "$INPUT" diff --git a/tools/asm-processor/dist-workspace.toml b/tools/asm-processor/dist-workspace.toml deleted file mode 100644 index 542b690e..00000000 --- a/tools/asm-processor/dist-workspace.toml +++ /dev/null @@ -1,13 +0,0 @@ -[workspace] -members = ["cargo:rust/"] - -# Config for 'dist' -[dist] -# The preferred dist version to use in CI (Cargo.toml SemVer syntax) -cargo-dist-version = "0.28.0" -# CI backends to support -ci = "github" -# The installers to generate for each app -installers = [] -# Target platforms to build apps for (Rust target-triple syntax) -targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"] diff --git a/tools/asm-processor/include-stdin.c b/tools/asm-processor/include-stdin.c deleted file mode 100644 index c21aa6f6..00000000 --- a/tools/asm-processor/include-stdin.c +++ /dev/null @@ -1,2 +0,0 @@ -// (this is used for piping input to the IRIX compiler without needing to make a temporary .c file) -#include "/dev/stdin" diff --git a/tools/asm-processor/mypy.ini b/tools/asm-processor/mypy.ini deleted file mode 100644 index 9a57d3c5..00000000 --- a/tools/asm-processor/mypy.ini +++ /dev/null @@ -1,3 +0,0 @@ -[mypy] -files = asm_processor.py, build.py - diff --git a/tools/asm-processor/prelude.inc b/tools/asm-processor/prelude.inc deleted file mode 100644 index 7487b7cb..00000000 --- a/tools/asm-processor/prelude.inc +++ /dev/null @@ -1,55 +0,0 @@ -.set noat -.set noreorder -.set gp=64 - -.macro glabel label - .global \label - \label: -.endm - -.macro dlabel label - .global \label - \label: -.endm - -.macro jlabel label - \label: -.endm - -.macro endlabel label -.endm - -# Float register aliases (o32 ABI, odd ones are rarely used) - -.set $fv0, $f0 -.set $fv0f, $f1 -.set $fv1, $f2 -.set $fv1f, $f3 -.set $ft0, $f4 -.set $ft0f, $f5 -.set $ft1, $f6 -.set $ft1f, $f7 -.set $ft2, $f8 -.set $ft2f, $f9 -.set $ft3, $f10 -.set $ft3f, $f11 -.set $fa0, $f12 -.set $fa0f, $f13 -.set $fa1, $f14 -.set $fa1f, $f15 -.set $ft4, $f16 -.set $ft4f, $f17 -.set $ft5, $f18 -.set $ft5f, $f19 -.set $fs0, $f20 -.set $fs0f, $f21 -.set $fs1, $f22 -.set $fs1f, $f23 -.set $fs2, $f24 -.set $fs2f, $f25 -.set $fs3, $f26 -.set $fs3f, $f27 -.set $fs4, $f28 -.set $fs4f, $f29 -.set $fs5, $f30 -.set $fs5f, $f31 diff --git a/tools/asm-processor/run-tests.sh b/tools/asm-processor/run-tests.sh deleted file mode 100755 index 0448ffbb..00000000 --- a/tools/asm-processor/run-tests.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -TESTS=${*:-python rust-release} - -if [[ -z "$MIPS_CC" ]]; then - echo "MIPS_CC not set" - exit 1 -fi - -cd "$(dirname "${BASH_SOURCE[0]}")" - -FAILED=0 - -OBJDUMPFLAGS=-srt -for typ in $TESTS; do - for A in tests/*.c tests/*.p; do - echo "$A ($typ)" - ./compile-test.sh "$A" $typ && mips-linux-gnu-objdump $OBJDUMPFLAGS "${A%.*}.o" | diff -w "${A%.*}.objdump" - || (echo FAIL "$A" && exit 1) - FAILED=$(( $? + $FAILED )) - done -done - -exit $(( $FAILED != 0 )) diff --git a/tools/asm-processor/rust/Cargo.lock b/tools/asm-processor/rust/Cargo.lock deleted file mode 100644 index 53a27415..00000000 --- a/tools/asm-processor/rust/Cargo.lock +++ /dev/null @@ -1,236 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "anyhow" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" - -[[package]] -name = "argp" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7409aa6f1dd8464eac2e56cf538e1e5f7f79678caa32f198d214a3db8d5075c1" -dependencies = [ - "argp_derive", -] - -[[package]] -name = "argp_derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9b949411282939e3f7d8923127e3f18aa474b46da4e8bb0ddf2cb8c81f963a" -dependencies = [ - "proc-macro2", - "pulldown-cmark", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "array-init" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" - -[[package]] -name = "asm-processor" -version = "0.1.0" -dependencies = [ - "anyhow", - "argp", - "binrw", - "encoding_rs", - "enum-map", - "regex-lite", - "shlex", - "temp-dir", -] - -[[package]] -name = "binrw" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d4bca59c20d6f40c2cc0802afbe1e788b89096f61bdf7aeea6bf00f10c2909b" -dependencies = [ - "array-init", - "binrw_derive", - "bytemuck", -] - -[[package]] -name = "binrw_derive" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8ba42866ce5bced2645bfa15e97eef2c62d2bdb530510538de8dd3d04efff3c" -dependencies = [ - "either", - "owo-colors", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "bytemuck" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "enum-map" -version = "2.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" -dependencies = [ - "enum-map-derive", -] - -[[package]] -name = "enum-map-derive" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "getopts" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "owo-colors" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" - -[[package]] -name = "proc-macro2" -version = "1.0.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pulldown-cmark" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" -dependencies = [ - "bitflags", - "getopts", - "memchr", - "unicase", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex-lite" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "temp-dir" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc1ee6eef34f12f765cb94725905c6312b6610ab2b0940889cfe58dae7bc3c72" - -[[package]] -name = "unicase" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" - -[[package]] -name = "unicode-ident" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" diff --git a/tools/asm-processor/rust/Cargo.toml b/tools/asm-processor/rust/Cargo.toml deleted file mode 100644 index 3ef4479e..00000000 --- a/tools/asm-processor/rust/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "asm-processor" -version = "1.0.0" -edition = "2021" -description = "Pre-process .c files and post-process .o files to enable embedding MIPS assembly into IDO-compiled C." -license = "Unlicense" -repository = "https://github.com/simonlindholm/asm-processor" -readme = "../README.md" -keywords = ["decompilation", "ido", "mips", "asm"] - -[dependencies] -anyhow = "1.0" -binrw = "0.14.1" -encoding_rs = "0.8.35" -enum-map = "2.7.3" -regex-lite = "0.1.6" -shlex = "1.3.0" -temp-dir = "0.1.14" -argp = "0.4.0" - -# The profile that 'dist' will build with -[profile.dist] -inherits = "release" -lto = "thin" diff --git a/tools/asm-processor/rust/src/main.rs b/tools/asm-processor/rust/src/main.rs deleted file mode 100644 index 8e214ee9..00000000 --- a/tools/asm-processor/rust/src/main.rs +++ /dev/null @@ -1,518 +0,0 @@ -mod postprocess; -mod preprocess; - -use std::{ - borrow::Cow, - ffi::OsString, - fmt::Display, - fs::{self, File}, - io::Write, - path::{Path, PathBuf}, - process::{exit, Command}, - str::FromStr, -}; - -use anyhow::Result; -use argp::{EarlyExit, FromArgs, HelpStyle}; -use encoding_rs::EUC_JP; -use enum_map::{Enum, EnumMap}; -use temp_dir::TempDir; - -use postprocess::fixup_objfile; -use preprocess::parse_source; - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Enum)] -enum OutputSection { - Text, - Data, - Rodata, - Bss, -} - -impl OutputSection { - fn as_str(&self) -> &'static str { - match self { - OutputSection::Text => ".text", - OutputSection::Data => ".data", - OutputSection::Rodata => ".rodata", - OutputSection::Bss => ".bss", - } - } -} - -impl Display for OutputSection { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -#[derive(Clone, Debug)] -struct Function { - text_glabels: Vec, - asm_conts: Vec, - late_rodata_dummy_bytes: Vec<[u8; 4]>, - jtbl_rodata_size: usize, - late_rodata_asm_conts: Vec, - fn_desc: String, - data: EnumMap, usize)>, -} - -#[derive(Clone, Copy, Debug)] -enum Encoding { - Latin1, - Custom(&'static encoding_rs::Encoding), -} - -impl Encoding { - fn encode<'a>(&self, s: &'a str) -> Result> { - match self { - Encoding::Latin1 => { - if encoding_rs::mem::is_str_latin1(s) { - return Ok(encoding_rs::mem::encode_latin1_lossy(s)); - } - } - Encoding::Custom(enc) => { - if *enc == EUC_JP { - let s = s.replace("〜", "~"); - let (ret, _, failed) = enc.encode(&s); - if !failed { - return Ok(Cow::Owned(ret.into_owned())); - } - } else { - let (ret, _, failed) = enc.encode(s); - if !failed { - return Ok(ret); - } - } - } - } - Err(anyhow::anyhow!("Failed to encode string: {}", s)) - } - - fn decode<'a>(&self, bytes: &'a [u8]) -> Result> { - match self { - Encoding::Latin1 => Ok(encoding_rs::mem::decode_latin1(bytes)), - Encoding::Custom(enc) => { - let (ret, _, failed) = enc.decode(bytes); - if !failed { - Ok(ret) - } else { - Err(anyhow::anyhow!("Failed to decode string: {}", ret)) - } - } - } - } -} - -impl FromStr for Encoding { - type Err = String; - - fn from_str(s: &str) -> Result { - if s == "latin1" { - Ok(Encoding::Latin1) - } else { - match encoding_rs::Encoding::for_label(s.as_bytes()) { - Some(enc) => Ok(Encoding::Custom(enc)), - None => Err(format!("Unsupported encoding: {}", s)), - } - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -enum ConvertStatics { - No, - Local, - Global, - GlobalWithFilename, -} - -impl FromStr for ConvertStatics { - type Err = String; - - fn from_str(s: &str) -> Result { - Ok(match s { - "no" => ConvertStatics::No, - "local" => ConvertStatics::Local, - "global" => ConvertStatics::Global, - "global-with-filename" => ConvertStatics::GlobalWithFilename, - _ => return Err("invalid value for symbol visibility".into()), - }) - } -} - -#[derive(Clone, Copy, Debug, PartialEq)] -enum OptLevel { - O0, - O1, - O2, - G, - G3, -} - -/// Pre-process .c files and post-process .o files to enable embedding MIPS assembly into IDO-compiled C. -#[derive(FromArgs)] -struct AsmProcArgs { - /// Path to a file containing a prelude to the assembly file (with .set and .macro directives, e.g.) - #[argp(option, arg_name = "FILE")] - asm_prelude: Option, - - /// Input encoding (default: latin1) - #[argp( - option, - default = "Encoding::Latin1", - from_str_fn(FromStr::from_str), - arg_name = "ENCODING" - )] - input_enc: Encoding, - - /// Output encoding (default: latin1) - #[argp( - option, - default = "Encoding::Latin1", - from_str_fn(FromStr::from_str), - arg_name = "ENCODING" - )] - output_enc: Encoding, - - /// Drop mdebug and gptab sections - #[argp(switch)] - drop_mdebug_gptab: bool, - - /// Change symbol visibility for static variables. Mode must be one of: - /// no, local, global, global-with-filename (default: local) - #[argp( - option, - default = "ConvertStatics::Local", - from_str_fn(FromStr::from_str), - arg_name = "MODE" - )] - convert_statics: ConvertStatics, - - /// Force processing of files without GLOBAL_ASM blocks - #[argp(switch)] - force: bool, - - /// Emit temporary files to this directory - #[argp(option, arg_name = "DIR")] - keep_preprocessed: Option, - - /// Replace floats with their encoded hexadecimal representation in CutsceneData data - #[argp(switch)] - encode_cutscene_data_floats: bool, - - /// Don't generate a .d make dependency file - #[argp(switch)] - no_dep_file: bool, - - #[argp(positional, greedy)] - rest: Vec, -} - -struct CompileOpts { - opt: OptLevel, - framepointer: bool, - mips1: bool, - kpic: bool, - pascal: bool, -} - -fn extract_compiler_input_output( - compile_args: &[String], -) -> Result<(PathBuf, PathBuf, Vec), &'static str> { - let mut compile_args: Vec = compile_args.to_vec(); - let out_ind = compile_args - .iter() - .position(|arg| arg == "-o") - .ok_or("missing -o argument")?; - let out_filename = compile_args - .get(out_ind + 1) - .ok_or("missing argument after -o")? - .clone(); - compile_args.remove(out_ind + 1); - compile_args.remove(out_ind); - - let in_file_str = compile_args - .last() - .ok_or("missing input file argument")? - .clone(); - compile_args.pop(); - - let out_file: PathBuf = out_filename.into(); - let in_file: PathBuf = in_file_str.into(); - - Ok((in_file, out_file, compile_args)) -} - -fn parse_compile_args( - compile_args: &[String], - in_file: &Path, -) -> Result { - let mut opt_flags = vec![]; - for x in compile_args { - opt_flags.push(match x.as_str() { - "-g" => OptLevel::G, - "-O0" => OptLevel::O0, - "-O1" => OptLevel::O1, - "-O2" => OptLevel::O2, - _ => continue, - }); - } - - if opt_flags.len() != 1 { - return Err("exactly one of -g/-O0/-O1/-O2 must be passed"); - } - let mut opt = opt_flags[0]; - - let mips1 = !compile_args.contains(&"-mips2".to_string()); - let framepointer = compile_args.contains(&"-framepointer".to_string()); - let kpic = compile_args.contains(&"-KPIC".to_string()); - if compile_args.contains(&"-g3".to_string()) { - if opt != OptLevel::O2 { - return Err("-g3 is only supported together with -O2"); - } - opt = OptLevel::G3; - } - - if mips1 && (!matches!(opt, OptLevel::O1 | OptLevel::O2) || framepointer) { - return Err("-mips1 is only supported together with -O1 or -O2"); - } - - let in_file_str = in_file.to_string_lossy(); - let pascal = in_file_str.ends_with(".p") - || in_file_str.ends_with(".pas") - || in_file_str.ends_with(".pp"); - - if pascal && !matches!(opt, OptLevel::O1 | OptLevel::O2 | OptLevel::G3) { - return Err("Pascal is only supported together with -O1, -O2 or -O2 -g3"); - } - - Ok(CompileOpts { - opt, - framepointer, - mips1, - kpic, - pascal, - }) -} - -fn parse_rest(rest: &[String]) -> Option<(&[String], &[String], &[String])> { - let mut iter = rest.splitn(3, |x| *x == "--"); - let compiler = iter.next()?; - let assembler = iter.next()?; - let compile_args = iter.next()?; - assert!(iter.next().is_none()); - Some((compiler, assembler, compile_args)) -} - -struct ParsedArgs { - args: AsmProcArgs, - compiler: Vec, - assembler: Vec, - compile_args: Vec, - in_file: PathBuf, - out_file: PathBuf, - opts: CompileOpts, -} - -/// Parse command line arguments while allowing --a=b syntax. -/// -/// This provides backward compatibility with Python argparse. -fn from_args_allow_eq(progname: &[&str], args: &[OsString]) -> Result { - let base_res = AsmProcArgs::from_args(progname, args); - if base_res.is_ok() { - return base_res; - } - - // Try splitting up = chars successively, until we get a valid parse. - // This ensures we don't impact the compiler/assembler parts. - // - // Technically this might end up splitting --a --b=c into --a --b c even - // where --a is a flag that takes an argument --b=c, but this seems unlikely - // with our use case. - let mut i = 0; - let mut args = args.to_vec(); - while i < args.len() { - let arg = args[i].as_encoded_bytes(); - if arg.starts_with(b"--") { - if let Some(eq) = arg.iter().position(|&x| x == b'=') { - // SAFETY: splitting on ASCII still results in valid encoded bytes - let before = unsafe { OsString::from_encoded_bytes_unchecked(arg[0..eq].into()) }; - let after = unsafe { OsString::from_encoded_bytes_unchecked(arg[eq + 1..].into()) }; - args.splice(i..i + 1, [before, after]); - let new_res = AsmProcArgs::from_args(progname, &args); - if new_res.is_ok() { - return new_res; - } - i += 1; - } - } - i += 1; - } - - base_res -} - -fn parse_args_or_exit() -> ParsedArgs { - let argv: Vec<_> = std::env::args_os().collect(); - let help_style = HelpStyle { - short_usage: true, - ..HelpStyle::default() - }; - let progname = argv[0].to_string_lossy(); - - let args = from_args_allow_eq(&[&progname], &argv[1..]).unwrap_or_else(|early_exit| { - exit(match early_exit { - EarlyExit::Help(help) => { - println!( - "{}", - help.generate(&help_style).replace( - "[rest...]", - " -- -- " - ) - ); - 0 - } - EarlyExit::Err(err) => { - eprintln!("{}\nRun {} --help for more information.", err, progname); - 1 - } - }) - }); - - let Some((compiler, assembler, compile_args)) = parse_rest(&args.rest) else { - eprintln!( - "Usage: {} [options] -- -- ", - progname - ); - eprintln!("Run {} --help for more information.", progname); - exit(1); - }; - - let (in_file, out_file, compile_args) = extract_compiler_input_output(compile_args) - .unwrap_or_else(|err| { - eprintln!("Failed to parse compiler flags: {}", err); - exit(1); - }); - - let opts = parse_compile_args(&compile_args, &in_file).unwrap_or_else(|err| { - eprintln!("Unsupported compiler flags: {}", err); - exit(1); - }); - - let compiler = compiler.into(); - let assembler = assembler.into(); - - ParsedArgs { - args, - compiler, - assembler, - compile_args, - in_file, - out_file, - opts, - } -} - -fn main() -> Result<()> { - let ParsedArgs { - args, - compiler, - assembler, - compile_args, - in_file, - out_file, - opts, - } = parse_args_or_exit(); - - let assembler_sh = assembler - .iter() - .map(|s| shlex::try_quote(s).unwrap().into_owned()) - .collect::>() - .join(" "); - - let in_dir = fs::canonicalize(in_file.parent().unwrap().join("."))?; - - let temp_dir = TempDir::with_prefix("asm_processor")?; - let preprocessed_filename = format!( - "preprocessed_{}", - in_file.file_name().unwrap().to_str().unwrap() - ); - let preprocessed_path = temp_dir.path().join(&preprocessed_filename); - let mut preprocessed_file = File::create(&preprocessed_path)?; - - let res = parse_source(&in_file, &args, &opts, true)?; - preprocessed_file.write_all(&res.output)?; - - if let Some(keep_output_dir) = &args.keep_preprocessed { - fs::create_dir_all(keep_output_dir)?; - fs::copy( - &preprocessed_path, - keep_output_dir.join(&preprocessed_filename), - )?; - } - - // Run compiler - let mut compile_command = Command::new(&compiler[0]); - compile_command - .args(&compile_args) - .arg("-I") - .arg(in_dir) - .arg("-o") - .arg(&out_file) - .arg(&preprocessed_path); - - match compile_command.status() { - Ok(status) if status.success() => {} - _ => { - return Err(anyhow::anyhow!( - "Failed to compile file {}. Command line:\n\n{:?}\n", - in_file.display(), - compile_command - )); - } - } - - if !res.functions.is_empty() || args.force { - let prelude_str; - let asm_prelude = match &args.asm_prelude { - Some(prelude) => { - if let Ok(res) = fs::read_to_string(prelude) { - prelude_str = res; - &prelude_str - } else { - return Err(anyhow::anyhow!("Failed to read asm prelude")); - } - } - None => include_str!("../../prelude.inc"), - }; - - fixup_objfile( - &out_file, - &res.functions, - asm_prelude, - &assembler_sh, - &args.output_enc, - args.drop_mdebug_gptab, - args.convert_statics, - )?; - } - - if !res.deps.is_empty() && !args.no_dep_file { - let deps_file = out_file.with_extension("asmproc.d"); - let mut deps_file = File::create(&deps_file)?; - - writeln!( - deps_file, - "{}: {}", - out_file.to_str().unwrap(), - res.deps.join(" \\\n ") - )?; - - for dep in res.deps { - writeln!(deps_file, "\n{dep}:")?; - } - } - - Ok(()) -} diff --git a/tools/asm-processor/rust/src/postprocess.rs b/tools/asm-processor/rust/src/postprocess.rs deleted file mode 100644 index 60b782b5..00000000 --- a/tools/asm-processor/rust/src/postprocess.rs +++ /dev/null @@ -1,1312 +0,0 @@ -use anyhow::Result; -use std::{ - cmp::Ordering, - collections::{HashMap, HashSet}, - fs::{self, File}, - io::{self, BufWriter, Cursor, Seek, SeekFrom, Write}, - path::Path, - process::Command, -}; - -use binrw::{binrw, BinRead, BinResult, BinWrite, Endian}; -use enum_map::EnumMap; -use temp_dir::TempDir; - -use crate::{ConvertStatics, Encoding, Function, OutputSection}; - -const EI_NIDENT: usize = 16; -const EI_CLASS: usize = 4; -const EI_DATA: usize = 5; - -const SHN_UNDEF: usize = 0; -const SHN_ABS: usize = 0xfff1; -const SHN_XINDEX: usize = 0xffff; - -const STT_OBJECT: u8 = 1; -const STT_FUNC: u8 = 2; - -const STB_LOCAL: u8 = 0; -const STB_GLOBAL: u8 = 1; - -const STV_DEFAULT: u8 = 0; - -const SHT_NULL: u32 = 0; -const SHT_SYMTAB: u32 = 2; -const SHT_STRTAB: u32 = 3; -const SHT_RELA: u32 = 4; -const SHT_NOBITS: u32 = 8; -const SHT_REL: u32 = 9; -const SHT_MIPS_GPTAB: u32 = 0x70000003; -const SHT_MIPS_DEBUG: u32 = 0x70000005; - -const SHF_LINK_ORDER: u32 = 0x80; - -const MIPS_DEBUG_ST_STATIC: usize = 2; -const MIPS_DEBUG_ST_PROC: usize = 6; -const MIPS_DEBUG_ST_BLOCK: usize = 7; -const MIPS_DEBUG_ST_END: usize = 8; -const MIPS_DEBUG_ST_FILE: usize = 11; -const MIPS_DEBUG_ST_STATIC_PROC: usize = 14; -const MIPS_DEBUG_ST_STRUCT: usize = 26; -const MIPS_DEBUG_ST_UNION: usize = 27; -const MIPS_DEBUG_ST_ENUM: usize = 28; - -#[binrw] -struct ElfHeader { - e_ident: [u8; EI_NIDENT], - e_type: u16, - e_machine: u16, - e_version: u32, - e_entry: u32, - e_phoff: u32, - e_shoff: u32, - e_flags: u32, - e_ehsize: u16, - e_phentsize: u16, - e_phnum: u16, - e_shentsize: u16, - e_shnum: u16, - e_shstrndx: u16, -} - -impl ElfHeader { - const SIZE: usize = 52; - - fn new(data: &[u8], endian: Endian) -> BinResult { - let mut cursor = Cursor::new(data); - - let header = Self::read_options(&mut cursor, endian, ())?; - - assert_eq!(header.e_ident[EI_CLASS], 1, "ELF must be 32-bit"); - assert_eq!(header.e_type, 1, "ELF must be relocatable"); - assert_eq!(header.e_machine, 8, "ELF must be MIPS 1"); - assert_eq!(header.e_phoff, 0, "ELF must not have program headers"); - assert_ne!(header.e_shoff, 0, "ELF must have section headers"); - assert_ne!( - header.e_shstrndx, SHN_UNDEF as u16, - "ELF must have a section header string table" - ); - - Ok(header) - } - - fn to_bin(&self, endian: Endian) -> [u8; Self::SIZE] { - let mut rv = [0; Self::SIZE]; - let mut cursor = Cursor::new(rv.as_mut_slice()); - - self.write_options(&mut cursor, endian, ()).unwrap(); - rv - } -} - -#[binrw] -struct SymbolData { - st_name: u32, - st_value: u32, - st_size: u32, - st_info: u8, - st_other: u8, - st_shndx: u16, -} - -#[derive(Clone)] -struct Symbol { - st_name: usize, - st_value: usize, - st_size: usize, - st_shndx: usize, - st_type: u8, - st_bind: u8, - st_visibility: u8, - name: Vec, -} - -impl Symbol { - fn new(data: &[u8], strtab: &Section, endian: Endian) -> BinResult { - let mut cursor = Cursor::new(data); - - let data = SymbolData::read_options(&mut cursor, endian, ())?; - if data.st_shndx == SHN_XINDEX as u16 { - panic!("too many sections (SHN_XINDEX not supported)"); - } - let st_type = data.st_info & 0xf; - let st_bind = data.st_info >> 4; - let st_visibility = data.st_other & 0x3; - let name = strtab.lookup_str(data.st_name as usize); - - Ok(Self { - st_name: data.st_name as usize, - st_value: data.st_value as usize, - st_size: data.st_size as usize, - st_shndx: data.st_shndx as usize, - st_type, - st_bind, - st_visibility, - name, - }) - } - - fn to_bin(&self) -> Vec { - let mut rv = vec![]; - let mut cursor = Cursor::new(&mut rv); - - SymbolData { - st_name: self.st_name as u32, - st_value: self.st_value as u32, - st_size: self.st_size as u32, - st_info: self.st_bind << 4 | self.st_type, - st_other: self.st_visibility, - st_shndx: self.st_shndx as u16, - } - .write_options(&mut cursor, Endian::Big, ()) - .unwrap(); - rv - } -} - -#[derive(Clone)] -struct Relocation { - r_offset: usize, - sym_index: usize, - rel_type: u32, - r_addend: Option, -} - -impl Relocation { - fn new(data: &[u8], sh_type: u32, endian: Endian) -> BinResult { - let mut cursor = Cursor::new(data); - - let r_offset = u32::read_options(&mut cursor, endian, ())? as usize; - let r_info = u32::read_options(&mut cursor, endian, ())?; - let r_addend = if sh_type == SHT_REL { - None - } else { - Some(u32::read_options(&mut cursor, endian, ())?) - }; - - let sym_index = (r_info >> 8) as usize; - let rel_type = r_info & 0xff; - - Ok(Self { - r_offset, - sym_index, - rel_type, - r_addend, - }) - } - - fn to_bin(&self, endian: Endian) -> Vec { - let mut rv = vec![]; - let mut cursor = Cursor::new(&mut rv); - let r_offset = self.r_offset as u32; - let r_info = ((self.sym_index as u32) << 8) | self.rel_type; - r_offset.write_options(&mut cursor, endian, ()).unwrap(); - r_info.write_options(&mut cursor, endian, ()).unwrap(); - self.r_addend - .write_options(&mut cursor, endian, ()) - .unwrap(); - rv - } -} - -#[binrw] -struct Hdrr { - magic: u16, - vstamp: u16, - iline_max: u32, - cb_line: u32, - cb_line_offset: u32, - idn_max: u32, - cb_dn_offset: u32, - ipd_max: u32, - cb_pd_offset: u32, - isym_max: u32, - cb_sym_offset: u32, - iopt_max: u32, - cb_opt_offset: u32, - iaux_max: u32, - cb_aux_offset: u32, - iss_max: u32, - cb_ss_offset: u32, - iss_ext_max: u32, - cb_ss_ext_offset: u32, - ifd_max: u32, - cb_fd_offset: u32, - crfd: u32, - cb_rfd_offset: u32, - iext_max: u32, - cb_ext_offset: u32, -} - -impl Hdrr { - const SIZE: usize = 96; -} - -#[binrw] -#[derive(Clone)] -struct SectionHeader { - sh_name: u32, - sh_type: u32, - sh_flags: u32, - sh_addr: u32, - sh_offset: u32, - sh_size: u32, - sh_link: u32, - sh_info: u32, - sh_addralign: u32, - sh_entsize: u32, -} - -impl SectionHeader { - const SIZE: usize = 40; -} - -#[derive(Clone)] -struct Section { - header: SectionHeader, - data: Vec, - index: usize, - relocated_by: Vec, - relocations: Vec, - name: String, -} - -impl Section { - fn new(data: &[u8], other_data: &[u8], index: usize, endian: Endian) -> BinResult { - let mut cursor = Cursor::new(data); - - let header = SectionHeader::read_options(&mut cursor, endian, ())?; - assert!(header.sh_flags & SHF_LINK_ORDER == 0); - if header.sh_entsize != 0 { - assert_eq!(header.sh_size % header.sh_entsize, 0); - } - - let data = if header.sh_type == SHT_NOBITS { - vec![] - } else { - other_data[header.sh_offset as usize..(header.sh_offset + header.sh_size) as usize] - .to_vec() - }; - Ok(Self { - header, - data, - index, - relocated_by: vec![], - relocations: vec![], - name: "".into(), - }) - } - - fn from_parts( - sh_name: u32, - fields: &HeaderFields, - data: &[u8], - index: usize, - endian: Endian, - ) -> Self { - let header = SectionHeader { - sh_name, - sh_type: fields.sh_type, - sh_flags: fields.sh_flags, - sh_addr: 0, - sh_offset: 0, - sh_size: data.len() as u32, - sh_link: fields.sh_link, - sh_info: fields.sh_info, - sh_addralign: fields.sh_addralign, - sh_entsize: fields.sh_entsize, - }; - - let mut rv = [0; SectionHeader::SIZE]; - let mut cursor = Cursor::new(rv.as_mut_slice()); - - header.write_options(&mut cursor, endian, ()).unwrap(); - - Self::new(&rv, data, index, endian).unwrap() - } - - fn lookup_str(&self, index: usize) -> Vec { - assert_eq!(self.header.sh_type, SHT_STRTAB); - let to = self.data[index..] - .iter() - .position(|&x| x == 0) - .expect("bad strtab index") - + index; - self.data[index..to].to_owned() - } - - fn add_str(&mut self, string: &[u8]) -> u32 { - assert_eq!(self.header.sh_type, SHT_STRTAB); - let index = self.data.len() as u32; - - self.data.extend_from_slice(string); - self.data.push(0); - index - } - - fn is_rel(&self) -> bool { - self.header.sh_type == SHT_REL || self.header.sh_type == SHT_RELA - } - - fn header_to_bin(&mut self, endian: Endian) -> [u8; SectionHeader::SIZE] { - if self.header.sh_type != SHT_NOBITS { - self.header.sh_size = self.data.len() as u32; - } - - let mut rv = [0; SectionHeader::SIZE]; - let mut cursor = Cursor::new(rv.as_mut_slice()); - - self.header.write_options(&mut cursor, endian, ()).unwrap(); - - rv - } - - fn init_relocs(&mut self, endian: Endian) { - assert!(self.is_rel()); - - let mut entries = vec![]; - for i in (0..self.header.sh_size).step_by(self.header.sh_entsize as usize) { - entries.push( - Relocation::new( - &self.data[i as usize..(i + self.header.sh_entsize) as usize], - self.header.sh_type, - endian, - ) - .unwrap(), - ); - } - self.relocations = entries; - } - - fn relocate_mdebug(&mut self, original_offset: u32, endian: Endian) { - assert_eq!(self.header.sh_type, SHT_MIPS_DEBUG); - let shift_by = self.header.sh_offset.wrapping_sub(original_offset); - - let mut hdrr = Hdrr::read_options(&mut Cursor::new(&self.data), endian, ()).unwrap(); - - assert_eq!(hdrr.magic, 0x7009); - - let relocate = |a, b: &mut u32| { - if a != 0 { - *b = b.wrapping_add(shift_by); - } - }; - relocate(hdrr.cb_line, &mut hdrr.cb_line_offset); - relocate(hdrr.idn_max, &mut hdrr.cb_dn_offset); - relocate(hdrr.ipd_max, &mut hdrr.cb_pd_offset); - relocate(hdrr.isym_max, &mut hdrr.cb_sym_offset); - relocate(hdrr.iopt_max, &mut hdrr.cb_opt_offset); - relocate(hdrr.iaux_max, &mut hdrr.cb_aux_offset); - relocate(hdrr.iss_max, &mut hdrr.cb_ss_offset); - relocate(hdrr.iss_ext_max, &mut hdrr.cb_ss_ext_offset); - relocate(hdrr.ifd_max, &mut hdrr.cb_fd_offset); - relocate(hdrr.crfd, &mut hdrr.cb_rfd_offset); - relocate(hdrr.iext_max, &mut hdrr.cb_ext_offset); - - let mut new_data = [0; Hdrr::SIZE]; - let mut cursor = Cursor::new(new_data.as_mut_slice()); - hdrr.write_options(&mut cursor, endian, ()).unwrap(); - - self.data = new_data.to_vec(); - } -} - -struct ElfFile { - data: Vec, - endian: Endian, - header: ElfHeader, - sections: Vec
    , - symbol_entries: Vec, - symtab: usize, - sym_strtab: usize, -} - -struct HeaderFields { - sh_type: u32, - sh_flags: u32, - sh_link: u32, - sh_info: u32, - sh_addralign: u32, - sh_entsize: u32, -} - -impl ElfFile { - fn new(data: &[u8]) -> BinResult { - let data = data.to_vec(); - assert_eq!(data[..4], [0x7f, b'E', b'L', b'F']); - - let endian: Endian = if data[EI_DATA] == 1 { - Endian::Little - } else if data[5] == 2 { - Endian::Big - } else { - panic!("Invalid ELF endianness"); - }; - let header = ElfHeader::new(&data[..ElfHeader::SIZE], endian).unwrap(); - let offset = header.e_shoff as usize; - let size = header.e_shentsize as usize; - let null_section = Section::new(&data[offset..offset + size], &data, 0, endian).unwrap(); - let num_sections = if header.e_shnum == 0 { - null_section.header.sh_size as usize - } else { - header.e_shnum as usize - }; - let mut sections = vec![null_section]; - - for i in 1..num_sections { - let ind = offset + i * size; - let section = Section::new(&data[ind..ind + size], &data, i, endian).unwrap(); - sections.push(section); - } - - let symtab_index = sections - .iter() - .position(|s| s.header.sh_type == SHT_SYMTAB) - .expect("missing symtab"); - let sym_strtab_index = sections[symtab_index].header.sh_link as usize; - - let symtab = §ions[symtab_index]; - let sym_strtab = §ions[sym_strtab_index]; - let symbol_entries = ElfFile::init_symbols(symtab, sym_strtab, endian); - - let shstr = sections[header.e_shstrndx as usize].clone(); - - for i in 0..sections.len() { - let s = &mut sections[i]; - s.name = String::from_utf8(shstr.lookup_str(s.header.sh_name as usize)).unwrap(); - assert!(s.name.is_ascii()); - - if s.is_rel() { - let target_index = s.header.sh_info as usize; - s.init_relocs(endian); - sections[target_index].relocated_by.push(i); - } - } - - Ok(ElfFile { - data, - endian, - header, - sections, - symbol_entries, - symtab: symtab_index, - sym_strtab: sym_strtab_index, - }) - } - - fn find_section(&self, name: &str) -> Option<&Section> { - self.sections.iter().find(|s| s.name == name) - } - - fn find_section_mut(&mut self, name: &str) -> Option<&mut Section> { - self.sections.iter_mut().find(|s| s.name == name) - } - - fn symtab(&self) -> &Section { - &self.sections[self.symtab] - } - - fn symtab_mut(&mut self) -> &mut Section { - &mut self.sections[self.symtab] - } - - fn sym_strtab(&self) -> &Section { - &self.sections[self.sym_strtab] - } - - fn sym_strtab_mut(&mut self) -> &mut Section { - &mut self.sections[self.sym_strtab] - } - - fn init_symbols(symtab: &Section, strtab: &Section, endian: Endian) -> Vec { - assert_eq!(symtab.header.sh_type, SHT_SYMTAB); - assert_eq!(symtab.header.sh_entsize, 16); - - let mut syms = Vec::new(); - for i in 0..(symtab.data.len() / 16) { - syms.push(Symbol::new(&symtab.data[i * 16..(i + 1) * 16], strtab, endian).unwrap()); - } - syms - } - - fn find_symbol(&self, name: &[u8]) -> Option<(usize, usize)> { - for s in &self.symbol_entries { - if s.name == name { - return Some((s.st_shndx, s.st_value)); - } - } - None - } - - fn find_symbol_in_section(&self, name: &[u8], section: &Section) -> usize { - let Some((st_shndx, st_value)) = self.find_symbol(name) else { - panic!("failed to find symbol: {}", String::from_utf8_lossy(name)); - }; - if st_shndx != section.index { - panic!( - "symbol {} is in wrong section", - String::from_utf8_lossy(name) - ); - } - st_value - } - - fn add_section(&mut self, name: &str, fields: &HeaderFields, data: &[u8], endian: Endian) { - let shstr = self - .sections - .get_mut(self.header.e_shstrndx as usize) - .expect("bad e_shstrndx"); - let sh_name = shstr.add_str(name.as_bytes()); - let mut s = Section::from_parts(sh_name, fields, data, self.sections.len(), endian); - s.name = name.to_string(); - self.sections.push(s); - } - - fn drop_mdebug_gptab(&mut self) { - // We can only drop sections at the end, since otherwise section - // references might be wrong. Luckily, these sections typically are. - while let Some(s) = self.sections.last() { - if s.header.sh_type != SHT_MIPS_DEBUG && s.header.sh_type != SHT_MIPS_GPTAB { - break; - } - self.sections.pop(); - } - } - - fn pad_out(writer: &mut BufWriter<&mut File>, align: usize) -> io::Result<()> { - let pos = writer.stream_position()? as usize; - - if align > 0 && pos % align != 0 { - let pad = align - (pos % align); - for _ in 0..pad { - writer.write_all(&[0])?; - } - } - Ok(()) - } - - fn write(&mut self, writer: &mut BufWriter<&mut File>) -> io::Result<()> { - self.header.e_shnum = self.sections.len() as u16; - writer.write_all(&self.header.to_bin(self.endian))?; - - for s in &mut self.sections { - if s.header.sh_type != SHT_NOBITS && s.header.sh_type != SHT_NULL { - Self::pad_out(writer, s.header.sh_addralign as usize)?; - let old_offset = s.header.sh_offset; - s.header.sh_offset = writer.stream_position()? as u32; - if s.header.sh_type == SHT_MIPS_DEBUG && s.header.sh_offset != old_offset { - // The .mdebug section has moved, relocate offsets - s.relocate_mdebug(old_offset, self.endian); - } - writer.write_all(&s.data)?; - } - } - - Self::pad_out(writer, 4)?; - self.header.e_shoff = writer.stream_position()? as u32; - - for s in &mut self.sections { - writer.write_all(&s.header_to_bin(self.endian))?; - } - - writer.seek(SeekFrom::Start(0))?; - writer.write_all(&self.header.to_bin(self.endian))?; - writer.flush()?; - Ok(()) - } -} - -pub(crate) fn fixup_objfile( - objfile_path: &Path, - functions: &[Function], - asm_prelude: &str, - assembler: &str, - output_enc: &Encoding, - drop_mdebug_gptab: bool, - convert_statics: ConvertStatics, -) -> Result<()> { - const OUTPUT_SECTIONS: [OutputSection; 4] = [ - OutputSection::Data, - OutputSection::Text, - OutputSection::Rodata, - OutputSection::Bss, - ]; - const INPUT_SECTION_NAMES: [&str; 5] = [".data", ".text", ".rodata", ".bss", ".late_rodata"]; - - let objfile_data = fs::read(objfile_path)?; - let mut objfile = ElfFile::new(&objfile_data)?; - let endian = objfile.endian; - - let mut prev_locs: EnumMap = EnumMap::default(); - - struct ToCopyData { - loc: usize, - size: usize, - temp_name: String, - fn_desc: String, - } - - let mut to_copy: EnumMap> = EnumMap::default(); - - let mut asm: Vec = vec![]; - let mut all_late_rodata_dummy_bytes: Vec> = vec![]; - let mut all_jtbl_rodata_size: Vec = vec![]; - let mut late_rodata_asm: Vec = vec![]; - let late_rodata_source_name_start = "_asmpp_late_rodata_start"; - let late_rodata_source_name_end = "_asmpp_late_rodata_end"; - - // Generate an assembly file with all the assembly we need to fill in. For - // simplicity we pad with nops/.space so that addresses match exactly, so we - // don't have to fix up relocations/symbol references. - let mut all_text_glabels: HashSet> = HashSet::new(); - let mut func_sizes: HashMap, usize> = HashMap::new(); - - for function in functions.iter() { - let text_glabels = function - .text_glabels - .iter() - .map(|x| output_enc.encode(x)) - .collect::>>()?; - let mut ifdefed = false; - for (sectype, &(ref temp_name, size)) in function.data.iter() { - let Some(temp_name) = temp_name else { continue }; - if size == 0 { - panic!("Size of section {} is 0", sectype.as_str()); - } - let Some((_, loc)) = objfile.find_symbol(temp_name.as_bytes()) else { - ifdefed = true; - break; - }; - let prev_loc = prev_locs[sectype]; - if loc < prev_loc { - // If the dummy C generates too little asm, and we have two - // consecutive GLOBAL_ASM blocks, we detect that error here. - // On the other hand, if it generates too much, we don't have - // a good way of discovering that error: it's indistinguishable - // from a static symbol occurring after the GLOBAL_ASM block. - panic!( - "Wrongly computed size for section {} (diff {}). This is an asm-processor bug!", - sectype, - prev_loc - loc - ); - } - if loc != prev_loc { - asm.push(format!(".section {}", sectype)); - if sectype == OutputSection::Text { - for _ in 0..((loc - prev_loc) / 4) { - asm.push("nop".to_owned()); - } - } else { - asm.push(format!(".space {}", loc - prev_loc)); - } - } - to_copy[sectype].push(ToCopyData { - loc, - size, - temp_name: temp_name.clone(), - fn_desc: function.fn_desc.clone(), - }); - if !text_glabels.is_empty() && sectype == OutputSection::Text { - func_sizes.insert(text_glabels[0].to_vec(), size); - } - prev_locs[sectype] = loc + size; - } - - if !ifdefed { - all_text_glabels.extend(text_glabels.iter().map(|x| x.to_vec())); - all_late_rodata_dummy_bytes.push(function.late_rodata_dummy_bytes.clone()); - all_jtbl_rodata_size.push(function.jtbl_rodata_size); - late_rodata_asm.extend(function.late_rodata_asm_conts.iter().cloned()); - for (sectype, (temp_name, _)) in function.data.iter() { - if let Some(temp_name) = temp_name { - asm.push(format!(".section {}", sectype)); - asm.push(format!("glabel {}_asm_start", temp_name)); - } - } - asm.push(".text".to_owned()); - asm.extend(function.asm_conts.iter().cloned()); - for (sectype, (temp_name, _)) in function.data.iter() { - if let Some(temp_name) = temp_name { - asm.push(format!(".section {}", sectype)); - asm.push(format!("glabel {}_asm_end", temp_name)); - } - } - } - } - - if !late_rodata_asm.is_empty() { - asm.push(".section .late_rodata".to_string()); - // Put some padding at the start to avoid conflating symbols with - // references to the whole section. - asm.push(".word 0, 0".to_string()); - asm.push(format!("glabel {}", late_rodata_source_name_start)); - asm.extend(late_rodata_asm.iter().cloned()); - asm.push(format!("glabel {}", late_rodata_source_name_end)); - } - - let temp_dir = TempDir::with_prefix("asm_processor")?; - - let obj_stem = objfile_path.file_stem().unwrap().to_str().unwrap(); - - let o_file_path = temp_dir - .path() - .join(format!("asm_processor_{}.o", obj_stem)); - let s_file_path = temp_dir - .path() - .join(format!("asm_processor_{}.s", obj_stem)); - { - let mut s_file = File::create(&s_file_path)?; - s_file.write_all(&output_enc.encode(asm_prelude)?)?; - s_file.write_all(&output_enc.encode("\n")?)?; - - for line in asm { - s_file.write_all(&output_enc.encode(&line)?)?; - s_file.write_all(&output_enc.encode("\n")?)?; - } - } - - let status = Command::new("sh") - .arg("-c") - .arg(format!( - "{} {} -o {}", - assembler, - shlex::try_quote(s_file_path.to_str().unwrap()).unwrap(), - shlex::try_quote(o_file_path.to_str().unwrap()).unwrap(), - )) - .status() - .expect("Failed to run shell"); - if !status.success() { - return Err(anyhow::anyhow!("Failed to assemble")); - } - let asm_objfile = ElfFile::new(&fs::read(&o_file_path)?)?; - - // Remove clutter from objdump output for tests, and make the tests - // portable by avoiding absolute paths. Outside of tests .mdebug is - // useful for showing source together with asm, though. - let mdebug_section = objfile.find_section(".mdebug").cloned(); - if drop_mdebug_gptab { - objfile.drop_mdebug_gptab(); - } - - // Unify reginfo sections - if let Some(target_reginfo) = objfile.find_section_mut(".reginfo") { - let source_reginfo = &asm_objfile - .find_section(".reginfo") - .expect("couldn't find source .reginfo"); - for (s, t) in source_reginfo - .data - .iter() - .zip(target_reginfo.data.iter_mut()) - { - *t |= *s; - } - } - - // Move over section contents - let mut modified_text_positions = HashSet::new(); - let mut jtbl_rodata_positions: HashSet = HashSet::new(); - let mut last_rodata_pos = 0; - for sectype in OUTPUT_SECTIONS { - if to_copy[sectype].is_empty() { - continue; - } - let Some(source) = asm_objfile.find_section(sectype.as_str()) else { - panic!("didn't find source section: {}", sectype); - }; - for &ToCopyData { - loc, - size, - ref temp_name, - ref fn_desc, - } in to_copy[sectype].iter() - { - let loc1 = asm_objfile - .find_symbol_in_section(format!("{}_asm_start", &temp_name).as_bytes(), source); - let loc2 = asm_objfile - .find_symbol_in_section(format!("{}_asm_end", &temp_name).as_bytes(), source); - if loc1 != loc { - panic!( - "assembly and C files don't line up for section {}, {}", - sectype, fn_desc - ); - } - if loc2 - loc1 != size { - return Err(anyhow::anyhow!( - "incorrectly computed size for section {}, {}. If using .double, make sure to provide explicit alignment padding.", - sectype, - fn_desc - )); - } - } - - if sectype == OutputSection::Bss { - continue; - } - - let Some(target) = objfile.find_section_mut(sectype.as_str()) else { - panic!("didn't find target section: {}", sectype); - }; - - for &ToCopyData { loc, size, .. } in to_copy[sectype].iter() { - target.data[loc..loc + size].copy_from_slice(&source.data[loc..loc + size]); - - if sectype == OutputSection::Text { - assert_eq!(size % 4, 0); - assert_eq!(loc % 4, 0); - for j in 0..size / 4 { - modified_text_positions.insert(loc + 4 * j); - } - } else if sectype == OutputSection::Rodata { - last_rodata_pos = loc + size; - } - } - } - - // Move over late rodata. This is heuristic, sadly, since I can't think - // of another way of doing it. - let mut moved_late_rodata: HashMap = HashMap::new(); - if all_late_rodata_dummy_bytes.iter().any(|b| !b.is_empty()) - || all_jtbl_rodata_size.iter().any(|&s| s > 0) - { - let source = asm_objfile - .find_section(".late_rodata") - .expect(".late_rodata source section should exist"); - let target = objfile - .find_section_mut(".rodata") - .expect(".rodata target section should exist"); - let mut source_pos = - asm_objfile.find_symbol_in_section(late_rodata_source_name_start.as_bytes(), source); - let source_end = - asm_objfile.find_symbol_in_section(late_rodata_source_name_end.as_bytes(), source); - let num_dummies: usize = all_late_rodata_dummy_bytes.iter().map(|x| x.len()).sum(); - let expected_size = num_dummies * 4 + all_jtbl_rodata_size.iter().sum::(); - - if source_end - source_pos != expected_size { - return Err(anyhow::anyhow!("computed wrong size of .late_rodata")); - } - let mut new_data = target.data.clone(); - - for (dummy_bytes_list, &jtbl_rodata_size) in all_late_rodata_dummy_bytes - .iter_mut() - .zip(all_jtbl_rodata_size.iter()) - { - let dummy_bytes_list_len = dummy_bytes_list.len(); - - for (index, dummy_bytes) in dummy_bytes_list.iter_mut().enumerate() { - if endian == Endian::Little { - dummy_bytes.reverse(); - } - - let mut pos = target.data[last_rodata_pos..] - .windows(4) - .position(|x| x == dummy_bytes) - .expect("failed to find dummy .late_rodata bytes") - + last_rodata_pos; - - if index == 0 - && dummy_bytes_list_len > 1 - && target.data[pos + 4..pos + 8] == *b"\0\0\0\0" - { - // Ugly hack to handle double alignment for non-matching builds. - // We were told by .late_rodata_alignment (or deduced from a .double) - // that a function's late_rodata started out 4 (mod 8), and emitted - // a float and then a double. But it was actually 0 (mod 8), so our - // double was moved by 4 bytes. To make them adjacent to keep jump - // tables correct, move the float by 4 bytes as well. - new_data[pos..pos + 4].copy_from_slice(b"\0\0\0\0"); - pos += 4; - } - new_data[pos..pos + 4].copy_from_slice(&source.data[source_pos..source_pos + 4]); - moved_late_rodata.insert(source_pos, pos); - last_rodata_pos = pos + 4; - source_pos += 4; - } - - if jtbl_rodata_size > 0 { - assert!(!dummy_bytes_list.is_empty()); - let pos = last_rodata_pos; - new_data[pos..pos + jtbl_rodata_size] - .copy_from_slice(&source.data[source_pos..source_pos + jtbl_rodata_size]); - for i in (0..jtbl_rodata_size).step_by(4) { - moved_late_rodata.insert(source_pos + i, pos + i); - jtbl_rodata_positions.insert(pos + i); - } - last_rodata_pos += jtbl_rodata_size; - source_pos += jtbl_rodata_size; - } - } - target.data = new_data; - } - - // Merge strtab data. - let strtab = objfile.sym_strtab_mut(); - let strtab_adj = strtab.data.len(); - strtab.data.extend(&asm_objfile.sym_strtab().data); - - // Find relocated symbols in asm_objfile - let mut relocated_symbols = HashSet::new(); - for sectype in INPUT_SECTION_NAMES.iter() { - if let Some(sec) = asm_objfile.find_section(sectype) { - for reltab_idx in &sec.relocated_by { - let reltab = &asm_objfile.sections[*reltab_idx]; - for rel in &reltab.relocations { - relocated_symbols.insert(rel.sym_index); - } - } - } - } - - enum SymInd { - Obj(usize), - Asm(usize), - } - - // Move over symbols, deleting the temporary function labels. - // Skip over new local symbols that aren't relocated against, to - // avoid conflicts. - let empty_symbol = objfile.symbol_entries[0].clone(); - let mut new_syms: Vec<(Symbol, Vec)> = objfile - .symbol_entries - .iter() - .enumerate() - .map(|(i, x)| (x, vec![SymInd::Obj(i)])) - .skip(1) - .filter(|(x, _)| !x.name.starts_with(b"_asmpp_")) - .map(|(x, inds)| (x.clone(), inds)) - .collect(); - - for (i, s) in asm_objfile.symbol_entries.iter().enumerate() { - let is_local = i < asm_objfile.symtab().header.sh_info as usize; - if is_local && !relocated_symbols.contains(&i) { - continue; - } - if s.name.starts_with(b"_asmpp_") { - assert!(!relocated_symbols.contains(&i)); - continue; - } - let mut s = s.clone(); - if s.st_shndx != SHN_UNDEF && s.st_shndx != SHN_ABS { - let section_name = asm_objfile.sections[s.st_shndx].name.clone(); - let mut target_section_name = section_name.clone(); - if section_name == ".late_rodata" { - target_section_name = ".rodata".to_string(); - } else if !INPUT_SECTION_NAMES.contains(§ion_name.as_str()) { - return Err(anyhow::anyhow!( - "generated assembly .o must only have symbols for .text, .data, .rodata, .late_rodata, ABS and UNDEF, but found {}", - section_name - )); - } - let Some(objfile_section) = objfile.find_section(&target_section_name) else { - return Err(anyhow::anyhow!( - "generated assembly .o has section that real objfile lacks: {}", - target_section_name - )); - }; - s.st_shndx = objfile_section.index; - // glabels aren't marked as functions, making objdump output confusing. Fix that. - if all_text_glabels.contains(&s.name) { - s.st_type = STT_FUNC; - if let Some(&size) = func_sizes.get(&s.name) { - s.st_size = size; - } - } - if section_name == ".late_rodata" { - if s.st_value == 0 { - // This must be a symbol corresponding to the whole .late_rodata - // section, being referred to from a relocation. - // Moving local symbols is tricky, because it requires fixing up - // lo16/hi16 relocation references to .late_rodata+. - // Just disallow it for now. - return Err(anyhow::anyhow!( - "local symbols in .late_rodata are not allowed" - )); - } - s.st_value = moved_late_rodata[&s.st_value]; - } - } - s.st_name += strtab_adj; - new_syms.push((s, vec![SymInd::Asm(i)])); - } - - // Add static symbols from .mdebug, so they can be referred to from GLOBAL_ASM - if mdebug_section.is_some() && convert_statics != ConvertStatics::No { - let mdebug_section = mdebug_section.unwrap(); - let mut static_name_count: HashMap, usize> = HashMap::new(); - let mut strtab_index = objfile.sym_strtab().data.len(); - let mut new_strtab_data = vec![]; - - let read_u32 = |data: &[u8], offset| { - u32::from_be_bytes(data[offset..offset + 4].try_into().unwrap()) as usize - }; - - let ifd_max = read_u32(&mdebug_section.data, 18 * 4); - let cb_fd_offset = read_u32(&mdebug_section.data, 19 * 4); - let cb_sym_offset = read_u32(&mdebug_section.data, 9 * 4); - let cb_ss_offset = read_u32(&mdebug_section.data, 15 * 4); - - for i in 0..ifd_max { - let offset = cb_fd_offset + 18 * 4 * i; - let iss_base = read_u32(&objfile.data, offset + 2 * 4); - let isym_base = read_u32(&objfile.data, offset + 4 * 4); - let csym = read_u32(&objfile.data, offset + 5 * 4); - let mut scope_level = 0; - - for j in 0..csym { - let offset2 = cb_sym_offset + 12 * (isym_base + j); - let iss = read_u32(&objfile.data, offset2); - let value = read_u32(&objfile.data, offset2 + 4); - let st_sc_index = read_u32(&objfile.data, offset2 + 8); - let st = st_sc_index >> 26; - let sc = (st_sc_index >> 21) & 0x1F; - - if st == MIPS_DEBUG_ST_STATIC || st == MIPS_DEBUG_ST_STATIC_PROC { - let symbol_name_offset = cb_ss_offset + iss_base + iss; - let symbol_name_offset_end = objfile_data[symbol_name_offset..] - .iter() - .position(|x| *x == 0) - .expect("bad .mdebug strtab reference") - + symbol_name_offset; - let mut symbol_name = - objfile_data[symbol_name_offset..symbol_name_offset_end].to_owned(); - if scope_level > 1 { - // For in-function statics, append an increasing counter to - // the name, to avoid duplicate conflicting symbols. - let count = static_name_count.get(&symbol_name).unwrap_or(&0) + 1; - static_name_count.insert(symbol_name.clone(), count); - symbol_name.extend(format!(":{}", count).as_bytes()); - } - let mut emitted_symbol_name = symbol_name.clone(); - if convert_statics == ConvertStatics::GlobalWithFilename { - // Change the emitted symbol name to include the filename, - // but don't let that affect deduplication logic (we still - // want to be able to reference statics from GLOBAL_ASM). - let mut new_name = objfile_path.to_string_lossy().into_owned().into_bytes(); - new_name.push(b':'); - new_name.extend(emitted_symbol_name); - emitted_symbol_name = new_name; - }; - let section_name = match sc { - 1 => ".text", - 2 => ".data", - 3 => ".bss", - 15 => ".rodata", - _ => { - return Err(anyhow::anyhow!("unsupported MIPS_DEBUG_SC value: {}", sc)); - } - }; - let Some(section) = objfile.find_section(section_name) else { - panic!( - "couldn't find section referenced from .mdebug: {}", - section_name - ); - }; - let symtype = if sc == 1 { STT_FUNC } else { STT_OBJECT }; - let binding = match convert_statics { - ConvertStatics::Global | ConvertStatics::GlobalWithFilename => STB_GLOBAL, - _ => STB_LOCAL, - }; - let sym = Symbol { - st_name: strtab_index, - st_value: value, - st_size: 0, - st_bind: binding, - st_type: symtype, - st_visibility: STV_DEFAULT, - st_shndx: section.index, - name: symbol_name, - }; - strtab_index += emitted_symbol_name.len() + 1; - new_strtab_data.extend(&emitted_symbol_name); - new_strtab_data.push(b'\0'); - new_syms.push((sym, vec![])); - } - match st { - MIPS_DEBUG_ST_FILE - | MIPS_DEBUG_ST_STRUCT - | MIPS_DEBUG_ST_UNION - | MIPS_DEBUG_ST_ENUM - | MIPS_DEBUG_ST_BLOCK - | MIPS_DEBUG_ST_PROC - | MIPS_DEBUG_ST_STATIC_PROC => { - scope_level += 1; - } - MIPS_DEBUG_ST_END => { - scope_level -= 1; - } - _ => {} - } - } - assert_eq!(scope_level, 0); - } - - objfile.sym_strtab_mut().data.extend(new_strtab_data); - } - - // Get rid of duplicate symbols, favoring ones that are not UNDEF. - // Skip this for unnamed local symbols though. - new_syms.sort_by(|(a, _), (b, _)| { - if a.st_shndx != SHN_UNDEF && b.st_shndx == SHN_UNDEF { - Ordering::Less - } else { - Ordering::Greater - } - }); - - let new_syms_prev = new_syms; - let mut new_syms = vec![]; - let mut name_to_sym = HashMap::new(); - for (mut s, inds) in new_syms_prev { - if s.name == b"_gp_disp" { - s.st_type = STT_OBJECT; - } - if s.st_bind == STB_LOCAL && s.st_shndx == SHN_UNDEF { - return Err(anyhow::anyhow!( - "local symbol \"{}\" is undefined", - String::from_utf8_lossy(&s.name) - )); - } - if s.name.is_empty() { - if s.st_bind != STB_LOCAL { - return Err(anyhow::anyhow!("global symbol with no name")); - } - new_syms.push((s.clone(), inds)); - } else { - match name_to_sym.get(&s.name) { - None => { - name_to_sym.insert(s.name.clone(), new_syms.len()); - new_syms.push((s.clone(), inds)); - } - Some(&existing) => { - let (s2, inds2) = &mut new_syms[existing]; - if s.st_shndx != SHN_UNDEF - && !(s2.st_shndx == s.st_shndx && s2.st_value == s.st_value) - { - return Err(anyhow::anyhow!( - "symbol \"{}\" defined twice", - String::from_utf8_lossy(&s.name) - )); - } - inds2.extend(inds); - } - } - } - } - - // Put local symbols in front, with the initial dummy entry first, and - // _gp_disp at the end if it exists. - new_syms.insert(0, (empty_symbol.clone(), vec![])); - new_syms.sort_by_key(|(a, _)| (a.st_bind != STB_LOCAL, a.name == b"_gp_disp")); - - let mut obj_new_index: HashMap = HashMap::new(); - let mut asm_new_index: HashMap = HashMap::new(); - - for (new_index, (_, inds)) in new_syms.iter().enumerate() { - for i in inds { - match i { - SymInd::Obj(i) => obj_new_index.insert(*i, new_index), - SymInd::Asm(i) => asm_new_index.insert(*i, new_index), - }; - } - } - - let new_syms: Vec<_> = new_syms.iter().map(|(s, _)| s).collect(); - let num_local_syms = new_syms.iter().filter(|s| s.st_bind == STB_LOCAL).count(); - let new_sym_data: Vec = new_syms.iter().flat_map(|s| s.to_bin()).collect(); - - objfile.symtab_mut().data = new_sym_data; - objfile.symtab_mut().header.sh_info = num_local_syms as u32; - - // Fix up relocation symbol references - for sectype in OUTPUT_SECTIONS { - let target = objfile.find_section(sectype.as_str()).cloned(); - - if let Some(target) = target { - // fixup relocation symbol indices, since we butchered them above - for reltab in target.relocated_by.iter() { - let reltab = &mut objfile.sections[*reltab]; - let mut nrels = vec![]; - for rel in reltab.relocations.iter() { - let mut rel = rel.clone(); - if (sectype == OutputSection::Text - && modified_text_positions.contains(&rel.r_offset)) - || (sectype == OutputSection::Rodata - && jtbl_rodata_positions.contains(&rel.r_offset)) - { - // don't include relocations for late_rodata dummy code - continue; - } - rel.sym_index = obj_new_index[&rel.sym_index]; - nrels.push(rel); - } - reltab.data = nrels.iter().flat_map(|x| x.to_bin(endian)).collect(); - reltab.relocations = nrels; - } - } - } - - // Move over relocations - for sectype in INPUT_SECTION_NAMES.iter() { - if let Some(source) = asm_objfile.find_section(sectype) { - if source.data.is_empty() { - continue; - } - - let target_sectype = if *sectype == ".late_rodata" { - ".rodata" - } else { - sectype - }; - let target_index = objfile - .find_section(target_sectype) - .expect("didn't find target section") - .index; - for reltab in &source.relocated_by { - let reltab = &mut asm_objfile.sections[*reltab].clone(); - for rel in &mut reltab.relocations { - rel.sym_index = asm_new_index[&rel.sym_index]; - if *sectype == ".late_rodata" { - rel.r_offset = moved_late_rodata[&rel.r_offset]; - } - } - let new_data: Vec = reltab - .relocations - .iter() - .flat_map(|x| x.to_bin(endian)) - .collect(); - - let (prefix, sh_entsize) = if reltab.header.sh_type == SHT_REL { - (".rel", 8) - } else { - (".rela", 12) - }; - let rel_section_name = format!("{}{}", prefix, target_sectype); - - if let Some(target_reltab) = objfile.find_section_mut(&rel_section_name) { - target_reltab.data.extend(new_data); - } else { - objfile.add_section( - &rel_section_name, - &HeaderFields { - sh_type: reltab.header.sh_type, - sh_flags: 0, - sh_link: objfile.symtab().index as u32, - sh_info: target_index as u32, - sh_addralign: 4, - sh_entsize, - }, - &new_data, - endian, - ); - } - } - } - } - - let mut file = std::fs::File::create(objfile_path).expect("unable to write to .o file"); - let mut writer = BufWriter::new(&mut file); - objfile.write(&mut writer)?; - - fs::remove_file(s_file_path)?; - fs::remove_file(o_file_path)?; - Ok(()) -} diff --git a/tools/asm-processor/rust/src/preprocess.rs b/tools/asm-processor/rust/src/preprocess.rs deleted file mode 100644 index 7442cd30..00000000 --- a/tools/asm-processor/rust/src/preprocess.rs +++ /dev/null @@ -1,961 +0,0 @@ -use std::{fs, io::Write, iter, path::Path, sync::OnceLock}; - -use anyhow::Result; -use enum_map::{Enum, EnumMap}; -use regex_lite::Regex; - -use crate::{AsmProcArgs, CompileOpts, Encoding, Function, OptLevel, OutputSection}; - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Enum)] -enum InputSection { - Text, - Data, - Rodata, - LateRodata, - Bss, -} - -impl InputSection { - fn from_str(name: &str) -> Option { - match name { - ".text" => Some(InputSection::Text), - ".data" => Some(InputSection::Data), - ".rodata" => Some(InputSection::Rodata), - ".late_rodata" => Some(InputSection::LateRodata), - ".bss" => Some(InputSection::Bss), - _ => None, - } - } -} - -#[derive(Clone, Debug)] -struct GlobalState { - late_rodata_hex: u32, - valuectr: usize, - namectr: usize, - min_instr_count: usize, - skip_instr_count: usize, - use_jtbl_for_rodata: bool, - prelude_if_late_rodata: usize, - mips1: bool, - pascal: bool, -} - -impl GlobalState { - fn new( - min_instr_count: usize, - skip_instr_count: usize, - use_jtbl_for_rodata: bool, - prelude_if_late_rodata: usize, - mips1: bool, - pascal: bool, - ) -> Self { - Self { - // A value that hopefully never appears as a 32-bit rodata constant (or we - // miscompile late rodata). Increases by 1 in each step. - late_rodata_hex: 0xE0123456, - valuectr: 0, - namectr: 0, - min_instr_count, - skip_instr_count, - use_jtbl_for_rodata, - prelude_if_late_rodata, - mips1, - pascal, - } - } - - fn next_late_rodata_hex(&mut self) -> [u8; 4] { - let dummy_bytes = self.late_rodata_hex.to_be_bytes(); - if (self.late_rodata_hex & 0xffff) == 0 { - // Avoid lui - self.late_rodata_hex += 1; - } - self.late_rodata_hex += 1; - dummy_bytes - } - - fn make_name(&mut self, cat: &str) -> String { - self.namectr += 1; - format!("_asmpp_{}{}", cat, self.namectr) - } - - fn func_prologue(&self, name: &str) -> String { - if self.pascal { - [ - &format!("procedure {}();", name), - "type", - " pi = ^integer;", - " pf = ^single;", - " pd = ^double;", - "var", - " vi: pi;", - " vf: pf;", - " vd: pd;", - "begin", - " vi := vi;", - " vf := vf;", - " vd := vd;", - ] - .join(" ") - } else { - format!("void {}(void) {{", name) - } - } - - fn func_epilogue(&self) -> String { - if self.pascal { - "end;".to_string() - } else { - '}'.to_string() - } - } - - fn pascal_assignment_float(&mut self, val: f32) -> String { - self.valuectr += 1; - let address = (8 * self.valuectr) & 0x7FFF; - format!("vf := pf({}); vf^ := {:?};", address, val) - } - - fn pascal_assignment_double(&mut self, val: f64) -> String { - self.valuectr += 1; - let address = (8 * self.valuectr) & 0x7FFF; - format!("vd := pd({}); vd^ := {:?};", address, val) - } - - fn pascal_assignment_int(&mut self, val: i32) -> String { - self.valuectr += 1; - let address = (8 * self.valuectr) & 0x7FFF; - format!("vi := pi({}); vi^ := {};", address, val) - } -} - -#[derive(Clone, Debug)] -struct GlobalAsmBlock { - fn_desc: String, - cur_section: InputSection, - asm_conts: Vec, - late_rodata_asm_conts: Vec, - late_rodata_alignment: usize, - late_rodata_alignment_from_context: bool, - text_glabels: Vec, - fn_section_sizes: EnumMap, - fn_ins_inds: Vec<(usize, usize)>, - glued_line: String, - num_lines: usize, -} - -impl GlobalAsmBlock { - fn new(fn_desc: String) -> Self { - Self { - fn_desc, - cur_section: InputSection::Text, - asm_conts: vec![], - late_rodata_asm_conts: vec![], - late_rodata_alignment: 0, - late_rodata_alignment_from_context: false, - text_glabels: vec![], - fn_section_sizes: EnumMap::default(), - fn_ins_inds: vec![], - glued_line: String::new(), - num_lines: 0, - } - } - - fn fail_without_line(&self, msg: &str) -> Result { - Err(anyhow::anyhow!("{}\nwithin {}", msg, self.fn_desc)) - } - - fn fail_at_line(&self, msg: &str, line: &str) -> Result { - Err(anyhow::anyhow!( - "{}\nwithin {} at line {}", - msg, - self.fn_desc, - line - )) - } - - fn count_quoted_size( - &self, - line: &str, - z: bool, - real_line: &str, - output_enc: &Encoding, - ) -> Result { - let line = output_enc.encode(line)?; - - let mut in_quote = false; - let mut has_comma = true; - let mut num_parts = 0; - let mut ret = 0; - let mut i = 0; - let digits = b"0123456789"; // 0-7 would be more sane, but this matches GNU as - let hexdigits = b"0123456789abcdefABCDEF"; - - while i < line.len() { - let c = line[i]; - i += 1; - if !in_quote { - if c == b'"' { - in_quote = true; - if z && !has_comma { - return self.fail_at_line(".asciiz with glued strings is not supported due to GNU as version diffs", real_line); - } - num_parts += 1; - } else if c == b',' { - has_comma = true; - } - } else { - if c == b'"' { - in_quote = false; - has_comma = false; - continue; - } - ret += 1; - if c != b'\\' { - continue; - } - if i == line.len() { - return self.fail_at_line("backslash at end of line not supported", real_line); - } - let c = line[i]; - i += 1; - // (if c is in "bfnrtv", we have a real escaped literal) - if c == b'x' { - // hex literal, consume any number of hex chars, possibly none - while i < line.len() && hexdigits.contains(&line[i]) { - i += 1; - } - } else if digits.contains(&c) { - // octal literal, consume up to two more digits - let mut it = 0; - while i < line.len() && digits.contains(&line[i]) && it < 2 { - i += 1; - it += 1; - } - } - } - } - - if in_quote { - return self.fail_at_line("unterminated string literal", real_line); - } - if num_parts == 0 { - return self.fail_at_line(".ascii with no string", real_line); - } - Ok(ret + if z { num_parts } else { 0 }) - } - - fn align(&mut self, n: usize) { - let size = &mut self.fn_section_sizes[self.cur_section]; - while *size % n != 0 { - *size += 1; - } - } - - fn add_sized(&mut self, size: isize, line: &str) -> Result<()> { - if (self.cur_section == InputSection::Text || self.cur_section == InputSection::LateRodata) - && size % 4 != 0 - { - return self.fail_at_line("size must be a multiple of 4", line); - } - - if size < 0 { - return self.fail_at_line("size cannot be negative", line); - } - - self.fn_section_sizes[self.cur_section] += size as usize; - - if self.cur_section == InputSection::Text { - if self.text_glabels.is_empty() { - return self.fail_at_line(".text block without an initial glabel", line); - } - self.fn_ins_inds - .push((self.num_lines - 1, size as usize / 4)); - } - - Ok(()) - } - - fn process_line(&mut self, line: &str, output_enc: &Encoding) -> Result<()> { - self.num_lines += 1; - if let Some(stripped) = line.strip_suffix("\\") { - self.glued_line = format!("{}{}", self.glued_line, stripped); - return Ok(()); - } - let mut line = self.glued_line.clone() + line; - self.glued_line = String::new(); - - static CACHE: OnceLock<(Regex, Regex)> = OnceLock::new(); - let (re_comment_or_string, re_label) = CACHE.get_or_init(|| { - ( - Regex::new(r#"#.*|/\*.*?\*/|"(?:\\.|[^\\"])*""#).unwrap(), - Regex::new(r"^[a-zA-Z0-9_]+:\s*").unwrap(), - ) - }); - - fn re_comment_replacer(caps: ®ex_lite::Captures) -> String { - let s = caps[0].to_string(); - if s.starts_with("/") || s.starts_with("#") { - " ".to_owned() - } else { - s - } - } - - let real_line = line.clone(); - line = re_comment_or_string - .replace_all(&line, re_comment_replacer) - .into_owned(); - line = line.trim().to_string(); - line = re_label.replace_all(&line, "").into_owned(); - let mut changed_section = false; - let mut emitting_double = false; - - if (line.starts_with("glabel ") || line.starts_with("jlabel ")) - && self.cur_section == InputSection::Text - { - self.text_glabels - .push(line.split_whitespace().nth(1).unwrap().to_string()); - } - if line.is_empty() { - // empty line - } else if line.starts_with("glabel ") - || line.starts_with("dlabel ") - || line.starts_with("jlabel ") - || line.starts_with("endlabel ") - || (!line.contains(" ") && line.ends_with(":")) - { - // label - } else if line.starts_with(".section") - || matches!( - line.as_str(), - ".text" | ".data" | ".rdata" | ".rodata" | ".bss" | ".late_rodata" - ) - { - // section change - self.cur_section = if line == ".rdata" { - InputSection::Rodata - } else { - let first_arg = line.split(',').next().unwrap().to_string(); - let name = first_arg.split_whitespace().last().unwrap(); - match InputSection::from_str(name) { - Some(s) => s, - None => { - return self.fail_at_line("unrecognized .section directive", &real_line) - } - } - }; - - changed_section = true; - } else if line.starts_with(".late_rodata_alignment") { - if self.cur_section != InputSection::LateRodata { - return self.fail_at_line( - ".late_rodata_alignment must occur within .late_rodata section", - &real_line, - ); - } - - let value = line.split_whitespace().nth(1).unwrap().parse::()?; - if value != 4 && value != 8 { - return self - .fail_at_line(".late_rodata_alignment argument must be 4 or 8", &real_line); - } - if self.late_rodata_alignment != 0 && self.late_rodata_alignment != value { - return self.fail_without_line( - ".late_rodata_alignment alignment assumption conflicts with earlier .double directive. Make sure to provide explicit alignment padding." - ); - } - self.late_rodata_alignment = value; - changed_section = true; - } else if line.starts_with(".incbin") { - let size = line.split(',').last().unwrap().trim().parse::()?; - self.add_sized(size, &real_line)?; - } else if line.starts_with(".word") - || line.starts_with(".gpword") - || line.starts_with(".float") - { - self.align(4); - - self.add_sized(4 * line.split(',').count() as isize, &real_line)?; - } else if line.starts_with(".double") { - self.align(4); - - if self.cur_section == InputSection::LateRodata { - let align8 = self.fn_section_sizes[self.cur_section] % 8; - // Automatically set late_rodata_alignment, so the generated C code uses doubles. - // This gives us correct alignment for the transferred doubles even when the - // late_rodata_alignment is wrong, e.g. for non-matching compilation. - if self.late_rodata_alignment == 0 { - self.late_rodata_alignment = 8 - align8; - self.late_rodata_alignment_from_context = true; - } else if self.late_rodata_alignment != 8 - align8 { - if self.late_rodata_alignment_from_context { - return self.fail_at_line( - "found two .double directives with different start addresses mod 8. Make sure to provide explicit alignment padding.", - &real_line - ); - } else { - return self.fail_at_line( - ".double at address that is not 0 mod 8 (based on .late_rodata_alignment assumption). Make sure to provide explicit alignment padding.\n{}", - &real_line - ); - } - } - - self.add_sized(8 * line.split(',').count() as isize, &real_line)?; - emitting_double = true; - } - } else if line.starts_with(".space") { - let size = line.split_whitespace().nth(1).unwrap().parse::()?; - self.add_sized(size, &real_line)?; - } else if line.starts_with(".balign") { - let align = line.split_whitespace().nth(1).unwrap().parse::()?; - if align != 4 { - return self.fail_at_line("only .balign 4 is supported", &real_line); - } - self.align(4); - } else if line.starts_with(".align") { - let align = line.split_whitespace().nth(1).unwrap().parse::()?; - if align != 2 { - return self.fail_at_line("only .align 2 is supported", &real_line); - } - self.align(4); - } else if line.starts_with(".asci") { - let z = line.starts_with(".asciz") || line.starts_with(".asciiz"); - self.add_sized( - self.count_quoted_size(&line, z, &real_line, output_enc)? as isize, - &real_line, - )?; - } else if line.starts_with(".byte") { - self.add_sized(line.split(',').count() as isize, &real_line)?; - } else if line.starts_with(".half") - || line.starts_with(".hword") - || line.starts_with(".short") - { - self.align(2); - self.add_sized(2 * line.split(',').count() as isize, &real_line)?; - } else if line.starts_with(".size") { - } else if line.starts_with('.') { - return self.fail_at_line("asm directive not supported", &real_line); - } else { - // Unfortunately, macros are hard to support for .rodata -- - // we don't know how how space they will expand to before - // running the assembler, but we need that information to - // construct the C code. So if we need that we'll either - // need to run the assembler twice (at least in some rare - // cases), or change how this program is invoked. - // Similarly, we can't currently deal with pseudo-instructions - // that expand to several real instructions. - if self.cur_section != InputSection::Text { - return self.fail_at_line( - "instruction or macro call in non-.text section? not supported", - &real_line, - ); - } - self.add_sized(4, &real_line)?; - } - - if self.cur_section == InputSection::LateRodata { - if !changed_section { - if emitting_double { - self.late_rodata_asm_conts.push(".align 0".to_string()); - } - self.late_rodata_asm_conts.push(real_line.clone()); - if emitting_double { - self.late_rodata_asm_conts.push(".align 2".to_string()); - } - } - } else { - self.asm_conts.push(real_line.clone()); - } - - Ok(()) - } - - const MAX_FN_SIZE: usize = 100; - - fn finish(&self, state: &mut GlobalState) -> Result<(Vec, Function)> { - let mut src = vec!["".to_owned(); self.num_lines + 1]; - let mut late_rodata_dummy_bytes = vec![]; - let mut jtbl_rodata_size = 0; - let mut late_rodata_fn_output = vec![]; - - let num_instr = self.fn_section_sizes[InputSection::Text] / 4; - - if self.fn_section_sizes[InputSection::LateRodata] > 0 { - // Generate late rodata by emitting unique float constants. - // This requires 3 instructions for each 4 bytes of rodata. - // If we know alignment, we can use doubles, which give 3 - // instructions for 8 bytes of rodata. - let size = self.fn_section_sizes[InputSection::LateRodata] / 4; - let mut skip_next = false; - let mut needs_double = self.late_rodata_alignment != 0; - let mut extra_mips1_nop = false; - let (jtbl_size, jtbl_min_rodata_size) = match (state.pascal, state.mips1) { - (true, true) => (9, 2), - (true, false) => (8, 2), - (false, true) => (11, 5), - (false, false) => (9, 5), - }; - - for i in 0..size { - if skip_next { - skip_next = false; - continue; - } - // Jump tables give 9 instructions (11 with -mips1) for >= 5 words of rodata, - // and should be emitted when: - // - -O2 or -O2 -g3 are used, which give the right codegen - // - we have emitted our first .float/.double (to ensure that we find the - // created rodata in the binary) - // - we have emitted our first .double, if any (to ensure alignment of doubles - // in shifted rodata sections) - // - we have at least 5 words of rodata left to emit (otherwise IDO does not - // generate a jump table) - // - we have at least 10 more instructions to go in this function (otherwise our - // function size computation will be wrong since the delay slot goes unused) - if !needs_double - && state.use_jtbl_for_rodata - && i >= 1 - && size - i >= jtbl_min_rodata_size - && num_instr - late_rodata_fn_output.len() >= jtbl_size + 1 - { - let line = if state.pascal { - let cases: String = (0..(size - i)) - .map(|case| format!("{}: ;", case)) - .collect::>() - .join("\n"); - format!("case 0 of {} otherwise end;", cases) - } else { - let cases: String = (0..(size - i)) - .map(|case| format!("case {}:", case)) - .collect::>() - .join(" "); - format!("switch (*(volatile int*)0) {{ {} ; }}", cases) - }; - late_rodata_fn_output.push(line); - late_rodata_fn_output.extend(iter::repeat("".to_owned()).take(jtbl_size - 1)); - jtbl_rodata_size = (size - i) * 4; - extra_mips1_nop = i != 2; - break; - } - - let dummy_bytes = state.next_late_rodata_hex(); - late_rodata_dummy_bytes.push(dummy_bytes); - if self.late_rodata_alignment == 4 * ((i + 1) % 2 + 1) && i + 1 < size { - let dummy_bytes2 = state.next_late_rodata_hex(); - late_rodata_dummy_bytes.push(dummy_bytes2); - let combined = [dummy_bytes, dummy_bytes2].concat().try_into().unwrap(); - let fval = f64::from_be_bytes(combined); - let line = if state.pascal { - state.pascal_assignment_double(fval) - } else { - format!("*(volatile double*)0 = {:?};", fval) - }; - late_rodata_fn_output.push(line); - skip_next = true; - needs_double = false; - if state.mips1 { - // mips1 does not have ldc1/sdc1 - late_rodata_fn_output.push("".to_owned()); - late_rodata_fn_output.push("".to_owned()); - } - extra_mips1_nop = false; - } else { - let fval = f32::from_be_bytes(dummy_bytes); - let line = if state.pascal { - state.pascal_assignment_float(fval) - } else { - format!("*(volatile float*)0 = {:?}f;", fval) - }; - late_rodata_fn_output.push(line); - extra_mips1_nop = true; - } - late_rodata_fn_output.push("".to_owned()); - late_rodata_fn_output.push("".to_owned()); - } - - if state.mips1 && extra_mips1_nop { - late_rodata_fn_output.push("".to_owned()); - } - } - - let mut text_name = None; - if self.fn_section_sizes[InputSection::Text] > 0 || !late_rodata_fn_output.is_empty() { - let new_name = state.make_name("func"); - src[0] = state.func_prologue(&new_name); - text_name = Some(new_name); - src[self.num_lines] = state.func_epilogue(); - let instr_count = self.fn_section_sizes[InputSection::Text] / 4; - if instr_count < state.min_instr_count { - return self.fail_without_line("too short .text block"); - } - let mut tot_emitted = 0; - let mut tot_skipped = 0; - let mut fn_emitted = 0; - let mut fn_skipped = 0; - let mut skipping = true; - let mut rodata_stack: Vec = late_rodata_fn_output.clone(); - rodata_stack.reverse(); - - for &(line, count) in &self.fn_ins_inds { - for _ in 0..count { - if fn_emitted > Self::MAX_FN_SIZE - && instr_count - tot_emitted > state.min_instr_count - && (rodata_stack.is_empty() || !rodata_stack.last().unwrap().is_empty()) - { - // Don't let functions become too large. When a function reaches 284 - // instructions, and -O2 -framepointer flags are passed, the IRIX - // compiler decides it is a great idea to start optimizing more. - // Also, Pascal cannot handle too large functions before it runs out - // of unique statements to write. - fn_emitted = 0; - fn_skipped = 0; - skipping = true; - let large_func_name = state.make_name("large_func"); - src[line] += &format!( - " {} {} ", - state.func_epilogue(), - state.func_prologue(&large_func_name) - ); - } - - let skip_for_late_rodata = if !rodata_stack.is_empty() { - state.prelude_if_late_rodata - } else { - 0 - }; - if skipping && fn_skipped < state.skip_instr_count + skip_for_late_rodata { - fn_skipped += 1; - tot_skipped += 1; - } else { - skipping = false; - if let Some(entry) = rodata_stack.pop() { - src[line] += &entry; - } else if state.pascal { - src[line] += &state.pascal_assignment_int(0); - } else { - src[line] += "*(volatile int*)0 = 0;"; - } - } - tot_emitted += 1; - fn_emitted += 1; - } - } - - if !rodata_stack.is_empty() { - let size = late_rodata_fn_output.len() / 3; - let available = instr_count - tot_skipped; - return self.fail_without_line(&format!( - "late rodata to text ratio is too high: {} / {} must be <= 1/3\n - add .late_rodata_alignment (4|8) to the .late_rodata block - to double the allowed ratio.", - size, available - )); - } - } - - let mut rodata_name = None; - if self.fn_section_sizes[InputSection::Rodata] > 0 { - if state.pascal { - return self.fail_without_line(".rodata isn't supported with Pascal for now"); - } - let new_name = state.make_name("rodata"); - src[self.num_lines] += &format!( - " const char {}[{}] = {{1}};", - new_name, - self.fn_section_sizes[InputSection::Rodata] - ); - rodata_name = Some(new_name); - } - - let mut data_name = None; - if self.fn_section_sizes[InputSection::Data] > 0 { - let new_name = state.make_name("data"); - let line = if state.pascal { - format!( - " var {}: packed array[1..{}] of char := [otherwise: 0];", - new_name, - self.fn_section_sizes[InputSection::Data] - ) - } else { - format!( - " char {}[{}] = {{1}};", - new_name, - self.fn_section_sizes[InputSection::Data] - ) - }; - src[self.num_lines] += &line; - data_name = Some(new_name); - } - - let mut bss_name = None; - if self.fn_section_sizes[InputSection::Bss] > 0 { - let new_name = state.make_name("bss"); - if state.pascal { - return self.fail_without_line(".bss isn't supported with Pascal for now"); - } - src[self.num_lines] += &format!( - " char {}[{}];", - new_name, - self.fn_section_sizes[InputSection::Bss] - ); - bss_name = Some(new_name); - } - - let mut data = EnumMap::default(); - data[OutputSection::Text] = (text_name, self.fn_section_sizes[InputSection::Text]); - data[OutputSection::Data] = (data_name, self.fn_section_sizes[InputSection::Data]); - data[OutputSection::Rodata] = (rodata_name, self.fn_section_sizes[InputSection::Rodata]); - data[OutputSection::Bss] = (bss_name, self.fn_section_sizes[InputSection::Bss]); - let ret_fn = Function { - text_glabels: self.text_glabels.clone(), - asm_conts: self.asm_conts.clone(), - late_rodata_dummy_bytes, - jtbl_rodata_size, - late_rodata_asm_conts: self.late_rodata_asm_conts.clone(), - fn_desc: self.fn_desc.clone(), - data, - }; - - Ok((src, ret_fn)) - } -} - -/// Convert a float string to its hexadecimal representation -fn repl_float_hex(cap: ®ex_lite::Captures) -> String { - let float_str = cap[0].trim().trim_end_matches('f'); - let float_val = float_str.parse::().unwrap(); - let hex_val = f32::to_be_bytes(float_val); - format!("{}", u32::from_be_bytes(hex_val)) -} - -pub(crate) struct ParseSourceResult { - pub functions: Vec, - pub deps: Vec, - pub output: Vec, -} - -pub(crate) fn parse_source( - infile_path: &Path, - args: &AsmProcArgs, - opts: &CompileOpts, - encode: bool, -) -> Result { - let (mut min_instr_count, mut skip_instr_count) = match opts.opt { - OptLevel::O0 => match opts.framepointer { - true => (8, 8), - false => (4, 4), - }, - OptLevel::O1 | OptLevel::O2 => match opts.framepointer { - true => (6, 5), - false => (2, 1), - }, - OptLevel::G => match opts.framepointer { - true => (7, 7), - false => (4, 4), - }, - OptLevel::G3 => match opts.framepointer { - true => (4, 4), - false => (2, 2), - }, - }; - - let mut prelude_if_late_rodata = 0; - if opts.kpic { - // Without optimizations, the PIC prelude always takes up 3 instructions. - // With optimizations, the prelude is optimized out if there's no late rodata. - if matches!(opts.opt, OptLevel::O2 | OptLevel::G3) { - prelude_if_late_rodata = 3; - } else { - min_instr_count += 3; - skip_instr_count += 3; - } - } - - let use_jtbl_for_rodata = - matches!(opts.opt, OptLevel::O2 | OptLevel::G3) && !opts.framepointer && !opts.kpic; - - let mut state = GlobalState::new( - min_instr_count, - skip_instr_count, - use_jtbl_for_rodata, - prelude_if_late_rodata, - opts.mips1, - opts.pascal, - ); - let input_enc = &args.input_enc; - let output_enc = &args.output_enc; - let mut global_asm: Option<(GlobalAsmBlock, usize)> = None; - let mut asm_functions: Vec = vec![]; - let mut output_lines: Vec = vec![format!("#line 1 \"{}\"", infile_path.display())]; - let mut deps: Vec = vec![]; - - let mut is_cutscene_data = false; - let mut is_early_include = false; - - let cutscene_re = Regex::new(r"CutsceneData (.|\n)*\[\] = \{")?; - let float_re = Regex::new(r"[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?f")?; - - let file_contents = fs::read(infile_path)?; - for (line_no, line) in input_enc.decode(&file_contents)?.lines().enumerate() { - let line_no = line_no + 1; - let mut raw_line = line.trim().to_owned(); - let line = raw_line.trim_start(); - - // Print exactly one output line per source line, to make compiler - // errors have correct line numbers. These will be overridden with - // reasonable content further down. - output_lines.push("".to_owned()); - - if let Some((ref mut gasm, start_index)) = global_asm { - if line.starts_with(')') { - let (mut src, fun) = gasm.finish(&mut state)?; - if state.pascal { - // Pascal has a 1600-character line length limit, so some - // of the lines we emit may be broken up. Correct for that - // using a #line directive. - *src.last_mut().unwrap() += &format!("\n#line {}", line_no + 1); - } - for (i, line2) in src.iter().enumerate() { - output_lines[start_index + i] = line2.clone(); - } - asm_functions.push(fun); - global_asm = None; - } else { - gasm.process_line(&raw_line, output_enc)?; - } - } else if line == "GLOBAL_ASM(" || line == "#pragma GLOBAL_ASM(" { - global_asm = Some(( - GlobalAsmBlock::new(format!("GLOBAL_ASM block at line {}", &line_no.to_string())), - output_lines.len(), - )); - } else if ((line.starts_with("GLOBAL_ASM(\"") || line.starts_with("#pragma GLOBAL_ASM(\"")) - && line.ends_with("\")")) - || ((line.starts_with("INCLUDE_ASM(\"") || line.starts_with("INCLUDE_RODATA(\"")) - && line.contains("\",") - && line.ends_with(");")) - { - let (prologue, fname) = if line.starts_with("INCLUDE_") { - // INCLUDE_ASM("path/to", functionname); - let (before, after) = line.split_once("\",").unwrap(); - let fname = format!( - "{}/{}.s", - before[before.find('(').unwrap() + 2..].to_owned(), - after.trim()[..after.len() - 3].trim() - ); - - if line.starts_with("INCLUDE_RODATA") { - (vec![".section .rodata".to_string()], fname) - } else { - (vec![], fname) - } - } else { - // GLOBAL_ASM("path/to/file.s") - let fname = line[line.find('(').unwrap() + 2..line.len() - 2].to_string(); - (vec![], fname) - }; - - let mut gasm = GlobalAsmBlock::new(fname.clone()); - for line2 in prologue { - gasm.process_line(line2.trim_end(), output_enc)?; - } - - if !Path::new(&fname).exists() { - // The GLOBAL_ASM block might be surrounded by an ifdef, so it's - // not clear whether a missing file actually represents a compile - // error. Pass the responsibility for determining that on to the - // compiler by emitting a bad include directive. (IDO treats - // #error as a warning for some reason.) - let output_lines_len = output_lines.len(); - output_lines[output_lines_len - 1] = format!("#include \"GLOBAL_ASM:{}\"", fname); - continue; - } - - let file_contents = fs::read(&fname)?; - for line2 in input_enc.decode(&file_contents)?.lines() { - gasm.process_line(line2.trim_end(), output_enc)?; - } - - let (mut src, fun) = gasm.finish(&mut state)?; - let output_lines_len = output_lines.len(); - if state.pascal { - // Pascal has a 1600-character line length limit, so avoid putting - // everything on the same line. - src.push(format!("#line {}", line_no + 1)); - output_lines[output_lines_len - 1] = src.join("\n"); - } else { - output_lines[output_lines_len - 1] = src.join(""); - } - asm_functions.push(fun); - deps.push(fname); - } else if line == "#pragma asmproc recurse" { - // C includes qualified as - // #pragma asmproc recurse - // #include "file.c" - // will be processed recursively when encountered - is_early_include = true; - } else if is_early_include { - // Previous line was a #pragma asmproc recurse - is_early_include = false; - if !line.starts_with("#include ") { - return Err(anyhow::anyhow!( - "#pragma asmproc recurse must be followed by an #include " - )); - } - let fpath = infile_path.parent().unwrap(); - let fname = fpath.join(line[line.find(' ').unwrap() + 2..].trim()); - deps.push(fname.to_str().unwrap().to_string()); - let mut res = parse_source(&fname, args, opts, false)?; - deps.append(&mut res.deps); - let res_str = format!( - "{}#line {} \"{}\"", - String::from_utf8(res.output).expect("nested calls generate utf-8"), - line_no + 1, - infile_path.file_name().unwrap().to_str().unwrap() - ); - - let output_lines_len = output_lines.len(); - output_lines[output_lines_len - 1] = res_str; - } else { - if args.encode_cutscene_data_floats { - // This is a hack to replace all floating-point numbers in an array of a particular type - // (in this case CutsceneData) with their corresponding IEEE-754 hexadecimal representation - if cutscene_re.is_match(line) { - is_cutscene_data = true; - } else if line.ends_with("};") { - is_cutscene_data = false; - } - - if is_cutscene_data { - raw_line = float_re.replace_all(&raw_line, repl_float_hex).into_owned(); - } - } - let output_lines_len = output_lines.len(); - output_lines[output_lines_len - 1] = raw_line.to_owned(); - } - } - - let out_data = if encode { - let newline_encoded = output_enc.encode("\n")?; - - let mut data = vec![]; - for line in output_lines { - let line_encoded = output_enc.encode(&line)?; - data.write_all(&line_encoded)?; - data.write_all(&newline_encoded)?; - } - data - } else { - let str = format!("{}\n", output_lines.join("\n")); - - str.as_bytes().to_vec() - }; - - Ok(ParseSourceResult { - functions: asm_functions, - deps, - output: out_data, - }) -} diff --git a/tools/asm-processor/tests/ascii.c b/tools/asm-processor/tests/ascii.c deleted file mode 100644 index bb27d252..00000000 --- a/tools/asm-processor/tests/ascii.c +++ /dev/null @@ -1,19 +0,0 @@ -void foo(void) { "abcdef"; } - -GLOBAL_ASM( -.rdata - .ascii "AB" - .ascii "CD", "EF" - .ascii "GH\n\n\n\0\11\222\3333\44444\x1234567\n\nIJK" -) - -void bar(void) { "hello"; } - -GLOBAL_ASM( -.rdata - .asciiz "12" - .asciiz "34", "56" - .asciiz "78\n\n\n\0\11\222\3333\44444\x1234567\n\n9A" -) - -void baz(void) { "ghijkl"; } diff --git a/tools/asm-processor/tests/ascii.objdump b/tools/asm-processor/tests/ascii.objdump deleted file mode 100644 index bf42638a..00000000 --- a/tools/asm-processor/tests/ascii.objdump +++ /dev/null @@ -1,29 +0,0 @@ - -tests/ascii.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000030 .text -00000000 l d .rodata 00000050 .rodata -00000000 g F .text 00000010 foo -00000010 g F .text 00000010 bar -00000020 g F .text 00000010 baz - - -Contents of section .text: - 0000 03e00008 00000000 03e00008 00000000 ................ - 0010 03e00008 00000000 03e00008 00000000 ................ - 0020 03e00008 00000000 03e00008 00000000 ................ -Contents of section .rodata: - 0000 61626364 65660000 41424344 45464748 abcdef..ABCDEFGH - 0010 0a0a0a00 0992db33 24343467 0a0a494a .......3$44g..IJ - 0020 4b000000 68656c6c 6f000000 31320033 K...hello...12.3 - 0030 34003536 0037380a 0a0a0009 92db3324 4.56.78.......3$ - 0040 3434670a 0a394100 6768696a 6b6c0000 44g..9A.ghijkl.. -Contents of section .options: - 0000 01200000 00000000 80000000 00000000 . .............. - 0010 00000000 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 80000000 00000000 00000000 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/comments.c b/tools/asm-processor/tests/comments.c deleted file mode 100644 index 4c936699..00000000 --- a/tools/asm-processor/tests/comments.c +++ /dev/null @@ -1,6 +0,0 @@ -const char before[] = "^"; -GLOBAL_ASM( -.rdata -.asciz "aaaa /* bbbb */ # cccc", /**//**//**//**/ /*/ "xxxx" /*/ /* dddd " eeee */ "# ffff" # gggg "hhhh" /* iiii */ -) -const char after[] = "$"; diff --git a/tools/asm-processor/tests/comments.objdump b/tools/asm-processor/tests/comments.objdump deleted file mode 100644 index 246df209..00000000 --- a/tools/asm-processor/tests/comments.objdump +++ /dev/null @@ -1,21 +0,0 @@ - -tests/comments.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .rodata 00000030 .rodata -00000000 g O .rodata 00000002 before -00000024 g O .rodata 00000002 after - - -Contents of section .rodata: - 0000 5e000000 61616161 202f2a20 62626262 ^...aaaa /* bbbb - 0010 202a2f20 23206363 63630023 20666666 */ # cccc.# fff - 0020 66000000 24000000 00000000 00000000 f...$........... -Contents of section .options: - 0000 01200000 00000000 00000000 00000000 . .............. - 0010 00000000 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 00000000 00000000 00000000 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/custom-prelude.c b/tools/asm-processor/tests/custom-prelude.c deleted file mode 100644 index 1b057d55..00000000 --- a/tools/asm-processor/tests/custom-prelude.c +++ /dev/null @@ -1,17 +0,0 @@ -// COMPILE-FLAGS: -O2 -// ASMP-FLAGS: --asm-prelude tests/custom-prelude.s - -GLOBAL_ASM( -glabel foo -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -endlabel foo -) diff --git a/tools/asm-processor/tests/custom-prelude.objdump b/tools/asm-processor/tests/custom-prelude.objdump deleted file mode 100644 index 37af655e..00000000 --- a/tools/asm-processor/tests/custom-prelude.objdump +++ /dev/null @@ -1,21 +0,0 @@ - -tests/custom-prelude.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000030 .text -00000000 g F .text 00000028 foo -00000028 g .text 00000000 myendlabel - - -Contents of section .text: - 0000 00000000 00000000 00000000 00000000 ................ - 0010 00000000 00000000 00000000 00000000 ................ - 0020 00000000 00000000 00000000 00000000 ................ -Contents of section .options: - 0000 01200000 00000000 80000000 00000000 . .............. - 0010 00000000 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 80000000 00000000 00000000 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/custom-prelude.s b/tools/asm-processor/tests/custom-prelude.s deleted file mode 100644 index 75f955a7..00000000 --- a/tools/asm-processor/tests/custom-prelude.s +++ /dev/null @@ -1,14 +0,0 @@ -.set noat -.set noreorder -.set gp=64 - -.macro glabel label - .global \label - \label: -.endm - -.macro endlabel label - .global myendlabel - myendlabel: -.endm - diff --git a/tools/asm-processor/tests/euc_jp_wavedash.c b/tools/asm-processor/tests/euc_jp_wavedash.c deleted file mode 100644 index d187d7dd..00000000 --- a/tools/asm-processor/tests/euc_jp_wavedash.c +++ /dev/null @@ -1,3 +0,0 @@ -// ASMP-FLAGS: --force --input-enc=utf-8 --output-enc=EUC-JP - -char *chars = "〜!?@#"; \ No newline at end of file diff --git a/tools/asm-processor/tests/euc_jp_wavedash.objdump b/tools/asm-processor/tests/euc_jp_wavedash.objdump deleted file mode 100644 index 5820e73e..00000000 --- a/tools/asm-processor/tests/euc_jp_wavedash.objdump +++ /dev/null @@ -1,26 +0,0 @@ - -tests/euc_jp_wavedash.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .rodata 00000010 .rodata -00000000 l d .data 00000010 .data -00000000 g O .data 00000004 chars - - -RELOCATION RECORDS FOR [.data]: -OFFSET TYPE VALUE -00000000 R_MIPS_32 .rodata - - -Contents of section .rodata: - 0000 a1c1a1aa a1a9a1f7 a1f40000 00000000 ................ -Contents of section .data: - 0000 00000000 00000000 00000000 00000000 ................ -Contents of section .options: - 0000 01200000 00000000 00000000 00000000 . .............. - 0010 00000000 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 00000000 00000000 00000000 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/force.c b/tools/asm-processor/tests/force.c deleted file mode 100644 index 32d8706b..00000000 --- a/tools/asm-processor/tests/force.c +++ /dev/null @@ -1,17 +0,0 @@ -// COMPILE-FLAGS: -O2 -// ASMP-FLAGS: --convert-statics global-with-filename --force -static int xtext(int a, int b, int c); -const int rodata1[] = {1}; -static const int rodata2[] = {2}; -int data1[] = {3}; -static int data2[] = {4}; -int bss1; -static int bss2; - -static int xtext(int a, int b, int c) { - return 1; -} - -void baz(void) { - xtext(bss2, rodata2[0], data2[0]); -} diff --git a/tools/asm-processor/tests/force.objdump b/tools/asm-processor/tests/force.objdump deleted file mode 100644 index 46941d36..00000000 --- a/tools/asm-processor/tests/force.objdump +++ /dev/null @@ -1,47 +0,0 @@ - -tests/force.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000050 .text -00000000 l d .rodata 00000010 .rodata -00000000 l d .data 00000010 .data -00000000 l d .bss 00000010 .bss -00000000 g O .rodata 00000004 rodata1 -00000000 g O .data 00000004 data1 -00000000 g O .bss 00000004 bss1 -00000014 g F .text 00000034 baz -00000004 g O .rodata 00000000 tests/force.o:rodata2 -00000004 g O .data 00000000 tests/force.o:data2 -00000004 g O .bss 00000000 tests/force.o:bss2 -00000000 g F .text 00000000 tests/force.o:xtext - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -0000001c R_MIPS_HI16 .bss -00000034 R_MIPS_LO16 .bss -00000020 R_MIPS_HI16 .rodata -0000002c R_MIPS_LO16 .rodata -00000024 R_MIPS_HI16 .data -00000028 R_MIPS_LO16 .data -00000030 R_MIPS_26 .text - - -Contents of section .text: - 0000 afa40000 afa50004 afa60008 03e00008 ................ - 0010 24020001 27bdffe8 afbf0014 3c040000 $...'.......<... - 0020 3c050000 3c060000 8cc60004 8ca50004 <...<........... - 0030 0c000000 8c840004 8fbf0014 27bd0018 ............'... - 0040 03e00008 00000000 00000000 00000000 ................ -Contents of section .rodata: - 0000 00000001 00000002 00000000 00000000 ................ -Contents of section .data: - 0000 00000003 00000004 00000000 00000000 ................ -Contents of section .options: - 0000 01200000 00000000 a0000074 00000000 . .........t.... - 0010 00000000 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 a0000074 00000000 00000000 00000000 ...t............ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/include_file.asmproc.d b/tools/asm-processor/tests/include_file.asmproc.d deleted file mode 100644 index 80d2d669..00000000 --- a/tools/asm-processor/tests/include_file.asmproc.d +++ /dev/null @@ -1,12 +0,0 @@ -tests/include_file.o: tests/include_file_1.s \ - tests/include_file_2.s \ - tests/include_file_3.s \ - tests//include_file_4.s - -tests/include_file_1.s: - -tests/include_file_2.s: - -tests/include_file_3.s: - -tests//include_file_4.s: diff --git a/tools/asm-processor/tests/include_file.c b/tools/asm-processor/tests/include_file.c deleted file mode 100644 index 97eb45d5..00000000 --- a/tools/asm-processor/tests/include_file.c +++ /dev/null @@ -1,8 +0,0 @@ -GLOBAL_ASM("tests/include_file_1.s") -#pragma GLOBAL_ASM("tests/include_file_2.s") -INCLUDE_ASM("tests", include_file_3); -INCLUDE_RODATA("tests/", include_file_4); -#if 0 -GLOBAL_ASM("tests/nonexisting.s"); -INCLUDE_ASM("tests", nonexisting); -#endif diff --git a/tools/asm-processor/tests/include_file.objdump b/tools/asm-processor/tests/include_file.objdump deleted file mode 100644 index c2b172b6..00000000 --- a/tools/asm-processor/tests/include_file.objdump +++ /dev/null @@ -1,27 +0,0 @@ - -tests/include_file.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000050 .text -00000000 l d .rodata 00000010 .rodata -00000000 g F .text 00000018 file_1 -00000018 g F .text 00000018 file_2 -00000030 g F .text 00000018 file_3 - - -Contents of section .text: - 0000 24050000 24050001 24050002 24050003 $...$...$...$... - 0010 24050004 24050005 24060000 24060001 $...$...$...$... - 0020 24060002 24060003 24060004 24060005 $...$...$...$... - 0030 24070000 24070001 24070002 24070003 $...$...$...$... - 0040 24070004 24070005 00000000 00000000 $...$........... -Contents of section .rodata: - 0000 00000005 00000006 00000007 00000008 ................ -Contents of section .options: - 0000 01200000 00000000 80000000 00000000 . .............. - 0010 00000000 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 800000e0 00000000 00000000 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/include_file_1.s b/tools/asm-processor/tests/include_file_1.s deleted file mode 100644 index 24a67f9b..00000000 --- a/tools/asm-processor/tests/include_file_1.s +++ /dev/null @@ -1,7 +0,0 @@ -glabel file_1 -li $a1, 0 -li $a1, 1 -li $a1, 2 -li $a1, 3 -li $a1, 4 -li $a1, 5 diff --git a/tools/asm-processor/tests/include_file_2.s b/tools/asm-processor/tests/include_file_2.s deleted file mode 100644 index 42601977..00000000 --- a/tools/asm-processor/tests/include_file_2.s +++ /dev/null @@ -1,7 +0,0 @@ -glabel file_2 -li $a2, 0 -li $a2, 1 -li $a2, 2 -li $a2, 3 -li $a2, 4 -li $a2, 5 diff --git a/tools/asm-processor/tests/include_file_3.s b/tools/asm-processor/tests/include_file_3.s deleted file mode 100644 index d0123af0..00000000 --- a/tools/asm-processor/tests/include_file_3.s +++ /dev/null @@ -1,7 +0,0 @@ -glabel file_3 -li $a3, 0 -li $a3, 1 -li $a3, 2 -li $a3, 3 -li $a3, 4 -li $a3, 5 diff --git a/tools/asm-processor/tests/include_file_4.s b/tools/asm-processor/tests/include_file_4.s deleted file mode 100644 index 94cb7106..00000000 --- a/tools/asm-processor/tests/include_file_4.s +++ /dev/null @@ -1 +0,0 @@ -.word 5, 6, 7, 8 diff --git a/tools/asm-processor/tests/kpic-o1.c b/tools/asm-processor/tests/kpic-o1.c deleted file mode 100644 index 4d3346d2..00000000 --- a/tools/asm-processor/tests/kpic-o1.c +++ /dev/null @@ -1,93 +0,0 @@ -// COMPILE-FLAGS: -O1 -KPIC -GLOBAL_ASM( -glabel foo -addiu $a0, $a0, 1 -addiu $a0, $a0, 2 -addiu $a0, $a0, 3 -addiu $a0, $a0, 4 -addiu $a0, $a0, 5 -addiu $a0, $a0, 6 -addiu $a0, $a0, 7 -addiu $a0, $a0, 8 -addiu $a0, $a0, 9 -addiu $a0, $a0, 10 -addiu $a0, $a0, 11 -addiu $a0, $a0, 12 -) -GLOBAL_ASM( -.late_rodata -.float 1 -.text -glabel float_fn -addiu $a0, $a0, 13 -addiu $a0, $a0, 14 -addiu $a0, $a0, 15 -addiu $a0, $a0, 16 -addiu $a0, $a0, 17 -addiu $a0, $a0, 18 -addiu $a0, $a0, 19 -addiu $a0, $a0, 20 -addiu $a0, $a0, 21 -addiu $a0, $a0, 22 -addiu $a0, $a0, 23 -addiu $a0, $a0, 24 -addiu $a0, $a0, 25 -addiu $a0, $a0, 26 -addiu $a0, $a0, 27 -addiu $a0, $a0, 28 -addiu $a0, $a0, 29 -addiu $a0, $a0, 30 -) -GLOBAL_ASM( -.late_rodata -.late_rodata_alignment 4 -.float 2 -.double 1 -.double 2 -.double 3 -.double 4 -.double 5 -.double 6 -.double 7 -.double 8 -.text -glabel doubles -addiu $a0, $a0, 31 -addiu $a0, $a0, 32 -addiu $a0, $a0, 33 -addiu $a0, $a0, 34 -addiu $a0, $a0, 35 -addiu $a0, $a0, 36 -addiu $a0, $a0, 37 -addiu $a0, $a0, 38 -addiu $a0, $a0, 39 -addiu $a0, $a0, 40 -addiu $a0, $a0, 41 -addiu $a0, $a0, 42 -addiu $a0, $a0, 43 -addiu $a0, $a0, 44 -addiu $a0, $a0, 45 -addiu $a0, $a0, 46 -addiu $a0, $a0, 47 -addiu $a0, $a0, 48 -addiu $a0, $a0, 49 -addiu $a0, $a0, 50 -addiu $a0, $a0, 51 -addiu $a0, $a0, 52 -addiu $a0, $a0, 53 -addiu $a0, $a0, 54 -addiu $a0, $a0, 55 -addiu $a0, $a0, 56 -addiu $a0, $a0, 57 -addiu $a0, $a0, 58 -addiu $a0, $a0, 59 -addiu $a0, $a0, 60 -addiu $a0, $a0, 61 -addiu $a0, $a0, 62 -addiu $a0, $a0, 63 -addiu $a0, $a0, 64 -addiu $a0, $a0, 65 -addiu $a0, $a0, 66 -addiu $a0, $a0, 67 -addiu $a0, $a0, 68 -) diff --git a/tools/asm-processor/tests/kpic-o1.objdump b/tools/asm-processor/tests/kpic-o1.objdump deleted file mode 100644 index 6e336753..00000000 --- a/tools/asm-processor/tests/kpic-o1.objdump +++ /dev/null @@ -1,46 +0,0 @@ - -tests/kpic-o1.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000110 .text -00000000 l d .rodata 00000050 .rodata -00000000 g F .text 00000030 foo -00000030 g F .text 00000048 float_fn -00000078 g F .text 00000098 doubles -00000000 O *UND* 00000000 _gp_disp - - -RELOCATION RECORDS FOR [.text]: (none) - -Contents of section .text: - 0000 24840001 24840002 24840003 24840004 $...$...$...$... - 0010 24840005 24840006 24840007 24840008 $...$...$...$... - 0020 24840009 2484000a 2484000b 2484000c $...$...$...$... - 0030 2484000d 2484000e 2484000f 24840010 $...$...$...$... - 0040 24840011 24840012 24840013 24840014 $...$...$...$... - 0050 24840015 24840016 24840017 24840018 $...$...$...$... - 0060 24840019 2484001a 2484001b 2484001c $...$...$...$... - 0070 2484001d 2484001e 2484001f 24840020 $...$...$...$.. - 0080 24840021 24840022 24840023 24840024 $..!$.."$..#$..$ - 0090 24840025 24840026 24840027 24840028 $..%$..&$..'$..( - 00a0 24840029 2484002a 2484002b 2484002c $..)$..*$..+$.., - 00b0 2484002d 2484002e 2484002f 24840030 $..-$...$../$..0 - 00c0 24840031 24840032 24840033 24840034 $..1$..2$..3$..4 - 00d0 24840035 24840036 24840037 24840038 $..5$..6$..7$..8 - 00e0 24840039 2484003a 2484003b 2484003c $..9$..:$..;$..< - 00f0 2484003d 2484003e 2484003f 24840040 $..=$..>$..?$..@ - 0100 24840041 24840042 24840043 24840044 $..A$..B$..C$..D -Contents of section .rodata: - 0000 3f800000 40000000 3ff00000 00000000 ?...@...?....... - 0010 40000000 00000000 40080000 00000000 @.......@....... - 0020 40100000 00000000 40140000 00000000 @.......@....... - 0030 40180000 00000000 401c0000 00000000 @.......@....... - 0040 40200000 00000000 00000000 00000000 @ .............. -Contents of section .options: - 0000 01200000 00000000 92000002 00000000 . .............. - 0010 000f0ff0 00000000 00000000 00000000 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 92000012 00000000 000f0ff0 00000000 ................ - 0010 00000000 00000000 ........ diff --git a/tools/asm-processor/tests/kpic-o2.c b/tools/asm-processor/tests/kpic-o2.c deleted file mode 100644 index f037341c..00000000 --- a/tools/asm-processor/tests/kpic-o2.c +++ /dev/null @@ -1,92 +0,0 @@ -// COMPILE-FLAGS: -O2 -KPIC -GLOBAL_ASM( -glabel foo -addiu $a0, $a0, 1 -addiu $a0, $a0, 2 -addiu $a0, $a0, 3 -addiu $a0, $a0, 4 -addiu $a0, $a0, 5 -addiu $a0, $a0, 6 -addiu $a0, $a0, 7 -addiu $a0, $a0, 8 -addiu $a0, $a0, 9 -addiu $a0, $a0, 10 -addiu $a0, $a0, 11 -addiu $a0, $a0, 12 -) -GLOBAL_ASM( -.late_rodata -.float 1 -.text -glabel float_fn -addiu $a0, $a0, 13 -addiu $a0, $a0, 14 -addiu $a0, $a0, 15 -addiu $a0, $a0, 16 -addiu $a0, $a0, 17 -addiu $a0, $a0, 18 -addiu $a0, $a0, 19 -addiu $a0, $a0, 20 -addiu $a0, $a0, 21 -addiu $a0, $a0, 22 -addiu $a0, $a0, 23 -addiu $a0, $a0, 24 -addiu $a0, $a0, 25 -addiu $a0, $a0, 26 -addiu $a0, $a0, 27 -addiu $a0, $a0, 28 -addiu $a0, $a0, 29 -addiu $a0, $a0, 30 -) -GLOBAL_ASM( -.late_rodata -.float 2 -.double 1 -.double 2 -.double 3 -.double 4 -.double 5 -.double 6 -.double 7 -.double 8 -.text -glabel doubles -addiu $a0, $a0, 31 -addiu $a0, $a0, 32 -addiu $a0, $a0, 33 -addiu $a0, $a0, 34 -addiu $a0, $a0, 35 -addiu $a0, $a0, 36 -addiu $a0, $a0, 37 -addiu $a0, $a0, 38 -addiu $a0, $a0, 39 -addiu $a0, $a0, 40 -addiu $a0, $a0, 41 -addiu $a0, $a0, 42 -addiu $a0, $a0, 43 -addiu $a0, $a0, 44 -addiu $a0, $a0, 45 -addiu $a0, $a0, 46 -addiu $a0, $a0, 47 -addiu $a0, $a0, 48 -addiu $a0, $a0, 49 -addiu $a0, $a0, 50 -addiu $a0, $a0, 51 -addiu $a0, $a0, 52 -addiu $a0, $a0, 53 -addiu $a0, $a0, 54 -addiu $a0, $a0, 55 -addiu $a0, $a0, 56 -addiu $a0, $a0, 57 -addiu $a0, $a0, 58 -addiu $a0, $a0, 59 -addiu $a0, $a0, 60 -addiu $a0, $a0, 61 -addiu $a0, $a0, 62 -addiu $a0, $a0, 63 -addiu $a0, $a0, 64 -addiu $a0, $a0, 65 -addiu $a0, $a0, 66 -addiu $a0, $a0, 67 -addiu $a0, $a0, 68 -) diff --git a/tools/asm-processor/tests/kpic-o2.objdump b/tools/asm-processor/tests/kpic-o2.objdump deleted file mode 100644 index abf87aeb..00000000 --- a/tools/asm-processor/tests/kpic-o2.objdump +++ /dev/null @@ -1,46 +0,0 @@ - -tests/kpic-o2.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000110 .text -00000000 l d .rodata 00000050 .rodata -00000000 g F .text 00000030 foo -00000030 g F .text 00000048 float_fn -00000078 g F .text 00000098 doubles -00000000 O *UND* 00000000 _gp_disp - - -RELOCATION RECORDS FOR [.text]: (none) - -Contents of section .text: - 0000 24840001 24840002 24840003 24840004 $...$...$...$... - 0010 24840005 24840006 24840007 24840008 $...$...$...$... - 0020 24840009 2484000a 2484000b 2484000c $...$...$...$... - 0030 2484000d 2484000e 2484000f 24840010 $...$...$...$... - 0040 24840011 24840012 24840013 24840014 $...$...$...$... - 0050 24840015 24840016 24840017 24840018 $...$...$...$... - 0060 24840019 2484001a 2484001b 2484001c $...$...$...$... - 0070 2484001d 2484001e 2484001f 24840020 $...$...$...$.. - 0080 24840021 24840022 24840023 24840024 $..!$.."$..#$..$ - 0090 24840025 24840026 24840027 24840028 $..%$..&$..'$..( - 00a0 24840029 2484002a 2484002b 2484002c $..)$..*$..+$.., - 00b0 2484002d 2484002e 2484002f 24840030 $..-$...$../$..0 - 00c0 24840031 24840032 24840033 24840034 $..1$..2$..3$..4 - 00d0 24840035 24840036 24840037 24840038 $..5$..6$..7$..8 - 00e0 24840039 2484003a 2484003b 2484003c $..9$..:$..;$..< - 00f0 2484003d 2484003e 2484003f 24840040 $..=$..>$..?$..@ - 0100 24840041 24840042 24840043 24840044 $..A$..B$..C$..D -Contents of section .rodata: - 0000 3f800000 40000000 3ff00000 00000000 ?...@...?....... - 0010 40000000 00000000 40080000 00000000 @.......@....... - 0020 40100000 00000000 40140000 00000000 @.......@....... - 0030 40180000 00000000 401c0000 00000000 @.......@....... - 0040 40200000 00000000 00000000 00000000 @ .............. -Contents of section .options: - 0000 01200000 00000000 92000002 00000000 . .............. - 0010 000f0ff0 00000000 00000000 00000000 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 92000012 00000000 000f0ff0 00000000 ................ - 0010 00000000 00000000 ........ diff --git a/tools/asm-processor/tests/label-sameline.c b/tools/asm-processor/tests/label-sameline.c deleted file mode 100644 index a35b43d8..00000000 --- a/tools/asm-processor/tests/label-sameline.c +++ /dev/null @@ -1,7 +0,0 @@ -GLOBAL_ASM( -.rdata -.word 0x12345678 -glabel blah -.word blah2 - /*a*/ blah2: /*b*/ .word blah /*c*/ -) diff --git a/tools/asm-processor/tests/label-sameline.objdump b/tools/asm-processor/tests/label-sameline.objdump deleted file mode 100644 index e69f69cc..00000000 --- a/tools/asm-processor/tests/label-sameline.objdump +++ /dev/null @@ -1,25 +0,0 @@ - -tests/label-sameline.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .rodata 00000010 .rodata -00000000 l d .rodata 00000000 -00000004 g .rodata 00000000 blah - - -RELOCATION RECORDS FOR [.rodata]: -OFFSET TYPE VALUE -00000004 R_MIPS_32 -00000008 R_MIPS_32 blah - - -Contents of section .rodata: - 0000 12345678 00000008 00000000 00000000 .4Vx............ -Contents of section .options: - 0000 01200000 00000000 00000000 00000000 . .............. - 0010 00000000 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 00000000 00000000 00000000 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/large.c b/tools/asm-processor/tests/large.c deleted file mode 100644 index 4ffb4ac1..00000000 --- a/tools/asm-processor/tests/large.c +++ /dev/null @@ -1,164 +0,0 @@ - -GLOBAL_ASM( -glabel test - -addiu $sp, $sp, -24 - sw $zero, 4($sp) -lw $t6, 4($sp) -addu $t7, $a0, $t6 -sb $zero, ($t7) -lw $t8, 4($sp) -addiu $t9, $t8, 1 -slt $at, $t9, $a1 - sw $t9, 4($sp) - nop -jr $ra - addiu $sp, $sp, 24 -addiu $sp, $sp, -24 - sw $zero, 4($sp) -lw $t6, 4($sp) -addu $t7, $a0, $t6 -sb $zero, ($t7) -lw $t8, 4($sp) -addiu $t9, $t8, 1 -slt $at, $t9, $a1 - sw $t9, 4($sp) - nop -jr $ra - addiu $sp, $sp, 24 -addiu $sp, $sp, -24 - sw $zero, 4($sp) -lw $t6, 4($sp) -addu $t7, $a0, $t6 -sb $zero, ($t7) -lw $t8, 4($sp) -addiu $t9, $t8, 1 -slt $at, $t9, $a1 - sw $t9, 4($sp) - nop -jr $ra - addiu $sp, $sp, 24 -addiu $sp, $sp, -24 - sw $zero, 4($sp) -lw $t6, 4($sp) -addu $t7, $a0, $t6 -sb $zero, ($t7) -lw $t8, 4($sp) -addiu $t9, $t8, 1 -slt $at, $t9, $a1 - sw $t9, 4($sp) - nop -jr $ra - addiu $sp, $sp, 24 -addiu $sp, $sp, -24 - sw $zero, 4($sp) -lw $t6, 4($sp) -addu $t7, $a0, $t6 -sb $zero, ($t7) -lw $t8, 4($sp) -addiu $t9, $t8, 1 -slt $at, $t9, $a1 - sw $t9, 4($sp) - nop -jr $ra - addiu $sp, $sp, 24 -addiu $sp, $sp, -24 - sw $zero, 4($sp) -lw $t6, 4($sp) -addu $t7, $a0, $t6 -sb $zero, ($t7) -lw $t8, 4($sp) -addiu $t9, $t8, 1 -slt $at, $t9, $a1 - sw $t9, 4($sp) - nop -jr $ra - addiu $sp, $sp, 24 -addiu $sp, $sp, -24 - sw $zero, 4($sp) -lw $t6, 4($sp) -addu $t7, $a0, $t6 -sb $zero, ($t7) -lw $t8, 4($sp) -addiu $t9, $t8, 1 -slt $at, $t9, $a1 - sw $t9, 4($sp) - nop -jr $ra - addiu $sp, $sp, 24 -addiu $sp, $sp, -24 - sw $zero, 4($sp) -lw $t6, 4($sp) -addu $t7, $a0, $t6 -sb $zero, ($t7) -lw $t8, 4($sp) -addiu $t9, $t8, 1 -slt $at, $t9, $a1 - sw $t9, 4($sp) - nop -jr $ra - addiu $sp, $sp, 24 -addiu $sp, $sp, -24 - sw $zero, 4($sp) -lw $t6, 4($sp) -addu $t7, $a0, $t6 -sb $zero, ($t7) -lw $t8, 4($sp) -addiu $t9, $t8, 1 -slt $at, $t9, $a1 - sw $t9, 4($sp) - nop -jr $ra - addiu $sp, $sp, 24 -addiu $sp, $sp, -24 - sw $zero, 4($sp) -lw $t6, 4($sp) -addu $t7, $a0, $t6 -sb $zero, ($t7) -lw $t8, 4($sp) -addiu $t9, $t8, 1 -slt $at, $t9, $a1 - sw $t9, 4($sp) - nop -jr $ra - addiu $sp, $sp, 24 -addiu $sp, $sp, -24 - sw $zero, 4($sp) -lw $t6, 4($sp) -addu $t7, $a0, $t6 -sb $zero, ($t7) -lw $t8, 4($sp) -addiu $t9, $t8, 1 -slt $at, $t9, $a1 - sw $t9, 4($sp) - nop -jr $ra - addiu $sp, $sp, 24 -addiu $sp, $sp, -24 - sw $zero, 4($sp) -lw $t6, 4($sp) -addu $t7, $a0, $t6 -sb $zero, ($t7) -lw $t8, 4($sp) -addiu $t9, $t8, 1 -slt $at, $t9, $a1 - sw $t9, 4($sp) - nop -jr $ra - addiu $sp, $sp, 24 -addiu $sp, $sp, -24 - sw $zero, 4($sp) -lw $t6, 4($sp) -addu $t7, $a0, $t6 -sb $zero, ($t7) -lw $t8, 4($sp) -addiu $t9, $t8, 1 -slt $at, $t9, $a1 - sw $t9, 4($sp) - nop -jr $ra - addiu $sp, $sp, 24 - -) - -void foo(void) {} diff --git a/tools/asm-processor/tests/large.objdump b/tools/asm-processor/tests/large.objdump deleted file mode 100644 index 17409a7a..00000000 --- a/tools/asm-processor/tests/large.objdump +++ /dev/null @@ -1,58 +0,0 @@ - -tests/large.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000280 .text -00000270 g F .text 00000010 foo -00000000 g F .text 00000270 test - - -Contents of section .text: - 0000 27bdffe8 afa00004 8fae0004 008e7821 '.............x! - 0010 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 0020 afb90004 00000000 03e00008 27bd0018 ............'... - 0030 27bdffe8 afa00004 8fae0004 008e7821 '.............x! - 0040 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 0050 afb90004 00000000 03e00008 27bd0018 ............'... - 0060 27bdffe8 afa00004 8fae0004 008e7821 '.............x! - 0070 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 0080 afb90004 00000000 03e00008 27bd0018 ............'... - 0090 27bdffe8 afa00004 8fae0004 008e7821 '.............x! - 00a0 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 00b0 afb90004 00000000 03e00008 27bd0018 ............'... - 00c0 27bdffe8 afa00004 8fae0004 008e7821 '.............x! - 00d0 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 00e0 afb90004 00000000 03e00008 27bd0018 ............'... - 00f0 27bdffe8 afa00004 8fae0004 008e7821 '.............x! - 0100 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 0110 afb90004 00000000 03e00008 27bd0018 ............'... - 0120 27bdffe8 afa00004 8fae0004 008e7821 '.............x! - 0130 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 0140 afb90004 00000000 03e00008 27bd0018 ............'... - 0150 27bdffe8 afa00004 8fae0004 008e7821 '.............x! - 0160 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 0170 afb90004 00000000 03e00008 27bd0018 ............'... - 0180 27bdffe8 afa00004 8fae0004 008e7821 '.............x! - 0190 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 01a0 afb90004 00000000 03e00008 27bd0018 ............'... - 01b0 27bdffe8 afa00004 8fae0004 008e7821 '.............x! - 01c0 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 01d0 afb90004 00000000 03e00008 27bd0018 ............'... - 01e0 27bdffe8 afa00004 8fae0004 008e7821 '.............x! - 01f0 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 0200 afb90004 00000000 03e00008 27bd0018 ............'... - 0210 27bdffe8 afa00004 8fae0004 008e7821 '.............x! - 0220 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 0230 afb90004 00000000 03e00008 27bd0018 ............'... - 0240 27bdffe8 afa00004 8fae0004 008e7821 '.............x! - 0250 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 0260 afb90004 00000000 03e00008 27bd0018 ............'... - 0270 03e00008 00000000 03e00008 00000000 ................ -Contents of section .options: - 0000 01200000 00000000 80000000 00000000 . .............. - 0010 00000000 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 a300c032 00000000 00000000 00000000 ...2............ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/late_rodata_align.c b/tools/asm-processor/tests/late_rodata_align.c deleted file mode 100644 index 7367c792..00000000 --- a/tools/asm-processor/tests/late_rodata_align.c +++ /dev/null @@ -1,80 +0,0 @@ -GLOBAL_ASM( -.late_rodata - .float 4.1 - .float 4.2 - .float 4.3 - .float 4.4 -.text -glabel a - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -) - -float foo(void) { "foo"; return 1.1f; } - -GLOBAL_ASM( -.late_rodata -.late_rodata_alignment 4 - .float 5.1 - .float 5.2 - .float 5.3 - .float 5.4 -.text -glabel b - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -) - -float bar(void) { "bar"; return 1.2f; } - -GLOBAL_ASM( -.late_rodata -.late_rodata_alignment 8 - .float 6.1 - .float 6.2 - .float 6.3 - .float 6.4 - .float 6.5 -.text -glabel c - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -) - diff --git a/tools/asm-processor/tests/late_rodata_align.objdump b/tools/asm-processor/tests/late_rodata_align.objdump deleted file mode 100644 index 0f7f4c04..00000000 --- a/tools/asm-processor/tests/late_rodata_align.objdump +++ /dev/null @@ -1,51 +0,0 @@ - -tests/late_rodata_align.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 000000f0 .text -00000000 l d .rodata 00000050 .rodata -00000040 g F .text 0000001c foo -00000090 g F .text 0000001c bar -00000000 g F .text 00000040 a -0000005c g F .text 00000034 b -000000ac g F .text 00000038 c - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -00000040 R_MIPS_HI16 .rodata -00000048 R_MIPS_LO16 .rodata -00000090 R_MIPS_HI16 .rodata -00000098 R_MIPS_LO16 .rodata - - -Contents of section .text: - 0000 00000000 00000000 00000000 00000000 ................ - 0010 00000000 00000000 00000000 00000000 ................ - 0020 00000000 00000000 00000000 00000000 ................ - 0030 00000000 00000000 00000000 00000000 ................ - 0040 3c010000 03e00008 c4200018 03e00008 <........ ...... - 0050 00000000 03e00008 00000000 00000000 ................ - 0060 00000000 00000000 00000000 00000000 ................ - 0070 00000000 00000000 00000000 00000000 ................ - 0080 00000000 00000000 00000000 00000000 ................ - 0090 3c010000 03e00008 c420002c 03e00008 <........ .,.... - 00a0 00000000 03e00008 00000000 00000000 ................ - 00b0 00000000 00000000 00000000 00000000 ................ - 00c0 00000000 00000000 00000000 00000000 ................ - 00d0 00000000 00000000 00000000 00000000 ................ - 00e0 00000000 00000000 00000000 00000000 ................ -Contents of section .rodata: - 0000 666f6f00 62617200 40833333 40866666 foo.bar.@.33@.ff - 0010 4089999a 408ccccd 3f8ccccd 40a33333 @...@...?...@.33 - 0020 40a66666 40a9999a 40accccd 3f99999a @.ff@...@...?... - 0030 40c33333 40c66666 40c9999a 40cccccd @.33@.ff@...@... - 0040 40d00000 00000000 00000000 00000000 @............... -Contents of section .options: - 0000 01200000 00000000 80000002 00000000 . .............. - 0010 000005f1 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 80000002 00000000 000005f1 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/late_rodata_doubles.c b/tools/asm-processor/tests/late_rodata_doubles.c deleted file mode 100644 index 0a27b414..00000000 --- a/tools/asm-processor/tests/late_rodata_doubles.c +++ /dev/null @@ -1,83 +0,0 @@ -GLOBAL_ASM( -.late_rodata - .float 4.1 -.text -glabel a - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -) - -float foo(void) { - return 4.15f; -} - -GLOBAL_ASM( -.late_rodata - .float 4.2 - .word 0 - .double 4.3 -.text -glabel b - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -) - -float bar(void) { - return 4.4f; -} - -GLOBAL_ASM( -.late_rodata - .float 4.55 - .double 4.6 -.text -glabel c - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -) - -float baz(void) { - return 4.6f; -} diff --git a/tools/asm-processor/tests/late_rodata_doubles.objdump b/tools/asm-processor/tests/late_rodata_doubles.objdump deleted file mode 100644 index 3545768e..00000000 --- a/tools/asm-processor/tests/late_rodata_doubles.objdump +++ /dev/null @@ -1,55 +0,0 @@ - -tests/late_rodata_doubles.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000120 .text -00000000 l d .rodata 00000030 .rodata -00000040 g F .text 0000001c foo -0000009c g F .text 0000001c bar -000000f8 g F .text 0000001c baz -00000000 g F .text 00000040 a -0000005c g F .text 00000040 b -000000b8 g F .text 00000040 c - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -00000040 R_MIPS_HI16 .rodata -00000048 R_MIPS_LO16 .rodata -0000009c R_MIPS_HI16 .rodata -000000a4 R_MIPS_LO16 .rodata -000000f8 R_MIPS_HI16 .rodata -00000100 R_MIPS_LO16 .rodata - - -Contents of section .text: - 0000 00000000 00000000 00000000 00000000 ................ - 0010 00000000 00000000 00000000 00000000 ................ - 0020 00000000 00000000 00000000 00000000 ................ - 0030 00000000 00000000 00000000 00000000 ................ - 0040 3c010000 03e00008 c4200004 03e00008 <........ ...... - 0050 00000000 03e00008 00000000 00000000 ................ - 0060 00000000 00000000 00000000 00000000 ................ - 0070 00000000 00000000 00000000 00000000 ................ - 0080 00000000 00000000 00000000 00000000 ................ - 0090 00000000 00000000 00000000 3c010000 ............<... - 00a0 03e00008 c4200018 03e00008 00000000 ..... .......... - 00b0 03e00008 00000000 00000000 00000000 ................ - 00c0 00000000 00000000 00000000 00000000 ................ - 00d0 00000000 00000000 00000000 00000000 ................ - 00e0 00000000 00000000 00000000 00000000 ................ - 00f0 00000000 00000000 3c010000 03e00008 ........<....... - 0100 c4200028 03e00008 00000000 03e00008 . .(............ - 0110 00000000 00000000 00000000 00000000 ................ -Contents of section .rodata: - 0000 40833333 4084cccd 40866666 00000000 @.33@...@.ff.... - 0010 40113333 33333333 408ccccd 4091999a @.333333@...@... - 0020 40126666 66666666 40933333 00000000 @.ffffff@.33.... -Contents of section .options: - 0000 01200000 00000000 80000002 00000000 . .............. - 0010 000000f1 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 80000002 00000000 000000f1 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/late_rodata_doubles_mips1.c b/tools/asm-processor/tests/late_rodata_doubles_mips1.c deleted file mode 100644 index b97261f6..00000000 --- a/tools/asm-processor/tests/late_rodata_doubles_mips1.c +++ /dev/null @@ -1,86 +0,0 @@ -// COMPILE-FLAGS: -O2 -// COMPILE-ISET: -mips1 -// exact copy of late_rodata_doubles.c except for the -mips1 -O2 additions -GLOBAL_ASM( -.late_rodata - .float 4.1 -.text -glabel a - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -) - -float foo(void) { - return 4.15f; -} - -GLOBAL_ASM( -.late_rodata - .float 4.2 - .word 0 - .double 4.3 -.text -glabel b - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -) - -float bar(void) { - return 4.4f; -} - -GLOBAL_ASM( -.late_rodata - .float 4.55 - .double 4.6 -.text -glabel c - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -) - -float baz(void) { - return 4.6f; -} diff --git a/tools/asm-processor/tests/late_rodata_doubles_mips1.objdump b/tools/asm-processor/tests/late_rodata_doubles_mips1.objdump deleted file mode 100644 index 667ee7d3..00000000 --- a/tools/asm-processor/tests/late_rodata_doubles_mips1.objdump +++ /dev/null @@ -1,52 +0,0 @@ - -tests/late_rodata_doubles_mips1.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 000000f0 .text -00000000 l d .rodata 00000030 .rodata -00000040 g F .text 00000010 foo -00000090 g F .text 00000010 bar -000000e0 g F .text 00000010 baz -00000000 g F .text 00000040 a -00000050 g F .text 00000040 b -000000a0 g F .text 00000040 c - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -00000040 R_MIPS_HI16 .rodata -00000044 R_MIPS_LO16 .rodata -00000090 R_MIPS_HI16 .rodata -00000094 R_MIPS_LO16 .rodata -000000e0 R_MIPS_HI16 .rodata -000000e4 R_MIPS_LO16 .rodata - - -Contents of section .text: - 0000 00000000 00000000 00000000 00000000 ................ - 0010 00000000 00000000 00000000 00000000 ................ - 0020 00000000 00000000 00000000 00000000 ................ - 0030 00000000 00000000 00000000 00000000 ................ - 0040 3c010000 c4200004 03e00008 00000000 <.... .......... - 0050 00000000 00000000 00000000 00000000 ................ - 0060 00000000 00000000 00000000 00000000 ................ - 0070 00000000 00000000 00000000 00000000 ................ - 0080 00000000 00000000 00000000 00000000 ................ - 0090 3c010000 c4200018 03e00008 00000000 <.... .......... - 00a0 00000000 00000000 00000000 00000000 ................ - 00b0 00000000 00000000 00000000 00000000 ................ - 00c0 00000000 00000000 00000000 00000000 ................ - 00d0 00000000 00000000 00000000 00000000 ................ - 00e0 3c010000 c4200028 03e00008 00000000 <.... .(........ -Contents of section .rodata: - 0000 40833333 4084cccd 40866666 00000000 @.33@...@.ff.... - 0010 40113333 33333333 408ccccd 4091999a @.333333@...@... - 0020 40126666 66666666 40933333 00000000 @.ffffff@.33.... -Contents of section .options: - 0000 01200000 00000000 80000002 00000000 . .............. - 0010 000c0011 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 80000002 00000000 000c0011 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/late_rodata_jtbl.c b/tools/asm-processor/tests/late_rodata_jtbl.c deleted file mode 100644 index 3c2a5bba..00000000 --- a/tools/asm-processor/tests/late_rodata_jtbl.c +++ /dev/null @@ -1,153 +0,0 @@ -// COMPILE-FLAGS: -O2 -GLOBAL_ASM( -.late_rodata -.double 1 -.double 2 -.double 3 -.double 4 -.double 5 -.double 6 -.double 7 -.double 8 -.text -glabel doubles1 -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -) - -float a(void) { return 1.1f; } - -GLOBAL_ASM( -.late_rodata -.float 1 -.double 2 -.double 3 -.double 4 -.double 5 -.double 6 -.double 7 -.double 8 -.double 9 -.float 10 -.text -glabel doubles2 -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -) - -GLOBAL_ASM( -glabel a2 -move $a0, $a0 -nop -nop -nop -jr $ra -move $a0, $a0 -) - -GLOBAL_ASM( -.late_rodata - -glabel jtbl -.word case0, case1, case2, case3, case4, case5, case6, case7, case8, case9, case10 -.word case11, case12, case13, case14, case15, case16, case17, case18, case19, case20 -.word case21, case22, case23, case24, case25, case26 - -.text -glabel foo -sltiu $at, $a0, 0xa -beqz $at, .L756E659B - sll $t7, $a0, 2 -lui $at, %hi(jtbl) -addu $at, $at, $t7 -lw $t7, %lo(jtbl)($at) -jr $t7 - nop -case0: addiu $a0, $a0, 1 -case1: addiu $a0, $a0, 1 -case2: addiu $a0, $a0, 1 -case3: addiu $a0, $a0, 1 -case4: addiu $a0, $a0, 1 -case5: addiu $a0, $a0, 1 -case6: addiu $a0, $a0, 1 -case7: addiu $a0, $a0, 1 -case8: addiu $a0, $a0, 1 -case9: addiu $a0, $a0, 1 -case10: addiu $a0, $a0, 1 -case11: addiu $a0, $a0, 1 -case12: addiu $a0, $a0, 1 -case13: addiu $a0, $a0, 1 -case14: addiu $a0, $a0, 1 -case15: addiu $a0, $a0, 1 -case16: addiu $a0, $a0, 1 -case17: addiu $a0, $a0, 1 -case18: addiu $a0, $a0, 1 -case19: addiu $a0, $a0, 1 -case20: addiu $a0, $a0, 1 -case21: addiu $a0, $a0, 1 -case22: addiu $a0, $a0, 1 -case23: addiu $a0, $a0, 1 -case24: addiu $a0, $a0, 1 -case25: addiu $a0, $a0, 1 -case26: -jr $ra - addiu $v0, $a0, 1 - -.L756E659B: -addiu $v0, $zero, 2 -jr $ra - nop -) - -GLOBAL_ASM( -glabel b2 -move $a0, $a0 -nop -nop -jr $ra -move $a0, $a0 -) - -float b(void) { return 1.2f; } diff --git a/tools/asm-processor/tests/late_rodata_jtbl.objdump b/tools/asm-processor/tests/late_rodata_jtbl.objdump deleted file mode 100644 index 53f664ba..00000000 --- a/tools/asm-processor/tests/late_rodata_jtbl.objdump +++ /dev/null @@ -1,110 +0,0 @@ - -tests/late_rodata_jtbl.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 000001a0 .text -00000000 l d .rodata 00000100 .rodata -00000000 l d .text 00000000 -0000005c g F .text 0000000c a -0000018c g F .text 0000000c b -00000000 g F .text 0000005c doubles1 -00000068 g F .text 0000005c doubles2 -000000c4 g F .text 00000018 a2 -000000dc g F .text 0000009c foo -0000008c g .rodata 00000000 jtbl -00000178 g F .text 00000014 b2 - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -0000005c R_MIPS_HI16 .rodata -00000064 R_MIPS_LO16 .rodata -0000018c R_MIPS_HI16 .rodata -00000194 R_MIPS_LO16 .rodata -000000e8 R_MIPS_HI16 jtbl -000000f0 R_MIPS_LO16 jtbl - - -RELOCATION RECORDS FOR [.rodata]: -OFFSET TYPE VALUE -0000008c R_MIPS_32 -00000090 R_MIPS_32 -00000094 R_MIPS_32 -00000098 R_MIPS_32 -0000009c R_MIPS_32 -000000a0 R_MIPS_32 -000000a4 R_MIPS_32 -000000a8 R_MIPS_32 -000000ac R_MIPS_32 -000000b0 R_MIPS_32 -000000b4 R_MIPS_32 -000000b8 R_MIPS_32 -000000bc R_MIPS_32 -000000c0 R_MIPS_32 -000000c4 R_MIPS_32 -000000c8 R_MIPS_32 -000000cc R_MIPS_32 -000000d0 R_MIPS_32 -000000d4 R_MIPS_32 -000000d8 R_MIPS_32 -000000dc R_MIPS_32 -000000e0 R_MIPS_32 -000000e4 R_MIPS_32 -000000e8 R_MIPS_32 -000000ec R_MIPS_32 -000000f0 R_MIPS_32 -000000f4 R_MIPS_32 - - -Contents of section .text: - 0000 00000000 00000000 00000000 00000000 ................ - 0010 00000000 00000000 00000000 00000000 ................ - 0020 00000000 00000000 00000000 00000000 ................ - 0030 00000000 00000000 00000000 00000000 ................ - 0040 00000000 00000000 00000000 00000000 ................ - 0050 00000000 00000000 00000000 3c010000 ............<... - 0060 03e00008 c4200040 00000000 00000000 ..... .@........ - 0070 00000000 00000000 00000000 00000000 ................ - 0080 00000000 00000000 00000000 00000000 ................ - 0090 00000000 00000000 00000000 00000000 ................ - 00a0 00000000 00000000 00000000 00000000 ................ - 00b0 00000000 00000000 00000000 00000000 ................ - 00c0 00000000 00802025 00000000 00000000 ...... %........ - 00d0 00000000 03e00008 00802025 2c81000a .......... %,... - 00e0 10200022 00047880 3c010000 002f0821 . ."..x.<..../.! - 00f0 8c2f0000 01e00008 00000000 24840001 ./..........$... - 0100 24840001 24840001 24840001 24840001 $...$...$...$... - 0110 24840001 24840001 24840001 24840001 $...$...$...$... - 0120 24840001 24840001 24840001 24840001 $...$...$...$... - 0130 24840001 24840001 24840001 24840001 $...$...$...$... - 0140 24840001 24840001 24840001 24840001 $...$...$...$... - 0150 24840001 24840001 24840001 24840001 $...$...$...$... - 0160 24840001 03e00008 24820001 24020002 $.......$...$... - 0170 03e00008 00000000 00802025 00000000 .......... %.... - 0180 00000000 03e00008 00802025 3c010000 .......... %<... - 0190 03e00008 c42000f8 00000000 00000000 ..... .......... -Contents of section .rodata: - 0000 3ff00000 00000000 40000000 00000000 ?.......@....... - 0010 40080000 00000000 40100000 00000000 @.......@....... - 0020 40140000 00000000 40180000 00000000 @.......@....... - 0030 401c0000 00000000 40200000 00000000 @.......@ ...... - 0040 3f8ccccd 3f800000 40000000 00000000 ?...?...@....... - 0050 40080000 00000000 40100000 00000000 @.......@....... - 0060 40140000 00000000 40180000 00000000 @.......@....... - 0070 401c0000 00000000 40200000 00000000 @.......@ ...... - 0080 40220000 00000000 41200000 000000fc @"......A ...... - 0090 00000100 00000104 00000108 0000010c ................ - 00a0 00000110 00000114 00000118 0000011c ................ - 00b0 00000120 00000124 00000128 0000012c ... ...$...(..., - 00c0 00000130 00000134 00000138 0000013c ...0...4...8...< - 00d0 00000140 00000144 00000148 0000014c ...@...D...H...L - 00e0 00000150 00000154 00000158 0000015c ...P...T...X...\ - 00f0 00000160 00000164 3f99999a 00000000 ...`...d?....... -Contents of section .options: - 0000 01200000 00000000 80004002 00000000 . ........@..... - 0010 000000f1 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 8000c016 00000000 000000f1 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/late_rodata_jtbl_mips1.c b/tools/asm-processor/tests/late_rodata_jtbl_mips1.c deleted file mode 100644 index 505f4c1d..00000000 --- a/tools/asm-processor/tests/late_rodata_jtbl_mips1.c +++ /dev/null @@ -1,155 +0,0 @@ -// COMPILE-FLAGS: -O2 -// COMPILE-ISET: -mips1 -// exact copy of late_rodata_jtbl.c except for the -mips1 addition -GLOBAL_ASM( -.late_rodata -.double 1 -.double 2 -.double 3 -.double 4 -.double 5 -.double 6 -.double 7 -.double 8 -.text -glabel doubles1 -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -) - -float a(void) { return 1.1f; } - -GLOBAL_ASM( -.late_rodata -.float 1 -.double 2 -.double 3 -.double 4 -.double 5 -.double 6 -.double 7 -.double 8 -.double 9 -.float 10 -.text -glabel doubles2 -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -) - -GLOBAL_ASM( -glabel a2 -move $a0, $a0 -nop -nop -nop -jr $ra -move $a0, $a0 -) - -GLOBAL_ASM( -.late_rodata - -glabel jtbl -.word case0, case1, case2, case3, case4, case5, case6, case7, case8, case9, case10 -.word case11, case12, case13, case14, case15, case16, case17, case18, case19, case20 -.word case21, case22, case23, case24, case25, case26 - -.text -glabel foo -sltiu $at, $a0, 0xa -beqz $at, .L756E659B - sll $t7, $a0, 2 -lui $at, %hi(jtbl) -addu $at, $at, $t7 -lw $t7, %lo(jtbl)($at) -jr $t7 - nop -case0: addiu $a0, $a0, 1 -case1: addiu $a0, $a0, 1 -case2: addiu $a0, $a0, 1 -case3: addiu $a0, $a0, 1 -case4: addiu $a0, $a0, 1 -case5: addiu $a0, $a0, 1 -case6: addiu $a0, $a0, 1 -case7: addiu $a0, $a0, 1 -case8: addiu $a0, $a0, 1 -case9: addiu $a0, $a0, 1 -case10: addiu $a0, $a0, 1 -case11: addiu $a0, $a0, 1 -case12: addiu $a0, $a0, 1 -case13: addiu $a0, $a0, 1 -case14: addiu $a0, $a0, 1 -case15: addiu $a0, $a0, 1 -case16: addiu $a0, $a0, 1 -case17: addiu $a0, $a0, 1 -case18: addiu $a0, $a0, 1 -case19: addiu $a0, $a0, 1 -case20: addiu $a0, $a0, 1 -case21: addiu $a0, $a0, 1 -case22: addiu $a0, $a0, 1 -case23: addiu $a0, $a0, 1 -case24: addiu $a0, $a0, 1 -case25: addiu $a0, $a0, 1 -case26: -jr $ra - addiu $v0, $a0, 1 - -.L756E659B: -addiu $v0, $zero, 2 -jr $ra - nop -) - -GLOBAL_ASM( -glabel b2 -move $a0, $a0 -nop -nop -jr $ra -move $a0, $a0 -) - -float b(void) { return 1.2f; } diff --git a/tools/asm-processor/tests/late_rodata_jtbl_mips1.objdump b/tools/asm-processor/tests/late_rodata_jtbl_mips1.objdump deleted file mode 100644 index a781a928..00000000 --- a/tools/asm-processor/tests/late_rodata_jtbl_mips1.objdump +++ /dev/null @@ -1,110 +0,0 @@ - -tests/late_rodata_jtbl_mips1.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 000001a0 .text -00000000 l d .rodata 00000100 .rodata -00000000 l d .text 00000000 -0000005c g F .text 00000010 a -00000190 g F .text 00000010 b -00000000 g F .text 0000005c doubles1 -0000006c g F .text 0000005c doubles2 -000000c8 g F .text 00000018 a2 -000000e0 g F .text 0000009c foo -0000008c g .rodata 00000000 jtbl -0000017c g F .text 00000014 b2 - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -0000005c R_MIPS_HI16 .rodata -00000060 R_MIPS_LO16 .rodata -00000190 R_MIPS_HI16 .rodata -00000194 R_MIPS_LO16 .rodata -000000ec R_MIPS_HI16 jtbl -000000f4 R_MIPS_LO16 jtbl - - -RELOCATION RECORDS FOR [.rodata]: -OFFSET TYPE VALUE -0000008c R_MIPS_32 -00000090 R_MIPS_32 -00000094 R_MIPS_32 -00000098 R_MIPS_32 -0000009c R_MIPS_32 -000000a0 R_MIPS_32 -000000a4 R_MIPS_32 -000000a8 R_MIPS_32 -000000ac R_MIPS_32 -000000b0 R_MIPS_32 -000000b4 R_MIPS_32 -000000b8 R_MIPS_32 -000000bc R_MIPS_32 -000000c0 R_MIPS_32 -000000c4 R_MIPS_32 -000000c8 R_MIPS_32 -000000cc R_MIPS_32 -000000d0 R_MIPS_32 -000000d4 R_MIPS_32 -000000d8 R_MIPS_32 -000000dc R_MIPS_32 -000000e0 R_MIPS_32 -000000e4 R_MIPS_32 -000000e8 R_MIPS_32 -000000ec R_MIPS_32 -000000f0 R_MIPS_32 -000000f4 R_MIPS_32 - - -Contents of section .text: - 0000 00000000 00000000 00000000 00000000 ................ - 0010 00000000 00000000 00000000 00000000 ................ - 0020 00000000 00000000 00000000 00000000 ................ - 0030 00000000 00000000 00000000 00000000 ................ - 0040 00000000 00000000 00000000 00000000 ................ - 0050 00000000 00000000 00000000 3c010000 ............<... - 0060 c4200040 03e00008 00000000 00000000 . .@............ - 0070 00000000 00000000 00000000 00000000 ................ - 0080 00000000 00000000 00000000 00000000 ................ - 0090 00000000 00000000 00000000 00000000 ................ - 00a0 00000000 00000000 00000000 00000000 ................ - 00b0 00000000 00000000 00000000 00000000 ................ - 00c0 00000000 00000000 00802025 00000000 .......... %.... - 00d0 00000000 00000000 03e00008 00802025 .............. % - 00e0 2c81000a 10200022 00047880 3c010000 ,.... ."..x.<... - 00f0 002f0821 8c2f0000 01e00008 00000000 ./.!./.......... - 0100 24840001 24840001 24840001 24840001 $...$...$...$... - 0110 24840001 24840001 24840001 24840001 $...$...$...$... - 0120 24840001 24840001 24840001 24840001 $...$...$...$... - 0130 24840001 24840001 24840001 24840001 $...$...$...$... - 0140 24840001 24840001 24840001 24840001 $...$...$...$... - 0150 24840001 24840001 24840001 24840001 $...$...$...$... - 0160 24840001 24840001 03e00008 24820001 $...$.......$... - 0170 24020002 03e00008 00000000 00802025 $............. % - 0180 00000000 00000000 03e00008 00802025 .............. % - 0190 3c010000 c42000f8 03e00008 00000000 <.... .......... -Contents of section .rodata: - 0000 3ff00000 00000000 40000000 00000000 ?.......@....... - 0010 40080000 00000000 40100000 00000000 @.......@....... - 0020 40140000 00000000 40180000 00000000 @.......@....... - 0030 401c0000 00000000 40200000 00000000 @.......@ ...... - 0040 3f8ccccd 3f800000 40000000 00000000 ?...?...@....... - 0050 40080000 00000000 40100000 00000000 @.......@....... - 0060 40140000 00000000 40180000 00000000 @.......@....... - 0070 401c0000 00000000 40200000 00000000 @.......@ ...... - 0080 40220000 00000000 41200000 00000100 @"......A ...... - 0090 00000104 00000108 0000010c 00000110 ................ - 00a0 00000114 00000118 0000011c 00000120 ............... - 00b0 00000124 00000128 0000012c 00000130 ...$...(...,...0 - 00c0 00000134 00000138 0000013c 00000140 ...4...8...<...@ - 00d0 00000144 00000148 0000014c 00000150 ...D...H...L...P - 00e0 00000154 00000158 0000015c 00000160 ...T...X...\...` - 00f0 00000164 00000168 3f99999a 00000000 ...d...h?....... -Contents of section .options: - 0000 01200000 00000000 80004002 00000000 . ........@..... - 0010 000000f1 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 8000c016 00000000 000000f1 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/late_rodata_misaligned_doubles.c b/tools/asm-processor/tests/late_rodata_misaligned_doubles.c deleted file mode 100644 index a453dbdd..00000000 --- a/tools/asm-processor/tests/late_rodata_misaligned_doubles.c +++ /dev/null @@ -1,77 +0,0 @@ -GLOBAL_ASM( -.late_rodata - .float 4.01 - .word 0 - .double 4.02 -.text -glabel a - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -) - -double foo(void) { return 4.03; } - -GLOBAL_ASM( -.late_rodata - .float 4.04 - .double 4.05 -.text -glabel b - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -) - -double bar(void) { return 4.06; } -float baz(void) { return 4.07f; } - -GLOBAL_ASM( -.late_rodata - .double 4.08 -.text -glabel c - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop -) - diff --git a/tools/asm-processor/tests/late_rodata_misaligned_doubles.objdump b/tools/asm-processor/tests/late_rodata_misaligned_doubles.objdump deleted file mode 100644 index 46cdc0c0..00000000 --- a/tools/asm-processor/tests/late_rodata_misaligned_doubles.objdump +++ /dev/null @@ -1,56 +0,0 @@ - -tests/late_rodata_misaligned_doubles.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000120 .text -00000000 l d .rodata 00000040 .rodata -00000040 g F .text 0000001c foo -0000009c g F .text 0000001c bar -000000b8 g F .text 0000001c baz -00000000 g F .text 00000040 a -0000005c g F .text 00000040 b -000000d4 g F .text 00000040 c - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -00000040 R_MIPS_HI16 .rodata -00000048 R_MIPS_LO16 .rodata -0000009c R_MIPS_HI16 .rodata -000000a4 R_MIPS_LO16 .rodata -000000b8 R_MIPS_HI16 .rodata -000000c0 R_MIPS_LO16 .rodata - - -Contents of section .text: - 0000 00000000 00000000 00000000 00000000 ................ - 0010 00000000 00000000 00000000 00000000 ................ - 0020 00000000 00000000 00000000 00000000 ................ - 0030 00000000 00000000 00000000 00000000 ................ - 0040 3c010000 03e00008 d4200010 03e00008 <........ ...... - 0050 00000000 03e00008 00000000 00000000 ................ - 0060 00000000 00000000 00000000 00000000 ................ - 0070 00000000 00000000 00000000 00000000 ................ - 0080 00000000 00000000 00000000 00000000 ................ - 0090 00000000 00000000 00000000 3c010000 ............<... - 00a0 03e00008 d4200028 03e00008 00000000 ..... .(........ - 00b0 03e00008 00000000 3c010000 03e00008 ........<....... - 00c0 c4200030 03e00008 00000000 03e00008 . .0............ - 00d0 00000000 00000000 00000000 00000000 ................ - 00e0 00000000 00000000 00000000 00000000 ................ - 00f0 00000000 00000000 00000000 00000000 ................ - 0100 00000000 00000000 00000000 00000000 ................ - 0110 00000000 00000000 00000000 00000000 ................ -Contents of section .rodata: - 0000 408051ec 00000000 4010147a e147ae14 @.Q.....@..z.G.. - 0010 40101eb8 51eb851f 00000000 408147ae @...Q.......@.G. - 0020 40103333 33333333 40103d70 a3d70a3d @.333333@.=p...= - 0030 40823d71 00000000 401051eb 851eb852 @.=q....@.Q....R -Contents of section .options: - 0000 01200000 00000000 80000002 00000000 . .............. - 0010 000000f3 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 80000002 00000000 000000f3 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/line-continuation-separate-file.s b/tools/asm-processor/tests/line-continuation-separate-file.s deleted file mode 100644 index e1301804..00000000 --- a/tools/asm-processor/tests/line-continuation-separate-file.s +++ /dev/null @@ -1,4 +0,0 @@ -.rdata - label: .asciiz "1\n\ -2", \ - "34", "56" diff --git a/tools/asm-processor/tests/line-continuation.asmproc.d b/tools/asm-processor/tests/line-continuation.asmproc.d deleted file mode 100644 index 687dd1ae..00000000 --- a/tools/asm-processor/tests/line-continuation.asmproc.d +++ /dev/null @@ -1,3 +0,0 @@ -tests/line-continuation.o: tests/line-continuation-separate-file.s - -tests/line-continuation-separate-file.s: diff --git a/tools/asm-processor/tests/line-continuation.c b/tools/asm-processor/tests/line-continuation.c deleted file mode 100644 index d5ab0937..00000000 --- a/tools/asm-processor/tests/line-continuation.c +++ /dev/null @@ -1,22 +0,0 @@ -void foo(void) { "abcdef"; } - -GLOBAL_ASM( -.rdata - .ascii "AB" \ - "CD", "EF" - .ascii "GH\n\n\n\0\11\222\3333\44444\x1234567\n\nIJK" -) - -void bar(void) { "hello"; } - -GLOBAL_ASM( -.rdata - .asciiz "1\ -2" - .asciiz "34", "56" - .asciiz "78\n\n\n\0\11\222\3333\44444\x1234567\n\n9A" -) - -void baz(void) { "ghijkl"; } - -GLOBAL_ASM("tests/line-continuation-separate-file.s") diff --git a/tools/asm-processor/tests/line-continuation.objdump b/tools/asm-processor/tests/line-continuation.objdump deleted file mode 100644 index 038766fd..00000000 --- a/tools/asm-processor/tests/line-continuation.objdump +++ /dev/null @@ -1,30 +0,0 @@ - -tests/line-continuation.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000030 .text -00000000 l d .rodata 00000060 .rodata -00000000 g F .text 00000010 foo -00000010 g F .text 00000010 bar -00000020 g F .text 00000010 baz - - -Contents of section .text: - 0000 03e00008 00000000 03e00008 00000000 ................ - 0010 03e00008 00000000 03e00008 00000000 ................ - 0020 03e00008 00000000 03e00008 00000000 ................ -Contents of section .rodata: - 0000 61626364 65660000 41424344 45464748 abcdef..ABCDEFGH - 0010 0a0a0a00 0992db33 24343467 0a0a494a .......3$44g..IJ - 0020 4b000000 68656c6c 6f000000 31320033 K...hello...12.3 - 0030 34003536 0037380a 0a0a0009 92db3324 4.56.78.......3$ - 0040 3434670a 0a394100 6768696a 6b6c0000 44g..9A.ghijkl.. - 0050 310a3200 33340035 36000000 00000000 1.2.34.56....... -Contents of section .options: - 0000 01200000 00000000 80000000 00000000 . .............. - 0010 00000000 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 80000000 00000000 00000000 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/o0.c b/tools/asm-processor/tests/o0.c deleted file mode 100644 index 6f8e5e41..00000000 --- a/tools/asm-processor/tests/o0.c +++ /dev/null @@ -1,28 +0,0 @@ -// COMPILE-FLAGS: -O0 - -int a(void) { return 1; } -GLOBAL_ASM( -glabel foo -addiu $a0, $a0, 1 -addiu $a0, $a0, 2 -addiu $a0, $a0, 3 -jr $ra -addiu $a0, $a0, 4 -) -float b(void) { return 1.2f; } -GLOBAL_ASM( -.late_rodata -glabel float1 -.float 12.34 - -.text -glabel bar -addiu $a0, $a0, 5 -addiu $a0, $a0, 6 -addiu $a0, $a0, 7 -addiu $a0, $a0, 8 -lui $v0, %hi(float1 + 1) -jr $ra -addiu $v0, $v0, %lo(float1 + 1) -) -float c(void) { return 1.3f; } diff --git a/tools/asm-processor/tests/o0.objdump b/tools/asm-processor/tests/o0.objdump deleted file mode 100644 index 98a27dc4..00000000 --- a/tools/asm-processor/tests/o0.objdump +++ /dev/null @@ -1,44 +0,0 @@ - -tests/o0.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000090 .text -00000000 l d .rodata 00000010 .rodata -00000000 g F .text 0000001c a -00000030 g F .text 00000020 b -0000006c g F .text 00000020 c -0000001c g F .text 00000014 foo -00000050 g F .text 0000001c bar -00000004 g .rodata 00000000 float1 - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -00000030 R_MIPS_HI16 .rodata -00000034 R_MIPS_LO16 .rodata -0000006c R_MIPS_HI16 .rodata -00000070 R_MIPS_LO16 .rodata -00000060 R_MIPS_HI16 float1 -00000068 R_MIPS_LO16 float1 - - -Contents of section .text: - 0000 24020001 03e00008 00000000 03e00008 $............... - 0010 00000000 03e00008 00000000 24840001 ............$... - 0020 24840002 24840003 03e00008 24840004 $...$.......$... - 0030 3c010000 c4200000 03e00008 00000000 <.... .......... - 0040 03e00008 00000000 03e00008 00000000 ................ - 0050 24840005 24840006 24840007 24840008 $...$...$...$... - 0060 3c020000 03e00008 24420001 3c010000 <.......$B..<... - 0070 c4200008 03e00008 00000000 03e00008 . .............. - 0080 00000000 03e00008 00000000 00000000 ................ -Contents of section .rodata: - 0000 3f99999a 414570a4 3fa66666 00000000 ?...AEp.?.ff.... -Contents of section .options: - 0000 01200000 00000000 80000006 00000000 . .............. - 0010 00000011 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 80000016 00000000 00000011 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/o2.c b/tools/asm-processor/tests/o2.c deleted file mode 100644 index 144a604e..00000000 --- a/tools/asm-processor/tests/o2.c +++ /dev/null @@ -1,26 +0,0 @@ -// COMPILE-FLAGS: -O2 - -int a(void) { return 1; } -GLOBAL_ASM( -glabel foo -addiu $a0, $a0, 1 -addiu $a0, $a0, 2 -addiu $a0, $a0, 3 -jr $ra -addiu $a0, $a0, 4 -) -float b(void) { return 1.2f; } -GLOBAL_ASM( -.late_rodata -glabel float1 -.float 12.34 - -.text -glabel bar -addiu $a0, $a0, 5 -addiu $a0, $a0, 6 -lui $v0, %hi(float1 + 1) -jr $ra -addiu $v0, $v0, %lo(float1 + 1) -) -float c(void) { return 1.3f; } diff --git a/tools/asm-processor/tests/o2.objdump b/tools/asm-processor/tests/o2.objdump deleted file mode 100644 index 07b3895b..00000000 --- a/tools/asm-processor/tests/o2.objdump +++ /dev/null @@ -1,40 +0,0 @@ - -tests/o2.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000050 .text -00000000 l d .rodata 00000010 .rodata -00000000 g F .text 00000008 a -0000001c g F .text 0000000c b -0000003c g F .text 0000000c c -00000008 g F .text 00000014 foo -00000028 g F .text 00000014 bar -00000004 g .rodata 00000000 float1 - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -0000001c R_MIPS_HI16 .rodata -00000024 R_MIPS_LO16 .rodata -0000003c R_MIPS_HI16 .rodata -00000044 R_MIPS_LO16 .rodata -00000030 R_MIPS_HI16 float1 -00000038 R_MIPS_LO16 float1 - - -Contents of section .text: - 0000 03e00008 24020001 24840001 24840002 ....$...$...$... - 0010 24840003 03e00008 24840004 3c010000 $.......$...<... - 0020 03e00008 c4200000 24840005 24840006 ..... ..$...$... - 0030 3c020000 03e00008 24420001 3c010000 <.......$B..<... - 0040 03e00008 c4200008 00000000 00000000 ..... .......... -Contents of section .rodata: - 0000 3f99999a 414570a4 3fa66666 00000000 ?...AEp.?.ff.... -Contents of section .options: - 0000 01200000 00000000 80000006 00000000 . .............. - 0010 00000011 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 80000016 00000000 00000011 00000000 ................ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/pascal.objdump b/tools/asm-processor/tests/pascal.objdump deleted file mode 100644 index de2db821..00000000 --- a/tools/asm-processor/tests/pascal.objdump +++ /dev/null @@ -1,137 +0,0 @@ - -tests/pascal.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 000000e0 .text -00000000 l d .rodata 00000030 .rodata -00000000 l d .data 00000010 .data -00000000 l d .bss 00000010 .bss -00000000 l O .bss 00000000 $dat -00000000 g F .text 0000000c foo -000000d0 g F .text 0000000c bar -0000000c g F .text 0000003c test -00000048 g F .text 00000044 test2 -0000008c g F .text 00000044 test3 -00000000 *UND* 00000000 get -00000000 *UND* 00000000 put -00000000 *UND* 00000000 pascal_close -00000000 *UND* 00000000 fflush -00000000 *UND* 00000000 filesize -00000000 *UND* 00000000 curpos -00000000 *UND* 00000000 seek -00000000 *UND* 00000000 eof -00000000 *UND* 00000000 eoln -00000000 *UND* 00000000 page -00000000 *UND* 00000000 reset -00000000 *UND* 00000000 rewrite -00000000 *UND* 00000000 cos -00000000 *UND* 00000000 exp -00000000 *UND* 00000000 sqrt -00000000 *UND* 00000000 log -00000000 *UND* 00000000 atan -00000000 *UND* 00000000 sin -00000000 *UND* 00000000 __random_float -00000000 *UND* 00000000 clock -00000000 *UND* 00000000 exit -00000000 *UND* 00000000 __date -00000000 *UND* 00000000 __time -00000000 *UND* 00000000 get_arg -00000000 *UND* 00000000 new -00000000 *UND* 00000000 dispose -00000000 *UND* 00000000 initfile -00000000 *UND* 00000000 peek_char -00000000 *UND* 00000000 next_char -00000000 *UND* 00000000 readln -00000000 *UND* 00000000 read_int64 -00000000 *UND* 00000000 read_card64 -00000000 *UND* 00000000 read_integer -00000000 *UND* 00000000 read_cardinal -00000000 *UND* 00000000 read_integer_range -00000000 *UND* 00000000 read_real -00000000 *UND* 00000000 read_double -00000000 *UND* 00000000 read_extended -00000000 *UND* 00000000 read_string -00000000 *UND* 00000000 read_enum -00000000 *UND* 00000000 read_char -00000000 *UND* 00000000 read_char_range -00000000 *UND* 00000000 read_boolean -00000000 *UND* 00000000 read_set -00000000 *UND* 00000000 writeln -00000000 *UND* 00000000 write_int64 -00000000 *UND* 00000000 write_card64 -00000000 *UND* 00000000 write_integer -00000000 *UND* 00000000 write_cardinal -00000000 *UND* 00000000 write_boolean -00000000 *UND* 00000000 write_char -00000000 *UND* 00000000 write_real -00000000 *UND* 00000000 write_double -00000000 *UND* 00000000 write_extended -00000000 *UND* 00000000 write_string -00000000 *UND* 00000000 write_enum -00000000 *UND* 00000000 write_set -00000000 *UND* 00000000 caseerror -00000000 *UND* 00000000 __pc_nloc_goto -00000000 *UND* 00000000 memcpy -00000000 *UND* 00000000 __in_range -00000000 *UND* 00000000 __ll_mul -00000000 *UND* 00000000 __ll_div -00000000 *UND* 00000000 __ull_div -00000000 *UND* 00000000 __ll_mod -00000000 *UND* 00000000 __ll_rem -00000000 *UND* 00000000 __ull_rem -00000000 *UND* 00000000 __ll_lshift -00000000 *UND* 00000000 __ll_rshift -00000000 *UND* 00000000 __ll_to_f -00000000 *UND* 00000000 __ull_to_f -00000000 *UND* 00000000 __ll_to_d -00000000 *UND* 00000000 __ull_to_d -00000000 *UND* 00000000 __f_ll_ll -00000000 *UND* 00000000 __f_to_ull -00000000 *UND* 00000000 __d_to_ll -00000000 *UND* 00000000 __d_to_ull -00000000 *UND* 00000000 round64 -00000000 *UND* 00000000 trunc64 -00000000 *UND* 00000000 max64 -00000000 *UND* 00000000 min64 -00000000 *UND* 00000000 abs64 -00000000 *UND* 00000000 odd64 -00000000 *UND* 00000000 trapNaN -00000000 *UND* 00000008 input -00000000 *UND* 00000008 output -00000000 *UND* 00000008 err -00000000 *UND* 00000008 __Argc - - -RELOCATION RECORDS FOR [.text]: (none) - -RELOCATION RECORDS FOR [.rodata]: (none) - -Contents of section .text: - 0000 00041080 03e00008 00441023 27bdffe8 .........D.#'... - 0010 18a00009 afa00004 8fae0004 008e7821 ..............x! - 0020 a1e00000 8fb80004 27190001 0325082a ........'....%.* - 0030 1420fff9 afb90004 10000001 00000000 . .............. - 0040 03e00008 27bd0018 00000000 00000000 ....'........... - 0050 00000000 00000000 00000000 00000000 ................ - 0060 00000000 00000000 00000000 00000000 ................ - 0070 00000000 00000000 00000000 00000000 ................ - 0080 00000000 00000000 00000000 00000000 ................ - 0090 00000000 00000000 00000000 00000000 ................ - 00a0 00000000 00000000 00000000 00000000 ................ - 00b0 00000000 00000000 00000000 00000000 ................ - 00c0 00000000 00000000 00000000 00000000 ................ - 00d0 00041080 03e00008 00441023 00000000 .........D.#.... -Contents of section .rodata: - 0000 00123123 00456456 00789789 00000001 ..1#.EdV.x...... - 0010 3ff19999 9999999a 00000002 00000003 ?............... - 0020 4000cccc cccccccd 00000000 00000000 @............... -Contents of section .data: - 0000 00002323 00003434 00000000 00000000 ..##..44........ -Contents of section .options: - 0000 01200000 00000000 80004016 00000000 . ........@..... - 0010 000000f0 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 a300c036 00000000 000000f0 00000000 ...6............ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/pascal.p b/tools/asm-processor/tests/pascal.p deleted file mode 100644 index 0886126a..00000000 --- a/tools/asm-processor/tests/pascal.p +++ /dev/null @@ -1,95 +0,0 @@ -{ COMPILE-FLAGS: -O2 } - -function foo(x: integer): integer; -begin - foo := x * 3 -end; - -GLOBAL_ASM( -.section .data -.word 0x2323 - -.late_rodata -.word 0x123123 -.word 0x456456 -.word 0x789789 -.text -glabel test -/* 000090 00400090 27BDFFF8 */ addiu $sp, $sp, -24 -/* 000094 00400094 18A00009 */ blez $a1, .L004000BC -/* 000098 00400098 AFA00004 */ sw $zero, 4($sp) -.L0040009C: -/* 00009C 0040009C 8FAE0004 */ lw $t6, 4($sp) -/* 0000A0 004000A0 008E7821 */ addu $t7, $a0, $t6 -/* 0000A4 004000A4 A1E00000 */ sb $zero, ($t7) -/* 0000A8 004000A8 8FB80004 */ lw $t8, 4($sp) -/* 0000AC 004000AC 27190001 */ addiu $t9, $t8, 1 -/* 0000B0 004000B0 0325082A */ slt $at, $t9, $a1 -/* 0000B4 004000B4 1420FFF9 */ bnez $at, .L0040009C -/* 0000B8 004000B8 AFB90004 */ sw $t9, 4($sp) -.L004000BC: -/* 0000BC 004000BC 10000001 */ b .L004000C4 -/* 0000C0 004000C0 00000000 */ nop -.L004000C4: -/* 0000C4 004000C4 03E00008 */ jr $ra -/* 0000C8 004000C8 27BD0008 */ addiu $sp, $sp, 24 -) - -GLOBAL_ASM( -.section .data -.word 0x3434 - -.late_rodata -.word 0x1 -.double 1.1 -.word 0x2, 0x3 -.text -glabel test2 -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -) - -GLOBAL_ASM( -.late_rodata -.double 2.1 -.text -glabel test3 -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -nop -) - -function bar(x: integer): integer; -begin - return x * 3 -end; - diff --git a/tools/asm-processor/tests/static-global.c b/tools/asm-processor/tests/static-global.c deleted file mode 100644 index 12b14346..00000000 --- a/tools/asm-processor/tests/static-global.c +++ /dev/null @@ -1,35 +0,0 @@ -// COMPILE-FLAGS: -O2 -// ASMP-FLAGS: --convert-statics=global -static int xtext(int a, int b, int c); -const int rodata1[] = {1}; -static const int rodata2[] = {2}; -int data1[] = {3}; -static int data2[] = {4}; -int bss1; -static int bss2; - -GLOBAL_ASM( -glabel bar -lui $a0, %hi(rodata2) -lw $a0, %lo(rodata2)($a0) -lui $a1, %hi(data2) -lw $a1, %lo(data2)($a0) -lui $a2, %hi(bss2) -lw $a2, %lo(bss2)($a0) -jal xtext -nop -jr $ra -nop -nop -nop -) - -static int xtext(int a, int b, int c) { - static int bss2; - return 1; -} - -void baz(void) { - { static int bss2; } - xtext(bss2, rodata2[0], data2[0]); -} diff --git a/tools/asm-processor/tests/static-global.objdump b/tools/asm-processor/tests/static-global.objdump deleted file mode 100644 index 0b21d2e2..00000000 --- a/tools/asm-processor/tests/static-global.objdump +++ /dev/null @@ -1,60 +0,0 @@ - -tests/static-global.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000080 .text -00000000 l d .rodata 00000010 .rodata -00000000 l d .data 00000010 .data -00000000 l d .bss 00000010 .bss -00000000 g O .rodata 00000004 rodata1 -00000000 g O .data 00000004 data1 -00000000 g O .bss 00000004 bss1 -00000044 g F .text 00000034 baz -00000000 g F .text 00000030 bar -00000004 g O .rodata 00000000 rodata2 -00000004 g O .data 00000000 data2 -00000004 g O .bss 00000000 bss2 -00000030 g F .text 00000000 xtext -00000008 g O .bss 00000000 bss2:1 -0000000c g O .bss 00000000 bss2:2 - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -0000004c R_MIPS_HI16 .bss -00000064 R_MIPS_LO16 .bss -00000050 R_MIPS_HI16 .rodata -0000005c R_MIPS_LO16 .rodata -00000054 R_MIPS_HI16 .data -00000058 R_MIPS_LO16 .data -00000060 R_MIPS_26 .text -00000000 R_MIPS_HI16 rodata2 -00000004 R_MIPS_LO16 rodata2 -00000008 R_MIPS_HI16 data2 -0000000c R_MIPS_LO16 data2 -00000010 R_MIPS_HI16 bss2 -00000014 R_MIPS_LO16 bss2 -00000018 R_MIPS_26 xtext - - -Contents of section .text: - 0000 3c040000 8c840000 3c050000 8c850000 <.......<....... - 0010 3c060000 8c860000 0c000000 00000000 <............... - 0020 03e00008 00000000 00000000 00000000 ................ - 0030 afa40000 afa50004 afa60008 03e00008 ................ - 0040 24020001 27bdffe8 afbf0014 3c040000 $...'.......<... - 0050 3c050000 3c060000 8cc60004 8ca50004 <...<........... - 0060 0c00000c 8c840004 8fbf0014 27bd0018 ............'... - 0070 03e00008 00000000 00000000 00000000 ................ -Contents of section .rodata: - 0000 00000001 00000002 00000000 00000000 ................ -Contents of section .data: - 0000 00000003 00000004 00000000 00000000 ................ -Contents of section .options: - 0000 01200000 00000000 a0000074 00000000 . .........t.... - 0010 00000000 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 a0000074 00000000 00000000 00000000 ...t............ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/static.c b/tools/asm-processor/tests/static.c deleted file mode 100644 index c265021e..00000000 --- a/tools/asm-processor/tests/static.c +++ /dev/null @@ -1,32 +0,0 @@ -// COMPILE-FLAGS: -O2 -static int xtext(int a, int b, int c); -const int rodata1[] = {1}; -static const int rodata2[] = {2}; -int data1[] = {3}; -static int data2[] = {4}; -int bss1; -static int bss2; - -GLOBAL_ASM( -glabel bar -lui $a0, %hi(rodata2) -lw $a0, %lo(rodata2)($a0) -lui $a1, %hi(data2) -lw $a1, %lo(data2)($a0) -lui $a2, %hi(bss2) -lw $a2, %lo(bss2)($a0) -jal xtext -nop -jr $ra -nop -nop -nop -) - -static int xtext(int a, int b, int c) { - return 1; -} - -void baz(void) { - xtext(bss2, rodata2[0], data2[0]); -} diff --git a/tools/asm-processor/tests/static.objdump b/tools/asm-processor/tests/static.objdump deleted file mode 100644 index a2f36380..00000000 --- a/tools/asm-processor/tests/static.objdump +++ /dev/null @@ -1,58 +0,0 @@ - -tests/static.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 00000080 .text -00000000 l d .rodata 00000010 .rodata -00000000 l d .data 00000010 .data -00000000 l d .bss 00000010 .bss -00000004 l O .rodata 00000000 rodata2 -00000004 l O .data 00000000 data2 -00000004 l O .bss 00000000 bss2 -00000030 l F .text 00000000 xtext -00000000 g O .rodata 00000004 rodata1 -00000000 g O .data 00000004 data1 -00000000 g O .bss 00000004 bss1 -00000044 g F .text 00000034 baz -00000000 g F .text 00000030 bar - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -0000004c R_MIPS_HI16 .bss -00000064 R_MIPS_LO16 .bss -00000050 R_MIPS_HI16 .rodata -0000005c R_MIPS_LO16 .rodata -00000054 R_MIPS_HI16 .data -00000058 R_MIPS_LO16 .data -00000060 R_MIPS_26 .text -00000000 R_MIPS_HI16 rodata2 -00000004 R_MIPS_LO16 rodata2 -00000008 R_MIPS_HI16 data2 -0000000c R_MIPS_LO16 data2 -00000010 R_MIPS_HI16 bss2 -00000014 R_MIPS_LO16 bss2 -00000018 R_MIPS_26 xtext - - -Contents of section .text: - 0000 3c040000 8c840000 3c050000 8c850000 <.......<....... - 0010 3c060000 8c860000 0c000000 00000000 <............... - 0020 03e00008 00000000 00000000 00000000 ................ - 0030 afa40000 afa50004 afa60008 03e00008 ................ - 0040 24020001 27bdffe8 afbf0014 3c040000 $...'.......<... - 0050 3c050000 3c060000 8cc60004 8ca50004 <...<........... - 0060 0c00000c 8c840004 8fbf0014 27bd0018 ............'... - 0070 03e00008 00000000 00000000 00000000 ................ -Contents of section .rodata: - 0000 00000001 00000002 00000000 00000000 ................ -Contents of section .data: - 0000 00000003 00000004 00000000 00000000 ................ -Contents of section .options: - 0000 01200000 00000000 a0000074 00000000 . .........t.... - 0010 00000000 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 a0000074 00000000 00000000 00000000 ...t............ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/test1.c b/tools/asm-processor/tests/test1.c deleted file mode 100644 index 475555a7..00000000 --- a/tools/asm-processor/tests/test1.c +++ /dev/null @@ -1,71 +0,0 @@ - -GLOBAL_ASM( -.rdata -.word 0x1212 -) - -GLOBAL_ASM( -.late_rodata -.word 0x123123 -.text -glabel test -/* 000090 00400090 27BDFFF8 */ addiu $sp, $sp, -24 -/* 000094 00400094 18A00009 */ blez $a1, .L004000BC -/* 000098 00400098 AFA00004 */ sw $zero, 4($sp) -.L0040009C: -/* 00009C 0040009C 8FAE0004 */ lw $t6, 4($sp) -/* 0000A0 004000A0 008E7821 */ addu $t7, $a0, $t6 -/* 0000A4 004000A4 A1E00000 */ sb $zero, ($t7) -/* 0000A8 004000A8 8FB80004 */ lw $t8, 4($sp) -/* 0000AC 004000AC 27190001 */ addiu $t9, $t8, 1 -/* 0000B0 004000B0 0325082A */ slt $at, $t9, $a1 -/* 0000B4 004000B4 1420FFF9 */ bnez $at, .L0040009C -/* 0000B8 004000B8 AFB90004 */ sw $t9, 4($sp) -.L004000BC: -/* 0000BC 004000BC 10000001 */ b .L004000C4 -/* 0000C0 004000C0 00000000 */ nop -.L004000C4: -/* 0000C4 004000C4 03E00008 */ jr $ra -/* 0000C8 004000C8 27BD0008 */ addiu $sp, $sp, 24 -) - -char bss1[3]; -GLOBAL_ASM( -.bss -bss2: -.space 3 -) -char bss3[3]; -char bss4[3]; -const int rodata1[2] = {1}; -extern int some_rodata; - -unsigned g(float, int); -unsigned f(void) { - return g(1.1f, some_rodata); -} - -GLOBAL_ASM( -.rdata -glabel some_rodata -.word 0x1313 -.text -.late_rodata -.word 0x321321 -.text -glabel g -/* 0000C0 004000C0 27BDFFE8 */ addiu $sp, $sp, -0x18 -/* 0000C4 004000C4 AFBF0014 */ sw $ra, 0x14($sp) -/* 0000C8 004000C8 240E0004 */ addiu $t6, $zero, 4 -/* 0000CC 004000CC 3C010041 */ lui $at, %hi(D_410100) -/* 0000D0 004000D0 AC2E0100 */ sw $t6, %lo(D_410100)($at) -/* 0000D4 004000D4 0C10002C */ jal func_004000B0 -/* 0000D8 004000D8 00000000 */ nop -/* 0000DC 004000DC 10000001 */ b .L004000E4 -/* 0000E0 004000E0 00000000 */ nop -.L004000E4: -/* 0000E4 004000E4 8FBF0014 */ lw $ra, 0x14($sp) -/* 0000E8 004000E8 27BD0018 */ addiu $sp, $sp, 0x18 -/* 0000EC 004000EC 03E00008 */ jr $ra -/* 0000F0 004000F0 00000000 */ nop -) diff --git a/tools/asm-processor/tests/test1.objdump b/tools/asm-processor/tests/test1.objdump deleted file mode 100644 index af12f90d..00000000 --- a/tools/asm-processor/tests/test1.objdump +++ /dev/null @@ -1,54 +0,0 @@ - -tests/test1.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 000000b0 .text -00000000 l d .rodata 00000020 .rodata -00000000 l d .bss 00000010 .bss -00000000 g O .bss 00000003 bss1 -00000008 g O .bss 00000003 bss3 -0000000c g O .bss 00000003 bss4 -00000004 g O .rodata 00000008 rodata1 -0000003c g F .text 0000003c f -00000000 g F .text 0000003c test -0000000c g .rodata 00000000 some_rodata -00000078 g F .text 00000034 g -00000000 *UND* 00000000 D_410100 -00000000 *UND* 00000000 func_004000B0 - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -00000044 R_MIPS_HI16 .rodata -00000054 R_MIPS_LO16 .rodata -00000048 R_MIPS_HI16 some_rodata -0000004c R_MIPS_LO16 some_rodata -00000050 R_MIPS_26 g -00000084 R_MIPS_HI16 D_410100 -00000088 R_MIPS_LO16 D_410100 -0000008c R_MIPS_26 func_004000B0 - - -Contents of section .text: - 0000 27bdffe8 18a00009 afa00004 8fae0004 '............... - 0010 008e7821 a1e00000 8fb80004 27190001 ..x!........'... - 0020 0325082a 1420fff9 afb90004 10000001 .%.*. .......... - 0030 00000000 03e00008 27bd0018 27bdffe8 ........'...'... - 0040 afbf0014 3c010000 3c050000 8ca50000 ....<...<....... - 0050 0c000000 c42c0014 10000003 00000000 .....,.......... - 0060 10000001 00000000 8fbf0014 27bd0018 ............'... - 0070 03e00008 00000000 27bdffe8 afbf0014 ........'....... - 0080 240e0004 3c010000 ac2e0000 0c000000 $...<........... - 0090 00000000 10000001 00000000 8fbf0014 ................ - 00a0 27bd0018 03e00008 00000000 00000000 '............... -Contents of section .rodata: - 0000 00001212 00000001 00000000 00001313 ................ - 0010 00123123 3f8ccccd 00321321 00000000 ..1#?....2.!.... -Contents of section .options: - 0000 01200000 00000000 a0000022 00000000 . .........".... - 0010 00001010 00000000 00000000 00007ff0 ................ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 a300c032 00000000 00001010 00000000 ...2............ - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/test2.c b/tools/asm-processor/tests/test2.c deleted file mode 100644 index 15969feb..00000000 --- a/tools/asm-processor/tests/test2.c +++ /dev/null @@ -1,69 +0,0 @@ -const char buf1[1] = {1}; -float func1(void) { - "func1"; - return 0.1f; -} -const char buf2[1] = {2}; -void func2(void) { - *(volatile float*)0 = -3.5792360305786133f; - *(volatile float*)0 = -3.5792362689971924f; - // "func2"; - // return 0.2f; -} -const char buf3[1] = {3}; -int func3(int x) { - switch(x) { - case 0: - return 1; - case 1: - return 2; - case 2: - return 3; - case 3: - return 4; - case 4: - return 5; - case 5: - return 4; - case 6: - return 4; - case 7: - return 4; - default: - return 3; - } -} - -#if 1 -GLOBAL_ASM( -.rdata -.word 0x66756e63 # func -.word 0x34000000 # 4\0\0\0 -.word jumptarget + 4 - -.late_rodata -glabel rv -.word 0x3e4ccccd # 0.2f -.word jumptarget + 8 - -.text -glabel func4 -lui $at, %hi(rv) -glabel jumptarget -jr $ra -lwc1 $f0, %lo(rv)($at) -jr $ra -nop -jr $ra -nop -jr $ra -nop -jr $ra -nop -) -#else -float func4(void) { - "func4"; - return 0.2f; -} -#endif diff --git a/tools/asm-processor/tests/test2.objdump b/tools/asm-processor/tests/test2.objdump deleted file mode 100644 index 968b7d0d..00000000 --- a/tools/asm-processor/tests/test2.objdump +++ /dev/null @@ -1,76 +0,0 @@ - -tests/test2.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 000000f0 .text -00000000 l d .rodata 00000060 .rodata -00000000 g O .rodata 00000001 buf1 -00000000 g F .text 0000001c func1 -0000000c g O .rodata 00000001 buf2 -0000001c g F .text 00000028 func2 -00000010 g O .rodata 00000001 buf3 -00000044 g F .text 0000007c func3 -000000c4 g F .text 00000000 jumptarget -000000c0 g F .text 0000002c func4 -0000004c g .rodata 00000000 rv - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -00000000 R_MIPS_HI16 .rodata -00000008 R_MIPS_LO16 .rodata -0000001c R_MIPS_HI16 .rodata -00000020 R_MIPS_LO16 .rodata -00000028 R_MIPS_HI16 .rodata -0000002c R_MIPS_LO16 .rodata -00000054 R_MIPS_HI16 .rodata -0000005c R_MIPS_LO16 .rodata -000000c0 R_MIPS_HI16 rv -000000c8 R_MIPS_LO16 rv - - -RELOCATION RECORDS FOR [.rodata]: -OFFSET TYPE VALUE -0000002c R_MIPS_32 .text -00000030 R_MIPS_32 .text -00000034 R_MIPS_32 .text -00000038 R_MIPS_32 .text -0000003c R_MIPS_32 .text -00000040 R_MIPS_32 .text -00000044 R_MIPS_32 .text -00000048 R_MIPS_32 .text -0000001c R_MIPS_32 jumptarget -00000050 R_MIPS_32 jumptarget - - -Contents of section .text: - 0000 3c010000 03e00008 c4200020 03e00008 <........ . .... - 0010 00000000 03e00008 00000000 3c010000 ............<... - 0020 c4240024 e4040000 3c010000 c4260028 .$.$....<....&.( - 0030 e4060000 03e00008 00000000 03e00008 ................ - 0040 00000000 2c810008 10200017 00000000 ....,.... ...... - 0050 00047080 3c010000 002e0821 8c2e002c ..p.<......!..., - 0060 01c00008 00000000 03e00008 24020001 ............$... - 0070 03e00008 24020002 03e00008 24020003 ....$.......$... - 0080 03e00008 24020004 03e00008 24020005 ....$.......$... - 0090 03e00008 24020004 03e00008 24020004 ....$.......$... - 00a0 03e00008 24020004 03e00008 24020003 ....$.......$... - 00b0 03e00008 00000000 03e00008 00000000 ................ - 00c0 3c010000 03e00008 c4200000 03e00008 <........ ...... - 00d0 00000000 03e00008 00000000 03e00008 ................ - 00e0 00000000 03e00008 00000000 00000000 ................ -Contents of section .rodata: - 0000 01000000 66756e63 31000000 02000000 ....func1....... - 0010 03000000 66756e63 34000000 00000004 ....func4....... - 0020 3dcccccd c0651234 c0651235 00000068 =....e.4.e.5...h - 0030 00000070 00000078 00000080 00000088 ...p...x........ - 0040 00000090 00000098 000000a0 3e4ccccd ............>L.. - 0050 00000008 00000000 00000000 00000000 ................ -Contents of section .options: - 0000 01200000 00000000 80004016 00000000 . ........@..... - 0010 00000051 00000000 00000000 00007ff0 ...Q............ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 80004016 00000000 00000051 00000000 ..@........Q.... - 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/test3.c b/tools/asm-processor/tests/test3.c deleted file mode 100644 index d74bb4cb..00000000 --- a/tools/asm-processor/tests/test3.c +++ /dev/null @@ -1,70 +0,0 @@ - -GLOBAL_ASM( -.rdata -.word 321321 -.text -glabel test -/* 000090 00400090 27BDFFF8 */ addiu $sp, $sp, -24 -/* 000094 00400094 18A00009 */ blez $a1, .L004000BC -/* 000098 00400098 AFA00004 */ sw $zero, 4($sp) -.L0040009C: -/* 00009C 0040009C 8FAE0004 */ lw $t6, 4($sp) -/* 0000A0 004000A0 008E7821 */ addu $t7, $a0, $t6 -/* 0000A4 004000A4 A1E00000 */ sb $zero, ($t7) -/* 0000A8 004000A8 8FB80004 */ lw $t8, 4($sp) -/* 0000AC 004000AC 27190001 */ addiu $t9, $t8, 1 -/* 0000B0 004000B0 0325082A */ slt $at, $t9, $a1 -/* 0000B4 004000B4 1420FFF9 */ bnez $at, .L0040009C -/* 0000B8 004000B8 AFB90004 */ sw $t9, 4($sp) -.L004000BC: -/* 0000BC 004000BC 10000001 */ b .L004000C4 -/* 0000C0 004000C0 00000000 */ nop -.L004000C4: -/* 0000C4 004000C4 03E00008 */ jr $ra -/* 0000C8 004000C8 27BD0008 */ addiu $sp, $sp, 24 -) - -// static -> no symbols -// bss -char globalBuf[4]; -const char constBuf[4]; - -// data -char globalBufInit[4] = {1}; - -// rodata -const char constBufInit[4] = {1}; -const char constBufInit2[1] = {2}; -const char constBufInit3[1] = {3}; - -unsigned g(void); -unsigned f(void) { - // aligns to 4 or 8 byte boundary (char -> 4, double -> 8) - double x = 5.1; - float y = 5.2f; - float z = 5.3f; - "Hello "; - "World"; - return g(); -} - -GLOBAL_ASM( -.rdata -.word 123123 -.text -glabel g -/* 0000C0 004000C0 27BDFFE8 */ addiu $sp, $sp, -0x18 -/* 0000C4 004000C4 AFBF0014 */ sw $ra, 0x14($sp) -/* 0000C8 004000C8 240E0004 */ addiu $t6, $zero, 4 -/* 0000CC 004000CC 3C010041 */ lui $at, %hi(D_410100) -/* 0000D0 004000D0 AC2E0100 */ sw $t6, %lo(D_410100)($at) -/* 0000D4 004000D4 0C10002C */ jal func_004000B0 -/* 0000D8 004000D8 00000000 */ nop -/* 0000DC 004000DC 10000001 */ b .L004000E4 -/* 0000E0 004000E0 00000000 */ nop -.L004000E4: -/* 0000E4 004000E4 8FBF0014 */ lw $ra, 0x14($sp) -/* 0000E8 004000E8 27BD0018 */ addiu $sp, $sp, 0x18 -/* 0000EC 004000EC 03E00008 */ jr $ra -/* 0000F0 004000F0 00000000 */ nop -) diff --git a/tools/asm-processor/tests/test3.objdump b/tools/asm-processor/tests/test3.objdump deleted file mode 100644 index e1e96c25..00000000 --- a/tools/asm-processor/tests/test3.objdump +++ /dev/null @@ -1,64 +0,0 @@ - -tests/test3.o: file format elf32-tradbigmips - -SYMBOL TABLE: -00000000 l d .text 000000d0 .text -00000000 l d .rodata 00000040 .rodata -00000000 l d .data 00000010 .data -00000000 l d .bss 00000010 .bss -00000000 g O .bss 00000004 globalBuf -00000004 g O .bss 00000004 constBuf -00000000 g O .data 00000004 globalBufInit -00000004 g O .rodata 00000004 constBufInit -00000008 g O .rodata 00000001 constBufInit2 -0000000c g O .rodata 00000001 constBufInit3 -0000003c g F .text 00000054 f -00000000 g F .text 0000003c test -00000090 g F .text 00000034 g -00000000 *UND* 00000000 D_410100 -00000000 *UND* 00000000 func_004000B0 - - -RELOCATION RECORDS FOR [.text]: -OFFSET TYPE VALUE -00000044 R_MIPS_HI16 .rodata -00000048 R_MIPS_LO16 .rodata -00000050 R_MIPS_HI16 .rodata -00000054 R_MIPS_LO16 .rodata -0000005c R_MIPS_HI16 .rodata -00000060 R_MIPS_LO16 .rodata -00000068 R_MIPS_26 g -0000009c R_MIPS_HI16 D_410100 -000000a0 R_MIPS_LO16 D_410100 -000000a4 R_MIPS_26 func_004000B0 - - -Contents of section .text: - 0000 27bdffe8 18a00009 afa00004 8fae0004 '............... - 0010 008e7821 a1e00000 8fb80004 27190001 ..x!........'... - 0020 0325082a 1420fff9 afb90004 10000001 .%.*. .......... - 0030 00000000 03e00008 27bd0018 27bdffd8 ........'...'... - 0040 afbf0014 3c010000 d4240028 f7a40020 ....<....$.(... - 0050 3c010000 c4260030 e7a6001c 3c010000 <....&.0....<... - 0060 c4280034 e7a80018 0c000000 00000000 .(.4............ - 0070 10000003 00000000 10000001 00000000 ................ - 0080 8fbf0014 27bd0028 03e00008 00000000 ....'..(........ - 0090 27bdffe8 afbf0014 240e0004 3c010000 '.......$...<... - 00a0 ac2e0000 0c000000 00000000 10000001 ................ - 00b0 00000000 8fbf0014 27bd0018 03e00008 ........'....... - 00c0 00000000 00000000 00000000 00000000 ................ -Contents of section .rodata: - 0000 0004e729 01000000 02000000 03000000 ...)............ - 0010 48656c6c 6f202000 576f726c 64000000 Hello .World... - 0020 0001e0f3 00000000 40146666 66666666 ........@.ffffff - 0030 40a66666 40a9999a 00000000 00000000 @.ff@........... -Contents of section .data: - 0000 01000000 00000000 00000000 00000000 ................ -Contents of section .options: - 0000 01200000 00000000 a0000002 00000000 . .............. - 0010 00000170 00000000 00000000 00007ff0 ...p............ - 0020 07100000 00000000 00000000 00000000 ................ - 0030 08100000 00000000 00000000 00000000 ................ -Contents of section .reginfo: - 0000 a300c032 00000000 00000170 00000000 ...2.......p.... - 0010 00000000 00007ff0 ........ diff --git a/tools/ge-stats.py b/tools/ge-stats.py index 1bbf70ca..8f831132 100644 --- a/tools/ge-stats.py +++ b/tools/ge-stats.py @@ -484,7 +484,8 @@ def print_default_stats(stats: StatResults, version): d_completed_func_count = s.function_count - s.nonmatching_count print('\t{:12}\t{:7,} / {:7,} \t{:6.2f}%'.format(s.path, int(d_completed_func_count), int(s.function_count), (percent_complete(d_completed_func_count, s.function_count) * 100))) print() - print('\ttotal \t{:7,} / {:7,} \t{:6.2f}%'.format(int(stats.total_nonmatching_count), int(stats.total_function_count), (percent_complete(stats.total_nonmatching_count, stats.total_function_count) * 100))) + total_completed_func_count = stats.total_function_count - stats.total_nonmatching_count + print('\ttotal \t{:7,} / {:7,} \t{:6.2f}%'.format(int(total_completed_func_count), int(stats.total_function_count), (percent_complete(total_completed_func_count, stats.total_function_count) * 100))) print('__________________________________________________________________') print() @@ -714,9 +715,16 @@ def main(): src_libultrare_completed_list = [ 'ultra80069080.s'] + # files to count as complete, in src/game directory + # These are intentionally kept in assembly. + src_game_completed_list = [ + 'sub_GAME_7F01D1C0.s', + 'chrObjRandom.s', + 'math_sincos.s'] + search = [] search.append(SearchDir('src', False, completed=src_completed_list)) - search.append(SearchDir('src/game', False)) + search.append(SearchDir('src/game', False, completed=src_game_completed_list)) search.append(SearchDir('src/inflate', False)) search.append(SearchDir('src/libultrare', True, completed=src_libultrare_completed_list)) diff --git a/tools/include-stdin.c b/tools/include-stdin.c new file mode 100644 index 00000000..d99eae74 --- /dev/null +++ b/tools/include-stdin.c @@ -0,0 +1,2 @@ +// Used for piping generated C source into the IRIX compiler. +#include "/dev/stdin" diff --git a/tools/report/main.c b/tools/report/main.c index 432e45cc..d1095b50 100644 --- a/tools/report/main.c +++ b/tools/report/main.c @@ -258,15 +258,18 @@ int main(int argc, char **argv) fprintf(html_out, "%s\n", missions[cur_mis].part); fprintf(html_out, "STATISTICS:\n"); fprintf(html_out, "Time:\n"); - fprintf(html_out, "%02d:%02d\n", cur_time / 60, cur_time % 60); - fprintf(html_out, "Target:\n"); + fprintf(html_out, "%02d:%02d ", cur_time / 60, cur_time % 60); + fprintf(html_out, "[New Decomp Available]\n"); + fprintf(html_out, "Target:\n"); fprintf(html_out, "%02d:%02d\n", missions[cur_mis].time / 60, missions[cur_mis].time % 60); if(cur_obj == cur_mis_objs_max) { fprintf(html_out, "(Best Time: %02d:%02d)\n", cur_time / 60, cur_time % 60); } - fprintf(html_out, "Decomp:\n"); + /* + fprintf(html_out, "Decomp:\n"); fprintf(html_out, "%0.1f%%\n", PERCENTF(decompiled_words, decompiled_words_max)); + */ if(last_modified_file_arg_active) { fprintf(html_out, "Last modified file:\n");