Compare commits

...

144 Commits

Author SHA1 Message Date
Zeno Rogue 7b3d2c2626
Merge pull request #377 from jlmjlm/prune_tab
Prune table of new land candidates.
2024-05-16 22:04:51 +02:00
Zeno Rogue 126f45a714
Merge pull request #376 from jlmjlm/nows1
Remove trailing whitespace from system.cpp
2024-05-16 21:56:25 +02:00
Jacob Mandelson 11837d9614 Check for having pruned all land candidates. 2024-05-16 12:46:06 -07:00
Zeno Rogue 64569f1818 debug removed 2024-05-16 21:42:49 +02:00
Jacob Mandelson cd2152ffad Prune table of getNewLand() candidates. 2024-05-16 12:41:19 -07:00
Zeno Rogue eee39b0340 fixed fake-mobile 2024-05-16 21:21:42 +02:00
Zeno Rogue 937c830571 fixed model orientation for spiral 2024-05-16 21:21:14 +02:00
Zeno Rogue 4ec627b1a1 fixed errors about underlying_map uninitialized 2024-05-16 21:21:14 +02:00
Zeno Rogue 1a70e54e24 hopefully fixed yet another C++20 bug 2024-05-16 21:21:13 +02:00
Zeno Rogue a70a9dc663 fixed a bug causing not compiling in C++20 2024-05-16 21:21:13 +02:00
Zeno Rogue 879549ca5d fixed 'race angle' setting: no crash, rotates immediately 2024-05-16 21:21:13 +02:00
Zeno Rogue 7982ea0e58 Removed references to private/daily.cpp and private/hypersteam.cpp. Also removed HAVE_ACHIEVEMENTS as it was redundant to CAP_ACHIEVE 2024-05-16 21:21:13 +02:00
Zeno Rogue 7b99248c06
Merge pull request #374 from jlmjlm/time2
Fix minor menu glitches.
2024-05-16 20:28:22 +02:00
Zeno Rogue dc136cc937
Merge pull request #375 from jlmjlm/time5
Make option to show turns on the main screen.
2024-05-16 20:27:16 +02:00
Jacob Mandelson 3f78c11e6c Remove trailing whitespace from system.cpp 2024-05-16 09:13:48 -07:00
Jacob Mandelson 1dd4da5135 Make option to show turns on the main screen.
"Liberal" version that shows the turncount unguarded by
nomenukey and ISMOBILE.  Hopefully this means that it'll
display properly on mobile, outside the map region's "DRAG" area.
But this display mode is only used by the mobile builds which I
don't have toolchains for, so can't test it.  :(
2024-05-16 08:31:45 -07:00
Jacob Mandelson 601274e67a Fix minor menu glitches.
Currently, if CAP_TOUR is not set then "(v) menu" is displayed
unconditionally, because the "else" statement which suppresses its
display when nomenukey is set is guarded by CAP_TOUR.  That "else"
statement is moved outside the guard.

Currently, the "timeline" -- containing the elapsed time, turn count,
and YASC code -- is not displayed if cheats are active, because it's
replaced by a cheats count line.  Since these lines don't conflict
and the timeline contains useful information, changed to display both.
2024-05-16 07:12:28 -07:00
Zeno Rogue 7581ba887b 13.0i 2024-05-10 20:40:54 +02:00
Zeno Rogue 6b03aca3c0 threecolor now uses its own ctab, not nestcolors 2024-05-10 19:34:01 +02:00
Zeno Rogue 80df589bd2 reverted numlock on MAC 2024-05-10 19:29:14 +02:00
Zeno Rogue 159b47e72a full_rotate_camera no longer reacts to val==0 2024-05-10 19:29:01 +02:00
Zeno Rogue 9a33e63f53 unflipped mine_zero_display 2024-05-10 19:28:47 +02:00
Zeno Rogue 10184f9087 edit minefield colors in minefield config 2024-05-10 19:28:26 +02:00
Zeno Rogue 6b0dd547bd fixed rosebush/crystal world interaction 2024-05-10 19:10:44 +02:00
Zeno Rogue 542e2520c1 changed the guarding in Power landscape 2024-05-10 18:52:23 +02:00
Zeno Rogue f2d81746a7 fixed crash on adding/deleting colors to colortables 2024-05-10 18:37:05 +02:00
Zeno Rogue a130fbbc50 display Compass beason on radar 2024-05-09 21:10:53 +02:00
Zeno Rogue 2097fde609 display Orb of Yendor beacon on radar 2024-05-09 21:07:44 +02:00
Zeno Rogue bc5e1d78c9 always checkTide 2024-05-09 20:44:25 +02:00
Zeno Rogue e324ae07f3 Merge branch 'master' of https://github.com/zenorogue/hyperrogue 2024-05-09 20:42:43 +02:00
Zeno Rogue 215be1ea17
Merge pull request #372 from jlmjlm/tidefix2
Check tide before drawing cells.
2024-05-09 20:42:03 +02:00
Zeno Rogue 53461e6c5a removed yendor debug 2024-05-09 20:21:55 +02:00
Zeno Rogue 7a81b6b0de version 13.0h 2024-05-09 10:50:02 +02:00
Zeno Rogue 723422e137 disable custom_land_list in princess 2024-05-09 10:44:37 +02:00
Zeno Rogue 50881f519f do not count achievements if custom_land_list is used 2024-05-09 10:44:37 +02:00
Zeno Rogue df67249ec0 fixup to distance 534 2024-05-09 10:44:37 +02:00
Zeno Rogue 0a9714e657 cleanup of LB_ constants 2024-05-09 10:44:37 +02:00
Zeno Rogue 5eb7cfc17a LB_PRINCESS instead of magic value 36 2024-05-09 10:44:37 +02:00
Zeno Rogue 000bfd4b97 fixed a bug in celldistance_534 2024-05-09 10:44:37 +02:00
Zeno Rogue 0b0ad4abe3 made bfs in 3D always know nearby cells even if gmatrix not known 2024-05-09 10:44:37 +02:00
Zeno Rogue 305d546ae1 fixed the Yendor beacon to appear in the correct place (usually on the boundary, not the closest visible tile) 2024-05-09 10:44:37 +02:00
Zeno Rogue c369c08bc9 fixed CR3 generated in CR2 layout 2024-05-09 10:44:37 +02:00
Zeno Rogue 52f9cc820b fixed CR2 generated in CR3/CR4 layouts 2024-05-09 10:44:37 +02:00
Zeno Rogue 4c81c0cc5d fixed single wrong tile of the first land when safetying in landscape etc 2024-05-09 10:44:37 +02:00
Zeno Rogue 51ecd882e1 Orb of Summoning now works on deep water, shallow water, and Camelot moat tiles 2024-05-09 10:44:37 +02:00
Zeno Rogue 9ba9797068 fixed CLI -picload 2024-05-09 10:44:37 +02:00
Zeno Rogue ba972ea8d8 more settings for minefield graphics 2024-05-09 10:44:37 +02:00
Zeno Rogue e4b0ebbd89 removed Haunted and Elemental from the landscape mode 2024-05-09 10:44:37 +02:00
Zeno Rogue 35ddcf6fe1 stone gargoyles and statues are now non-blocking for missiles 2024-05-09 10:44:37 +02:00
Zeno Rogue 7c2aca91a4 Orb of Earth now cancels Invisibility only if it is doing something 2024-05-09 10:44:37 +02:00
Zeno Rogue 43702b82a1 clear boats from removed Orbs of Water 2024-05-09 10:44:37 +02:00
Zeno Rogue 43a3e8f030 color change in rogueviz 2024-05-09 10:44:37 +02:00
Zeno Rogue ce825db2c0 redone the canvas coloring system 2024-05-09 10:44:37 +02:00
Zeno Rogue b8a7e6e093 line patterns easier to reach 2024-05-05 17:09:34 +02:00
Zeno Rogue 962efb3152 new linepattern 'wall highlight' 2024-05-05 17:09:13 +02:00
Zeno Rogue 84666ade8c fixed a crash setting landscape_div to 0 2024-05-05 15:19:52 +02:00
Zeno Rogue 9aa15f96e1 fixed a crash with irregular spherical maps 2024-05-05 15:11:07 +02:00
Zeno Rogue bc22d17a16 fixed a possible crash with bad Steam data 2024-05-05 15:10:45 +02:00
Zeno Rogue d9a03ab1d3 renamed tehora to Tehora Rogue in credits 2024-05-05 14:59:07 +02:00
Zeno Rogue 5ae3bc02d1 rogueviz:: dhrg:: removed %Lf 2024-04-28 02:49:53 +02:00
Zeno Rogue aafced83aa rogueviz:: dhrg:: Ld to lld 2024-04-28 02:49:24 +02:00
Zeno Rogue 33aacfa289 disabled simple test 2024-04-28 02:40:43 +02:00
Zeno Rogue d074606cae rogueviz:: sag:: Ld to lld 2024-04-28 02:36:42 +02:00
Zeno Rogue 6aecf921bf rogueviz:: dhrg:: Lf to llf 2024-04-28 02:35:49 +02:00
Zeno Rogue fa99e83019 added the Discord link to README 2024-04-28 02:34:39 +02:00
Zeno Rogue 1003808999 removed badges from README 2024-04-28 02:34:32 +02:00
Zeno Rogue 5085853fb4 removed Emscripten CI 2024-04-28 02:26:24 +02:00
Zeno Rogue 9372ecb8f8 github_ci:: removed Android CI for now 2024-04-28 02:25:27 +02:00
Zeno Rogue 690b2164db github_ci: disabled macos-latest 2024-04-28 02:18:18 +02:00
Zeno Rogue 16e3daeab5 rogueviz:: dhrg:: fixed format 2024-04-28 02:16:28 +02:00
Zeno Rogue 0a16e53561 rogueviz:: fixed missing virtual destructor in model 2024-04-28 02:13:42 +02:00
Zeno Rogue 443be1acda rogueviz:: dhrg:: fixed warning on %p 2024-04-28 02:11:14 +02:00
Zeno Rogue ba9c41bed2 rogueviz:: dhrg:: fixed incorrect initialization 2024-04-28 02:10:22 +02:00
Zeno Rogue 329ad76c3c rogueviz:: dhrg:: fixed VLA 2024-04-28 02:09:19 +02:00
Zeno Rogue de20daf708 rogueviz:: undef IF_ macros 2024-04-28 02:04:40 +02:00
Zeno Rogue f229c489cd rogueviz:: antidesitter:: fixed uninitialized variable 2024-04-28 02:03:13 +02:00
Zeno Rogue 1e3347590b rogueviz:: sag:: fixed unini variable 2024-04-28 02:01:30 +02:00
Zeno Rogue fd1960191e rogueviz:: fixed pedantic error in embedded-chess 2024-04-28 01:52:20 +02:00
Zeno Rogue 942fd9dafb rogueviz::dhrg:: fixed VLA 2024-04-28 01:47:50 +02:00
Zeno Rogue f1e91a1614 rogueviz::dhr:: fixed unused result 2024-04-28 01:46:47 +02:00
Zeno Rogue e71ddf1140 rogueviz::som:: string cannot be constexpr 2024-04-28 01:46:13 +02:00
Zeno Rogue a0ba84d70c Merge branch 'master' of https://github.com/zenorogue/hyperrogue 2024-04-28 01:41:46 +02:00
Zeno Rogue 404b964f28 fixed unused-result error 2024-04-28 01:41:25 +02:00
Jacob Mandelson b56d2d21bf Check tide before drawing cells. 2024-04-22 15:48:08 -07:00
Zeno Rogue 27fb2d92d7
Merge pull request #370 from jlmjlm/build1
Fix the build.
2024-04-22 18:44:02 +02:00
Zeno Rogue ec9be47a83
Merge pull request #371 from jlmjlm/geom_wmark
Show weapon watermark with geometric xbow.
2024-04-22 18:42:57 +02:00
Jacob Mandelson 14519dc258 Show weapon watermark with geometric xbow. 2024-04-22 09:26:29 -07:00
Jacob Mandelson c3ef9c2733 Include the GCC compiler's install too. 2024-04-20 15:29:31 -07:00
Jacob Mandelson c29517b5b0 Fix the build.
Explain how to install the required dev libraries for Windows.
Update C++ std to use from C++11 to C++14.
Put the MSYS2 SDL include dir in the include files path.
2024-04-20 15:13:01 -07:00
Zeno Rogue e91c11ffb7
Merge pull request #368 from jlmjlm/srfix3
Record asteroids_generated and asteroid_orbs_generated in the saveline.
2024-04-17 11:53:03 +02:00
Zeno Rogue 7d3d3a0869
Merge pull request #369 from Tokarak/pr-mac-build
Fix Mac Build
2024-04-17 11:51:56 +02:00
Tokarak d0d4b24f91 Update README.md with up-to-date build info 2024-04-17 10:27:02 +01:00
Tokarak 2659d08b78 Add message about using glew and libpng to Makefile 2024-04-17 10:23:40 +01:00
Tokarak 45db9977a0 Fix SDL include from sdl_gfx
Resolves #332; for MacOS only.
2024-04-17 10:16:55 +01:00
Tokarak aa78aacdf3 Update MacOS Makefile comments to match README
Also fix an unintentially modified Linux comment in parrent commit
2024-04-17 08:49:17 +01:00
Tokarak fd128d24c6 Fix MacOS-silicon compile
Use the right Homebrew prefix — not hard-coded any more.
2024-04-16 17:09:59 +01:00
Jacob Mandelson d756224f8d Record asteroids_generated and asteroid_orbs_generated in the saveline. 2024-04-13 15:43:44 -07:00
Zeno Rogue fbea2d91ce 13.0g 2024-04-09 02:52:01 +02:00
Zeno Rogue d4f449d994 since the Aether users now see adjacent items in water, they can also pick them up 2024-04-09 02:42:25 +02:00
Zeno Rogue 9807b1b3ba simplified the boat logic 2024-04-09 02:34:30 +02:00
Zeno Rogue 4d761385ac a new pseudopept pattern in Binary4 and Ternary 2024-04-08 19:14:01 +02:00
Zeno Rogue 05b6cdea3e fixed a bug ion Ternary emeraldval 2024-04-08 19:13:48 +02:00
Zeno Rogue 10646933db fixed the West Wall being not inaccessible from some lands 2024-04-08 00:58:34 +02:00
Zeno Rogue 521b452436 auto-pause game when it loses focus 2024-04-08 00:45:20 +02:00
Zeno Rogue 0323e4100e fixed the key being generated on ivy 2024-04-08 00:45:03 +02:00
Zeno Rogue 0708c0e2bc fixed a possible crash when using Orb of Space on Orb of Safety 2024-04-07 23:48:49 +02:00
Zeno Rogue b7db56812e fixed a possible freeze in Ocean in the chaos modes 2024-04-07 23:37:28 +02:00
Zeno Rogue 7fc90f116b fixed a possible crash after killing 400 mutants 2024-04-07 23:37:00 +02:00
Zeno Rogue 824fa9a732 push an exploding barrel on a mine now causes an explosion 2024-04-07 23:36:06 +02:00
Zeno Rogue 92603dddcc fixed pressing numpad keys with numpad on acting both as moves and quick-keys 2024-04-07 23:35:33 +02:00
Zeno Rogue 32d329d81e fixed a possible crash when generating YASC message 2024-04-07 23:35:08 +02:00
Zeno Rogue b9608dcd4c save the Halloween stuff 2024-04-06 18:36:14 +02:00
Zeno Rogue 977bd8ca9d ls:: cursed walls 2024-04-06 18:33:29 +02:00
Zeno Rogue 869c63cb88 Merge branch 'master' of https://github.com/zenorogue/hyperrogue 2024-04-06 11:48:06 +02:00
Zeno Rogue 5377147b1a new land structure, CR2-like 2024-04-06 11:45:51 +02:00
Zeno Rogue e83d38e267 new land structure: excessive crossing walls 2024-04-06 10:36:51 +02:00
Zeno Rogue 1fc02631c8 fixed CR4 still appearing in 'landscape' land structure, and when disabled via custom land list 2024-04-06 09:50:41 +02:00
Zeno Rogue edff317759
Merge pull request #367 from jlmjlm/srfix2
Record fuel collected and space rocks killed.
2024-03-28 17:47:58 +01:00
Jacob Mandelson b8de8155da Record fuel collected and space rocks killed. 2024-03-27 21:07:20 -07:00
Zeno Rogue 9bc4e21f10 13.0f 2024-03-27 23:52:22 +01:00
Zeno Rogue a328568ee5 new messages on Orb of Phasing, Slaying, and Weakness 2024-03-27 23:52:22 +01:00
Zeno Rogue 494fc4ec11 more accurate messages on dice pushing 2024-03-27 23:52:22 +01:00
Zeno Rogue 6f7e5b4d6a load_mode_data error checking 2024-03-27 23:52:22 +01:00
Zeno Rogue ccea416237 when loading save, load full mode data including custom lands 2024-03-27 23:52:22 +01:00
Zeno Rogue 4a908273d0 irregular maps no longer save a different modeline every time due to floating point precision 2024-03-27 23:52:22 +01:00
Zeno Rogue 5efacd787d save_cheats option, also fixed buffer overflow 2024-03-27 23:52:22 +01:00
Zeno Rogue b07987b2f4 removed debug displayed by irregular 2024-03-27 23:52:22 +01:00
Zeno Rogue 84ada5184f Space Rock monsters now drop treasure only if in Space Rock land 2024-03-27 23:52:22 +01:00
Zeno Rogue 14b68f0b64 ineligible starting land also if land is not in game 2024-03-27 23:52:22 +01:00
Zeno Rogue 960485ec8e autocheat now circumvents the lock on the Princess Challenge 2024-03-27 23:52:22 +01:00
Zeno Rogue e032e619c0 do not crash if no New Sealand is available 2024-03-27 23:52:22 +01:00
Zeno Rogue 57f6fb5f71 in countHyperstones, two variants of Mirror are counted once 2024-03-27 23:52:22 +01:00
Zeno Rogue d2cd6fa2c1 Princess Quest now marked as 'ingame' when in Princess Challenge 2024-03-27 23:52:22 +01:00
Zeno Rogue 8a407f4505 specially generated lands now respect Unlocked and LandIngame rules 2024-03-27 23:52:22 +01:00
Zeno Rogue 6abb82174e fixed some more crashes related to SDL2 (e.g., right-click in shmup) 2024-03-27 16:28:37 +01:00
Zeno Rogue dea9fea67f mention custom mode in watermark 2024-03-24 21:41:52 +01:00
Zeno Rogue d618b10889 fixed crashes in 'shift to target' option 2024-03-24 21:22:58 +01:00
Zeno Rogue d250abf1a4 added Pasu4 to the credits 2024-03-24 20:43:46 +01:00
Zeno Rogue 89563ebde9 in 3D, rosebushes now blink if they are close to going off 2024-03-24 20:03:02 +01:00
Zeno Rogue 445c240c79 rosebushes now show up on the radar 2024-03-24 20:02:31 +01:00
Zeno Rogue 15b711e099 if you are in water (and have no Fish), you can now see Orbs of Fish and Aether in adjacent water tiles, and also you can move there and pick them up 2024-03-24 19:29:44 +01:00
Zeno Rogue 8002f42d71 added AntiRogue to knight names 2024-03-24 19:28:02 +01:00
Zeno Rogue 79f2940683 crossbow bolt now ignore rose restrictions on attack 2024-03-24 19:12:42 +01:00
Zeno Rogue 0ec4e46bf0 SDL2 bugfix to shmup and game_keys_scroll 2024-03-24 13:15:58 +01:00
84 changed files with 1600 additions and 1366 deletions

View File

@ -1,68 +0,0 @@
name: Github CI on Android
on:
workflow_dispatch:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
android_build:
name: Test build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Validate gradle-wrapper.jar
uses: gradle/wrapper-validation-action@v1
- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get -y install gcc libsdl1.2-dev libsdl-ttf2.0-dev libsdl-gfx1.2-dev libsdl-mixer1.2-dev libglew-dev libpng-dev
- name: Build
run: |
cd hyperroid
./copy.sh
./gradlew assembleDebug
- name: Upload APK
uses: actions/upload-artifact@v2
with:
name: hyperroid_debug
path: hyperroid/app/build/outputs/apk/debug/app-debug.apk
android_test:
needs: android_build
name: Test-run in emulator
runs-on: macos-latest
steps:
- name: Download APK
uses: actions/download-artifact@v2
with:
name: hyperroid_debug
- name: Create a helper wait script
run: |
cat > wait-for-load.sh << ENDOFSCRIPT
#!/bin/sh
while ! adb logcat -d "HyperRogue:V" "*:S" | grep "Game initialized"
do
sleep 2
done
ENDOFSCRIPT
chmod u+x wait-for-load.sh
- name: Run in emulator
uses: ReactiveCircus/android-emulator-runner@v2.11.1
with:
api-level: 28
emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -no-snapstorage -noaudio -no-boot-anim -skin 1440x2560
script: |
adb wait-for-device
adb install -t app-debug.apk
adb shell am start -W -n com.roguetemple.hyperroid/com.roguetemple.hyperroid.HyperRogue
./wait-for-load.sh
adb shell input keyevent 41 # send "M" keypress to display main menu
adb shell screencap /sdcard/hyperroid.png
adb pull /sdcard/hyperroid.png
- name: Upload screenshot
uses: actions/upload-artifact@v2
with:
name: screenshot
path: hyperroid.png

View File

@ -13,7 +13,9 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
# os: [ubuntu-latest, macos-latest]
# macos is broken for now
os: [ubuntu-latest]
compiler: [gcc, clang]
build_system: [makefile, mymake]
hyper_use_rviz: [rviz_1, rviz_0]
@ -71,13 +73,15 @@ jobs:
- name: Do a simple test
run: .github/workflows/test_simple.sh
emscripten:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: |
docker run --rm -v $(pwd):/src trzeci/emscripten make emscripten
- name: Do a simple test
run: |
ls -lAF hyper.html hyper.js hyper.wasm
# broken for now
# emscripten:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
# - name: Build
# run: |
# docker run --rm -v $(pwd):/src trzeci/emscripten make emscripten
# - name: Do a simple test
# run: |
# ls -lAF hyper.html hyper.js hyper.wasm

View File

@ -9,7 +9,9 @@ cat << ENDOFCMDS > .github/workflows/gdb_cmds.txt
exit 1
ENDOFCMDS
gdb --batch -x .github/workflows/gdb_cmds.txt ./hyperrogue
echo not running gdb -- not working currently
echo gdb --batch -x .github/workflows/gdb_cmds.txt ./hyperrogue
else
./hyperrogue --version
fi

View File

@ -1,193 +0,0 @@
language: cpp
dist: bionic
services:
- docker
matrix:
include:
- os: linux # Linux GCC, make
compiler: gcc
env: >-
TRAVIS_OS_NAME=linux
TRAVIS_COMPILER_NAME=gcc
TRAVIS_BUILD_SYSTEM=Makefile
HYPERROGUE_USE_GLEW=1
HYPERROGUE_USE_PNG=1
- os: linux # Linux GCC, make, no libpng
compiler: gcc
env: >-
TRAVIS_OS_NAME=linux
TRAVIS_COMPILER_NAME=gcc
TRAVIS_BUILD_SYSTEM=Makefile
HYPERROGUE_USE_GLEW=1
HYPERROGUE_USE_PNG=0
- os: linux # Linux GCC, make, Rogueviz
compiler: gcc
env: >-
TRAVIS_OS_NAME=linux
TRAVIS_COMPILER_NAME=gcc
TRAVIS_BUILD_SYSTEM=Makefile
HYPERROGUE_USE_GLEW=1
HYPERROGUE_USE_PNG=1
HYPERROGUE_USE_ROGUEVIZ=1
- os: linux # Linux Clang, make
compiler: clang
env: >-
TRAVIS_OS_NAME=linux
TRAVIS_COMPILER_NAME=clang
TRAVIS_BUILD_SYSTEM=Makefile
HYPERROGUE_USE_GLEW=1
HYPERROGUE_USE_PNG=1
- os: linux # Linux Clang, make, Rogueviz
compiler: clang
env: >-
TRAVIS_OS_NAME=linux
TRAVIS_COMPILER_NAME=clang
TRAVIS_BUILD_SYSTEM=Makefile
HYPERROGUE_USE_GLEW=1
HYPERROGUE_USE_PNG=1
HYPERROGUE_USE_ROGUEVIZ=1
- os: osx # OSX, make
osx_image: xcode12u
compiler: clang
env: >-
TRAVIS_OS_NAME=osx
TRAVIS_COMPILER_NAME=clang
TRAVIS_BUILD_SYSTEM=Makefile
HYPERROGUE_USE_GLEW=1
HYPERROGUE_USE_PNG=1
- os: osx # OSX, make, no libpng
osx_image: xcode11.6
compiler: clang
env: >-
TRAVIS_OS_NAME=osx
TRAVIS_COMPILER_NAME=clang
TRAVIS_BUILD_SYSTEM=Makefile
HYPERROGUE_USE_GLEW=1
HYPERROGUE_USE_PNG=0
- os: osx # OSX, make, Rogueviz
osx_image: xcode11.5
compiler: clang
env: >-
TRAVIS_OS_NAME=osx
TRAVIS_COMPILER_NAME=clang
TRAVIS_BUILD_SYSTEM=Makefile
HYPERROGUE_USE_GLEW=1
HYPERROGUE_USE_PNG=1
HYPERROGUE_USE_ROGUEVIZ=1
- os: linux # Linux GCC, mymake
compiler: gcc
env: >-
TRAVIS_OS_NAME=linux
TRAVIS_COMPILER_NAME=gcc
TRAVIS_BUILD_SYSTEM=mymake
HYPERROGUE_USE_GLEW=1
HYPERROGUE_USE_PNG=1
- os: linux # Linux GCC, mymake, Rogueviz
compiler: gcc
env: >-
TRAVIS_OS_NAME=linux
TRAVIS_COMPILER_NAME=gcc
TRAVIS_BUILD_SYSTEM=mymake
HYPERROGUE_USE_GLEW=1
HYPERROGUE_USE_PNG=1
HYPERROGUE_USE_ROGUEVIZ=1
- os: osx # OSX, mymake
osx_image: xcode11.4
compiler: clang
env: >-
TRAVIS_OS_NAME=osx
TRAVIS_COMPILER_NAME=clang
TRAVIS_BUILD_SYSTEM=mymake
HYPERROGUE_USE_GLEW=1
HYPERROGUE_USE_PNG=1
- os: osx # OSX, mymake, Rogueviz
osx_image: xcode11.3
compiler: clang
env: >-
TRAVIS_OS_NAME=osx
TRAVIS_COMPILER_NAME=clang
TRAVIS_BUILD_SYSTEM=mymake
HYPERROGUE_USE_GLEW=1
HYPERROGUE_USE_PNG=1
HYPERROGUE_USE_ROGUEVIZ=1
- os: linux # Emscripten
env: >-
TRAVIS_OS_NAME=linux
TRAVIS_COMPILER_NAME=emscripten
TRAVIS_BUILD_SYSTEM=emscripten
before_install:
- |-
# Install SDL
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
sudo apt-get update -qq
sudo apt-get install -qq libsdl1.2-dev libsdl-gfx1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev
elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew update
brew install sdl sdl_gfx sdl_mixer sdl_ttf
# work around https://stackoverflow.com/questions/51034399/ for now
(cd /usr/local/include && ln -sf SDL/SDL.h)
else
exit 'Unsupported OS'
fi
- |-
# Install GLEW if asked for
if [[ "$HYPERROGUE_USE_GLEW" == "1" ]]; then
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
sudo apt-get install -qq libglew-dev
elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew install glew
else
exit 'Unsupported OS'
fi
fi
- |-
# Install libpng if asked for
if [[ "$HYPERROGUE_USE_PNG" == "1" ]]; then
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
echo 'libpng is installed by default'
elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew install libpng
else
exit 'Unsupported OS'
fi
fi
script:
- |-
make clean
if [[ "$(git status --porcelain)" ]]; then
git status
exit 'A build artifact was committed; git rm it and try again'
fi
- |-
# Build hyperrogue.
export CXXFLAGS_EARLY=-Werror
if [[ "$TRAVIS_BUILD_SYSTEM" == "Makefile" ]]; then
make
elif [[ "$TRAVIS_BUILD_SYSTEM" == "mymake" ]]; then
make mymake
if [[ "$HYPERROGUE_USE_ROGUEVIZ" == "1" ]]; then
./mymake -rv
else
./mymake
fi
mv hyper hyperrogue
elif [[ "$TRAVIS_BUILD_SYSTEM" == "emscripten" ]]; then
docker run --rm -v $(pwd):/src trzeci/emscripten make emscripten
else
exit 'Unsupported build system'
fi
- |-
# Test hyperrogue.
if [[ "$TRAVIS_BUILD_SYSTEM" == "emscripten" ]]; then
ls -lAF hyper.html hyper.js hyper.wasm
else
./hyperrogue --help
fi
- |-
make clean
if [[ "$(git status --porcelain)" ]]; then
git status
exit 'make clean did not return the repository to its pre-build state'
fi

View File

@ -1,16 +1,24 @@
# This Makefile works for Mac OS X (El Capitan), MinGW, and Linux.
#
# Environmental vairables:
# If you want to build with Glew, set
# HYPERROGUE_USE_GLEW=1
# If you want to use libpng, set
# HYPERROGUE_USE_PNG=1
#
# For Mac OS X:
# Run "brew install sdl" to install SDL in /usr/local.
# Run "brew install sdl_gfx".
# Run "brew install sdl_mixer".
# Run "brew install sdl_ttf".
# Run "make" to build HyperRogue as ./hyperrogue.
# Run `brew install sdl12-compat sdl_gfx sdl_mixer sdl_ttf`
# Run `brew install glew libpng` to install the optional dependencies
# Run `make` to build HyperRogue as `./hyperrogue`.
#
# For MSYS2 and MinGW-w64:
# You might need to run commands such as "pacman -S mingw-w64-x86_64-SDL"
# to install SDL and other required libraries.
# Run "make" to build HyperRogue as ./hyperrogue.exe.
# To install SDL and other required libraries, run these commands
# from the MSYS2 shell:
# pacman -S mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-glew
# pacman -S mingw-w64-ucrt-x86_64-SDL mingw-w64-ucrt-x86_64-SDL_mixer
# pacman -S mingw-w64-ucrt-x86_64-SDL_ttf mingw-w64-ucrt-x86_64-SDL_gfx
# pacman -S make
# Then run "make" to build HyperRogue as ./hyperrogue.exe.
#
# For Ubuntu Linux:
# Run "sudo apt-get install libsdl-dev" to install SDL in /usr/local.
@ -54,7 +62,7 @@ ifeq (${OS},linux)
endif
ifeq (${OS},mingw)
CXXFLAGS_EARLY += -DWINDOWS -mwindows -D_A_VOLID=8
CXXFLAGS_EARLY += -DWINDOWS -mwindows -D_A_VOLID=8 -I/ucrt64/include/SDL
EXE_EXTENSION := .exe
LDFLAGS_GL := -lopengl32
LDFLAGS_GLEW := -lglew32
@ -68,9 +76,10 @@ ifeq (${OS},mingw)
endif
ifeq (${OS},osx)
CXXFLAGS_EARLY += -DMAC -I/usr/local/include
HOMEBREW_PREFIX := $(shell brew --prefix)
CXXFLAGS_EARLY += -DMAC -I$(HOMEBREW_PREFIX)/include -I$(HOMEBREW_PREFIX)/include/SDL
EXE_EXTENSION :=
LDFLAGS_EARLY += -L/usr/local/lib
LDFLAGS_EARLY += -L$(HOMEBREW_PREFIX)/lib
LDFLAGS_GL := -framework AppKit -framework OpenGL
LDFLAGS_GLEW := -lGLEW
LDFLAGS_PNG := -lpng
@ -80,7 +89,7 @@ ifeq (${OS},osx)
endif
ifeq (${TOOLCHAIN},clang)
CXXFLAGS_STD = -std=c++11
CXXFLAGS_STD = -std=c++14
CXXFLAGS_EARLY += -fPIC
CXXFLAGS_EARLY += -W -Wall -Wextra -Wsuggest-override -pedantic
CXXFLAGS_EARLY += -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized -Wno-char-subscripts -Wno-unknown-warning-option
@ -88,7 +97,7 @@ ifeq (${TOOLCHAIN},clang)
endif
ifeq (${TOOLCHAIN},gcc)
CXXFLAGS_STD = -std=c++11
CXXFLAGS_STD = -std=c++14
CXXFLAGS_EARLY += -fPIC
CXXFLAGS_EARLY += -W -Wall -Wextra -pedantic
CXXFLAGS_EARLY += -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized
@ -96,7 +105,7 @@ ifeq (${TOOLCHAIN},gcc)
endif
ifeq (${TOOLCHAIN},mingw)
CXXFLAGS_STD = -std=c++11
CXXFLAGS_STD = -std=c++14
CXXFLAGS_EARLY += -W -Wall -Wextra
CXXFLAGS_EARLY += -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized
CXXFLAGS_EARLY += -Wno-invalid-offsetof
@ -173,7 +182,7 @@ mymake$(EXE_EXTENSION): mymake.cpp
emscripten: hyper.html
%.html %.js %.wasm: %.emscripten-sources
emcc -std=c++11 -O3 -s USE_ZLIB=1 -s LEGACY_GL_EMULATION=1 -s TOTAL_MEMORY=128MB hyperweb.cpp -o hyper.html
emcc -std=c++14 -O3 -s USE_ZLIB=1 -s LEGACY_GL_EMULATION=1 -s TOTAL_MEMORY=128MB hyperweb.cpp -o hyper.html
hyper.emscripten-sources: *.cpp autohdr.h

View File

@ -1,11 +1,4 @@
# HyperRogue
<p>
<a href="https://travis-ci.org/zenorogue/hyperrogue/builds">
<img src="https://badges.herokuapp.com/travis/zenorogue/hyperrogue?branch=master&env=TRAVIS_BUILD_SYSTEM=Makefile&label=make" alt="TravisCI badge">
<img src="https://badges.herokuapp.com/travis/zenorogue/hyperrogue?branch=master&env=TRAVIS_BUILD_SYSTEM=mymake&label=mymake" alt="TravisCI badge">
<img src="https://badges.herokuapp.com/travis/zenorogue/hyperrogue?branch=master&env=TRAVIS_BUILD_SYSTEM=emscripten&label=web" alt="TravisCI badge">
</a>
</p>
A puzzle roguelike in the hyperbolic plane. See the [HyperRogue website](http://roguetemple.com/z/hyper.php) for detailed and most up-to-date information.
Compiled executables can be downloaded from [itch.io](https://zenorogue.itch.io/hyperrogue) and from the [HyperRogue website](http://www.roguetemple.com/z/hyper/download.php).
@ -62,15 +55,13 @@ On Linux with apt-get:
On macOS with Homebrew:
```brew install sdl sdl_ttf sdl_gfx sdl_mixer glew```
macOS users might also have to edit /usr/local/include/SDL/SDL_gfxPrimitives.h at line 38 to use quote include.
```brew install sdl sdl_ttf sdl_gfx sdl_mixer glew libpng```
### Building HyperRogue from source ###
```
git clone https://github.com/zenorogue/hyperrogue.git hyperrogue
cd hyperrogue
make
HYPERROGUE_USE_GLEW=1 HYPERROGUE_USE_PNG=1 make
```
The `mymake` program builds HyperRogue in parts. It takes longer than the method shown above, but it uses significantly less memory during compilation, and when you change something, `mymake` will only recompile the changed file.
@ -83,3 +74,6 @@ make mymake && ./mymake
```
The source code is not documented very well. You can see the current state of the documentation, as generated by Doxygen, [here](https://zenorogue.github.io/hyperrogue-doc/).
## Discussion ##
The best place to discuss HyperRogue is our [Discord server|https://discord.com/invite/8G44XkR].

View File

@ -10,7 +10,9 @@
#include "hyper.h"
namespace hr {
#if HDR
#define NUMLEADER 90
#endif
EX bool test_achievements = false;
@ -86,9 +88,27 @@ EX const char* leadernames[NUMLEADER] = {
"Crossbow (geometric)", // 89
};
#if HDR
#define LB_PRINCESS 36
#define LB_STATISTICS 62
#define LB_HALLOWEEN 63
#define LB_HALLOWEEN 63
#define LB_YENDOR_CHALLENGE 40
#define LB_PURE_TACTICS 41
#define LB_PURE_TACTICS_SHMUP 49
#define LB_PURE_TACTICS_COOP 50
#define LB_RACING 81
#endif
EX void achievement_init();
EX string myname();
EX void achievement_close();
EX void achievement_pump();
/** gain the given achievement.
* @param s name of the achievement, e.g., DIAMOND1
* @param flags one of the constants from namespace rg. The achievement is only awarded if special modes are matched exactly.
*/
EX void achievement_gain(const char* s, char flags IS(0));
EX bool haveLeaderboard(int id);
EX int get_currentscore(int id);
@ -96,7 +116,7 @@ EX void set_priority_board(int id);
EX int get_sync_status();
EX bool score_loaded(int id);
EX int score_default(int id);
EX void improveItemScores();
EX void upload_score(int id, int v);
string achievementMessage[3];
@ -219,29 +239,24 @@ EX void achievement_log(const char* s, char flags) {
#endif
}
EX void achievement_init();
EX string myname();
EX void achievement_close();
#ifndef LEADER
#define LEADER "Unknown"
#define LEADERFULL "Unknown"
#endif
/** gain the given achievement.
* @param s name of the achievement, e.g., DIAMOND1
* @param flags one of the constants from namespace rg. The achievement is only awarded if special modes are matched exactly.
*/
EX void achievement_gain(const char* s, char flags IS(0));
#if ISSTEAM
void improveItemScores();
#include "private/hypersteam.cpp"
#elif !ISANDROID && !ISIOS
#if !CAP_ACHIEVE
void achievement_init() {}
string myname() { return "Rogue"; }
void achievement_close() {}
// gain the achievement with the given name.
// flags: 'e' - for Euclidean, 's' - for Shmup, '7' - for heptagonal
// Only awarded if special modes are matched exactly.
void achievement_gain(const char* s, char flags IS(0)) {
void achievement_gain(const char* s, char flags) {
achievement_log(s, flags);
}
void achievement_pump() {}
EX int get_sync_status() { return 0; }
EX void set_priority_board(int) { }
#endif
// gain the achievement for collecting a number of 'it'.
@ -646,7 +661,7 @@ int specific_what = 0;
EX void improve_score(int i, eItem what) {
if(offlineMode) return;
LATE( improve_score(i, what); )
#ifdef HAVE_ACHIEVEMENTS
#if CAP_ACHIEVE
if(haveLeaderboard(i)) updateHi(what, get_currentscore(i));
if(items[what] && haveLeaderboard(i)) {
if(items[what] > get_currentscore(i) && score_loaded(i)) {
@ -660,7 +675,7 @@ EX void improve_score(int i, eItem what) {
// scores for special challenges
EX void achievement_score(int cat, int number) {
if(offlineMode) return;
#ifdef HAVE_ACHIEVEMENTS
#if CAP_ACHIEVE
if(cheater) return;
if(casual) return;
LATE( achievement_score(cat, number); )
@ -682,6 +697,7 @@ EX void achievement_score(int cat, int number) {
return;
if(racing::on && cat != LB_RACING) return;
if(bow::weapon) return;
if(use_custom_land_list) return;
upload_score(cat, number);
#endif
}
@ -765,7 +781,7 @@ EX void achievement_final(bool really_final) {
LATE( achievement_final(really_final); )
#ifdef HAVE_ACHIEVEMENTS
#if CAP_ACHIEVE
if(ticks > next_stat_tick) {
upload_score(LB_STATISTICS, time(NULL));
next_stat_tick = ticks + 600000;
@ -900,7 +916,7 @@ EX void check_total_victory() {
EX void achievement_victory(bool hyper) {
DEBBI(DF_STEAM, ("achievement_victory"))
if(offlineMode) return;
#ifdef HAVE_ACHIEVEMENTS
#if CAP_ACHIEVE
if(cheater) return;
if(casual) return;
if(bow::weapon) return;
@ -913,6 +929,7 @@ EX void achievement_victory(bool hyper) {
if(tactic::on) return;
if(!ls::nice_walls()) return;
if(ineligible_starting_land) return;
if(use_custom_land_list) return;
LATE( achievement_victory(hyper); )
DEBB(DF_STEAM, ("after checks"))
@ -1033,13 +1050,9 @@ EX string get_rich_presence_text() {
return res;
}
#ifndef HAVE_ACHIEVEMENTS
void achievement_pump() {}
#endif
/** display the last achievement gained. */
EX void achievement_display() {
#ifdef HAVE_ACHIEVEMENTS
#if CAP_ACHIEVE
if(achievementTimer) {
int col = (ticks - achievementTimer);
if(col > 5000) { achievementTimer = 0; return; }
@ -1069,9 +1082,4 @@ EX int score_default(int i) {
else return 0;
}
#ifndef HAVE_ACHIEVEMENTS
EX int get_sync_status() { return 0; }
EX void set_priority_board(int) { }
#endif
}

View File

@ -220,8 +220,7 @@ void ensure_geometry(eGeometryClass c) {
if(specialland != laCanvas) {
canvas_default_wall = waInvisibleFloor;
patterns::whichCanvas = 'g';
patterns::canvasback = 0xFFFFFF;
ccolor::set_plain(0xFFFFFF);
enable_canvas();
}
start_game();
@ -1283,7 +1282,7 @@ void connection_debugger() {
curvepoint(sh[0]);
color_t col = colortables['A'][id];
color_t col = ccolor::shape.ctab[id];
col = darkena(col, 0, 0xFF);
if(&p == &last) {

View File

@ -1340,11 +1340,12 @@ EX void enable(archimedean_tiling& arct) {
start_game();
}
function<void()> setcanvas(char c) {
return [c] () {
function<void()> setcanvas(ccolor::data& c) {
auto pc = &c;
return [pc] () {
stop_game();
enable_canvas();
patterns::whichCanvas = c;
ccolor::which = pc;
start_game();
};
}
@ -1467,9 +1468,9 @@ EX void show() {
dialog::addSelItem(XLAT("edge length"), current.get_class() == gcEuclid ? (fts(current.edgelength) + XLAT(" (arbitrary)")) : fts(current.edgelength), 0);
dialog::addItem(XLAT("color by symmetries"), 't');
dialog::add_action(setcanvas('A'));
dialog::add_action(setcanvas(ccolor::shape));
dialog::addItem(XLAT("color by symmetries (reversed tiles marked)"), 'r');
dialog::add_action(setcanvas('R'));
dialog::add_action(setcanvas(ccolor::shape_mirror));
}
else {
dialog::addBreak(100);
@ -1479,20 +1480,20 @@ EX void show() {
if(true) {
dialog::addItem(XLAT("color by sides"), 'u');
dialog::add_action(setcanvas('B'));
dialog::add_action(setcanvas(ccolor::sides));
}
if(geosupport_threecolor() == 2) {
dialog::addItem(XLAT("three colors"), 'w');
dialog::add_action(setcanvas('T'));
dialog::add_action(setcanvas(ccolor::threecolor));
}
else if(geosupport_football() == 2) {
dialog::addItem(XLAT("football"), 'w');
dialog::add_action(setcanvas('F'));
dialog::add_action(setcanvas(ccolor::football));
}
else if(geosupport_chessboard()) {
dialog::addItem(XLAT("chessboard"), 'w');
dialog::add_action(setcanvas('c'));
dialog::add_action(setcanvas(ccolor::chessboard));
}
else dialog::addBreak(100);

View File

@ -151,7 +151,7 @@ EX bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags)
if(!(flags & (AF_GUN | AF_SWORD | AF_SWORD_INTO | AF_MAGIC | AF_PLAGUE)))
if(c1 != c2 && !logical_adjacent(c1, m1, c2)) return false;
if(!(flags & (AF_LANCE | AF_STAB | AF_BACK | AF_APPROACH | AF_GUN | AF_MAGIC | AF_PLAGUE | AF_SIDE)))
if(!(flags & (AF_LANCE | AF_STAB | AF_BACK | AF_APPROACH | AF_GUN | AF_MAGIC | AF_PLAGUE | AF_SIDE | AF_BOW)))
if(c1 && c2 && againstRose(c1, c2) && !ignoresSmell(m1))
return false;
@ -757,7 +757,7 @@ EX void killMonster(cell *c, eMonster who, flagtype deathflags IS(0)) {
// a reward for killing him before he shoots!
c->item = itOrbDragon;
}
if(m == moAsteroid && !shmup::on && c->item == itNone && c->wall != waChasm) {
if(m == moAsteroid && !shmup::on && c->item == itNone && c->wall != waChasm && c->land == laAsteroids) {
c->item = itAsteroid;
changes.value_add(splitrocks, 2);
}
@ -944,6 +944,14 @@ EX void fightmessage(eMonster victim, eMonster attacker, bool stun, flagtype fla
else
addMessage(XLAT("You pierce %the1.", victim)); // normal
}
else if(items[itOrbSlaying]) {
playSound(NULL, "hit-crush"+pick123());
addMessage(XLAT("You crush %the1!", victim)); // normal
}
else if(stun && items[itCurseWeakness]) {
playSound(NULL, "click");
addMessage(XLAT("You punch %the1.", victim)); // normal
}
else if(!peace::on) {
playSound(NULL, "hit-sword"+pick123());
addMessage(XLAT("You kill %the1.", victim)); // normal

View File

@ -559,7 +559,9 @@ EX bool isbar4(cell *c) {
}
EX bool barrier_cross(eLand l, eLand r) {
if(land_structure == lsVineWalls) return false;
if(l == laCrossroads3 || r == laCrossroads3) return hrand(100) < 66;
if(land_structure == lsCrossWalls && !among(laCrossroads2, l, r)) return hrand(100) < 90;
if(isElemental(l) && isElemental(r)) return hrand(100) < 75;
return false;
}
@ -615,6 +617,12 @@ EX void extendBarrier(cell *c) {
if(buildBarrier6(cw, 2)) return;
}
if(land_structure == lsCursedWalls && c->barleft != laMirror && c->barright != laMirror && hrand(100) < 80 && !among(laCrossroads2, c->barleft, c->barright)) {
cellwalker cw(c, c->bardir);
cw = cw + wstep + 3 + wstep - 1;
if(buildBarrier6(cw, c->barright, c->barleft)) return;
}
if(barrier_cross(c->barleft, c->barright) || (firstmirror && hrand(100) < 60)) {
cellwalker cw(c, c->bardir);
@ -680,6 +688,7 @@ EX void buildBarrier(cell *c, int d, eLand l IS(laNone)) {
buildBarrierForce(c, d, l);
}
/** mirror variant of 6-fold walls */
EX bool buildBarrier6(cellwalker cw, int type) {
limitgen("build6 %p/%d (%d)\n", hr::voidp(cw.at), cw.spin, type);
@ -724,21 +733,28 @@ EX bool buildBarrier6(cellwalker cw, int type) {
if(!(PURE?checkBarriersFront:checkBarriersBack)(b[0], 6, true)) return false;
if(!(PURE?checkBarriersFront:checkBarriersBack)(b[3], 6, true)) return false;
}
eLand m0 = laMirror;
eLand m1 = laMirrored;
eLand m2 = laMirrored2;
eLand mw1 = laMirrorWall;
eLand mw2 = laMirrorWall2;
eWall w = waMirrorWall;
for(int d=0; d<4; d++) {
b[d].at->bardir = b[d].spin;
if(PURE) {
b[0].at->barleft = laMirrored, b[0].at->barright = laMirrored2;
b[1].at->barleft = laMirror, b[1].at->barright = laMirrored;
b[2].at->barleft = laMirrored2, b[2].at->barright = laMirrored;
b[3].at->barleft = laMirrored, b[3].at->barright = laMirror;
b[0].at->barleft = m1, b[0].at->barright = m2;
b[1].at->barleft = m0, b[1].at->barright = m1;
b[2].at->barleft = m2, b[2].at->barright = m1;
b[3].at->barleft = m1, b[3].at->barright = m0;
}
else {
b[0].at->barleft = laMirror, b[0].at->barright = laMirrored;
b[1].at->barleft = laMirrored, b[1].at->barright = laMirror;
b[2].at->barleft = laMirrored, b[2].at->barright = laMirrored2;
b[3].at->barleft = laMirrored2, b[3].at->barright = laMirrored;
b[0].at->barleft = m0, b[0].at->barright = m1;
b[1].at->barleft = m1, b[1].at->barright = m0;
b[2].at->barleft = m1, b[2].at->barright = m2;
b[3].at->barleft = m2, b[3].at->barright = m1;
}
(PURE?extendBarrierFront:extendBarrierBack)(b[d].at);
@ -752,45 +768,87 @@ EX bool buildBarrier6(cellwalker cw, int type) {
}
if(BITRUNCATED) {
setland((cw+1).cpeek(), laMirrorWall);
setland((cw+2).cpeek(), laMirrored);
setland((cw+3).cpeek(), laMirrorWall2);
setland((cw+4).cpeek(), laMirrorWall2);
setland((cw+5).cpeek(), laMirrored);
setland((cw+0).cpeek(), laMirrorWall);
setland((b[0]+2).cpeek(), laMirrored);
setland((b[3]+6).cpeek(), laMirrored2);
setland((b[3]+5).cpeek(), laMirrored2);
setland((b[1]-1).cpeek(), laMirrored);
setland((b[2]-2).cpeek(), laMirrored);
setland((b[1]-2).cpeek(), laMirrored);
setland((b[0]-2).cpeek(), laMirror);
cw.at->land = laMirrorWall;
cw.at->wall = waMirrorWall;
setland((cw+1).cpeek(), mw1);
setland((cw+2).cpeek(), m1);
setland((cw+3).cpeek(), mw2);
setland((cw+4).cpeek(), mw2);
setland((cw+5).cpeek(), m1);
setland((cw+0).cpeek(), mw1);
setland((b[0]+2).cpeek(), m1);
setland((b[3]+6).cpeek(), m2);
setland((b[3]+5).cpeek(), m2);
setland((b[1]-1).cpeek(), m1);
setland((b[2]-2).cpeek(), m1);
setland((b[1]-2).cpeek(), m1);
setland((b[0]-2).cpeek(), m0);
cw.at->land = mw1;
cw.at->wall = w;
cw.at->landparam = 1;
}
else {
setland(cw.at, laMirrorWall2);
setland((cw+0).cpeek(), laMirrorWall2);
setland((cw+1).cpeek(), laMirrored);
setland((cw+2).cpeek(), laMirrored);
setland((cw+3).cpeek(), laMirrorWall);
setland((cw+4).cpeek(), laMirrored);
setland((cw+5).cpeek(), laMirrorWall2);
setland((cw+6).cpeek(), laMirrored2);
setland(cw.at, mw2);
setland((cw+0).cpeek(), mw2);
setland((cw+1).cpeek(), m1);
setland((cw+2).cpeek(), m1);
setland((cw+3).cpeek(), mw1);
setland((cw+4).cpeek(), m1);
setland((cw+5).cpeek(), mw2);
setland((cw+6).cpeek(), m2);
setland((b[1]).cpeek(), laMirrorWall);
setland((b[1]+1).cpeek(), laMirror);
setland((b[1]+2).cpeek(), laMirrorWall);
setland((b[1]+6).cpeek(), laMirrored);
setland((b[1]).cpeek(), mw1);
setland((b[1]+1).cpeek(), m0);
setland((b[1]+2).cpeek(), mw1);
setland((b[1]+6).cpeek(), m1);
setland((b[0] + wstep - 2).cpeek(), laMirrored);
setland((b[3] + wstep - 2).cpeek(), laMirrored);
setland((b[0] + wstep - 2).cpeek(), m1);
setland((b[3] + wstep - 2).cpeek(), m1);
}
return true;
}
EX int curse_percentage = 10;
/** cursed variant of 6-fold walls */
EX bool buildBarrier6(cellwalker cw, eLand m0, eLand m1) {
cellwalker b[6];
if(buggyGeneration) return true;
for(int i=0; i<6; i+=2)
b[i] = cw + i + wstep;
for(int i=1; i<6; i+=2)
b[i] = cw + i + wstep + 3 + wstep;
for(int i=0; i<6; i++) if(i != 1) {
if(!(PURE?checkBarriersFront:checkBarriersBack)(b[i], 6, true)) return false;
}
for(int d=0; d<6; d++) {
b[d].at->bardir = b[d].spin;
b[d].at->barleft = (d&1) ? m1 : m0;
b[d].at->barright = (d&1) ? m0 : m1;
(PURE?extendBarrierFront:extendBarrierBack)(b[d].at);
}
cw.at->land = laBarrier;
cw.at->wall = waBarrier;
forCellCM(c, cw.at) { c->land = laBarrier; c->wall = waBarrier; }
for(int d=0; d<6; d+=2) {
setland((b[d]-2).cpeek(), m0);
setland((b[d]+2).cpeek(), m1);
setland((b[d+1]-2).cpeek(), m1);
setland((b[d+1]+2).cpeek(), m0);
}
if(hrand(100) < curse_percentage) {
setland(cw.at, laCursed);
cw.at->wall = waRubble;
cw.at->monst = moHexer;
cw.at->item = random_curse();
}
return true;
}
EX bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr) {
limitgen("build4 %p\n", hr::voidp(c));
if(buggyGeneration) return true;

View File

@ -703,6 +703,9 @@ EX int coastval(cell *c, eLand base) {
if(!c->landparam) return UNKNOWN;
return c->landparam & 255;
}
else if(base == laWestWall) {
if(c->land != base) return 0;
}
else {
if(c->land == laOceanWall || c->land == laCaribbean || c->land == laWhirlpool ||
c->land == laLivefjord || c->land == laWarpSea || c->land == laKraken || c->land == laDocks || c->land == laBrownian)
@ -1005,7 +1008,7 @@ EX void buildEquidistant(cell *c) {
if(c->landparam > 30 && b == laOcean && !generatingEquidistant && !mhybrid && hrand(10) < 5 && chance)
buildAnotherEquidistant(c);
if(c->landparam > HAUNTED_RADIUS+5 && b == laGraveyard && !generatingEquidistant && !mhybrid && hrand(100) < (PURE?25:5) && items[itBone] >= U10 && chance)
if(c->landparam > HAUNTED_RADIUS+5 && b == laGraveyard && !generatingEquidistant && !mhybrid && hrand(100) < (PURE?25:5) && landUnlockedIngame(laHaunted) && chance)
buildAnotherEquidistant(c);
}
@ -1326,7 +1329,7 @@ EX void setLandEuclid(cell *c) {
return;
}
#endif
setland(c, specialland);
if(!c->land) setland(c, specialland);
if(ls::any_nowall()) {
auto co = euc2_coordinates(c);
int y = co.second;
@ -1771,6 +1774,21 @@ EX void build_walls(cell *c, cell *from) {
else if(good_for_wall(c) && isWarpedType(c->land) && hrand(10000) < 3000 && c->land &&
buildBarrierNowall(c, eLand(c->land ^ laWarpSea ^ laWarpCoast))) { }
else if(land_structure == lsVineWalls) {
int ev = emeraldval(c);
if((ev | 11) == 43 && c->bardir == NODIR) {
for(int i=0; i<c->type; i++) if(emeraldval(c->cmove(i)) == ev-4) {
bool oldleft = true;
for(int j=1; j<=3; j++)
if(c->modmove(i+j) && c->modmove(i+j)->mpdist < c->mpdist)
oldleft = false;
buildBarrierStrong(c, i, oldleft, getNewLand(c->land));
extendBarrier(c);
}
}
return;
}
else if(ls::single()) return;
@ -1792,11 +1810,11 @@ EX void build_walls(cell *c, cell *from) {
return;
}
else if(good_for_wall(c) && c->land == laCrossroads4 && hrand(10000) < 7000 && c->land && !c->master->alt && !tactic::on && !racing::on &&
else if(good_for_wall(c) && ls::any_wall() && c->land == laCrossroads4 && hrand(10000) < 7000 && c->land && !c->master->alt && !tactic::on && !racing::on &&
buildBarrierNowall(c, getNewLand(laCrossroads4))) ;
else if(good_for_wall(c) && hrand(I10000) < 20 && !generatingEquidistant && !yendor::on && !tactic::on && !racing::on && !isCrossroads(c->land) &&
gold() >= R200 && !weirdhyperbolic && !c->master->alt && c->bardir != NOBARRIERS &&
else if(good_for_wall(c) && ls::any_wall() && hrand(I10000) < 20 && !generatingEquidistant && !yendor::on && !tactic::on && !racing::on && !isCrossroads(c->land) &&
landUnlockedIngame(laCrossroads4) && !weirdhyperbolic && !c->master->alt && c->bardir != NOBARRIERS &&
!inmirror(c) && !isSealand(c->land) && !isHaunted(c->land) && !isGravityLand(c->land) &&
(c->land != laRlyeh || rlyehComplete()) &&
c->land != laTortoise && c->land != laPrairie && c->land &&
@ -1876,13 +1894,13 @@ EX void build_horocycles(cell *c, cell *from) {
items[itEmerald] >= U5)))
start_camelot(c);
if(c->land == laRlyeh && can_start_horo(c) && (quickfind(laTemple) || peace::on || (hrand(I2000) < 100 && items[itStatue] >= U5)))
if(c->land == laRlyeh && can_start_horo(c) && (quickfind(laTemple) || (hrand(I2000) < 100 && landUnlockedIngame(laTemple))))
create_altmap(c, horo_gen_distance(), hsA);
if(c->land == laJungle && can_start_horo(c) && (quickfind(laMountain) || (hrand(I2000) < 100 && landUnlocked(laMountain))))
if(c->land == laJungle && can_start_horo(c) && (quickfind(laMountain) || (hrand(I2000) < 100 && landUnlockedIngame(laMountain))))
create_altmap(c, horo_gen_distance(), hsA);
if(c->land == laOvergrown && can_start_horo(c) && (quickfind(laClearing) || (hrand(I2000) < 25 && items[itMutant] >= U5 && isLandIngame(laClearing)))) {
if(c->land == laOvergrown && can_start_horo(c) && (quickfind(laClearing) || (hrand(I2000) < 25 && landUnlockedIngame(laClearing)))) {
heptagon *h = create_altmap(c, horo_gen_distance(), hsA);
if(h) clearing::bpdata[h].root = NULL;
}
@ -1894,11 +1912,12 @@ EX void build_horocycles(cell *c, cell *from) {
if(c->land == laOcean && deepOcean && !generatingEquidistant && !peace::on && can_start_horo(c) &&
(quickfind(laWhirlpool) || (
hrand(2000) < (PURE ? 500 : 1000))))
hrand(2000) < (PURE ? 500 : 1000) && landUnlockedIngame(laWhirlpool))))
create_altmap(c, horo_gen_distance(), hsA);
#if CAP_COMPLEX2
if(c->land == laOcean && deepOcean && !generatingEquidistant && hrand(10000) < 20 && no_barriers_in_radius(c, 2) && hyperbolic && !quotient && !tactic::on && !safety && !ls::hv_structure())
if(c->land == laOcean && deepOcean && !generatingEquidistant && hrand(10000) < 20 && no_barriers_in_radius(c, 2) && hyperbolic && !quotient && !tactic::on && !safety && !ls::hv_structure()
&& landUnlockedIngame(laBrownian))
brownian::init_further(c);
#endif
@ -1919,7 +1938,7 @@ EX void build_horocycles(cell *c, cell *from) {
if(c->land == laPalace && can_start_horo(c) && !princess::generating && !shmup::on && multi::players == 1 && !weirdhyperbolic &&
(princess::forceMouse ? canReachPlayer(from, moMouse) :
(hrand(2000) < (peace::on ? 100 : 20))) &&
(princess::challenge || kills[moVizier] || peace::on)) {
landUnlockedIngame(laPrincessQuest)) {
create_altmap(c, PRADIUS0, hsOrigin, waPalace);
celllister cl(c, 5, 1000000, NULL);
for(cell *c: cl.lst) if(c->master->alt) currentmap->extend_altmap(c->master);
@ -2318,7 +2337,7 @@ EX void pregen() {
currentlands.clear();
if(ls::any_chaos() && !ls::std_chaos())
for(eLand l: land_over)
if(landUnlocked(l) && isLandIngame(l))
if(landUnlockedIngame(l))
currentlands.push_back(l);
}

View File

@ -136,7 +136,7 @@ EX namespace bt {
h->emeraldval = gmod((parent->emeraldval - d1) * 7508, 15015);
break;
case gTernary:
if(d < 2)
if(d <= 2)
h->emeraldval = gmod(parent->emeraldval * 3 + d, 10010);
else
h->emeraldval = gmod((parent->emeraldval - d1) * 3337, 10010);
@ -854,14 +854,35 @@ auto bt_config = arg::add2("-btwidth", [] {arg::shift_arg_formula(vid.binary_wid
#endif
EX bool pseudohept(cell *c) {
if(WDIM == 2)
return c->type & c->master->distance & 1;
else if(geometry == gHoroRec)
return c->c.spin(S7-1) == 0 && (c->master->distance & 1) && c->cmove(S7-1)->c.spin(S7-1) == 0;
else if(geometry == gHoroTris)
return c->c.spin(S7-1) == 0 && (c->master->distance & 1);
else
return (c->master->zebraval == 1) && (c->master->distance & 1);
switch(geometry) {
case gBinary4:
c->cmove(3);
return (c->master->distance & 1) && (c->c.spin(3) == 0);
case gBinaryTiling:
return c->master->distance & c->type & 1;
case gTernary: {
return c->master->emeraldval & 1;
/* auto m = dynamic_cast<hrmap_binary*> (current_map());
auto o = m->origin;
int flips = 0;
while(m != o) {
if(m->master->distance >= o->master->distance) { if(m->c.spin(4) == 1) flips++; m = m->cmove(4); }
}
heptagon *origin;
c->cmove(4); return (c->c.spin(4) == 1); */
}
case gHoroRec:
return c->c.spin(S7-1) == 0 && (c->master->distance & 1) && c->cmove(S7-1)->c.spin(S7-1) == 0;
case gHoroTris:
return c->c.spin(S7-1) == 0 && (c->master->distance & 1);
default:
return (c->master->zebraval == 1) && (c->master->distance & 1);
}
}
EX pair<gp::loc, gp::loc> gpvalue(heptagon *h) {

View File

@ -94,6 +94,14 @@ void eclectic_red(color_t& col) {
constexpr ld spinspeed = .75 / M_PI;
EX color_t apply_mine_knowledge(color_t wcol, cell* c) {
if(mine::marked_safe(c))
return gradient(wcol, 0x40FF40, 0, 0.2, 1);
if(mine::marked_mine(c))
return gradient(wcol, 0xFF4040, -1, vid.ispeed ? sintick(100) : 1, 1);
return wcol;
}
void celldrawer::setcolors() {
wcol = fcol = winf[c->wall].color;
@ -541,10 +549,7 @@ void celldrawer::setcolors() {
case waMineUnknown: case waMineMine:
#if CAP_COMPLEX2
if(mine::marked_safe(c))
fcol = wcol = gradient(wcol, 0x40FF40, 0, 0.2, 1);
else if(mine::marked_mine(c))
fcol = wcol = gradient(wcol, 0xFF4040, -1, vid.ispeed ? sintick(100) : 1, 1);
if(!mine_markers) fcol = wcol = apply_mine_knowledge(wcol, c);
goto fallthrough;
#endif
@ -847,13 +852,6 @@ void celldrawer::draw_grid() {
int prec = grid_prec();
if(vid.grid && c->bardir != NODIR && c->bardir != NOBARRIERS && c->land != laHauntedWall &&
c->barleft != NOWALLSEP_USED && GDIM == 2 && geometry == gNormal && (PURE || BITRUNCATED)) {
color_t col = darkena(0x505050, 0, 0xFF);
gridline(V, C0, tC0(cgi.heptmove[c->bardir]), col, prec+1);
gridline(V, C0, tC0(cgi.hexmove[c->bardir]), col, prec+1);
}
if(inmirrorcount) return;
if(vid.grid || (c->land == laAsteroids && !(WDIM == 2 && GDIM == 3))) ; else return;
@ -1386,6 +1384,39 @@ bool celldrawer::set_randompattern_floor() {
}
EX bool numerical_minefield;
EX int mine_zero_display = 1;
EX bool mine_hollow;
EX bool mine_markers;
EX void draw_mine_numbers(int mines, const shiftmatrix& V, int ct6) {
auto hollow = [&] (hpcshape& sh, color_t col) {
if(mine_hollow) {
dynamicval<color_t> dc(poly_outline, col);
queuepoly(V, sh, 0);
}
else
queuepoly(V, sh, col);
};
if(mines == 0 && mine_zero_display < (WDIM == 3 ? 1 : 2)) return;
if(numerical_minefield) {
string label = its(mines);
queuestr(V, (mines >= 10 ? .5 : 1) * mapfontscale / 100, label, darkened(minecolors[mines]), 8);
}
else {
if(mines >= isize(minecolors)) hollow(cgi.shBigMineMark[ct6], darkena(minecolors[mines/isize(minecolors)], 0, 0xFF));
hollow(cgi.shMineMark[ct6], darkena(minecolors[mines], 0, 0xFF));
}
}
EX void draw_mine_markers(cell *c, const shiftmatrix& V) {
if(mine_markers && !mine::marked_safe(c)) {
color_t col = 0xFF4040;
if(mine::marked_mine(c))
col = gradient(winf[waMineMine].color, col, -1, vid.ispeed ? sintick(100) : 1, 1);
dynamicval<color_t> dc(poly_outline, (col << 8) | 0xFF);
queuepoly(V, cgi.shJoint, 0);
}
}
void celldrawer::draw_features() {
char xch = winf[c->wall].glyph;
@ -1631,18 +1662,12 @@ void celldrawer::draw_features() {
case waMineOpen: {
int mines = countMinesAround(c);
if(numerical_minefield) {
if(mines) {
string label = its(mines);
queuestr(V, (mines >= 10 ? .5 : 1) * mapfontscale / 100, label, darkened(minecolors[mines]), 8);
}
}
else {
if(mines >= isize(minecolors))
queuepoly(V, cgi.shBigMineMark[ct6], darkena(minecolors[mines/isize(minecolors)], 0, 0xFF));
if(mines)
queuepoly(V, cgi.shMineMark[ct6], darkena(minecolors[mines], 0, 0xFF));
}
draw_mine_numbers(mines, V, ct6);
break;
}
case waMineUnknown: case waMineMine: {
draw_mine_markers(c, V);
break;
}
@ -1772,6 +1797,9 @@ void celldrawer::draw_features_and_walls_3d() {
if(anyshiftclick) return;
}
if(among(c->wall, waMineUnknown, waMineMine))
draw_mine_markers(c, face_the_player(V));
if(isWall3(c, wcol)) {
if(!no_wall_rendering) {
if(c->wall == waChasm && c->land == laMemory && !in_perspective()) {
@ -1848,6 +1876,12 @@ void celldrawer::draw_features_and_walls_3d() {
queuepoly(V, cgi.shPlainWall3D[ofs + a], darkena(wcol2 - d * get_darkval(c, a), 0, 0xFF));
}
}
if(WDIM == 3 && c->wall == waRose) {
color_t col = winf[waRose].color;
color_t col2 = (col << 8) | 0xFF;
if(rosephase == 7) col2 = 0xFFFFFFFF;
addradar(V, winf[waRose].glyph, col, col2);
}
} }
else {
if(!no_wall_rendering) for(int a=0; a<c->type; a++) if(c->move(a)) {
@ -1875,9 +1909,7 @@ void celldrawer::draw_features_and_walls_3d() {
}
else {
int mines = countMinesAround(c);
if(mines >= isize(minecolors))
queuepoly(face_the_player(V), cgi.shBigMineMark[0], darkena(minecolors[mines/isize(minecolors)], 0, 0xFF));
queuepoly(face_the_player(V), cgi.shMineMark[0], darkena(minecolors[mines], 0, 0xFF));
draw_mine_numbers(mines, face_the_player(V), 0);
}
}
@ -2848,7 +2880,7 @@ void celldrawer::draw() {
if(callhandlers(false, hooks_drawcell, c, V)) return;
if(history::on || inHighQual || WDIM == 3 || shmup::on || sightrange_bonus > gamerange_bonus || !playermoved) checkTide(c);
checkTide(c);
if(1) {

View File

@ -5181,3 +5181,71 @@ Bug fixes:
* Fixed troll nests in Horodisk/Voronoi.
* Fixed a crash when running away from Clearing in single-land mode.
* Some values are tracked in savefiles while previously they did not (fatigue, snake oil, crossbow reload time, gun ammo, etc.) (Thanks to jlm)
2024-03-24 20:10 Update 13.0e:
* in Steam, option `-achievement-always` to always display achievements, even if you already got them.
* rosebushes now show up on the radar in 3D geometries, and they now blink if they are close to going off
* if you are in water (and have no Fish), you can now see Orbs of Fish and Aether in adjacent water tiles, and also you can move there and pick them up
* crossbow bolt now ignore rose restrictions on attack
* migrating to SDL2 caused crashes in shmup, with the game_keys_scroll option, and with the shift-target option -- this should be fixed
* 'custom' land list mode is now mentioned in the watermark (bottom left of the screen)
2024-03-27 23:47 Update 13.0f:
* new messages on Orb of Phasing, Slaying, and Weakness
* more accurate messages on dice pushing
* when loading save, load full mode data including custom lands
* irregular maps no longer change on every load due to floating point precision
* [custom lands list] Space Rock monsters now drop treasure only if in Space Rock land
* ineligible starting land also if land is not in game
* [custom lands list] do not freeze if no new sealand is available
* in countHyperstones, two variants of Mirror are counted once
* specially generated lands (horocycles, Brown Islands) now respect Unlocked and LandIngame rules
* fixed some more crashes related to SDL2 (e.g., right-click in shmup)
2024-04-09 02:46 Update 13.0g:
- New land structures: CR2-like, CR3-like, and "cursed"
- Space Rocks and Halloween stuff are now saved correctly (thanks to jlm)
- since the Aether users now see adjacent items in water, they can also pick them up
- fixed the bug where moving a boat with Compass would cause items to be picked up
- pushing an exploding barrel on a mine now causes an explosion
- fixed pressing numpad keys with numpad on acting both as moves and quick-keys
- a new pseudoheptagon pattern in standard binary and ternary tiling
- fixed the Free Fall being not inaccessible from some lands
- auto-pause shmup game when it loses focus
- fixed some possible crashes: with keys being generated on ivy, when using Orb of Space on Orb of Safety, Ocean in the chaos modes, after killing 400 mutants, when generating YASC message
2024-05-09 10:45 Update 13.0h
- Orb of Summoning now works on deep water, shallow water, and Camelot moat tiles
- more settings for minefield graphics
- removed Haunted and Elemental from the landscape mode
- stone gargoyles and statues are now non-blocking for missiles
- Orb of Earth now cancels Invisibility only if it is doing something
- new line pattern 'wall highlight', and also line patterns are now easier to reach (via creative mode)
- fixed the Yendor beacon to appear in the correct place (usually on the boundary, not the closest visible tile)
Minor bug fixes:
- some leaderboards still activated when custom_land_list was used
- fixed CR3 generated in CR2 layout
- fixed CR2 generated in CR3/CR4 layouts
- fixed single wrong tile of the first land when safetying in landscape etc
- fixed 534 distance computation
- fixed CLI -picload
- clear boats from removed Orbs of Water
- fixed a crash setting landscape_div to 0
- fixed a crash with irregular spherical maps
- show weapon watermark with geometric xbow (thanks to @jlm)
2024-05-10 19:36 Update 13.0i
- reverted numlock fix on MAC since it apparently does not work as expected
- right shift no longer assumes mouse-strafe if no mouse moved
- fixed the "display zeros in minefield" option
- fixed crashes when adding/deleting colors
- rosewaves no longer go through the fake cells in Crystal World
- changed the guarding in Power landscape
- display Compass and Orb of Yendor beacon on radar
- fixed some problems with tides (thanks to jlm)

View File

@ -181,9 +181,7 @@ EX bool monstersnear(cell *c, eMonster who) {
}
// consider normal monsters
if(c2 &&
isArmedEnemy(c2, who) &&
(c2->monst != moLancer || isUnarmed(who) || !logical_adjacent(c, who, c2))) {
if(c2 && isArmedEnemy(c2, who)) {
eMonster m = c2->monst;
if(elec::affected(c2)) continue;
if(fast && c2->monst != moWitchSpeed) continue;
@ -390,7 +388,7 @@ EX void create_yasc_message() {
if(captures.size() == 2 && context.size() == 1 && cwt.at->type == 6) {
vector<int> dirs;
forCellIdEx(c1, i, cwt.at) for(auto cap: captures) if(cap.first == c1) dirs.push_back(i);
if(abs(dirs[0]-dirs[1]) == 3) {
if(isize(dirs) == 2 && abs(dirs[0]-dirs[1]) == 3) {
auto c1 = captures.begin(); c1++;
yasc_message = XLAT("pinched by %the1 and %the2", captures.begin()->second, c1->second);
}

View File

@ -648,7 +648,7 @@ struct info {
if(newdist == OUT_OF_PRISON && princess::challenge) {
addMessage(XLAT("Congratulations! Your score is %1.", its(i->value)));
achievement_gain_once("PRINCESS2", rg::princess);
if(!cheater) achievement_score(36, i->value);
if(!cheater) achievement_score(LB_PRINCESS, i->value);
LATE( showMissionScreen(); )
}
}

View File

@ -354,6 +354,8 @@ vector<string> knight_names = {
"JeLomun", "kip", "Warmonger", "Fooruman", "Zyalin", "Prezombie", "ashley89", "bjobae", "MFErtre", "Roaringdragon2", "howilovepi", "Yulgash", "Sir Endipitous", "Roshlev",
"BTernaryTau", "HiGuy", "coper", "Tirear", "qoala _", "Tyzone", "Tiegon", "Airin", "Metroid26", "Sklorg", "Fumblestealth", "Toph", "Tzaphqiel", "jruderman", "ray",
"Deathroll", "Sinquetica", "mootmoot", "Noobinator", "freeofme", "Helyea", "Snakebird Priestess", "brisingre", "Khashishi", "Shiny", "kabado", "Berenthas", "Misery", "Altripp", "Aldrenean",
// via itch.io and reports on Discord
"AntiRogue"
};
map<cell*, int> knight_id;

View File

@ -1050,8 +1050,8 @@ EX void initConfig() {
param_f(linepatterns::tree_starter, "tree_starter")
-> editable(0, 1, 0.05, "tree-drawing parameter", "How much of edges to draw for tree patterns (to show how the tree edges are oriented).", 't');
param_char(patterns::whichCanvas, "whichCanvas", 0);
param_i(patterns::rwalls, "randomwalls");
// param_char(patterns::whichCanvas, "whichCanvas", 0); %TODO
param_i(ccolor::rwalls, "randomwalls");
param_b(vid.grid, "grid");
param_b(models::desitter_projections, "desitter_projections", false);
@ -1173,6 +1173,8 @@ EX void initConfig() {
param_i(min_cells_drawn, "min_cells_drawn");
param_b(show_turns, "show_turns", false)
-> editable("show turn count", 'T');
param_i(menu_darkening, "menu_darkening", 2)
-> editable(0, 8, 1, "menu map darkening", "A larger number means darker game map in the background. Set to 8 to disable the background.", 'd')
-> set_sets([] { dialog::bound_low(0); dialog::bound_up(8); dialog::get_di().dialogflags |= sm::DARKEN; });
@ -1347,7 +1349,7 @@ EX void initConfig() {
->set_extra(draw_crosshair);
param_b(mapeditor::drawplayer, "drawplayer");
param_color((color_t&) patterns::canvasback, "color:canvasback", false);
param_color((color_t&) ccolor::plain.ctab[0], "color:canvasback", false);
param_color(backcolor, "color:background", false);
param_color(forecolor, "color:foreground", false);
@ -1359,8 +1361,8 @@ EX void initConfig() {
param_color(stdgridcolor, "color:stdgrid", true);
param_f(vid.multiplier_grid, "mgrid", "mult:grid", 1);
param_color(dialog::dialogcolor, "color:dialog", false);
for(auto& p: colortables)
savecolortable(p.second, s0+"canvas"+p.first);
for(auto p: ccolor::all)
savecolortable(p->ctab, s0+"canvas:"+p->name);
savecolortable(distcolors, "distance");
savecolortable(minecolors, "mines");
#if CAP_COMPLEX2
@ -2443,6 +2445,7 @@ EX void configureInterface() {
};
});
add_edit(show_turns);
add_edit(menu_darkening);
add_edit(centered_menus);
add_edit(startanims::enabled);
@ -3121,7 +3124,15 @@ EX int config3 = addHook(hooks_configfile, 100, [] {
param_b(vid.fixed_yz, "fixed YZ", true);
param_b(frustum_culling, "frustum_culling");
param_b(numerical_minefield, "numerical_minefield")
->editable("display mine counts numerically", 'n');
-> editable("toggle numerical display", 'n');
param_b(mine_hollow, "mine_hollow")
-> editable("hollow mine symbols", 'h');
param_b(mine_markers, "mine_markers")
-> editable("markers on possible mines", 'm');
param_i(mine_opacity, "minefield opacity", 255)
->editable(0, 255, 51, "opacity of undiscovered minefield", "3D modes only\n\n0 = invisible, 255 = fully opaque", 'o');
param_enum(mine_zero_display, "minefield_zero", "minefield_zero", 1)
->editable({{"OFF", "never display zeros"}, {"3D", "only in 3D modes"}, {"ON", "always display zeros"}}, "display zeros in minefield", 'z');
param_b(dont_display_minecount, "dont_display_minecount");
#if MAXMDIM >= 4
param_enum(draw_sky, "draw_sky", "draw_sky", skyAutomatic)
@ -3337,6 +3348,12 @@ EX int config3 = addHook(hooks_configfile, 100, [] {
"land size in landscape structure",
"Each cell gets three coordinates, each of which change smoothly, using the same method as used for the generation of landscapes e.g. in Dragon Chasms. "
"Then, we find a cell of the bitruncated cubic honeycomb at these cordinates, and this cell determines which land it is. The bigger the value, the larger the lands.", 'R')
->set_sets([] { dialog::bound_low(1); })
->set_reaction([] { if(game_active) { stop_game(); start_game(); } });
param_i(curse_percentage, "curse_percentage")->editable(0, 100, 1,
"curse percentage",
"The percentage of towers in Cursed Walls mode to be manned by Canyon Hags", 'R')
->set_reaction([] { if(game_active) { stop_game(); start_game(); } });
param_f(global_boundary_ratio, "global_boundary_ratio")
@ -3450,7 +3467,7 @@ EX void refresh_canvas() {
int at = 0;
while(at < isize(cl.lst)) {
cell *c2 = cl.lst[at];
c2->landparam = patterns::generateCanvas(c2);
c2->landparam = ccolor::generateCanvas(c2);
at++;
forCellEx(c3, c2) cl.add(c3);
@ -3472,8 +3489,8 @@ EX void edit_color_table(colortable& ct, const reaction_t& r IS(reaction_t()), b
ct[i] ^= 0x1000000;
if(!(ct[i] & 0x1000000)) return;
}
dialog::openColorDialog(ct[i]);
dialog::get_di().reaction = r;
dialog::openColorDialog(ct[i]);
if(r) dialog::get_di().reaction = r;
dialog::colorAlpha = false;
dialog::get_di().dialogflags |= sm::SIDE;
});
@ -3482,14 +3499,14 @@ EX void edit_color_table(colortable& ct, const reaction_t& r IS(reaction_t()), b
dialog::addItem("add a color", 'A');
dialog::add_action([&ct, r] {
ct.push_back(rand() & 0x1FFFFFF);
r();
if(r) r();
});
if(isize(ct) > 2) {
dialog::addItem("delete a color", 'D');
dialog::add_action([&ct, r] {
ct.pop_back();
r();
if(r) r();
});
}
@ -3541,13 +3558,13 @@ EX void show_color_dialog() {
dialog::add_action([] () { dialog::openColorDialog(dialog::dialogcolor); dialog::colorAlpha = false; dialog::get_di().dialogflags |= sm::SIDE; });
dialog::addBreak(50);
if(specialland == laCanvas && colortables.count(patterns::whichCanvas)) {
if(specialland == laCanvas && ccolor::which->ctab.size()) {
dialog::addItem(XLAT("pattern colors"), 'P');
dialog::add_action_push([] { edit_color_table(colortables[patterns::whichCanvas], refresh_canvas, true); });
dialog::add_action_push([] { edit_color_table(ccolor::which->ctab, refresh_canvas, true); });
if(patterns::whichCanvas == 'R') {
if(ccolor::which == &ccolor::shape_mirror) {
dialog::addItem(XLAT("unreversed colors"), 'U');
dialog::add_action_push([] { edit_color_table(colortables['A'], refresh_canvas, true); });
dialog::add_action_push([] { edit_color_table(ccolor::shape.ctab, refresh_canvas, true); });
}
}
@ -3964,7 +3981,7 @@ EX int read_color_args() {
PHASEFROM(2); shift(); modelcolor = argcolor(32);
}
else if(argis("-apeirocolor")) {
PHASEFROM(2); shift(); patterns::apeirogonal_color = argcolor(32);
PHASEFROM(2); shift(); ccolor::apeirogonal_color = argcolor(32);
}
else if(argis("-ring")) {
PHASEFROM(2); shift(); ringcolor = argcolor(32);

View File

@ -973,7 +973,7 @@ WALL( '+', 0xFF0000, "giant rug", waGiantRug, ZERO | WF_ON, RESERVED, 0, sgNone,
"This is the biggest Hypersian Rug you have ever seen! "
"Unfortunately, it is too large to take it as a trophy." )
WALL( '#', 0xfffff0, "platform", waPlatform, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, "You can stand here.")
WALL( '#', 0x909090, "stone gargoyle", waGargoyle, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, gargdesc)
WALL( '#', 0x909090, "stone gargoyle", waGargoyle, WF_WALL | WF_HIGHWALL | WF_NONBLOCK, RESERVED, 0, sgNone, gargdesc)
WALL( '.', 0xB0B0B0, "stone gargoyle floor", waGargoyleFloor, ZERO | WF_ON, RESERVED, 1, sgNone, gargdesc)
WALL( '.', 0x909090, "rubble", waRubble, ZERO | WF_ON, RESERVED, 1, sgNone, "Some rubble.")
WALL( '+', 0x804000, "ladder", waLadder, ZERO | WF_ON, RESERVED, 0, sgNone,
@ -1018,7 +1018,7 @@ WALL( '+', 0x60C060, "canopy", waCanopy, ZERO, RESERVED, 0, sgNone,
)
WALL( '#', 0xD0C060, "barrow wall", waBarrowWall, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, "This wall is quite strong. You will need another way in.")
WALL( '#', 0x90A060, "barrow", waBarrowDig, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, "Your Orb of the Sword can be used to dig here.")
WALL( '#', 0xE0E0E0, "stone statue", waPetrified, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, "A petrified creature.")
WALL( '#', 0xE0E0E0, "stone statue", waPetrified, WF_WALL | WF_HIGHWALL | WF_NONBLOCK, RESERVED, 0, sgNone, "A petrified creature.")
WALL( '.', 0xE8E8E8, "tower of Camelot", waTower, ZERO, RESERVED, 3, sgNone, camelothelp)
WALL( '-', 0x402000, "big bush", waBigBush, ZERO | WF_NOFLIGHT | WF_ON, RESERVED, 0, sgNone,
"You can hold this bush to climb the Lost Mountain. "
@ -1298,7 +1298,7 @@ LAND( 0xE08020, "Canvas", laCanvas, ZERO | LF_TECHNICAL, itNone, RESERVED, "A fa
LAND( 0x00C000, "Palace Quest", laPrincessQuest, ZERO, itSavedPrincess, RESERVED, princessdesc) // fake
NATIVE(isNative(laPalace, m))
REQ(ACCONLY(laPalace) KILL(moVizier, laPalace))
REQ(ACCONLY(laPalace) INMODE(princess::challenge) KILL(moVizier, laPalace))
LAND( 0xD0D060, "Wild West", laWildWest, ZERO, itBounty, RESERVED, wildwestdesc)
NATIVE((m == moOutlaw) ? 2 : 0)
@ -1797,4 +1797,5 @@ MONSTER( '*', 0, "vertex", moRogueviz, ZERO | CF_TECHNICAL, RESERVED, moN
#undef ACCONLY2
#undef ACCONLY3
#undef ACCONLYF
#undef IFINGAME
#undef IFINGAME
#undef INMODE

View File

@ -376,6 +376,7 @@ EX void full_ystrafe_camera(ld t) {
EX ld third_person_rotation = 0;
EX void full_rotate_camera(int dir, ld val) {
if(!val) return;
if(rug::rug_control() && lshiftclick) {
val *= camera_rot_speed;
hyperpoint h;
@ -524,7 +525,7 @@ EX void handleKeyNormal(int sym, int uni) {
if(!(uni >= 'A' && uni <= 'Z') && DEFAULTCONTROL && !game_keys_scroll) {
for(int i=0; i<8; i++)
if(among(sym, keys_vi[i], keys_wasd[i], keys_numpad[i]))
if(among(sym, keys_vi[i], keys_wasd[i], (uni >= '0' && uni <= '9' && !ISMAC) ? -1 : keys_numpad[i]))
movepckeydir(i);
}
@ -872,7 +873,7 @@ EX void mainloopiter() {
targetclick = pandora_leftclick | pandora_rightclick;
pandora_leftclick = pandora_rightclick = 0;
#else
targetclick = keystate[SDLK_RSHIFT] | keystate[SDLK_LSHIFT];
targetclick = keystate[SDL12(SDLK_RSHIFT, SDL_SCANCODE_RSHIFT)] | keystate[SDL12(SDLK_LSHIFT, SDL_SCANCODE_LSHIFT)];
#endif
}
else {
@ -957,7 +958,7 @@ EX void mainloopiter() {
}
else sc_ticks = ticks;
if(game_keys_scroll && !shmup::on && (cmode & sm::NORMAL) && !keystate[SDLK_LALT] && !keystate[SDLK_RALT]) {
if(game_keys_scroll && !shmup::on && (cmode & sm::NORMAL) && !keystate[SDL12(SDLK_LALT, SDL_SCANCODE_LALT)] && !keystate[SDL12(SDLK_RALT, SDL_SCANCODE_RALT)]) {
rug::using_rugview urv;
auto& lastticks = sc_ticks2;
ld t = (ticks - lastticks) * shiftmul / 1000.;

View File

@ -28,6 +28,7 @@ EX namespace bow {
#if HDR
enum eWeapon { wBlade, wCrossbow };
enum eCrossbowStyle { cbBull, cbGeodesic, cbGeometric };
const string bowName[] = { "bull", "geod", "geom" };
#endif
EX eWeapon weapon;

View File

@ -660,6 +660,9 @@ int read_cheat_args() {
PHASEFROM(2);
shift(); vid.stereo_mode = eStereo(argi());
}
else if(argis("-save-cheats")) {
save_cheats = true;
}
else if(argis("-cmove")) {
PHASE(3); shift();
for(char c: args()) cheat_move(c);

View File

@ -368,7 +368,7 @@ EX void bfs() {
c2->wall = waSea;
if(c2 && signed(c2->cpdist) > d+1) {
if(WDIM == 3 && !gmatrix.count(c2)) {
if(WDIM == 3 && (d > 2 && !gmatrix.count(c2))) {
if(!first7) first7 = qb;
continue;
}

View File

@ -9,7 +9,7 @@
#include <string>
namespace hr {
string scorefile = "fakemobile_score.txt";
std::string scorefile = "fakemobile_score.txt";
}
#include <SDL/SDL.h>

View File

@ -75,6 +75,7 @@ EX namespace fake {
}
hrmap_fake() {
underlying_map = nullptr;
in_underlying([this] { initcells(); underlying_map = currentmap; });
for(hrmap*& m: allmaps) if(m == underlying_map) m = NULL;
}

View File

@ -347,6 +347,8 @@ EX void pushThumper(const movei& mi) {
if(w == waThumperOn)
explode = 2;
}
if(w == waExplosiveBarrel && cto->wall == waMineMine)
explode = 2;
destroyTrapsOn(cto);
if(cto->wall == waOpenPlate || cto->wall == waClosePlate) {
toggleGates(cto, cto->wall);

View File

@ -1113,7 +1113,7 @@ EX void showEuclideanMenu() {
}
dialog::addBoolItem(XLAT("pattern"), specialland == laCanvas, 'p');
if(specialland == laCanvas) dialog::lastItem().value = patterns::whichCanvas;
if(specialland == laCanvas) dialog::lastItem().value = ccolor::which->name;
dialog::add_action_push(patterns::showPrePattern);
validity_info();
if(WDIM == 3) {

View File

@ -1269,6 +1269,7 @@ EX namespace gp {
}
hrmap_inverse() {
underlying_map = nullptr;
if(0) {
println(hlog, "making ucgi");
dynamicval<eVariation> gva(variation, variation_for(param));

View File

@ -878,6 +878,7 @@ EX bool mark_compass(cell *c, shiftpoint& P1) {
// queuestr(V, 1, its(compassDist(c)), 0x10101 * int(128 - 100 * sin(ticks / 150.)), 1);
queue_goal_text(P1, 1, its(-compassDist(c)), 0x10101 * int(128 - 100 * sintick(150)));
addauraspecial(P1, 0xFF0000, 0);
addradar(P, 'X', iinf[itCompass].color, 0xFF, true);
}
return true;
}
@ -4028,12 +4029,16 @@ EX int colorhash(color_t i) {
return (i * 0x471211 + i*i*0x124159 + i*i*i*0x982165) & 0xFFFFFF;
}
EX int mine_opacity = 255;
EX bool isWall3(cell *c, color_t& wcol) {
if(c->wall == waRose) { wcol = gradient(0, wcol, -5 - 5 * (7-rosephase), sintick(50 * (8 - rosephase)), 1); }
if(isWall(c)) return true;
if(c->wall == waChasm && c->land == laMemory && (anyshiftclick || !(cgflags & qFRACTAL))) { wcol = 0x606000; return true; }
if(c->wall == waInvisibleFloor) return false;
// if(chasmgraph(c)) return true;
if(among(c->wall, waMirror, waCloud, waMineUnknown, waMineMine)) return true;
if(among(c->wall, waMirror, waCloud)) return true;
if(among(c->wall, waMineUnknown, waMineMine) && mine_opacity == 255) return true;
return false;
}
@ -4076,6 +4081,8 @@ EX color_t transcolor(cell *c, cell *c2, color_t wcol) {
}
if(among(c->wall, waRubble, waDeadfloor2) && !snakelevel(c2)) return darkena3(winf[c->wall].color, 0, 0x40);
if(c->wall == waMagma && c2->wall != waMagma) return darkena3(magma_color(lavatide(c, -1)/4), 0, 0x80);
if(among(c->wall, waMineUnknown, waMineMine) && !among(c2->wall, waMineMine, waMineUnknown) && mine_opacity > 0 && mine_opacity < 255)
return 0xFFFFFF00 | mine_opacity;
return 0;
}
@ -4793,13 +4800,13 @@ EX void drawMarkers() {
using namespace yendor;
if(yii < isize(yi) && !yi[yii].found) {
cell *keycell = NULL;
int i;
for(i=0; i<YDIST; i++)
int last_i = 0;
for(int i=0; i<YDIST; i++)
if(yi[yii].path[i]->cpdist <= get_sightrange_ambush()) {
keycell = yi[yii].path[i];
keycell = yi[yii].path[i]; last_i = i;
}
if(keycell) {
for(; i<YDIST; i++) {
for(int i = last_i+1; i<YDIST; i++) {
cell *c = yi[yii].path[i];
if(inscreenrange(c))
keycell = c;
@ -4812,12 +4819,12 @@ EX void drawMarkers() {
int cd2 = celldistance(cwt.at, yi[yii].path[i2]);
if(cd2 != DISTANCE_UNKNOWN) {
cd = cd2 + (YDIST-1-i2);
println(hlog, "i2 = ", i2, " cd = ", celldistance(cwt.at, keycell));
}
}
queue_goal_text(H, 1, its(cd), 0x10101 * int(128 - 100 * sintick(150)));
#endif
addauraspecial(H, iinf[itOrbYendor].color, 0);
addradar(ggmatrix(keycell), 'X', iinf[itKey].color, kind_outline(itKey), true);
}
}
}
@ -5665,6 +5672,7 @@ EX bool just_refreshing;
EX int menu_darkening = 2;
EX bool centered_menus = false;
EX bool show_turns = false;
EX void gamescreen() {
@ -5791,13 +5799,15 @@ EX void normalscreen() {
cmode = sm::NORMAL | sm::DOTOUR | sm::CENTER;
if(viewdists && show_distance_lists) cmode |= sm::SIDE | sm::MAYDARK;
gamescreen(); drawStats();
if(nomenukey || ISMOBILE)
if(show_turns)
displayButton(vid.xres-8, vid.yres-vid.fsize, "t:" + its(turncount), 'v', 16);
else if(nomenukey || ISMOBILE)
;
#if CAP_TOUR
else if(tour::on)
displayButton(vid.xres-8, vid.yres-vid.fsize, XLAT("(ESC) tour menu"), SDLK_ESCAPE, 16);
else
#endif
else
displayButton(vid.xres-8, vid.yres-vid.fsize, XLAT("(v) menu"), 'v', 16);
keyhandler = handleKeyNormal;

View File

@ -236,12 +236,12 @@ EX void buildCredits() {
help += XLAT(
"special thanks to the following people for their bug reports, feature requests, porting, and other help:\n\n%1\n\n",
"Konstantin Stupnik, ortoslon, chrysn, Adam Borowski, Damyan Ivanov, Ryan Farnsley, mcobit, Darren Grey, tricosahedron, Maciej Chojecki, Marek Čtrnáct, "
"wonderfullizardofoz, Piotr Migdał, tehora, Michael Heerdegen, Sprite Guard, zelda0x181e, Vipul, snowyowl0, Patashu, phenomist, Alan Malloy, Tom Fryers, Sinquetica, _monad, CtrlAltDestroy, jruderman, "
"wonderfullizardofoz, Piotr Migdał, Tehora Rogue, Michael Heerdegen, Sprite Guard, zelda0x181e, Vipul, snowyowl0, Patashu, phenomist, Alan Malloy, Tom Fryers, Sinquetica, _monad, CtrlAltDestroy, jruderman, "
"Kojiguchi Kazuki, baconcow, Alan, SurelyYouJest, hotdogPi, DivisionByZero, xXxWeedGokuxXx, jpystynen, Dmitry Marakasov, Alexandre Moine, Arthur O'Dwyer, "
"Triple_Agent_AAA, bluetailedgnat, Allalinor, Shitford, KittyTac, Christopher King, KosGD, TravelDemon, Bubbles, rdococ, frozenlake, MagmaMcFry, "
"Snakebird Priestess, roaringdragon2, Stopping Dog, bengineer8, Sir Light IJIJ, ShadeBlade, Saplou, shnourok, Ralith, madasa, 6% remaining, Chimera245, Remik Pi, alien foxcat thing, "
"Piotr Grochowski, Ann, still-flow, tyzone, Paradoxica, LottieRatWorld, aismallard, albatross, EncodedSpirit, Jacob Mandelson, CrashTuvai, cvoight, jennlbw, Kali Ranya, spiritbackup, Dylan, L_Lord, AntiRogue, "
"masonlgreen, A human"
"masonlgreen, A human, Pasu4"
);
#ifdef EXTRALICENSE
help += EXTRALICENSE;
@ -553,6 +553,20 @@ EX string generateHelpForItem(eItem it) {
return help;
}
void mine_dialog() {
cmode = sm::SIDE;
gamescreen();
dialog::init("Minefield graphics");
add_edit(numerical_minefield);
add_edit(mine_zero_display);
add_edit(mine_opacity);
add_edit(mine_hollow);
add_edit(mine_markers);
dialog::addItem(XLAT("minefield colors"), 'c');
dialog::add_action_push([] { edit_color_table(minecolors); });
dialog::display();
}
void addMinefieldExplanation(string& s) {
s += XLAT(
@ -568,7 +582,7 @@ void addMinefieldExplanation(string& s) {
s += XLAT("Known mines may be marked by touching while in drag mode. Your allies won't step on marked mines.");
#endif
help_extensions.push_back(help_extension{'n', XLAT("toggle numerical display"), [] () { numerical_minefield = !numerical_minefield; }});
help_extensions.push_back(help_extension{'c', XLAT("configure"), [] () { pushScreen(mine_dialog); } });
}
EX string generateHelpForWall(eWall w) {
@ -700,6 +714,7 @@ void add_reqs(eLand l, string& s) {
#define COND(x,y) s += (y);
#define ITEMS_TOTAL(list, z) \
{ int now = 0; string t = "("; for(eItem i: list) { if(t!="(") t += " | "; t += XLATN(iinf[i].name); now += items[i]; } t += ")"; s += XLAT("Treasure required: %1 x %2.\n", its(z), t); buteol(s, now, z); }
#define INMODE(x) ;
#define ACCONLY(z) s += XLAT("Accessible only from %the1.\n", z);
#define ACCONLY2(z,x) s += XLAT("Accessible only from %the1 or %the2.\n", z, x);
#define ACCONLY3(z,y,x) s += XLAT("Accessible only from %the1, %2, or %3.\n", z, y, x);
@ -882,7 +897,6 @@ EX void describeMouseover() {
if(shmup::on)
out += " (" + its(c->landparam)+")";
else {
calcTidalPhase();
bool b = c->landparam >= tide[turncount % tidalsize];
int t = 1;
for(; t < 1000 && b == (c->landparam >= tide[(turncount+t) % tidalsize]); t++) ;

View File

@ -705,12 +705,12 @@ EX void drawStats() {
if(peace::on) vers += " peace";
if(racing::on) vers += " racing";
if(daily::on) vers += " strange";
if(bow::weapon && bow::style == bow::cbBull) vers += " b/bull";
if(bow::weapon && bow::style == bow::cbGeodesic) vers += " b/geo";
if(bow::crossbow_mode()) vers += " b/" + bow::bowName[bow::style];
if(land_structure != default_land_structure())
vers += land_structure_name(true);
vers += " " + land_structure_name(true);
if(princess::challenge) vers += " Princess";
if(randomPatternsMode) vers += " RPM";
if(use_custom_land_list) vers += " custom";
if(geometry != gNormal || !BITRUNCATED)
vers = vers + " " + full_geometry_name();

View File

@ -132,9 +132,7 @@
#include "rogueviz/rogueviz-all.cpp"
#endif
#if CAP_DAILY
#include "private/daily.cpp"
#else
#if !CAP_DAILY
namespace hr { namespace daily { bool on; int historical; } }
#endif

14
hyper.h
View File

@ -13,8 +13,8 @@
#define _HYPER_H_
// version numbers
#define VER "13.0d"
#define VERNUM_HEX 0xAA04
#define VER "13.0i"
#define VERNUM_HEX 0xAA09
#include "sysconfig.h"
@ -221,15 +221,6 @@ void addMessage(string s, char spamtype = 0);
#define NUMWITCH 7
// achievements
#define LB_YENDOR_CHALLENGE 40
#define LB_PURE_TACTICS 41
#define NUMLEADER 90
#define LB_PURE_TACTICS_SHMUP 49
#define LB_PURE_TACTICS_COOP 50
#define LB_RACING 81
#if ISMOBILE || ISWEB || ISPANDORA || 1
typedef double ld;
#define LDF "%lf"
@ -780,6 +771,7 @@ enum orbAction { roMouse, roKeyboard, roCheck, roMouseForce, roMultiCheck, roMul
#define pmodel (pconf.model)
static constexpr int DISTANCE_UNKNOWN = 127;
static constexpr int DISTANCE_UNKNOWN_BIG = 99999999;
template<class T, class U> int addHook(hookset<T>& m, int prio, U&& hook) {
return m.add(prio, static_cast<U&&>(hook));

View File

@ -1467,7 +1467,10 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
case mdSpiral: {
cld z;
if(hyperbolic || sphere) makeband(H_orig, ret, band_conformal);
if(hyperbolic || sphere) {
makeband(H_orig, ret, band_conformal);
models::scr_to_ori(ret);
}
else ret = H;
z = cld(ret[0], ret[1]) * models::spiral_multiplier;
@ -1492,6 +1495,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
if(pconf.skiprope)
ret = mobius(ret, pconf.skiprope, 1);
}
models::ori_to_scr(ret);
break;
}
@ -3019,6 +3023,7 @@ EX void draw_boundary(int w) {
hyperpoint ret = point2(real(z), imag(z));
ret = mobius(ret, pconf.skiprope, 1);
ret *= current_display->radius;
models::ori_to_scr(ret);
curvepoint(ret);
}
queuecurve(shiftless(Id), ringcolor, 0, p).flags |= POLY_ALWAYS_IN;

View File

@ -402,10 +402,7 @@ bool step(int delta) {
if(notfound) { status[4] = XLAT("cells badly paired: %1", its(notfound)); runlevel = 0; break; }
int heptas = 0;
for(auto p: cells_of_heptagon) {
printf("%p: %d\n", hr::voidp(p.first), isize(p.second));
heptas++;
}
for(auto p: cells_of_heptagon) heptas++;
if(heptas != isize(all)) {
status[4] = XLAT("cells not covered: %1", its(isize(all) - heptas));
@ -807,6 +804,8 @@ bool save_map(const string& fname) {
return true;
}
vector<ld> float_order;
EX void save_map_bin(hstream& f) {
if(!base) { f.write<short>(-1); return; }
auto& all = base->allcells();
@ -817,6 +816,19 @@ EX void save_map_bin(hstream& f) {
f.write<short> (base_geometry);
f.write<short> (isize(all));
f.write<short> (origcells);
int foi = 0;
auto check_float_order = [&] (ld x) {
if(foi >= isize(float_order)) {
float_order.push_back(x);
f.write<ld>(x);
}
else if(abs(float_order[foi] - x) > 1e-6) {
println(hlog, float_order[foi], " vs ", x, " : abs difference is ", abs(float_order[foi] - x));
float_order[foi] = x;
}
f.write<ld>(float_order[foi++]);
};
for(auto h: all) {
origcells = 0;
@ -826,9 +838,9 @@ EX void save_map_bin(hstream& f) {
f.write<short> (origcells);
for(auto i: cells_of_heptagon[h->master]) if(cells[i].generation == 0) {
auto &ci = cells[i];
f.write<ld>(ci.p[0]);
f.write<ld>(ci.p[1]);
f.write<ld>(ci.p[LDIM]);
check_float_order(ci.p[0]);
check_float_order(ci.p[1]);
check_float_order(ci.p[LDIM]);
}
}
}
@ -877,6 +889,7 @@ EX void load_map_bin(hstream& f) {
density = cellcount * 1. / isize(all);
cells.clear();
float_order.clear();
for(auto h: all) {
int q = f.get<short>();
@ -889,6 +902,9 @@ EX void load_map_bin(hstream& f) {
a = f.get<ld>();
b = f.get<ld>();
c = f.get<ld>();
float_order.push_back(a);
float_order.push_back(b);
float_order.push_back(c);
s.p = hpxyz(a, b, c);
s.p = normalize(s.p);
for(auto c0: all) s.relmatrices[c0] = calc_relative_matrix(c0, h, s.p);

View File

@ -16,8 +16,13 @@ EX array<int, ittypes> items;
EX map<modecode_t, array<int, ittypes> > hiitems;
EX bool pickable_from_water(eItem it) {
return among(it, itOrbFish, itOrbAether);
}
EX bool cannotPickupItem(cell *c, bool telekinesis) {
return itemHidden(c) && !telekinesis && !(isWatery(c) && markOrb(itOrbFish));
if(pickable_from_water(c->item) && isWatery(c)) return false;
return itemHidden(c) && !telekinesis && !(isWatery(c) && (markOrb(itOrbFish) || markOrb(itOrbAether)));
}
EX bool canPickupItemWithMagnetism(cell *c, cell *from) {
@ -737,7 +742,7 @@ EX void collectMessage(cell *c2, eItem which) {
EX bool itemHiddenFromSight(cell *c) {
return isWatery(c) && !items[itOrbInvis] && !(items[itOrbFish] && playerInWater())
&& !(shmup::on && shmup::boatAt(c));
&& !(shmup::on && shmup::boatAt(c)) && !(c->cpdist <= 1 && playerInWater());
}
}

View File

@ -288,9 +288,20 @@ EX void gen_baby_tortoise(cell *c) {
EX int rebalance_treasure(int x, int y, eLand l) {
int res = ((tactic::on || quotient == 2 || daily::on) ? (y) : inv::on ? min(2*(y),x) : (x));
if(use_custom_land_list) res = (res * custom_land_treasure[l] + 50) / 100;
res *= ls::ls_mul();
return res;
}
EX eItem random_curse() {
return pick(itCurseWeakness, itCurseDraining, itCurseWater, itCurseFatigue, itCurseRepulsion, itCurseGluttony);
}
EX void clear_item(cell *c) {
if(c->item == itOrbWater && c->wall == waStrandedBoat)
c->wall = waNone;
c->item = itNone;
}
EX void giantLandSwitch(cell *c, int d, cell *from) {
bool fargen = d == 9;
switch(c->land) {
@ -547,7 +558,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
// no Plates or Trapdoors in the Princess cell
if(d < 3 && (c->wall == waClosePlate || c->wall == waOpenPlate || c->wall == waTrapdoor))
c->wall = waNone;
if(d > 1) c->item = itNone;
if(d > 1) clear_item(c);
// the Princess herself
if(d == 0) {
c->monst = moPrincess;
@ -754,7 +765,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
}
}
// seal entrances to the Land of Power.
if(d == 7 && ctof(c)) {
if(d == 7 && ctof(c) && land_structure != lsLandscape) {
bool onwall = false;
for(int i=0; i<c->type; i++) if(c->move(i) && c->move(i)->land == laBarrier)
onwall = true;
@ -764,13 +775,16 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
cell *c3 = c2->modmove(c->c.spin(i) + 3);
if(!c3) continue;
if(c3->land != laPower && c3->land != laBarrier)
if(c2->wall != waFire && c2->wall != waGlass) {
if(c2->wall != waEternalFire && c2->wall != waGlass) {
if(isFire(c)) c->monst = moWitchWinter;
else if(c->wall == waGlass) c->monst = moWitchGhost;
else c->monst = moEvilGolem;
}
}
}
if(d == 7 && land_structure == lsLandscape) {
forCellEx(c2, c) if(c2->land != laPower) c->wall = waEternalFire;
}
ONEMPTY {
if(hrand(5000+50*items[itPower]) < 1200) {
eItem powerorbs[6] = {
@ -936,7 +950,13 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
case laTrollheim:
if(fargen) {
if(hrand(50000) < (ls::tame_chaos() ? 1000: ls::any_chaos() ?50:5) && c->wall != waBarrier && celldist(c) >= 7 && !safety && !peace::on) {
int freq =
land_structure == lsVineWalls ? 10000 :
ls::wall_chaos() ? 2500 :
ls::tame_chaos() ? 1000 :
ls::any_chaos() ? 50 :
5;
if(hrand(50000) < freq && c->wall != waBarrier && celldist(c) >= 7 && !safety && !peace::on) {
bool okay = true;
forCellCM(c2, c) forCellCM(c3, c2) forCellCM(c4, c3) forCellCM(c5, c4) {
cell *cx = ls::any_chaos() ? c3 : c5;
@ -1280,7 +1300,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
if(d == 8) {
bool ok = c->landparam == 0;
forCellEx(c2, c) if(c2->landparam) ok = false;
if(ok && hrand(doCross ?450:15000) < 20 + (2 * items[itMutant] + yendor::hardness()) && !safety) {
if(ok && hrand(doCross ?450:15000) < (20 + (2 * items[itMutant] + yendor::hardness())) * ls::ls_mul_big() && !safety) {
if(!peace::on) c->item = itMutant;
c->landparam = items[itMutant] + 5 + hrand(11);
c->wall = waNone;
@ -2065,7 +2085,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
case laHunting:
if(d == 7 && c->land == laHunting && !racing::on && !safety && !reptilecheat) {
if(hrand(1000) < 20) {
if(hrand(1000) < 20 * ls::ls_mul_big()) {
if(openplains(c)) {
if(hrand(2) == 0) {
if(!items[itHunting]) {
@ -2273,11 +2293,11 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
c->monst = moMonkey;
else if(hrand_monster(80000) < 5 + items[itRuby] + yendor::hardness())
c->monst = moEagle;
else if(pseudohept_r(c) && c != currentmap->gamestart() && hrand_monster(4000) < 300 + items[itRuby] && !c->monst) {
else if(pseudohept_r(c) && c != currentmap->gamestart() && hrand_monster(4000) < (300 + items[itRuby]) * ls::ls_mul_big() && !c->monst) {
int hardchance = items[itRuby] + yendor::hardness();
if(hardchance > 25) hardchance = 25;
bool hardivy = hrand(100) < hardchance;
if((cgflags & qFRACTAL) ? buildIvy(c, 0, 2) : hat::in() ? buildIvy(c, 0, 4) : (hardivy ? buildIvy(c, 1, 9) : buildIvy(c, 0, c->type)) && !peace::on)
if(land_structure == lsVineWalls ? buildIvy(c, 0, 2) : (cgflags & qFRACTAL) ? buildIvy(c, 0, 2) : hat::in() ? buildIvy(c, 0, 4) : (hardivy ? buildIvy(c, 1, 9) : buildIvy(c, 0, c->type)) && !peace::on)
c->item = itRuby;
}
}
@ -2396,7 +2416,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
if(hrand(1500) < PT(30 + kills[moHexDemon] + kills[moAltDemon] + kills[moMonk] + kills[moPair] + kills[moCrusher], 100) && notDippingFor(itRuins)) {
c->item = itRuins;
forCellEx(c2, c) if(c2->monst == moMonk)
c->item = itNone;
clear_item(c);
}
if(hrand_monster(7000) < kf && !c->monst) {
c->monst = genRuinMonster(c);
@ -2534,7 +2554,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
if(d == 7) {
c->wall = waNone;
c->item = itNone; c->monst = moNone;
clear_item(c); c->monst = moNone;
if(hrand(100) < 25)
c->wall = hrand(2) ? waBigTree : waSmallTree;
@ -2575,7 +2595,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
treasure_rate += variant::features[i].rate_change;
variant::features[i].build(c);
}
if(hrand(2000 - PT(kills[moVariantWarrior] * 5, 250)) < treasure_rate && !c->wall && !c->monst)
if(hrand(max(100, 2000 - PT(kills[moVariantWarrior] * 5, 250))) < treasure_rate && !c->wall && !c->monst)
c->item = itVarTreasure;
}
if(d == 7 && c->wall == waTrapdoor) {
@ -2646,7 +2666,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
}
case laCursed: {
if(fargen) {
if(fargen && c->wall != waRubble) {
c->wall = waStone;
for(int i=0; i<3; i++) {
auto ew = [i] (cell *c1) {
@ -2682,7 +2702,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
c->wall = waStone;
else {
c->monst = moHexer;
c->item = pick(itCurseWeakness, itCurseDraining, itCurseWater, itCurseFatigue, itCurseRepulsion, itCurseGluttony);
c->item = random_curse();
}
break;
}
@ -2910,7 +2930,7 @@ EX void set_land_for_geometry(cell *c) {
return;
}
if(land_structure == lsLandscape) {
if(landscape_div < 0) landscape_div = 1;
if(landscape_div <= 0) landscape_div = 1;
array<int, 3> a;
for(int i=0; i<3; i++) a[i] = getCdata(c, i);
auto& ld = landscape_div;
@ -3055,7 +3075,7 @@ EX void setdist(cell *c, int d, cell *from) {
}
if(d == BARLEV && c->land == laCanvas) {
color_t col = patterns::generateCanvas(c);
color_t col = ccolor::generateCanvas(c);
c->landparam = col;
c->wall = canvas_default_wall;
if((GDIM == 3 || geom3::flipped) && (col & 0x1000000)) c->wall = waWaxWall;

View File

@ -81,7 +81,7 @@ EX eLand firstland = laIce;
EX eLand specialland = laIce;
#if HDR
enum eLandStructure { lsNiceWalls, lsChaos, lsPatchedChaos, lsTotalChaos, lsChaosRW, lsWallChaos, lsSingle, lsNoWalls, lsHorodisks, lsVoronoi, lsLandscape, lsGUARD };
enum eLandStructure { lsNiceWalls, lsChaos, lsPatchedChaos, lsTotalChaos, lsChaosRW, lsWallChaos, lsSingle, lsNoWalls, lsHorodisks, lsVoronoi, lsLandscape, lsCrossWalls, lsVineWalls, lsCursedWalls, lsGUARD };
#endif
EX eLandStructure land_structure;
@ -90,9 +90,9 @@ EX namespace ls {
EX bool single() { return land_structure == lsSingle; }
EX bool any_chaos() { return among(land_structure, lsChaos, lsPatchedChaos, lsWallChaos, lsTotalChaos, lsChaosRW, lsLandscape); }
EX bool any_chaos() { return among(land_structure, lsChaos, lsPatchedChaos, lsWallChaos, lsTotalChaos, lsChaosRW, lsCrossWalls, lsVineWalls, lsCursedWalls, lsLandscape); }
EX bool std_chaos() { return land_structure == lsChaos; }
EX bool wall_chaos() { return land_structure == lsWallChaos; }
EX bool wall_chaos() { return among(land_structure, lsWallChaos, lsCrossWalls, lsVineWalls, lsCursedWalls); }
EX bool patched_chaos() { return land_structure == lsPatchedChaos; }
EX bool any_order() { return among(land_structure, lsNiceWalls, lsNoWalls, lsHorodisks, lsVoronoi); }
@ -112,11 +112,31 @@ EX int chaoticity() {
if(land_structure == lsChaos) return 40;
if(land_structure == lsLandscape) return 35;
if(land_structure == lsWallChaos) return 30;
if(land_structure == lsCrossWalls) return 32;
if(land_structure == lsCursedWalls) return 34;
if(land_structure == lsVoronoi) return 20;
if(land_structure == lsSingle) return 0;
return 10;
}
/** a multiplier to make stuff more frequent in Wall Chaos and Cross Wall Chaos: treasure */
EX int ls_mul() {
if(land_structure == lsWallChaos) return 2;
if(land_structure == lsCrossWalls) return 3;
if(land_structure == lsVineWalls) return 3;
if(land_structure == lsCursedWalls) return 3;
return 1;
}
/** a multiplier to make stuff more frequent in Wall Chaos and Cross Wall Chaos: even bigger */
EX int ls_mul_big() {
if(land_structure == lsWallChaos) return 5;
if(land_structure == lsCrossWalls) return 10;
if(land_structure == lsVineWalls) return 10;
if(land_structure == lsCursedWalls) return 10;
return 1;
}
EX bool tame_chaos() { return any_chaos() && chaoticity() < 35; }
EX }
@ -144,6 +164,12 @@ EX string land_structure_name(bool which) {
return XLAT("landscape");
case lsNoWalls:
return XLAT("wall-less");
case lsCrossWalls:
return XLAT("excessive crossing walls");
case lsVineWalls:
return XLAT("regular walls");
case lsCursedWalls:
return XLAT("cursed walls");
default:
return "error structure";
}
@ -164,6 +190,12 @@ EX void fix_land_structure_choice() {
land_structure = lsNoWalls;
if(!nice_walls_available() && land_structure == lsWallChaos)
land_structure = lsChaos;
if(!nice_walls_available() && land_structure == lsCrossWalls)
land_structure = lsChaos;
if(land_structure == lsVineWalls && (geometry != gNormal || !BITRUNCATED))
land_structure = lsNiceWalls;
if(land_structure == lsCursedWalls && (geometry != gNormal || !BITRUNCATED))
land_structure = lsNiceWalls;
if(ls::hv_structure() && (!hyperbolic || bt::in() || quotient))
land_structure = lsSingle;
if(walls_not_implemented() && among(land_structure, lsChaos, lsNoWalls))
@ -230,6 +262,7 @@ EX bool landUnlocked(eLand l) {
#define ACCONLY3(x,y,z)
#define ACCONLYF(x)
#define IFINGAME(land, ok, fallback) if(isLandIngame(land)) { ok } else { fallback }
#define INMODE(x) if(x) return true;
#include "content.cpp"
case landtypes: return false;
@ -251,7 +284,10 @@ EX void countHyperstoneQuest(int& i1, int& i2) {
i1 = 0; i2 = 0;
generateLandList(isLandIngame);
for(eLand l: landlist) {
// no treasure
if(l == laCA) continue;
// same treasure, so count only once
if(l == laMirrorOld && isLandIngame(laMirror)) continue;
eItem ttype = treasureType(l);
if(!required_for_hyperstones(ttype)) continue;
i2++; if(items[ttype] >= R10) i1++;
@ -383,7 +419,7 @@ EX eLand pickluck(eLand l1, eLand l2) {
} */
EX eLand getNewSealand(eLand old) {
while(true) {
for(int it=0; it<100; it++) {
eLand p = pick(laOcean, pick(laCaribbean, laLivefjord, laWarpSea, laKraken, laDocks));
if(p == laKraken && !landUnlocked(p)) continue;
if(p == laKraken && peace::on) continue;
@ -392,6 +428,7 @@ EX eLand getNewSealand(eLand old) {
if(!isLandIngame(p)) continue;
return p;
}
return old;
}
EX bool createOnSea(eLand old) {
@ -638,15 +675,24 @@ EX eLand getNewLand(eLand old) {
if(ls::horodisk_structure() && tortoise::seek()) LIKELY tab[cnt++] = laTortoise;
int attempts = 0;
eLand n = old;
while(incompatible(n, old) || !isLandIngame(n)) {
n = tab[hrand(cnt)];
if(weirdhyperbolic && specialland == laCrossroads4 && isCrossroads(n))
n = laCrossroads4;
attempts++; if(attempts == 2000) break;
int idx = 0;
while (idx < cnt) {
eLand n = tab[idx];
if (incompatible(n, old) || !isLandIngame(n))
tab[idx] = tab[--cnt];
else
idx++;
}
if (!cnt) {
addMessage("No eligible land candidates!");
return old;
}
eLand n = tab[hrand(cnt)];
if (weirdhyperbolic && specialland == laCrossroads4 && isCrossroads(n))
n = laCrossroads4;
return n;
}
@ -741,6 +787,11 @@ EX bool isLandIngame(eLand l) {
return land_validity(l).flags & lv::appears_in_full;
}
EX bool landUnlockedIngame(eLand l) {
if(!peace::on && !landUnlocked(l)) return false;
return isLandIngame(l);
}
namespace lv {
flagtype q0 = lv::display_error_message | lv::display_in_help | lv::appears_in_geom_exp;
@ -766,6 +817,7 @@ namespace lv {
land_validity_t out_of_theme = { 3, qm2 &~ lv::appears_in_full, "Out of theme for the full game."};
land_validity_t no_game = { 2, q2 &~ lv::appears_in_full, "No game here."};
land_validity_t not_in_chaos = { 0, q0, "Does not work in chaos mode."};
land_validity_t not_in_landscape = { 0, q0, "Does not work in landscape mode."};
land_validity_t not_in_full_game = {2, qm2 &~ lv::appears_in_full, "Not in the full game."};
land_validity_t not_in_full_game3 = {3, qm2 &~ lv::appears_in_full, "Not in the full game."};
land_validity_t special_chaos = { 2, qm2, "Special construction in the Chaos mode." };
@ -1142,7 +1194,7 @@ EX land_validity_t& land_validity(eLand l) {
if(l == laWhirlwind && hyperbolic_not37)
return pattern_incompatibility;
bool better_mirror = !geometry && STDVAR && !ls::hv_structure() && !among(land_structure, lsTotalChaos, lsPatchedChaos, lsLandscape);
bool better_mirror = !geometry && STDVAR && !ls::hv_structure() && !among(land_structure, lsTotalChaos, lsPatchedChaos, lsLandscape, lsVineWalls);
// available only in non-standard geometries
if(l == laMirrorOld && better_mirror)
@ -1163,6 +1215,9 @@ EX land_validity_t& land_validity(eLand l) {
if(l == laHaunted && ls::std_chaos())
return not_in_chaos;
if(among(l, laHaunted, laElementalWall) && land_structure == lsLandscape)
return not_in_landscape;
// standard, non-PTM specific
if(l == laCrossroads5 && old_daily_id < 999 && tactic::on)
return not_in_ptm;

View File

@ -213,7 +213,7 @@ template<class T> struct walker {
int spin;
/** \brief are we mirrored */
bool mirrored;
walker<T> (T *at = NULL, int s = 0, bool m = false) : at(at), spin(s), mirrored(m) { if(at) s = at->c.fix(s); }
walker(T *at = NULL, int s = 0, bool m = false) : at(at), spin(s), mirrored(m) { if(at) s = at->c.fix(s); }
/** \brief spin by i to the left (or right, when mirrored */
walker<T>& operator += (int i) {
spin = at->c.fix(spin+(mirrored?-i:i));

View File

@ -746,14 +746,16 @@ EX namespace mapstream {
f.write(gen_wandering);
f.write(reptilecheat);
f.write(timerghost);
f.write(patterns::canvasback);
f.write(ccolor::plain.ctab[0]);
f.write(patterns::whichShape);
f.write(patterns::subpattern_flags);
f.write(patterns::whichCanvas);
char wc = '*';
f.write(wc);
f.write(ccolor::which->name);
f.write(patterns::displaycodes);
f.write(canvas_default_wall);
f.write(mapeditor::drawplayer);
if(patterns::whichCanvas == 'f') f.write(patterns::color_formula);
if(ccolor::which == &ccolor::formula) f.write(ccolor::color_formula);
f.write(canvasfloor);
f.write(canvasdark);
@ -946,15 +948,21 @@ EX namespace mapstream {
f.read(gen_wandering);
f.read(reptilecheat);
f.read(timerghost);
f.read(patterns::canvasback);
f.read(ccolor::plain.ctab[0]);
f.read(patterns::whichShape);
f.read(patterns::subpattern_flags);
f.read(patterns::whichCanvas);
char wc;
f.read(wc);
if(wc == '*') {
string name;
f.read(name);
for(auto& p: ccolor::all) if(p->name == name) ccolor::which = p;
}
f.read(patterns::displaycodes);
if(f.vernum >= 0xA816)
f.read(canvas_default_wall);
f.read(mapeditor::drawplayer);
if(patterns::whichCanvas == 'f') f.read(patterns::color_formula);
if(wc == 'f') f.read(ccolor::color_formula);
if(f.vernum >= 0xA90D) {
f.read(canvasfloor);
f.read(canvasdark);
@ -2594,16 +2602,16 @@ EX namespace mapeditor {
bool onelayeronly;
bool loadPicFile(const string& s) {
fhstream f(picfile, "rt");
fhstream f(s, "rt");
if(!f.f) {
addMessage(XLAT("Failed to load pictures from %1", picfile));
addMessage(XLAT("Failed to load pictures from %1", s));
return false;
}
scanline(f);
scan(f, f.vernum);
printf("vernum = %x\n", f.vernum);
if(f.vernum == 0) {
addMessage(XLAT("Failed to load pictures from %1", picfile));
addMessage(XLAT("Failed to load pictures from %1", s));
return false;
}
@ -2631,6 +2639,7 @@ EX namespace mapeditor {
}
initShape(i, j);
println(hlog, "shape ", tie(i, j), " layer ", l);
usershapelayer& ds(usershapes[i][j]->d[l]);
if(f.vernum >= 0xA608) scan(f, ds.zlevel);
ds.shift = readHyperpoint(f);
@ -2744,8 +2753,7 @@ EX namespace mapeditor {
stop_game();
enable_canvas();
canvas_default_wall = waInvisibleFloor;
patterns::whichCanvas = 'g';
patterns::canvasback = 0xFFFFFF;
ccolor::set_plain(0xFFFFFF);
dtcolor = (forecolor << 8) | 255;
drawplayer = false;
vid.use_smart_range = 2;

View File

@ -575,6 +575,7 @@ EX bool destroyHalfvine(cell *c, eWall newwall IS(waNone), int tval IS(6)) {
}
EX int coastvalEdge(cell *c) { return coastval(c, laIvoryTower); }
EX int coastvalWest(cell *c) { return coastval(c, laWestWall); }
EX int gravityLevel(cell *c) {
if(c->land == laIvoryTower && ls::hv_structure())
@ -601,10 +602,10 @@ EX int gravityLevelDiff(cell *c, cell *d) {
if(shmup::on) return 0;
int nid = neighborId(c, d);
int id1 = parent_id(c, 1, coastvalEdge) + 1;
int id1 = parent_id(c, 1, coastvalWest) + 1;
int di1 = angledist(c->type, id1, nid);
int id2 = parent_id(c, -1, coastvalEdge) - 1;
int id2 = parent_id(c, -1, coastvalWest) - 1;
int di2 = angledist(c->type, id2, nid);
if(di1 < di2) return 1;
@ -708,8 +709,8 @@ EX void checkTide(cell *c) {
if(!c2) continue;
if(c2->land == laBarrier || c2->land == laOceanWall) ;
else if(c2->land == laOcean)
seadist = min(seadist, c2->SEADIST ? c2->SEADIST+1 : 7),
landdist = min(landdist, c2->LANDDIST ? c2->LANDDIST+1 : 7);
seadist = min(seadist, c2->SEADIST >= 1 ? c2->SEADIST+1 : 7),
landdist = min(landdist, c2->LANDDIST >= 1 ? c2->LANDDIST+1 : 7);
else if(isSealand(c2->land)) seadist = 1;
else landdist = 1;
}
@ -745,18 +746,27 @@ EX void checkTide(cell *c) {
#endif
}
EX bool makeEmpty(cell *c) {
EX bool makeNoMonster(cell *c) {
changes.ccell(c);
if(isAnyIvy(c->monst)) killMonster(c, moPlayer, 0);
else if(c->monst == moPair) {
changes.ccell(c->move(c->mondir));
if(c->move(c->mondir)->monst == moPair)
c->move(c->mondir)->monst = moNone;
}
else if(isWorm(c->monst)) {
if(!items[itOrbDomination]) return false;
}
else if(isMultitile(c->monst)) {
return false;
}
else c->monst = moNone;
return true;
}
EX bool makeEmpty(cell *c) {
if(c->monst != moPrincess) {
if(isAnyIvy(c->monst)) killMonster(c, moPlayer, 0);
else if(c->monst == moPair) {
if(c->move(c->mondir)->monst == moPair)
c->move(c->mondir)->monst = moNone;
}
else if(isWorm(c->monst)) {
if(!items[itOrbDomination]) return false;
}
else c->monst = moNone;
if(!makeNoMonster(c)) return false;
}
if(c->land == laCanvas) ;

View File

@ -374,6 +374,9 @@ EX void showCreative() {
}
#endif
dialog::addItem(XLAT("line patterns"), 'l');
dialog::add_action_push(linepatterns::showMenu);
// dialog::addBoolItem(XLAT("expansion"), viewdists, 'x');
dialog::addBreak(50);
@ -466,6 +469,8 @@ EX void show_chaos() {
add_edit(randomwalk_size);
else if(land_structure == lsLandscape)
add_edit(landscape_div);
else if(land_structure == lsCursedWalls)
add_edit(curse_percentage);
else
dialog::addBreak(100);
dialog::addBack();
@ -780,7 +785,7 @@ EX void showChangeMode() {
#endif
dialog::addBoolItem(XLAT("%1 Challenge", moPrincess), (princess::challenge), 'P');
dialog::add_action_confirmed([] {
if(!princess::everSaved)
if(!princess::everSaved && !autocheat)
addMessage(XLAT("Save %the1 first to unlock this challenge!", moPrincess));
else restart_game(rg::princess);
});
@ -1007,7 +1012,7 @@ EX void showStartMenu() {
stop_game();
enable_canvas();
cheater = true;
patterns::canvasback = 0xFFFFFF;
ccolor::set_plain(0xFFFFFF);
mapeditor::drawplayer = false;
start_game();
clearMessages();

View File

@ -11,13 +11,14 @@ namespace hr {
EX namespace multi {
#if HDR
static constexpr int SCANCODES = 512;
static constexpr int MAXJOY = 8;
static constexpr int MAXBUTTON = 64;
static constexpr int MAXAXE = 16;
static constexpr int MAXHAT = 4;
struct config {
char keyaction[512];
char keyaction[SCANCODES];
char joyaction[MAXJOY][MAXBUTTON];
char axeaction[MAXJOY][MAXAXE];
char hataction[MAXJOY][MAXHAT][4];
@ -171,7 +172,7 @@ int* dzconfigs[24];
string listkeys(config& scfg, int id) {
#if CAP_SDL
string lk = "";
for(int i=0; i<512; i++)
for(int i=0; i<SCANCODES; i++)
if(scfg.keyaction[i] == id)
#if CAP_SDL2
lk = lk + " " + SDL_GetScancodeName(SDL_Scancode(i));
@ -265,7 +266,8 @@ struct key_configurer {
if(!setwhat) dialog::handleNavigation(sym, uni);
if(sym) {
if(setwhat) {
which_config->keyaction[sym] = setwhat;
int scan = key_to_scan(sym);
if(scan >= 0 && scan < SCANCODES) which_config->keyaction[scan] = setwhat;
setwhat = 0;
}
else if(uni >= 'a' && uni < 'a' + isize(shmupcmdtable) && shmupcmdtable[uni-'a'][0])
@ -584,9 +586,19 @@ void pressaction(int id) {
actionspressed[id]++;
}
EX int key_to_scan(int sym) {
#if CAP_SDL2
return SDL_GetScancodeFromKey(sym);
#else
return sym;
#endif
}
EX bool notremapped(int sym) {
auto& scfg = scfg_default;
int k = scfg.keyaction[sym];
int sc = key_to_scan(sym);
if(sc < 0 || sc >= SCANCODES) return true;
int k = scfg.keyaction[sc];
if(k == 0) return true;
k /= 16;
if(k > 3) k--; else if(k==3) k = 0;
@ -595,7 +607,7 @@ EX bool notremapped(int sym) {
EX void sconfig_savers(config& scfg, string prefix) {
// unfortunately we cannot use key names here because SDL is not yet initialized
for(int i=0; i<512; i++)
for(int i=0; i<SCANCODES; i++)
addsaver(scfg.keyaction[i], prefix + string("key:")+its(i));
for(int i=0; i<MAXJOY; i++) {
@ -613,7 +625,7 @@ EX void sconfig_savers(config& scfg, string prefix) {
}
EX void clear_config(config& scfg) {
for(int i=0; i<512; i++) scfg.keyaction[i] = 0;
for(int i=0; i<SCANCODES; i++) scfg.keyaction[i] = 0;
}
EX void initConfig() {
@ -821,7 +833,8 @@ EX void handleInput(int delta, config &scfg) {
get_actions(scfg);
const Uint8 *keystate = SDL12_GetKeyState(NULL);
if(keystate[SDLK_LCTRL] || keystate[SDLK_RCTRL]) d /= 5;
if(keystate[SDL12(SDLK_LCTRL, SDL_SCANCODE_LCTRL)] || keystate[SDL12(SDLK_RCTRL, SDL_SCANCODE_RCTRL)]) d /= 5;
double panx =
actionspressed[49] - actionspressed[51] + axespressed[2] / 32000.0;

View File

@ -29,7 +29,7 @@ struct gamedata {
::new (&record[index]) T(std::move(x));
}
else {
T& at = (T&) record[index];
T& at = *((T*) (void*) &(record[index]));
x = std::move(at);
at.~T();
}
@ -78,7 +78,7 @@ void gamedata_all(gamedata& gd) {
gd.store(genrange_bonus);
gd.store(gamerange_bonus);
gd.store(targets);
gd.store(patterns::rwalls);
gd.store(ccolor::rwalls);
if(GOLDBERG) gd.store(gp::param);
callhooks(hooks_gamedata, &gd);
}

View File

@ -1360,6 +1360,7 @@ EX namespace hybrid {
cell* gamestart() override { return getCell(underlying_map->gamestart(), 0); }
hrmap_hybrid() {
underlying_map = nullptr;
twisted = false;
disc_quotient = 0;
in_underlying([this] { initcells(); underlying_map = currentmap; });

View File

@ -664,7 +664,7 @@ EX void teleportTo(cell *dest) {
}
/* calls changes.rollback or changes.commit */
EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMonster dashmon IS(moNone)) {
EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMonster dashmon IS(moNone), cell *phasecell IS(nullptr)) {
if(byWhat != itStrongWind) playSound(dest, "orb-frog");
cell *from = cwt.at;
changes.value_keep(cwt);
@ -683,7 +683,10 @@ EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMons
if(byWhat == itOrbPhasing) {
useupOrb(itOrbPhasing, 5);
addMessage(XLAT("You jump!"));
if(phasecell->monst)
addMessage(XLAT("You phase through %the1!", phasecell->monst));
else
addMessage(XLAT("You phase through %the1!", phasecell->wall));
}
movecost(from, dest, 1);
@ -823,10 +826,11 @@ void telekinesis(cell *dest) {
moveItem(dest, cwt.at, true);
eItem it = cwt.at->item;
bool saf = it == itOrbSafety;
collectItem(cwt.at, cwt.at, true);
if(cwt.at->item == it)
animateMovement(match(dest, cwt.at), LAYER_BOAT);
else
else if(!saf)
animate_item_throw(dest, cwt.at, it);
useupOrb(itOrbSpace, cost.first);
@ -880,6 +884,10 @@ EX eMonster summonedAt(cell *dest) {
dest->land == laWarpCoast ? moRatling :
dest->land == laDocks ? moWaterElemental :
moPirate;
if(among(dest->wall, waDeepWater, waShallow))
return moRusalka;
if(dest->wall == waCamelotMoat)
return moWaterElemental;
if(isReptile(dest->wall))
return moReptile;
if(dest->wall == waChasm)
@ -1523,7 +1531,7 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
}
if(phasestate == 3) {
if(jumpTo(a, c, itOrbPhasing)) phasestate = 4;
if(jumpTo(a, c, itOrbPhasing, 0, moNone, jumpthru)) phasestate = 4;
else wouldkill_there = true;
}
else changes.rollback();

View File

@ -169,6 +169,7 @@ EX bool passable(cell *w, cell *from, flagtype flags) {
if(airdist(w) < 3) return false;
if(againstWind(w,from)) return false;
if(isGravityLand(w)) return false;
if(w->wall == waChasm && w->land == laDual) return false;
}
if(from && strictlyAgainstGravity(w, from, vrevdir, flags)
@ -258,7 +259,8 @@ EX bool passable(cell *w, cell *from, flagtype flags) {
}
if(isWatery(w)) {
if(in_gravity_zone(w)) ;
if((flags & P_ISPLAYER) && from && isWatery(from) && pickable_from_water(w->item)) ;
else if(in_gravity_zone(w)) ;
else if(from && from->wall == waBoat && F(P_USEBOAT) &&
(!againstCurrent(w, from) || F(P_MARKWATER)) && !(from->item == itOrbYendor)) ;
else if(from && isWatery(from) && F(P_CHAIN) && F(P_USEBOAT) && !againstCurrent(w, from)) ;
@ -419,6 +421,8 @@ EX bool canPushStatueOn(cell *c, flagtype flags) {
}
EX void moveBoat(const movei& mi) {
changes.ccell(mi.t);
changes.ccell(mi.s);
eWall x = mi.t->wall; mi.t->wall = mi.s->wall; mi.s->wall = x;
mi.t->mondir = mi.rev_dir_or(NODIR);
moveItem(mi.s, mi.t, false);

File diff suppressed because it is too large Load Diff

View File

@ -214,6 +214,7 @@ struct pcmove {
bool fmsMove, fmsAttack, fmsActivate;
int d;
int subdir;
/** used to tell perform_actual_move() that this is a boat move and thus we should not pick up items */
bool boatmove;
bool good_tortoise;
flagtype attackflags;
@ -802,6 +803,16 @@ bool pcmove::actual_move() {
c2->monst = moNone;
c2->wall = waRichDie;
}
else {
if(vmsg(miWALL, siWALL, c2, c2->monst))
addMessage(XLAT("You can only push this die if the highest number would be on the top!"));
return false;
}
}
else if(mip.d == NO_SPACE) {
if(vmsg(miWALL, siWALL, c2, c2->monst))
addMessage(XLAT("No room to push %the1.", c2->monst));
return false;
}
}
#endif
@ -834,13 +845,10 @@ bool pcmove::actual_move() {
return boat_move();
if(!c2->monst && cwt.at->wall == waBoat && cwt.at->item != itOrbYendor && boatGoesThrough(c2) && markOrb(itOrbWater) && !nonAdjacentPlayer(c2, cwt.at) && fmsMove) {
if(c2->item && !cwt.at->item) moveItem(c2, cwt.at, false), boatmove = true;
placeWater(c2, cwt.at);
moveBoat(mi);
if(c2->item && collectItem(c2, cwt.at)) return true;
changes.ccell(c2);
c2->mondir = revhint(cwt.at, d);
if(c2->item) boatmove = !boatmove;
placeWater(c2, cwt.at);
moveBoat(mi); boatmove = true;
return perform_actual_move();
}
@ -921,8 +929,6 @@ void pcmove::tell_why_cannot_attack() {
addMessage(XLAT("You cannot attack Raiders directly!"));
else if(isSwitch(c2->monst))
addMessage(XLAT("You cannot attack Jellies in their wall form!"));
else if(c2->monst == moAnimatedDie)
addMessage(XLAT("You can only push this die if the highest number would be on the top!"));
else if(c2->monst == moAngryDie)
addMessage(XLAT("This die is really angry at you!"));
else if((attackflags & AF_WEAK) && isIvy(c2))
@ -1285,21 +1291,15 @@ bool pcmove::perform_actual_move() {
handle_friendly_ivy();
if(items[itOrbDigging]) {
invismove = false;
if(earthMove(mi)) markOrb(itOrbDigging);
if(earthMove(mi)) {
invismove = false;
markOrb(itOrbDigging);
}
}
movecost(cwt.at, c2, 1);
if(!boatmove && collectItem(c2, cwt.at)) return true;
if(boatmove && c2->item && cwt.at->item) {
eItem it = c2->item;
c2->item = cwt.at->item;
if(collectItem(c2, cwt.at)) return true;
eItem it2 = c2->item;
c2->item = it;
cwt.at->item = it2;
}
if(doPickupItemsWithMagnetism(c2)) return true;
if(isIcyLand(cwt.at) && cwt.at->wall == waNone && markOrb(itOrbWinter)) {

View File

@ -50,7 +50,7 @@ string timeline() {
else {
s = XLAT("%1 turns (%2)", its(turncount), getgametime_s());
if(display_yasc_codes)
s+= XLAT(" YASC code: ") + formatted_yasc_code();
s += XLAT(" YASC code: ") + formatted_yasc_code();
}
return s;
}
@ -332,7 +332,7 @@ EX void showGameMenu() {
#if CAP_TOUR
tour::on ? (canmove ? XLAT("guided tour") : XLAT("GAME OVER")) :
#endif
(cheater && !autocheat)? XLAT("It is a shame to cheat!") :
(cheater && !autocheat) ? XLAT("It is a shame to cheat!") :
racing::on ? "racing mode" :
(canmove && princess::challenge) ? XLAT("%1 Challenge", moPrincess) :
canmove ? XLAT("Quest status") :
@ -445,7 +445,7 @@ EX void showGameMenu() {
if(cheater && !autocheat) {
dialog::addInfo(XLAT("you have cheated %1 times", its(cheater)), 0xFF2020);
}
else if(!racing::on) {
if(!racing::on) {
dialog::addInfo(timeline(), dialog::dialogcolor);
}

View File

@ -1039,10 +1039,15 @@ void race_projection() {
if(GDIM == 2) {
dialog::addMatrixItem(XLAT("race angle"), race_angle.get(), 'a');
dialog::add_action([] () {
dialog::editMatrix(race_angle.get(), XLAT("model orientation"), "", GDIM);
dialog::editMatrix(race_angle.get(), XLAT("race angle"), "", GDIM);
auto& d = dialog::get_di();
auto q = rot_inverse(race_angle) * pconf.mori();
auto last = dialog::get_ne().reaction;
dialog::get_ne().reaction = [q, last] () { last(); pconf.mori() = race_angle * q; };
auto last = d.reaction;
d.reaction = [q, last] () {
if(last) last();
pconf.mori() = race_angle * q;
if(racing::on) set_view();
};
});
}

View File

@ -2,7 +2,7 @@
namespace hr {
#if MAXMDIM >= 4
pair<bool, hyperpoint> makeradar(shiftpoint h) {
pair<bool, hyperpoint> makeradar(shiftpoint h, bool distant) {
hyperpoint h1;
@ -23,8 +23,13 @@ pair<bool, hyperpoint> makeradar(shiftpoint h) {
if(WDIM == 3) {
ld d = hdist0(h);
if(d >= vid.radarrange) return {false, h1};
if(d) h1 = h1 * (d / vid.radarrange / hypot_d(3, h1));
if(distant) {
h1 = h1 / hypot_d(3, h1);
}
else {
if(d >= vid.radarrange) return {false, h1};
if(d) h1 = h1 * (d / vid.radarrange / hypot_d(3, h1));
}
}
else {
h1 = cgi.emb->actual_to_base(h1);
@ -45,16 +50,16 @@ pair<bool, hyperpoint> makeradar(shiftpoint h) {
return {true, h1};
}
EX void addradar(const shiftmatrix& V, char ch, color_t col, color_t outline) {
EX void addradar(const shiftmatrix& V, char ch, color_t col, color_t outline, bool distant IS(false)) {
shiftpoint h = V * tile_center();
auto hp = makeradar(h);
auto hp = makeradar(h, distant);
if(hp.first)
current_display->radarpoints.emplace_back(radarpoint{hp.second, ch, col, outline});
}
EX void addradar(const shiftpoint h1, const shiftpoint h2, color_t col) {
auto hp1 = makeradar(h1);
auto hp2 = makeradar(h2);
auto hp1 = makeradar(h1, false);
auto hp2 = makeradar(h2, false);
if(hp1.first && hp2.first)
current_display->radarlines.emplace_back(radarline{hp1.second, hp2.second, col});
}

View File

@ -2585,13 +2585,13 @@ int celldistance_534(cell *c1, cell *c2) {
vector<cell*> s1 = {c1};
vector<cell*> s2 = {c2};
int best = 99999999;
int best = DISTANCE_UNKNOWN_BIG;
int d0 = 0;
auto go_nearer = [&] (vector<cell*>& v, int& d) {
vector<cell*> w;
for(cell *c: v)
forCellEx(c1, c)
for(cell *c: v)
forCellCM(c1, c)
if(celldist(c1) < d)
w.push_back(c1);
sort(w.begin(), w.end());
@ -2601,7 +2601,7 @@ int celldistance_534(cell *c1, cell *c2) {
v = w;
};
while(d0 < best) {
while(d0 < best) {
for(cell *a1: s1) for(cell *a2: s2) {
if(a1 == a2) best = min(best, d0);
else if(isNeighbor(a1, a2)) best = min(best, d0+1);
@ -2612,6 +2612,7 @@ int celldistance_534(cell *c1, cell *c2) {
if(d1 >= d2) go_nearer(s1, d1);
if(d1 < d2) go_nearer(s2, d2);
}
if(best == DISTANCE_UNKNOWN_BIG) best = DISTANCE_UNKNOWN; /* just in case */
return best;
}

View File

@ -643,7 +643,7 @@ bool view_ads_ca() {
flatresult center;
vector<flatresult> hlist;
color_t statecolor;
color_t statecolor = 0;
if(1) {
dynamicval<eGeometry> b(geometry, gRotSpace);
shiftmatrix S = where_matrix[c];
@ -750,7 +750,7 @@ bool view_ads_ca() {
break;
}
}
addaura(shiftless(center.h), statecolor, 0);
addaura(shiftless(center.h), statecolor, 0); // todo statecolor not changed
}
if(acc) {
poly_outline = 0xFF;

View File

@ -46,8 +46,7 @@ void run_sb() {
crystal::set_crystal(6);
set_variation(eVariation::pure);
enable_canvas();
patterns::whichCanvas = 'g';
patterns::canvasback = 0x101010;
ccolor::set_plain(0x101010);
check_cgi();
start_game();

View File

@ -342,7 +342,7 @@ void compute_betweenness(bool verify) {
auto b = betweenness3(c1);
// add_to_set(c1, 1, 0);
auto b4 = betweenness4(c1);
print(hlog, hr::format("B;%10Ld;%10Ld;%20.10Lf;%3d;%-40s", b.first, b.second, b4, vertices[i]->lev, rogueviz::vdata[i].name.c_str()));
print(hlog, hr::format("B;%10lld;%10lld;%20.10f;%3d;%-40s", b.first, b.second, (double) b4, vertices[i]->lev, rogueviz::vdata[i].name.c_str()));
if(verify) {
/*
betweenness_type a = b.first;

View File

@ -86,7 +86,8 @@ int movearound() {
int move_restart() {
indenter_finish im("move_restart");
ld llo = loglik_chosen();
array<array<int, 128>, 2> distances_map = {0};
array<array<int, 128>, 2> distances_map;
for(int a=0; a<2; a++) for(int b=0; b<128; b++) distances_map[a][b] = 0;
int moves = 0;
// int im = 0;
@ -319,7 +320,7 @@ void load_embedded(const string s) {
while(true) {
char who[500], where[500];
who[0] = 0;
fscanf(f, "%s%s", who, where);
if(fscanf(f, "%s%s", who, where) < 0) throw hstream_exception("error loading embedding");
if(who[0] == 0) break;
if(!ids.count(who)) printf("unknown vertex: %s\n", who);
string wh = where;

View File

@ -139,8 +139,7 @@ void cellcoords() {
// needs cellcoords/rvcoords/origcoords
void build_disttable() {
indenter_finish im("build_disttable");
int tab[N];
for(int i=0; i<N; i++) tab[i] = N;
vector<int> tab(N, N);
disttable0.clear();
disttable1.clear();
@ -269,7 +268,7 @@ void writestats() {
ld placement_loglik = loglik_placement();
for(int u=0; u<MAXDIST; u++) if(tally[u]) {
println(hlog, hr::format("* %4d: %8d / %12Ld = %lf %.10" PLDF " %.10" PLDF,
println(hlog, hr::format("* %4d: %8d / %12lld = %lf %.10" PLDF " %.10" PLDF,
u, edgetally[u], tally[u], double(edgetally[u]) / tally[u],
saved_logistic.yes(u), current_logistic.yes(u)));
}
@ -338,8 +337,7 @@ void build_disttable_approx() {
for(int k=0; k<threads; k++)
v.emplace_back([&,k] () {
auto& dt = results[k];
int tab[N];
for(int i=0; i<N; i++) tab[i] = N;
vector<int> tab(N, N);
auto p = k ? nullptr : new progressbar(N/threads, "build_disttable_approx");
for(int i=k; i<N; i+=threads) {
if(p) (*p)++;

View File

@ -53,7 +53,7 @@ void test_paths(int radius) {
add_to_tally(mc2, 1, 0);
// int v = 0;
if(tally[quickdist(mc1, mc2)] != 1) {
printf("[%p] [%p]\n", mc1, mc2);
printf("[%p] [%p]\n", (void*) mc1, (void*) mc2);
printf("quickdist = %d\n", quickdist(mc1, mc2));
for(int i=0; i<MAXDIST; i++) if(tally[i]) printf("in tally = %d\n", i);
mc1->ascell()->item = itDiamond;

View File

@ -35,6 +35,9 @@ struct embset {
string name;
geom3::eSpatialEmbedding se;
ld walls, scale, depth, eye, sun, sky, star;
embset(const string& n, geom3::eSpatialEmbedding se, ld walls, ld scale, ld depth, ld eye, ld sun, ld sky, ld star) :
name(n), se(se), walls(walls), scale(scale), depth(depth), eye(eye), sun(sun), sky(sky), star(star) {}
embset() {}
};
embset current() {
@ -94,30 +97,30 @@ void print(hstream& hs, const embset& e) {
print(hlog, "embset{.name=\"", e.name, "\", .se=eEmbeddingMethod(", int(e.se), "), .walls=", e.walls, ", .scale=", e.scale, ", .depth=", e.depth, ", .eye=", e.eye, ", .sun=", e.sun, ", .sky=", e.sky, ", .star=", e.star, "}");
}
embset edefault = embset{.name="default", .se=geom3::seDefault, .walls=1.2, .scale=0, .depth=0, .eye=1.5, .sun=0.333333, .sky=10, .star=9};
embset edefaulti = embset{.name="default", .se=geom3::seDefault, .walls=-1.2, .scale=0, .depth=0, .eye=-1.5, .sun=0.333333, .sky=10, .star=9};
embset edefault = embset("default", geom3::seDefault, 1.2, 0, 0, 1.5, 0.333333, 10, 9);
embset edefaulti = embset("default", geom3::seDefault, -1.2, 0, 0, 1.5, 0.333333, 10, 9);
// embset eincyl = embset{.name="in cylinder", .se=geom3::seCylinderE, .walls=0.75, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=4, .star=3.6};
embset eincyl = embset{.name="in cylinder E", .se=geom3::seCylinderE, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
embset eoutcyl = embset{.name="out cylinder E", .se=geom3::seCylinderE, .walls=-1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.3, .sky=10, .star=9};
embset eouthoro = embset{.name="out horosphere", .se=geom3::seLowerCurvature, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=8, .star=7.5};
embset einhoro = embset{.name="in horosphere", .se=geom3::seLowerCurvature, .walls=-1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11};
embset einhoro_small = embset{.name="in horosphere (small sky)", .se=geom3::seLowerCurvature, .walls=-1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=18, .star=17};
embset esolv = embset{.name="solv", .se=geom3::seSol, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11};
embset einnih = embset{.name="in NIH", .se=geom3::seNIH, .walls=-1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11};
embset eoutnih = embset{.name="out NIH", .se=geom3::seNIH, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=8, .star=7.5};
embset eclifford = embset{.name="Clifford", .se=geom3::seCliffordTorus, .walls=1.2, .scale=M_PI/10, .depth=-0.0561826, .eye=1.5, .sun=0.25, .sky=2.55, .star=2.3};
embset enil = embset{.name="Nil flat", .se=geom3::seNil, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11};
embset esl2 = embset{.name="SL(2,R) flat", .se=geom3::seSL2, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11};
embset eincylh = embset{.name="in cylinderH", .se=geom3::seCylinderH, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
embset eincylhe = embset{.name="in cylinderHE", .se=geom3::seCylinderHE, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
embset eincylnil = embset{.name="in cylinder Nil", .se=geom3::seCylinderNil, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
embset eincylsl = embset{.name="in cylinder SL(2,R)", .se=geom3::seCylinderSL2, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
embset einhorocyl = embset{.name="in horocylinder", .se=geom3::seCylinderHoro, .walls=-1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=8, .star=7.5};
embset eouthorocyl = embset{.name="out horocylinder", .se=geom3::seCylinderHoro, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=4, .star=3.5};
embset eprodh_flat = embset{.name="hyperbolic product (flat)", .se=geom3::seProductH, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
embset eprodh_concave = embset{.name="hyperbolic product (concave)", .se=geom3::seProductH, .walls=1.2, .scale=M_PI/10, .depth=1, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
embset eprods_flat = embset{.name="spherical product (flat)", .se=geom3::seProductS, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
embset eprods_concave = embset{.name="spherical product (concave)", .se=geom3::seProductS, .walls=1.2, .scale=M_PI/10, .depth=0.8333, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
embset eincyl = embset("in cylinder E", geom3::seCylinderE, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
embset eoutcyl = embset("out cylinder E", geom3::seCylinderE, -1.2, M_PI/10, 0, 1.5, 0.3, 10, 9);
embset eouthoro = embset("out horosphere", geom3::seLowerCurvature, 1.2, 0.1, 0, 1.5, 0.25, 8, 7.5);
embset einhoro = embset("in horosphere", geom3::seLowerCurvature, -1.2, 0.1, 0, 1.5, 0.25, 12, 11);
embset einhoro_small = embset("in horosphere (small sky)", geom3::seLowerCurvature, -1.2, 0.1, 0, 1.5, 0.25, 18, 17);
embset esolv = embset("solv", geom3::seSol, 1.2, 0.1, 0, 1.5, 0.25, 12, 11);
embset einnih = embset("in NIH", geom3::seNIH, -1.2, 0.1, 0, 1.5, 0.25, 12, 11);
embset eoutnih = embset("out NIH", geom3::seNIH, 1.2, 0.1, 0, 1.5, 0.25, 8, 7.5);
embset eclifford = embset("Clifford", geom3::seCliffordTorus, 1.2, M_PI/10, -0.0561826, 1.5, 0.25, 2.55, 2.3);
embset enil = embset("Nil flat", geom3::seNil, 1.2, 0.1, 0, 1.5, 0.25, 12, 11);
embset esl2 = embset("SL(2,R) flat", geom3::seSL2, 1.2, 0.1, 0, 1.5, 0.25, 12, 11);
embset eincylh = embset("in cylinderH", geom3::seCylinderH, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
embset eincylhe = embset("in cylinderHE", geom3::seCylinderHE, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
embset eincylnil = embset("in cylinder Nil", geom3::seCylinderNil, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
embset eincylsl = embset("in cylinder SL(2,R)", geom3::seCylinderSL2, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
embset einhorocyl = embset("in horocylinder", geom3::seCylinderHoro, -1.2, M_PI/10, 0, 1.5, 0.10472, 8, 7.5);
embset eouthorocyl = embset("out horocylinder", geom3::seCylinderHoro, 1.2, M_PI/10, 0, 1.5, 0.10472, 4, 3.5);
embset eprodh_flat = embset("hyperbolic product (flat)", geom3::seProductH, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
embset eprodh_concave = embset("hyperbolic product (concave)", geom3::seProductH, 1.2, M_PI/10, 1, 1.5, 0.10472, 2.6, 2.4);
embset eprods_flat = embset("spherical product (flat)", geom3::seProductS, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
embset eprods_concave = embset("spherical product (concave)", geom3::seProductS, 1.2, M_PI/10, 0.8333, 1.5, 0.10472, 2.6, 2.4);
embset& edok() { return vid.wall_height > 0 ? edefault : edefaulti; }

View File

@ -325,6 +325,8 @@ bool view_labels = true, view_lines = true;
namespace hr {
extern ccolor::data grigorchuk_coloring;
struct hrmap_grigorchuk : hrmap_standard {
heptagon *origin;
@ -411,8 +413,8 @@ struct hrmap_grigorchuk : hrmap_standard {
if(grigorchuk::view_labels) queuestr(V, 0.3, grigorchuk::deform(dec[c->master]), 0xFFFFFF);
if(patterns::whichCanvas == 'G' && c->landparam == 0)
c->landparam = 0x102008 * (1 + ((hrmap_grigorchuk*)currentmap)->dec[c->master]->len);
if(ccolor::which == &grigorchuk_coloring && c->landparam == 0)
c->landparam = grigorchuk_coloring(c);
drawcell(c, V * currentmap->master_relative(c, false));
@ -436,6 +438,10 @@ struct hrmap_grigorchuk : hrmap_standard {
eGeometry gGrigorchuk(eGeometry(-1));
ccolor::data grigorchuk_coloring = ccolor::data("Grigorchuk", [] { return geometry == gGrigorchuk; }, [] (cell *c, ccolor::data& cco) {
return 0x102008 * (1 + ((hrmap_grigorchuk*)currentmap)->dec[c->master]->len);
}, {});
void create_grigorchuk_geometry() {
if(gGrigorchuk != eGeometry(-1)) return;
ginf.push_back(ginf[gNormal]);
@ -449,6 +455,7 @@ void create_grigorchuk_geometry() {
gi.menu_displayed_name = "Grigorchuk group";
gi.shortname = "Grig";
gi.default_variation = eVariation::pure;
ccolor::all.push_back(&grigorchuk_coloring);
}
int readArgsG() {
@ -483,11 +490,6 @@ int readArgsG() {
auto hook = addHook(hooks_args, 100, readArgsG)
+ addHook(hooks_newmap, 100, [] { return geometry == gGrigorchuk ? new hrmap_grigorchuk : nullptr; })
+ addHook(patterns::hooks_generate_canvas, 100, [] (cell* c) {
if(patterns::whichCanvas == 'G' && geometry == gGrigorchuk)
return 0x102008 * (1 + ((hrmap_grigorchuk*)currentmap)->dec[c->master]->len);
return -1;
})
+ addHook(dialog::hooks_display_dialog, 100, [] () {
if(current_screen_cfunction() == showEuclideanMenu && geometry == gGrigorchuk) {
dialog::addBoolItem_action(XLAT("Grigorchuk lines"), grigorchuk::view_lines, 'L');
@ -516,7 +518,7 @@ auto hook = addHook(hooks_args, 100, readArgsG)
if(mode == pmStart) {
grigorchuk::grig_limit = 10000;
gamestack::push();
slide_backup(patterns::whichCanvas, 'G');
slide_backup(ccolor::which, &grigorchuk_coloring);
slide_backup(firstland, laCanvas);
slide_backup(specialland, laCanvas);
set_geometry(gGrigorchuk);

View File

@ -74,8 +74,7 @@ void run_cpick() {
crystal::set_crystal(6);
set_variation(eVariation::pure);
enable_canvas();
patterns::whichCanvas = 'g';
patterns::canvasback = 0;
ccolor::set_plain(0);
check_cgi();
start_game();
current_center = currentmap->gamestart();
@ -208,8 +207,7 @@ void run_sb() {
crystal::set_crystal(6);
set_variation(eVariation::pure);
enable_canvas();
patterns::whichCanvas = 'g';
patterns::canvasback = 0;
ccolor::set_plain(0);
check_cgi();
rv_hook(hooks_drawcell, 100, sokomap);
start_game();
@ -394,7 +392,7 @@ int mycanvas(cell *c) {
}
void enable() {
rv_hook(patterns::hooks_generate_canvas, 100, mycanvas);
rv_hook(ccolor::hooks_generate_canvas, 100, mycanvas);
}
auto explore_structure(int _shapeid) {
@ -407,7 +405,7 @@ auto explore_structure(int _shapeid) {
stop_game();
set_geometry(geometry == gCrystal534 ? gCrystal534 : gCrystal344);
enable_canvas();
patterns::whichCanvas = ' ';
ccolor::which = &ccolor::plain;
shapeid = _shapeid;
enable();
crystal::crystal_period = 4;
@ -444,7 +442,7 @@ void house(int sides, int shape = 10) {
crystal::set_crystal(sides);
set_variation(eVariation::pure);
enable_canvas();
patterns::whichCanvas = ' ';
ccolor::which = &ccolor::plain;
shapeid = shape;
check_cgi();
enable();
@ -466,7 +464,7 @@ tour::slide *gen_high_demo() {
sync(mode, VC);
if(mode == pmStart) {
crystal::set_crystal(6);
patterns::whichCanvas = 'K';
ccolor::which = &ccolor::crystal_colors;
start_game();
}
}
@ -479,7 +477,7 @@ tour::slide *gen_high_demo() {
sync(mode, VC);
if(mode == pmStart) {
crystal::set_crystal(8);
patterns::whichCanvas = 'K';
ccolor::which = &ccolor::crystal_colors;
start_game();
}
}
@ -563,10 +561,7 @@ tour::slide *gen_high_demo() {
sync(mode, NO_VC | PLAYER);
if(mode == pmStart) {
crystal::set_crystal(6);
patterns::whichCanvas = 'c';
colortables['c'][0] = 0x208020;
colortables['c'][1] = 0x105010;
patterns::canvasback = 0x101010;
ccolor::set_colors(ccolor::chessboard, {0x208020, 0x105010});
start_game();
auto & us = vid.cs;
us.charid = 4;

View File

@ -374,10 +374,8 @@ void enable() {
vid.linequality = 4;
enable_canvas();
patterns::whichCanvas = 'F';
colortables['F'][0] = 0x80C080;
colortables['F'][1] = 0x80A080;
ccolor::set_colors(ccolor::football, {0x80C080, 0x80A080});
pconf.scale = .3;
vid.use_smart_range = 2;

View File

@ -246,7 +246,7 @@ vector<cell*> current_list;
void mine_slide(tour::presmode mode, reaction_t set_geom, function<vector<cell*>()> celllister, function<void(cell*)> assigner) {
using namespace tour;
patterns::canvasback = 0;
ccolor::plain.ctab = {0};
setCanvas(mode, '0');
if(mode == pmStart) {
slide_backup(mapeditor::drawplayer, false);
@ -334,7 +334,7 @@ void enable_earth() {
stop_game();
set_geometry(gSphere);
enable_canvas();
patterns::whichCanvas = 'F';
ccolor::which = &ccolor::football;
start_game();
texture::config.configname = "textures/earth.txc";
texture::config.load();
@ -543,8 +543,8 @@ slide sweeper_slides[] = {
stop_game();
set_geometry(g45);
set_variation(eVariation::pure);
tour::slide_backup(colortables['c'][0], 0x104010);
tour::slide_backup(colortables['c'][1], 0x10F010);
tour::slide_backup(ccolor::chessboard.ctab[0], 0x104010);
tour::slide_backup(ccolor::chessboard.ctab[1], 0x10F010);
tour::slide_backup(vid.use_smart_range, 2);
tour::slide_backup(vid.smart_range_detail, 1);
start_game();
@ -562,7 +562,7 @@ slide sweeper_slides[] = {
setCanvas(mode, 'g');
non_game_slide_scroll(mode);
if(mode == pmStart) {
tour::slide_backup(patterns::canvasback, 0x10A010);
tour::slide_backup(ccolor::plain.ctab[0], 0x10A010);
stop_game();
set_geometry(gBinary4);
set_variation(eVariation::pure);
@ -840,7 +840,7 @@ slide sweeper_slides[] = {
setCanvas(mode, 'g');
non_game_slide_scroll(mode);
if(mode == pmStart) {
tour::slide_backup(patterns::canvasback, 0x10A010);
tour::slide_backup(ccolor::plain.ctab[0], 0x10A010);
stop_game();
set_geometry(gBinary4);
set_variation(eVariation::pure);

View File

@ -217,8 +217,7 @@ void create_intra_solv() {
}
void create_intra_120() {
patterns::whichCanvas = 'r';
patterns::rwalls = 0;
ccolor::set_random(0);
if(intra::in) intra::become();
else stop_game();
arcm::current.parse("8,4,6");
@ -261,8 +260,7 @@ void create_intra_120() {
}
void create_intra_1440() {
patterns::whichCanvas = 'r';
patterns::rwalls = 0;
ccolor::set_random(0);
if(intra::in) intra::become();
else stop_game();
set_geometry(gCell8);
@ -330,8 +328,7 @@ vector<reaction_t> portals;
void create_intra_bxe() {
println(hlog, "called create_intra_bxe");
patterns::whichCanvas = 'r';
patterns::rwalls = 100;
ccolor::set_random(100);
if(intra::in) intra::become();
else stop_game();
hybrid::csteps = 0;
@ -404,8 +401,7 @@ void recurse_portal_solv2(int r, cell *cl, cell *cr) {
void create_intra_sol() {
println(hlog, "called create_intra_sol");
patterns::whichCanvas = 'r';
patterns::rwalls = 100;
ccolor::set_random(100);
if(intra::in) intra::become();
else stop_game();
@ -534,6 +530,12 @@ bool vr_keys(int sym, int uni) {
// all generators will add to the current scene
#if CAP_VR
#define IF_VR(x) x
#else
#define IF_VR(x)
#endif
auto hooks =
// generate scene with H3, H2xE, E3, S2xE (8x6), S3 (16-cell) with floors; runs automatically
arg::add3("-intra-floors", create_intra_floors)
@ -574,11 +576,11 @@ auto hooks =
mapstream::loadMap(s);
slide_backup(ray::fixed_map, true);
slide_backup(ray::max_iter_intra, y);
#if CAP_VR
IF_VR(
slide_backup(vrhr::hsm, vrhr::eHeadset::holonomy);
slide_backup(vrhr::eyes, vrhr::eEyes::truesim);
slide_backup(vrhr::cscr, vrhr::eCompScreen::eyes);
#endif
)
starter.clear();
rogueviz::rv_hook(hooks_handleKey, 101, vr_keys);
popScreenAll();
@ -630,5 +632,6 @@ auto hooks =
{loader{"run this visualization", 'r', load("solv-h3-scene.lev", 0.05, 3000)}});
}));
}
#undef IF_VR
#endif
}

View File

@ -144,8 +144,7 @@ void magic(int sides) {
crystal::set_crystal(sides);
set_variation(eVariation::pure);
enable_canvas();
patterns::whichCanvas = 'g';
patterns::canvasback = back;
ccolor::set_plain(back);
check_cgi();
start_game();

View File

@ -559,7 +559,7 @@ void pick_pattern() {
dialog::add_action([] {
chg_pattern([] {
enable_canvas();
patterns::whichCanvas = 'B';
ccolor::which = &ccolor::sides;
});
});
@ -570,7 +570,7 @@ void pick_pattern() {
gp::param.second = 0;
set_variation(eVariation::goldberg);
enable_canvas();
patterns::whichCanvas = 'F';
ccolor::which = &ccolor::football;
});
});
@ -579,7 +579,7 @@ void pick_pattern() {
chg_pattern([] {
set_geometry(gOctagon);
enable_canvas();
patterns::whichCanvas = 'T';
ccolor::which = &ccolor::zebra_stripes;
});
});
@ -612,7 +612,7 @@ void pick_pattern() {
arcm::current.parse("4^5");
set_geometry(gArchimedean);
enable_canvas();
patterns::whichCanvas = 'A';
ccolor::which = &ccolor::shape;
});
});

View File

@ -26,10 +26,10 @@ auto geoslide(eGeometry g, char canvas, int jhole, int jblock) {
tour::slide_backup<ld>(sightranges[gSol], 7);
tour::slide_backup<ld>(sightranges[gSpace435], 7);
vid.texture_step = 4;
tour::slide_backup(patterns::jhole, jhole);
tour::slide_backup(patterns::rwalls, jhole);
tour::slide_backup(patterns::jblock, jblock);
tour::slide_backup(patterns::whichCanvas, canvas);
tour::slide_backup(ccolor::jhole, jhole);
tour::slide_backup(ccolor::rwalls, jhole);
tour::slide_backup(ccolor::jblock, jblock);
tour::slide_backup(ccolor::which, ccolor::legacy(canvas));
tour::slide_backup(vid.linewidth, vid.linewidth / 10);
start_game();
if(jblock < 0) {
@ -45,7 +45,7 @@ auto geoslide(eGeometry g, char canvas, int jhole, int jblock) {
if(in_special && among(mode, pmGeometrySpecial, pmStop)) {
in_special = false;
gamestack::pop();
patterns::whichCanvas = canvas;
ccolor::which = ccolor::legacy(canvas);
vid.grid = false;
fat_edges = false;
sightranges[gSpace435] = 7;
@ -54,7 +54,7 @@ auto geoslide(eGeometry g, char canvas, int jhole, int jblock) {
else if(mode == pmGeometrySpecial && !in_special) {
in_special = true;
gamestack::push();
patterns::whichCanvas = 'g';
ccolor::set_plain(0);
vid.grid = true;
stdgridcolor = 0xFFFF00FF;
fat_edges = true;

View File

@ -114,7 +114,7 @@ void run_snub(int v, int w) {
check_cgi();
cgi.require_basics();
specialland = laCanvas;
patterns::whichCanvas = 'A';
ccolor::which = &ccolor::shape;
// vid.wallmode = 1;
printf("start game\n");
printf("distlimit = %d\n", cgi.base_distlimit);

View File

@ -591,7 +591,7 @@ void enable_earth() {
stop_game();
set_geometry(gSphere);
enable_canvas();
patterns::whichCanvas = 'F';
ccolor::which = &ccolor::football;
start_game();
texture::config.configname = "textures/earth.txc";
texture::config.load();
@ -635,8 +635,8 @@ slide dmv_slides[] = {
set_geometry(gArchimedean); arcm::current.parse("3^6");
set_variation(eVariation::pure);
slide_backup(colortables['F'][0], 0xC0FFC0);
slide_backup(colortables['F'][1], 0x80FF80);
slide_backup(ccolor::football.ctab[0], 0xC0FFC0);
slide_backup(ccolor::football.ctab[1], 0x80FF80);
slide_backup(pconf.alpha, 1);
slide_backup(pconf.scale, 1);
start_game();
@ -708,8 +708,8 @@ slide dmv_slides[] = {
slide_backup(specialland, laCanvas);
set_geometry(gNormal);
set_variation(eVariation::bitruncated);
slide_backup(colortables['F'][0], 0xC0FFC0);
slide_backup(colortables['F'][1], 0x80FF80);
slide_backup(ccolor::football.ctab[0], 0xC0FFC0);
slide_backup(ccolor::football.ctab[1], 0x80FF80);
slide_backup(pconf.alpha, 1);
slide_backup(pconf.scale, 1);
slide_backup(rug::mouse_control_rug, true);
@ -755,7 +755,7 @@ slide dmv_slides[] = {
[] (presmode mode) {
if(mode == pmStart) {
slide_backup(patterns::rwalls, 10);
slide_backup(ccolor::rwalls, 10);
slide_backup(vid.fov, 120);
}

View File

@ -190,6 +190,12 @@ int args() {
return 0;
}
#if CAP_RAY
#define IF_RAY(x) x
#else
#define IF_RAY(x)
#endif
auto hooks =
addHook(hooks_args, 100, args)
+ addHook_rvslides(180, [] (string s, vector<tour::slide>& v) {
@ -214,10 +220,10 @@ auto hooks =
set_geometry(gRotSpace);
slide_backup(rots::underlying_scale, .25);
slide_backup(qmode, m);
#if CAP_RAY
IF_RAY(
slide_backup(ray::max_cells, 32768);
slide_backup(ray::fixed_map, true);
#endif
)
slide_backup(camera_speed, .1);
enable();
start_game();
@ -240,11 +246,11 @@ auto hooks =
set_geometry(gRotSpace);
slide_backup(rots::underlying_scale, .25);
slide_backup(qmode, m);
#if CAP_RAY
IF_RAY(
slide_backup(ray::max_cells, 32768);
slide_backup(ray::fixed_map, true);
slide_backup(ray::want_use, 2);
#endif
)
slide_backup(camera_speed, .1);
enable();
start_game();
@ -256,6 +262,7 @@ auto hooks =
}
});
#undef IF_RAY
}
}

View File

@ -108,7 +108,7 @@ bool labeller(cell* c, const shiftmatrix& V) {
if(m) {
string s = m->asg[c->master].second;
cgi.scalefactor = 1;
queuestr(V, 0.5, s, colortables['j'][c->master->distance+1]);
queuestr(V, 0.5, s, ccolor::jmap.ctab[c->master->distance+1]);
}
return false;
}

View File

@ -179,7 +179,7 @@ namespace rogueviz {
template<class T, class U> function<void(presmode)> roguevizslide(char c, const T& t, const U& f) {
return [c,t,f] (presmode mode) {
f(mode);
patterns::canvasback = 0x101010;
ccolor::plain.ctab = {0x101010};
setCanvas(mode, c);
if(mode == 1 || mode == pmGeometryStart) t();
@ -201,7 +201,7 @@ template<class T> function<void(presmode)> roguevizslide(char c, const T& t) { r
template<class T, class U>
function<void(presmode)> roguevizslide_action(char c, const T& t, const U& act) {
return [c,t,act] (presmode mode) {
patterns::canvasback = 0x101010;
ccolor::plain.ctab = {0x101010};
setCanvas(mode, c);
if(mode == pmStart || mode == pmGeometryStart) t();
@ -342,6 +342,8 @@ namespace objmodels {
virtual void process_triangle(vector<hyperpoint>& hys, vector<hyperpoint>& tot, bool textured, object *co);
bool available();
virtual ~model() {}
};
void add_model_settings();

View File

@ -431,7 +431,7 @@ namespace sag {
if(t2 - tl > 980) {
tl = t2;
println(hlog, hr::format("it %12Ld temp %6.4f [1/e at %13.6f] cost = %f ",
println(hlog, hr::format("it %12lld temp %6.4f [1/e at %13.6f] cost = %f ",
numiter, double(sag::temperature), (double) exp(sag::temperature),
double(sag::cost)));
}
@ -458,7 +458,7 @@ namespace sag {
auto t2 = SDL_GetTicks();
if(t2 - t1 > 1000) {
t1 = t2;
println(hlog, hr::format("it %12Ld temp %6.4f [1/e at %13.6f] cost = %f ",
println(hlog, hr::format("it %12lld temp %6.4f [1/e at %13.6f] cost = %f ",
numiter, double(sag::temperature), (double) exp(sag::temperature),
double(sag::cost)));
}
@ -491,7 +491,7 @@ namespace sag {
if(t < (sag_ittime+1) / 2) ipturn *= 2;
else if(t > sag_ittime * 2) ipturn /= 2;
else ipturn = ipturn * sag_ittime / t;
print(hlog, hr::format("it %12Ld temp %6.4f [2:%8.6f,10:%8.6f,50:%8.6f] cost = %f\n",
print(hlog, hr::format("it %12lld temp %6.4f [2:%8.6f,10:%8.6f,50:%8.6f] cost = %f\n",
numiter, double(sag::temperature),
(double) exp(-2 * exp(-sag::temperature)),
(double) exp(-10 * exp(-sag::temperature)),
@ -734,7 +734,7 @@ namespace sag {
hyperpoint np = rgpushxto0(placement[i]) * h;
ld change;
ld change = 0;
for(auto e: edges_yes[i]) change -= lgemb.lyes(pdist(placement[i], placement[e]));
for(auto e: edges_no[i]) change -= lgemb.lno(pdist(placement[i], placement[e]));
for(auto e: edges_yes[i]) change += lgemb.lyes(pdist(np, placement[e]));
@ -1097,7 +1097,7 @@ namespace sag {
create_viz();
for(int i=0; i<DN; i++) {
color_t col = patterns::compute_cell_color(sagcells[sagid[i]]);
color_t col = ccolor::formula.f(sagcells[sagid[i]], ccolor::formula);
col <<= 8;
col |= 0xFF;
vdata[i].cp.color1 = vdata[i].cp.color2 = col;

View File

@ -314,6 +314,12 @@ auto hchook = addHook(hooks_drawcell, 100, draw_snow)
param_b(snow_not_player, "snow_not_player");
})
#if CAP_SOLV
#define IF_SOLV(x) x
#else
#define IF_SOLV(x)
#endif
#if CAP_RVSLIDES
+ addHook_rvslides(161, [] (string s, vector<tour::slide>& v) {
if(s != "noniso") return;
@ -381,16 +387,16 @@ auto hchook = addHook(hooks_drawcell, 100, draw_snow)
set_geometry(gRotSpace);
snow_lambda = 5;
});
#if CAP_SOLV
snow_slide(v, "Solv", "Solv geometry. Like the non-isotropic hyperbolic geometry but where the horizontal and vertical curvatures work in the other way.", [] {
IF_SOLV(snow_slide(v, "Solv", "Solv geometry. Like the non-isotropic hyperbolic geometry but where the horizontal and vertical curvatures work in the other way.", [] {
set_geometry(gSol);
// tour::slide_backup(snow_shape, 2);
snow_lambda = 3;
});
#endif
});)
})
#endif
+ 0;
#undef IF_SOLV
}
}

View File

@ -149,7 +149,7 @@ ld evaluate_measure(manidata& emb, manidata& orig, vector<int>& mapp, vector<pai
}
static constexpr string som_test_dir = "results/";
static const string som_test_dir = "results/";
}

View File

@ -108,7 +108,11 @@ string displayfor(int scoredisplay, score* S, bool shorten = false) {
return buf;
}
if(scoredisplay == POSSCORE) return modedesc(S);
if(scoredisplay == 68) return S->yasc_message + XLAT(" in %the1", eLand(S->box[68]));
if(scoredisplay == 68) {
eLand which = eLand(S->box[68]);
if(which >= landtypes || which < 0) return "fail";
return S->yasc_message + XLAT(" in %the1", which);
}
if(scoredisplay == 1) {
time_t tim = S->box[1];
char buf[128]; strftime(buf, 128, "%c", localtime(&tim));

View File

@ -2590,7 +2590,7 @@ EX void turn(int delta) {
lmousetarget = mousetarget;
if(!shmup::on) return;
if(!(cmode & sm::NORMAL)) {
if(!(cmode & sm::NORMAL) || outoffocus) {
#if CAP_RACING
if(!in_pause) {
in_pause = true;

View File

@ -178,6 +178,7 @@ struct hrmap_spherical : hrmap_standard {
}
transmatrix relative_matrixc(cell *c2, cell *c1, const hyperpoint& hint) override {
if(IRREGULAR) return relative_matrix_via_masters(c2, c1, hint);
transmatrix T = iso_inverse(get_where(c1)) * get_where(c2);
if(elliptic) fixelliptic(T);
return T;

View File

@ -26,9 +26,9 @@ namespace rg {
static constexpr char racing = 'R';
static constexpr char dualmode = 'U';
static constexpr char heptagons = '7';
/** \brief wrongmode only -- marks 'global' achievements not related to the current mode */
static constexpr char global = 'x';
static constexpr char global = 'x';
/** \brief wrongmode only -- change vid.scfg.players then restart_game(rg::nothing) instead */
static constexpr char multi = 'm';
/** \brief wrongmode only -- mark achievements for special geometries/variations, this automatically marks the expected land_structure as lsSingle */
@ -66,7 +66,7 @@ EX eLand top_land;
/** \brief a comparator for version number strings */
EX bool verless(string v, string cmp) {
if(isdigit(v[0]) && isdigit(v[1]))
if(isdigit(v[0]) && isdigit(v[1]))
v = "A" + v;
if(isdigit(cmp[0]) && isdigit(cmp[1]))
cmp = "A" + cmp;
@ -169,17 +169,17 @@ EX int easy_specialland;
/** \brief initialize the game */
EX void initgame() {
DEBBI(DF_INIT, ("initGame"));
callhooks(hooks_initgame);
callhooks(hooks_initgame);
if(!safety) fix_land_structure_choice();
if(multi::players < 1 || multi::players > MAXPLAYER)
multi::players = 1;
multi::whereto[0].d = MD_UNDECIDED;
multi::cpid = 0;
yendor::init(1);
if(safety && safetyseed) {
shrand(safetyseed);
firstland = safetyland;
@ -187,16 +187,16 @@ EX void initgame() {
if(!safety) {
firstland = specialland;
ineligible_starting_land = !landUnlocked(specialland);
ineligible_starting_land = !landUnlockedIngame(specialland);
}
if(firstland == laNone || firstland == laBarrier)
firstland = laCrossroads;
easy_specialland = 0;
if(firstland == laOceanWall) firstland = laOcean;
if(firstland == laHauntedWall) firstland = laGraveyard;
if(firstland == laOceanWall) firstland = laOcean;
if(firstland == laHauntedWall) firstland = laGraveyard;
if(firstland == laHauntedBorder) firstland = laGraveyard;
if(firstland == laHaunted && !tactic::on) firstland = laGraveyard;
if(firstland == laMercuryRiver) firstland = laTerracotta;
@ -208,7 +208,7 @@ EX void initgame() {
firstland = weirdhyperbolic ? laCrossroads4 : laCrossroads;
easy_specialland = 3;
}
clear_euland(firstland);
cwt.at = currentmap->gamestart(); cwt.spin = 0; cwt.mirrored = false;
@ -217,7 +217,7 @@ EX void initgame() {
#if CAP_COMPLEX2
if(firstland == laBrownian) brownian::init(cwt.at);
#endif
chaosAchieved = false;
clearing::direct = 0;
@ -228,11 +228,11 @@ EX void initgame() {
splitrocks = 0;
if(firstland == laElementalWall) cwt.at->land = randomElementalLand();
resetview();
resetview();
createMov(cwt.at, 0);
pregen();
pregen();
setdist(cwt.at, BARLEV, NULL);
if(!disable_bigstuff)
@ -242,11 +242,11 @@ EX void initgame() {
#endif
cwt.at->move(0)->land = firstland;
if(firstland == laWhirlpool) cwt.at->move(0)->wall = waSea;
setdist(cwt.at->move(0), BARLEV-1, cwt.at);
if(horo_ok()) {
if(specialland == laCamelot)
if(specialland == laCamelot)
start_camelot(cwt.at);
else {
heptagon *h = create_altmap(cwt.at, 2, hsA);
@ -254,13 +254,13 @@ EX void initgame() {
}
}
}
if(tactic::on && firstland == laPower) {
items[itOrbSpeed] = 30;
items[itOrbWinter] = 30;
items[itOrbFlash] = 30;
}
if(firstland == laCA)
items[itOrbAether] = 2;
@ -269,19 +269,19 @@ EX void initgame() {
if(hiitemsMax(itFernFlower) >= 25) items[itFernFlower] = min(hiitemsMax(itFernFlower), 50);
if(hiitemsMax(itWine) >= 25) items[itWine] = min(hiitemsMax(itWine), 50);
}
yendor::lastchallenge = yendor::challenge;
if(shmup::on) shmup::init();
yendor::init(2);
#if CAP_RACING
if(racing::on) racing::generate_track();
#endif
if(gamegen_failure) return;
if(euclid && specialland == laPrincessQuest) {
cell *c = euc::at(princess::coords());
princess::generating = true;
@ -297,15 +297,15 @@ EX void initgame() {
c->cmove(0)->landparam = 44;
c->cmove(0)->land = laCrossroads2;
}
sword::determine_sword_angles();
for(int i=0; i<numplayers(); i++)
for(int i=0; i<numplayers(); i++)
sword::dir[i] = sword::initial(cwt.at);
#if CAP_DAILY
daily::split();
#endif
// extern int sightrange; sightrange = 9;
// cwt.at->land = laHell; items[itHell] = 10;
for(int i=BARLEV; i>=7 - getDistLimit() - genrange_bonus; i--) {
@ -313,7 +313,7 @@ EX void initgame() {
currentmap->verify();
}
if(doCross) {
for(int i=0; i<ittypes; i++) if(itemclass(eItem(i)) == IC_TREASURE) items[i] = 50;
for(int i=0; i<motypes; i++) kills[i] = 30;
@ -322,13 +322,13 @@ EX void initgame() {
kills[moPrincessArmedMoved] = 0;
kills[moPlayer] = 0;
}
if(quotient && generateAll(firstland)) {
for(int i=0; i<isize(currentmap->allcells()); i++)
setdist(currentmap->allcells()[i], 8, NULL);
}
if(multi::players > 1 && !shmup::on) for(int i=0; i<numplayers(); i++) {
int idir = (3 * i) % cwt.at->type;
multi::player[i].at = cwt.at->move(idir);
@ -342,15 +342,15 @@ EX void initgame() {
multi::flipped[i] = true;
multi::whereto[i].d = MD_UNDECIDED;
}
yendor::init(3);
peace::simon::init();
multi::revive_queue.clear();
#if CAP_TOUR
if(tour::on) tour::presentation(tour::pmRestart);
#endif
if(multi::players > 1 && !shmup::on) {
for(cell *pc: player_positions())
makeEmpty(pc);
@ -358,7 +358,7 @@ EX void initgame() {
else {
makeEmpty(cwt.at);
}
if(specialland == laMinefield && closed_or_bounded) {
bfs();
generate_mines();
@ -370,10 +370,10 @@ EX void initgame() {
if(in_lovasz()) {
cwt.at->item = itOrbInvis;
}
princess::squeaked = false;
clearing::current_root = NULL;
if(!safety) {
usedSafety = false;
timerstart = time(NULL); turncount = 0; rosewave = 0; rosephase = 0;
@ -411,16 +411,16 @@ EX void initgame() {
usedSafety = true;
safety = false;
}
havewhat = hadwhat = 0; rosemap.clear();
elec::lightningfast = 0;
lastsafety = gold();
bfs();
checkmove();
playermoved = true;
if(quotient || sphere)
for(cell *c: currentmap->allcells()) setdist(c, 8, NULL);
@ -429,7 +429,8 @@ EX void initgame() {
if(vid.use_smart_range == 2) vid.use_smart_range = 1;
}
if(!allowIncreasedSight()) vid.use_smart_range = 0;
callhooks(hooks_post_initgame);
calcTidalPhase();
callhooks(hooks_post_initgame);
}
bool havesave = true;
@ -438,7 +439,7 @@ bool havesave = true;
/** \brief A namespace for loading and saving scores and saved games (system.cpp), and for displaying these scores (scores.cpp).
*
* Most ApplyBox functions are used both for saving savegames and scores to the logfile, loading savegames and scores from the logfile,
* Most ApplyBox functions are used both for saving savegames and scores to the logfile, loading savegames and scores from the logfile,
* and loading highscore information from the logfile. The flags saving, loading, and loadingHi specify what is actually done.
*/
EX namespace scores {
@ -447,7 +448,7 @@ EX namespace scores {
/** \brief the amount of boxes reserved for each hr::score item */
#define MAXBOX 500
/** \brief currently used boxes in hr::score */
#define POSSCORE 412
#define POSSCORE 418
/** \brief a struct to keep local score from an earlier game */
struct score {
/** \brief version used */
@ -528,7 +529,7 @@ void applyBoxI(eItem it, bool f = false) {
boxname[boxid] = iinf[it].name;
fakebox[boxid] = f;
monsbox[boxid] = false;
if(loadingHi) {
if(loadingHi) {
updateHi_for_code(it, save.box[boxid++], saved_modecode);
}
else applyBox(items[it]);
@ -544,7 +545,7 @@ void addinv(eItem it) {
void applyBoxOrb(eItem it) {
applyBoxI(it, true);
invorb.push_back(it);
}
}
/** \brief Handle the OSM information for all orbs that applyBoxOrb has been called for so far */
void list_invorb() {
@ -592,11 +593,11 @@ EX void applyBoxes() {
applyBoxNum(cellcount, "cells generated");
if(loading) timerstart = time(NULL);
for(int i=0; i<itOrbLightning; i++)
for(int i=0; i<itOrbLightning; i++)
if(i == 0) items[i] = 0, applyBoxI(itFernFlower);
else applyBoxI(eItem(i));
for(int i=0; i<43; i++) {
if(loading) kills[i] = 0;
if(i == moWormtail) applyBoxM(moCrystalSage);
@ -613,7 +614,7 @@ EX void applyBoxes() {
else if(i == moNone) applyBoxNum(kills[i], "icewalls melted");
else applyBoxM(eMonster(i));
}
if(saving) {
int totaltime = savetime;
if(!timerstopped) totaltime += timer - timerstart;
@ -621,19 +622,19 @@ EX void applyBoxes() {
}
else if(loading) savetime = applyBoxLoad("time played");
else boxname[boxid] = "time played", boxid++;
if(saving) savecount++;
applyBoxNum(savecount, "number of saves");
if(saving) savecount++;
applyBoxNum(savecount, "number of saves");
if(saving) savecount--;
applyBoxNum(cheater, "number of cheats");
fakebox[boxid] = false;
if(saving) applyBoxSave(items[itOrbSafety] ? safetyland : cwt.at->land, "@safetyland");
else if(loading) firstland = safetyland = eLand(applyBoxLoad("@safetyland"));
else lostin = eLand(save.box[boxid++]);
for(int i=itOrbLightning; i<25; i++) applyBoxOrb(eItem(i));
applyBoxI(itRoyalJelly);
applyBoxI(itWine);
applyBoxI(itSilver);
@ -663,18 +664,18 @@ EX void applyBoxes() {
applyBoxI(itGrimoire);
applyBoxM(moKnight);
applyBoxM(moCultistLeader);
applyBoxM(moPirate);
applyBoxM(moCShark);
applyBoxM(moParrot);
applyBoxI(itPirate);
applyBoxOrb(itOrbTime);
applyBoxM(moHexSnake);
applyBoxM(moRedTroll);
applyBoxI(itRedGem);
applyBoxOrb(itOrbSpace);
int geo = geometry;
applyBoxNum(geo, "@geometry"); geometry = eGeometry(geo);
applyBoxBool(hardcore, "hardcore");
@ -683,7 +684,7 @@ EX void applyBoxes() {
if(saving) applyBoxSave(specialland, "euclid land");
else if(loading) specialland = eLand(applyBoxLoad("euclid land"));
else fakebox[boxid++] = true;
applyBoxI(itCoast);
applyBoxI(itWhirlpool);
applyBoxI(itBombEgg);
@ -693,7 +694,7 @@ EX void applyBoxes() {
applyBoxOrb(itOrbFriend);
applyBoxOrb(itOrbAir);
applyBoxOrb(itOrbWater);
applyBoxI(itPalace);
applyBoxI(itFjord);
applyBoxOrb(itOrbFrog);
@ -705,7 +706,7 @@ EX void applyBoxes() {
applyBoxM(moViking);
applyBoxM(moFjordTroll);
applyBoxM(moWaterElemental);
applyBoxI(itSavedPrincess);
applyBoxOrb(itOrbLove);
applyBoxM(moPrincess);
@ -714,7 +715,7 @@ EX void applyBoxes() {
applyBoxM(moMouse);
applyBoxNum(princess::saveArmedHP, "@saveArmedHP");
applyBoxNum(princess::saveHP, "@saveHP");
applyBoxI(itIvory);
applyBoxI(itElemental);
applyBoxI(itZebra);
@ -722,7 +723,7 @@ EX void applyBoxes() {
applyBoxI(itWaterShard);
applyBoxI(itAirShard);
applyBoxI(itEarthShard);
applyBoxM(moAirElemental);
applyBoxM(moFireElemental);
applyBoxM(moFamiliar);
@ -742,10 +743,10 @@ EX void applyBoxes() {
applyBoxI(itBounty);
applyBoxOrb(itOrbLuck);
applyBoxOrb(itOrbStunning);
applyBoxBool(tactic::on, "@tactic");
applyBoxNum(elec::lightningfast, "@lightningfast");
// if(save.box[boxid]) printf("lotus = %d (lost = %d)\n", save.box[boxid], isHaunted(lostin));
if(loadingHi && isHaunted(lostin)) boxid++;
else applyBoxI(itLotus);
@ -759,7 +760,7 @@ EX void applyBoxes() {
applyBoxBool(survivalist, "@survivalist");
if(loadingHi) applyBoxI(itLotus);
else applyBoxNum(truelotus, "lotus/escape");
applyBoxEnum(variation, "variation");
applyBoxI(itRose);
applyBoxOrb(itOrbBeauty);
@ -775,8 +776,8 @@ EX void applyBoxes() {
if(multi::players < 1 || multi::players > MAXPLAYER)
multi::players = 1;
applyBoxM(moRatlingAvenger);
// printf("applybox %d\n", shmup::players);
// printf("applybox %d\n", shmup::players);
applyBoxI(itApple);
applyBoxM(moSparrowhawk);
applyBoxM(moResearcher);
@ -787,7 +788,7 @@ EX void applyBoxes() {
applyBoxNum(tortoise::seekbits, "@seekbits");
applyBoxM(moTortoise);
applyBoxOrb(itOrbShell);
applyBoxNum(safetyseed, "@safetyseed");
// (+18)
@ -807,22 +808,22 @@ EX void applyBoxes() {
applyBoxOrb(itOrbSword2);
applyBoxI(itTrollEgg);
applyBoxOrb(itOrbStone);
bool sph;
sph = false; applyBoxBool(sph, "sphere"); if(sph) geometry = gSphere;
sph = false; applyBoxBool(sph, "elliptic"); if(sph) geometry = gElliptic;
applyBoxNum(princess::reviveAt, "@reviveAt");
applyBoxI(itDodeca);
applyBoxI(itAmethyst);
applyBoxI(itSlime);
applyBoxOrb(itOrbNature);
applyBoxOrb(itOrbDash);
applyBoxOrb(itOrbDash);
addinv(itOrbRecall);
applyBoxM(moBat);
applyBoxM(moReptile);
applyBoxM(moFriendlyIvy);
applyBoxI(itGreenGrass);
applyBoxI(itBull);
applyBoxOrb(itOrbHorns);
@ -862,7 +863,7 @@ EX void applyBoxes() {
applyBoxM(moTerraWarrior);
applyBoxM(moSalamander);
applyBoxM(moLavaWolf);
applyBoxOrb(itOrbSlaying);
applyBoxOrb(itOrbMagnetism);
applyBoxOrb(itOrbPhasing);
@ -880,19 +881,19 @@ EX void applyBoxes() {
applyBoxM(moPair);
applyBoxM(moCrusher);
applyBoxM(moMonk);
bool v2 = false;
applyBoxBool(v2, "@variation"); if(loading && v2) variation = eVariation::goldberg;
applyBoxNum(gp::param.first, "@gp-first");
applyBoxNum(gp::param.second, "@gp-second");
v2 = false; applyBoxBool(v2); if(loading && v2) variation = eVariation::irregular;
applyBoxNum(irr::cellcount, "@irr-cellcount");
list_invorb();
applyBoxNum(irr::bitruncations_performed, "@irr-bitruncations");
applyBoxI(itVarTreasure);
applyBoxI(itBrownian);
applyBoxI(itWest);
@ -905,13 +906,13 @@ EX void applyBoxes() {
applyBoxOrb(itOrbChoice);
applyBoxOrb(itOrbGravity);
list_invorb();
applyBoxM(moNarciss);
applyBoxM(moMirrorSpirit);
applyBoxM(moMirrorSpirit);
applyBoxNum(clearing::direct, "@clearing-direct");
applyBoxBignum(clearing::imputed, "@clearing-imputed");
applyBoxOrb(itOrbImpact);
applyBoxOrb(itOrbChaos);
applyBoxOrb(itOrbPlague);
@ -927,10 +928,10 @@ EX void applyBoxes() {
applyBoxNum(saved_modecode, "modecode");
applyBoxBool(ineligible_starting_land, "ineligible_starting_land");
applyBoxNum(yasc_code, "YASC code");
applyBoxBool(casual, "casual mode");
applyBoxI(itCursed);
applyBoxI(itDice);
applyBoxOrb(itOrbPurity);
@ -954,6 +955,12 @@ EX void applyBoxes() {
applyBoxNum(items[itCrossbow]);
applyBoxNum(items[itRevolver]);
applyBoxNum(items[itAsteroid]);
applyBoxM(moAsteroid);
applyBoxNum(items[itTreat]);
applyBoxM(moVampire);
applyBoxNum(asteroids_generated);
applyBoxNum(asteroid_orbs_generated);
if(POSSCORE != boxid) printf("ERROR: %d boxes\n", boxid);
if(isize(invorb)) { println(hlog, "ERROR: Orbs not taken into account"); exit(1); }
@ -991,7 +998,7 @@ modecode_t fill_modecode() {
if(save.box[341]) variation = eVariation::goldberg;
if(save.box[344]) variation = eVariation::irregular;
if(multi::players < 0 || multi::players > MAXPLAYER)
if(multi::players < 0 || multi::players > MAXPLAYER)
return 6;
if(multi::players == 0)
@ -999,7 +1006,7 @@ modecode_t fill_modecode() {
if(shmup::on && multi::players == 1 && boxid <= 258)
return 6; /* not sure why */
return modecode(2);
}
@ -1038,7 +1045,7 @@ long long saveposition = -1;
EX void remove_emergency_save() {
if(scorefile == "") return;
#if !ISWINDOWS
if(saveposition >= 0) {
if(saveposition >= 0) {
if(truncate(scorefile.c_str(), saveposition)) {}
saveposition = -1;
}
@ -1047,29 +1054,31 @@ EX void remove_emergency_save() {
scores::score scorebox;
EX bool save_cheats;
EX void saveStats(bool emergency IS(false)) {
DEBBI(DF_INIT, ("saveStats [", scorefile, "]"));
if(autocheat) return;
if(autocheat && !save_cheats) return;
if(scorefile == "") return;
#if CAP_TOUR
if(tour::on) return;
if(tour::on && !save_cheats) return;
#endif
if(randomPatternsMode) return;
if(randomPatternsMode && !save_cheats) return;
if(daily::on) return;
if(peace::on) return;
if(peace::on && !save_cheats) return;
if(experimental) return;
if(!gold() && !racing::on) return;
remove_emergency_save();
auto& xcode = scores::saved_modecode;
xcode = modecode();
FILE *f = fopen(scorefile.c_str(), "at");
if(!f) {
// printf("Could not open the score file '%s'!\n", scorefile);
addMessage(XLAT("Could not open the score file: ") + scorefile);
@ -1080,24 +1089,24 @@ EX void saveStats(bool emergency IS(false)) {
saveposition = ftell(f);
// if(!timerghost) addMessage(XLAT("Emergency save at ") + its(saveposition));
}
time_t timer;
timer = time(NULL);
char sbuf[128]; strftime(sbuf, 128, "%c", localtime(&timerstart));
char buf[128]; strftime(buf, 128, "%c", localtime(&timer));
if((tactic::on || yendor::on) && !items[itOrbSafety] && !cheater) {
int t = (int) (timer - timerstart);
if(tactic::on) {
int score = items[treasureType(specialland)];
if(score) {
int c =
int c =
anticheat::certify(dnameof(specialland), turncount, t, (int) timerstart,
unsigned(xcode)*999 + tactic::id + 256 * score);
fprintf(f, "TACTICS %s %d %d %d %d %d %d %d %d date: %s\n", VER,
tactic::id, specialland, score, turncount, t, int(timerstart),
tactic::id, specialland, score, turncount, t, int(timerstart),
c, int(xcode), buf);
tactic::record(specialland, score);
anticheat::nextid(tactic::id, VER, c);
@ -1106,7 +1115,7 @@ EX void saveStats(bool emergency IS(false)) {
if(yendor::on)
fprintf(f, "YENDOR %s %d %d %d %d %d %d %d %d date: %s\n", VER,
yendor::lastchallenge, items[itOrbYendor], yendor::won, turncount, t, int(timerstart),
yendor::lastchallenge, items[itOrbYendor], yendor::won, turncount, t, int(timerstart),
anticheat::certify(yendor::won ? "WON" : "LOST", turncount, t, (int) timerstart,
unsigned(xcode)*999 + yendor::lastchallenge + 256 * items[itOrbYendor]),
int(xcode),
@ -1136,14 +1145,14 @@ EX void saveStats(bool emergency IS(false)) {
if(true) {
fprintf(f, VER);
if(!shmup::on) items[itOrbLife] = countMyGolems(moGolem);
if(!shmup::on) items[itOrbFriend] = countMyGolems(moTameBomberbird);
if(!shmup::on) kills[moPrincessMoved] = countMyGolems(moPrincess);
if(!shmup::on) kills[moPrincessArmedMoved] = countMyGolems(moPrincessArmed);
if(!shmup::on) princess::saveHP = countMyGolemsHP(moPrincess);
if(!shmup::on) princess::saveArmedHP = countMyGolemsHP(moPrincessArmed);
if(!shmup::on) items[itOrbLife] = countMyGolems(moGolem);
if(!shmup::on) items[itOrbFriend] = countMyGolems(moTameBomberbird);
if(!shmup::on) kills[moPrincessMoved] = countMyGolems(moPrincess);
if(!shmup::on) kills[moPrincessArmedMoved] = countMyGolems(moPrincessArmed);
if(!shmup::on) princess::saveHP = countMyGolemsHP(moPrincess);
if(!shmup::on) princess::saveArmedHP = countMyGolemsHP(moPrincessArmed);
scores::saveBox();
for(int i=0; i<scores::boxid; i++) fprintf(f, " %d", scores::save.box[i]);
scorebox = scores::save;
anticheat::save(f);
@ -1151,7 +1160,7 @@ EX void saveStats(bool emergency IS(false)) {
fprintf(f, "\n");
if(yasc_message != "") fprintf(f, "YASC %s\n", yasc_message.c_str());
}
fprintf(f, "Played on: %s - %s (%d %s)\n", sbuf, buf, turncount,
fprintf(f, "Played on: %s - %s (%d %s)\n", sbuf, buf, turncount,
shmup::on ? "knives" : "turns");
fprintf(f, "Total wealth: %d\n", gold());
fprintf(f, "Total enemies killed: %d\n", tkills());
@ -1161,27 +1170,27 @@ EX void saveStats(bool emergency IS(false)) {
if(!ls::nice_walls())
fprintf(f, "land structure: %s\n", land_structure_name(true).c_str());
if(shmup::on) fprintf(f, "Shoot-em up mode\n");
if(inv::on) fprintf(f, "Inventory mode\n");
if(multi::players > 1) fprintf(f, "Multi-player (%d players)\n", multi::players);
fprintf(f, "Number of cells explored, by distance from the player:\n");
fprintf(f, "Number of cells explored, by distance from the player:\n");
{for(int i=0; i<10; i++) fprintf(f, " %d", explore[i]);} fprintf(f, "\n");
if(kills[0]) fprintf(f, "walls melted: %d\n", kills[0]);
fprintf(f, "cells travelled: %d\n", celldist(cwt.at));
fprintf(f, "\n");
for(int i=0; i<ittypes; i++) if(items[i])
for(int i=0; i<ittypes; i++) if(items[i])
fprintf(f, "%4dx %s\n", items[i], iinf[i].name);
fprintf(f, "\n");
for(int i=1; i<motypes; i++) if(kills[i])
for(int i=1; i<motypes; i++) if(kills[i])
fprintf(f, "%4dx %s\n", kills[i], minf[i].name);
fprintf(f, "\n\n\n");
#if !ISMOBILE
DEBB(DF_INIT, ("Game statistics saved to ", scorefile));
addMessage(XLAT("Game statistics saved to %1", scorefile));
@ -1215,21 +1224,26 @@ EX void loadsave() {
load_modecode_line(s);
}
if(buf[0] == 'H' && buf[1] == 'y') {
if(fscanf(f, "%s", buf) <= 0) break;
if(fscanf(f, "%9999s", buf) <= 0) break;
sc.ver = buf;
if(sc.ver == "CHEATER!" && save_cheats) {
if(fgets(buf, 12000, f) == NULL) break;
if(fscanf(f, "%9999s", buf) <= 0) break;
sc.ver = buf;
}
if(sc.ver[1] != '.') sc.ver = '0' + sc.ver;
if(verless(sc.ver, "4.4") || sc.ver == "CHEATER!") { ok = false; continue; }
ok = true;
for(int i=0; i<MAXBOX; i++) {
if(fscanf(f, "%d", &sc.box[i]) <= 0) {
scores::boxid = i;
tamper = anticheat::load(f, sc, sc.ver);
using namespace scores;
for(int i=0; i<boxid; i++) save.box[i] = sc.box[i];
for(int i=boxid; i<MAXBOX; i++) save.box[i] = 0, sc.box[i] = 0;
if(boxid <= MODECODE_BOX) save.box[MODECODE_BOX] = sc.box[MODECODE_BOX] = fill_modecode();
if(save.box[258] >= 0 && save.box[258] < coh) {
@ -1257,17 +1271,17 @@ EX void loadsave() {
int xc = -1;
sscanf(buf, "%70s%9s%d%d%d%d%d%d%d%d",
buf1, ver, &tid, &land, &score, &tc, &t, &ts, &cert, &xc);
eLand l2 = eLand(land);
if(land == laMirror && verless(ver, "10.0")) l2 = laMirrorOld;
if(xc == -1)
for(xc=0; xc<32768; xc++)
if(anticheat::check(cert, ver, dnameof(l2), tc, t, ts, xc*999+unsigned(tid) + 256 * score))
if(anticheat::check(cert, ver, dnameof(l2), tc, t, ts, xc*999+unsigned(tid) + 256 * score))
break;
if(tid == tactic::id && (anticheat::check(cert, ver, dnameof(l2), tc, t, ts, xc*unsigned(999)+ unsigned(tid) + 256 * score))) {
if(score != 0
if(score != 0
&& !(land == laOcean && verless(ver, "8.0f"))
&& !(land == laTerracotta && verless(ver, "10.3e"))
&& !(land == laWildWest && verless(ver, "11.3b") && !verless(ver, "11.3")))
@ -1284,14 +1298,14 @@ EX void loadsave() {
if(xc == -1)
for(xc=0; xc<32768; xc++)
if(anticheat::check(cert, ver, won ? "WON" : "LOST", tc, t, ts, xc*999 + cid + 256 * oy))
if(anticheat::check(cert, ver, won ? "WON" : "LOST", tc, t, ts, xc*999 + cid + 256 * oy))
break;
if(won) if(anticheat::check(cert, ver, won ? "WON" : "LOST", tc, t, ts, xc*999 + cid + 256 * oy)) {
if(xc == 19 && cid == 25) xc = 0;
if(cid > 0 && cid < YENDORLEVELS)
if(!(verless(ver, "8.0f") && oy > 1 && cid == 15))
if(!(verless(ver, "9.3b") && oy > 1 && (cid == 27 || cid == 28)))
if(cid > 0 && cid < YENDORLEVELS)
if(!(verless(ver, "8.0f") && oy > 1 && cid == 15))
if(!(verless(ver, "9.3b") && oy > 1 && (cid == 27 || cid == 28)))
{
yendor::bestscore[xc][cid] = max(yendor::bestscore[xc][cid], oy);
}
@ -1314,7 +1328,8 @@ EX void loadsave() {
}
fclose(f);
if(ok && sc.box[65 + 4 + itOrbSafety - itOrbLightning])
// this is the index of Orb of Safety
if(ok && sc.box[65 + 4 + itOrbSafety - itOrbLightning])
load_last_save();
}
@ -1332,7 +1347,12 @@ EX void load_last_save() {
shstream ss;
ss.s = meaning[sc.box[MODECODE_BOX]];
ss.read(ss.vernum);
mapstream::load_geometry(ss);
if(ss.vernum < 0xAA05)
mapstream::load_geometry(ss);
else {
ss.write_char(0);
load_mode_data_with_zero(ss);
}
}
loadBox();
@ -1373,11 +1393,11 @@ EX void stop_game() {
for(int i=0; i<10; i++) for(int l=0; l<landtypes; l++)
exploreland[i][l] = 0;
for(int i: player_indices())
for(int i: player_indices())
multi::deaths[i]++;
#if CAP_SAVE
anticheat::tampered = false;
anticheat::tampered = false;
#endif
achievementsReceived.clear();
princess::saved = false;
@ -1424,7 +1444,7 @@ EX void set_geometry(eGeometry target) {
hybrid::configure(target);
}
geometry = target;
#if CAP_IRR
if(IRREGULAR) variation = eVariation::bitruncated;
#endif
@ -1447,14 +1467,14 @@ EX void set_geometry(eGeometry target) {
if(ginf[target].default_variation == eVariation::pure && geometry != gArchimedean && !mhybrid)
variation = eVariation::pure;
geometry_settings(was_default);
if(geometry == gArbitrary) {
arb::convert::base_geometry = geometry;
arb::convert::base_variation = variation;
}
if(rotspace) {
check_cgi(); cgi.require_basics();
check_cgi(); cgi.require_basics();
hybrid::csteps = cgi.psl_steps;
}
}
@ -1485,7 +1505,7 @@ EX void set_variation(eVariation target) {
variation = target;
}
}
void stop_tour() {
while(gamestack::pushed()) {
gamestack::pop();
@ -1498,12 +1518,12 @@ EX void switch_game_mode(char switchWhat) {
switch(switchWhat) {
case rg::peace:
peace::on = !peace::on;
tactic::on = yendor::on = princess::challenge =
tactic::on = yendor::on = princess::challenge =
randomPatternsMode = inv::on = false;
racing::on = false;
bow::weapon = bow::wBlade;
break;
case rg::dualmode:
stop_tour(); tour::on = false;
racing::on = false;
@ -1512,11 +1532,11 @@ EX void switch_game_mode(char switchWhat) {
if(!dual::state) dual::enable();
else dual::disable();
break;
case rg::inv:
inv::on = !inv::on;
if(tactic::on) firstland = specialland = laIce;
tactic::on = yendor::on = princess::challenge =
tactic::on = yendor::on = princess::challenge =
peace::on = false;
racing::on = false;
break;
@ -1560,7 +1580,7 @@ EX void switch_game_mode(char switchWhat) {
dual::disable();
break;
#if CAP_RACING
#if CAP_RACING
case rg::racing:
racing::on = !racing::on;
shmup::on = racing::on;
@ -1586,14 +1606,14 @@ EX void switch_game_mode(char switchWhat) {
if(!tactic::on) firstland = laIce;
dual::disable();
break;
case rg::shmup:
shmup::on = !shmup::on;
princess::challenge = false;
if(!shmup::on) racing::on = false;
if(!shmup::on && multi::players > 1) bow::weapon = bow::wBlade;
break;
case rg::randpattern:
randomPatternsMode = !randomPatternsMode;
tactic::on = false;
@ -1601,7 +1621,7 @@ EX void switch_game_mode(char switchWhat) {
peace::on = false;
princess::challenge = false;
break;
case rg::princess:
princess::challenge = !princess::challenge;
firstland = specialland = princess::challenge ? laPalace : laIce;
@ -1611,14 +1631,15 @@ EX void switch_game_mode(char switchWhat) {
land_structure = princess::challenge ? lsSingle : lsNiceWalls;
inv::on = false;
racing::on = false;
use_custom_land_list = false;
dual::disable();
break;
#if CAP_DAILY
case rg::daily:
daily::setup();
break;
case rg::daily_off:
daily::turnoff();
break;
@ -1629,7 +1650,7 @@ EX void switch_game_mode(char switchWhat) {
EX void start_game() {
if(game_active) return;
DEBBI(DF_INIT, ("start_game"));
if(dual::state == 1) dual::assign_landsides();
if(dual::state == 1) dual::assign_landsides();
if(dual::split(start_game)) return;
restart:
game_active = true;
@ -1673,7 +1694,7 @@ EX void start_game() {
// popAllScreens + popAllGames + stop_game + switch_game_mode + start_game
EX void restart_game(char switchWhat IS(rg::nothing)) {
popScreenAll();
popScreenAll();
#if CAP_RACING
if(switchWhat == rg::nothing && racing::on) {
racing::restore_goals();
@ -1756,10 +1777,10 @@ EX void initAll() {
achievement_init(); // not in ANDROID
firstland0 = firstland;
// initlanguage();
initialize_all();
#if CAP_SAVE
select_savefile();
loadsave();
@ -1767,7 +1788,7 @@ EX void initAll() {
#endif
start_game();
restore_all_golems();
firstland = firstland0;
polygonal::solve();
}
@ -1776,7 +1797,7 @@ EX purehookset hooks_final_cleanup;
EX void finishAll() {
achievement_final(!items[itOrbSafety]);
#if CAP_SAVE
if(!casual)
saveStats();
@ -1785,8 +1806,8 @@ EX void finishAll() {
#if !ISMOBILE
quit_all();
#endif
achievement_close();
achievement_close();
callhooks(hooks_final_cleanup);
}
@ -1853,7 +1874,7 @@ auto cgm = addHook(hooks_clearmemory, 40, [] () {
recallCell = NULL;
butterflies.clear();
buggycells.clear();
crush_next.clear();
crush_next.clear();
crush_now.clear();
rosemap.clear();
hv_land.clear();
@ -1861,7 +1882,7 @@ auto cgm = addHook(hooks_clearmemory, 40, [] () {
bow::clear_bowpath();
bow::fire_mode = false;
for(auto &am: adj_memo) am.clear();
}) +
}) +
addHook(hooks_gamedata, 0, [] (gamedata* gd) {
gd->store(pathq);
gd->store(dcal);

View File

@ -1329,14 +1329,13 @@ EX void showMenu() {
dialog::addBoolItem(XLATN("Canvas"), specialland == laCanvas, 'X');
dialog::add_action([] () {
bool inwhite = specialland == laCanvas && patterns::whichCanvas == 'g' && patterns::canvasback == 0xFFFFFF;
bool inwhite = specialland == laCanvas && ccolor::which == &ccolor::plain && ccolor::plain.ctab.size() == 1 && ccolor::plain.ctab[0] == 0xFFFFFF;
if(inwhite)
pushScreen(patterns::showPrePattern);
else {
stop_game();
enable_canvas();
patterns::whichCanvas = 'g';
patterns::canvasback = 0xFFFFFF;
ccolor::set_plain(0xFFFFFF);
start_game();
}
});

View File

@ -110,8 +110,8 @@ EX void slide_action(presmode mode, char key, string text, reaction_t act) {
help_extensions.push_back(help_extension{key, text, act});
}
EX void enable_canvas_backup(char canv) {
slide_backup(patterns::whichCanvas, canv);
EX void enable_canvas_backup(ccolor::data *canv) {
slide_backup(ccolor::which, canv);
slide_backup(firstland, laCanvas);
slide_backup(specialland, laCanvas);
slide_backup(land_structure);
@ -120,7 +120,7 @@ EX void enable_canvas_backup(char canv) {
}
/** \brief an auxiliary function to enable a visualization in the Canvas land */
EX void setCanvas(presmode mode, char canv) {
EX void setCanvas(presmode mode, ccolor::data *canv) {
if(mode == pmStart) {
gamestack::push();
enable_canvas_backup(canv);
@ -133,6 +133,10 @@ EX void setCanvas(presmode mode, char canv) {
}
}
EX void setCanvas(presmode mode, char c) {
setCanvas(mode, ccolor::legacy(c));
}
/** \brief static mode: we get Orbs of Teleport to use them instead of movement */
bool sickmode;
@ -638,7 +642,7 @@ EX slide default_slides[] = {
"The world of HyperRogue is tiled with hexagons "
"and heptagons; heptagons give extra space!\n\n",
[] (presmode mode) {
setCanvas(mode, 'F');
setCanvas(mode, &ccolor::football);
if(mode == 5) {
cwt.at->move(0)->monst = moRunDog;
cwt.at->move(1)->monst = moGoblin;
@ -700,7 +704,7 @@ EX slide default_slides[] = {
"running away in a straight line. "
"Press '2' to try the same in the Euclidean world -- it is impossible.",
[] (presmode mode) {
setCanvas(mode, 'F');
setCanvas(mode, &ccolor::football);
if(mode == 5) {
cwt.at->move(0)->monst = moRunDog;
cwt.at->move(1)->monst = moGoblin;
@ -861,7 +865,7 @@ EX slide default_slides[] = {
"Hyperbolic geometry yields much more interesting periodic patterns "
"than Euclidean.",
[] (presmode mode) {
setCanvas(mode, 't');
setCanvas(mode, &ccolor::zebra_stripes);
if(mode == 1)
patterns::displaycodes = true,
patterns::whichPattern = patterns::PAT_ZEBRA;
@ -895,7 +899,7 @@ EX slide default_slides[] = {
"On the following slide, the colors change smoothly in the whole infinite world. "
"Again, this works better than in Euclidean geometry.",
[] (presmode mode) {
setCanvas(mode, 'l');
setCanvas(mode, &ccolor::landscape);
SHOWLAND ( l == laCanvas );
}
},

View File

@ -122,7 +122,7 @@ EX namespace yendor {
int tscorelast;
void uploadScore() {
EX void uploadScore() {
int tscore = 0;
for(int i=1; i<YENDORLEVELS; i++)
if(bestscore[0][i]) tscore += 999 + bestscore[0][i];
@ -278,10 +278,12 @@ EX namespace yendor {
goto retry;
}
auto rollbacks = std::move(changes.rollbacks);
for(int i=-1; i<key->type; i++) {
cell *c2 = i >= 0 ? key->move(i) : key;
checkTide(c2);
c2->monst = moNone; c2->item = itNone;
makeNoMonster(c2);
c2->item = itNone;
if(!passable(c2, NULL, P_MIRROR | P_MONSTER)) {
if(c2->wall == waCavewall) c2->wall = waCavefloor;
else if(c2->wall == waDeadwall) c2->wall = waDeadfloor2;
@ -311,6 +313,7 @@ EX namespace yendor {
if(c2->land == laMirrorWall && i == -1)
c2->wall = waNone;
}
changes.rollbacks = std::move(rollbacks);
key->item = itKey;
bool split_found = false;
@ -760,18 +763,18 @@ EX namespace tactic {
if(csum > recordsum[xc][land]) recordsum[xc][land] = csum;
}
void record() {
EX void record() {
record(lasttactic, items[treasureType(lasttactic)]);
}
void unrecord(eLand land, flagtype xc = modecode()) {
EX void unrecord(eLand land, flagtype xc IS(modecode())) {
if(land >=0 && land < landtypes) {
for(int i=0; i<MAXTAC-1; i++) lsc[xc][land][i] = lsc[xc][land][i+1];
lsc[xc][land][MAXTAC-1] = -1;
}
}
void unrecord() {
EX void unrecord() {
unrecord(lasttactic);
}
@ -792,7 +795,7 @@ EX namespace tactic {
achievement_score(lb, tscore);
}
void uploadScore() {
EX void uploadScore() {
uploadScoreCode(0, LB_PURE_TACTICS);
uploadScoreCode(2, LB_PURE_TACTICS_SHMUP);
uploadScoreCode(4, LB_PURE_TACTICS_COOP);
@ -1053,7 +1056,7 @@ EX void load_mode_data_with_zero(hstream& f) {
case 3: {
use_custom_land_list = true;
int lt = f.get<int>();
if(lt > landtypes) throw hstream_exception();
if(lt > landtypes) throw hstream_exception("too many landtypes");
for(int i=0; i<lt; i++) {
custom_land_list[i] = f.get<char>();
custom_land_treasure[i] = f.get<int>();
@ -1079,7 +1082,7 @@ EX void load_mode_data_with_zero(hstream& f) {
vid.creature_scale = f.get<ld>();
default:
throw hstream_exception();
throw hstream_exception("wrong option");
}
}
}