Compare commits

...

340 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
Zeno Rogue c55550de57 13.0d 2024-03-24 12:18:40 +01:00
Zeno Rogue 886a7ff43e fixed on older compiler 2024-03-24 11:36:22 +01:00
Zeno Rogue deb207e4c3 load_mode_data now resets creature scale in shmup 2024-03-24 11:15:33 +01:00
Zeno Rogue 819d815d59 mode now includes specialland, creature_scale and global_boundary_ratio parameters 2024-03-24 11:15:13 +01:00
Zeno Rogue b20288557e specialland now has param 2024-03-24 11:14:49 +01:00
Zeno Rogue 4a8eb08340 fixed face_the_player in VR 2024-03-24 11:14:28 +01:00
Zeno Rogue 007a111eab compass/Yendor targets now should be displayed in VR 2024-03-24 11:14:05 +01:00
Zeno Rogue 65e9f68bc7 disable achievements on custom land list 2024-03-24 00:56:15 +01:00
Zeno Rogue 3e30a7ded1 test command in custom land list 2024-03-24 00:51:20 +01:00
Zeno Rogue 5f8d250940 refactored gen_landvisited 2024-03-24 00:51:00 +01:00
Zeno Rogue dee90f8d7c creature_scale saved to modedata 2024-03-24 00:41:36 +01:00
Zeno Rogue d43b19625e scale now always can be changed, but cheater flag is set in shmup 2024-03-24 00:39:02 +01:00
Zeno Rogue f32a2708b4 do not call auto_creator when loading valid irregular save 2024-03-24 00:30:50 +01:00
Zeno Rogue be27fc0fce protect save_map_bin and load_map_bin from possible lacking base 2024-03-24 00:30:04 +01:00
Zeno Rogue 61720cec5e nicer plain floorshapes in IRREGULAR maps 2024-03-24 00:29:45 +01:00
Zeno Rogue 7cf1643c5d ls:: removed debug from landscape 2024-03-23 23:48:48 +01:00
Zeno Rogue 3791daf9e3 map editor now can save irregular maps (also should save modes too) 2024-03-23 21:21:16 +01:00
Zeno Rogue e9941d29d3 hstream_exception now can contain explanation 2024-03-23 21:19:04 +01:00
Zeno Rogue afd4a3f4e3 custom mode manager and custom welcome messages 2024-03-22 01:22:34 +01:00
Zeno Rogue 66a79fe2cd ls:: no 'better_mirror' in Patched Chaos, Total Chaos, or Landscape 2024-03-21 22:51:13 +01:00
Zeno Rogue 350963852c landscape structure is now based on BCC honeycomb 2024-03-21 22:50:42 +01:00
Zeno Rogue a650fe7faf YASC codes work better if killed on a 10+ tile 2024-03-21 22:49:50 +01:00
Zeno Rogue fdf83820f2 ls:: landscape land structure 2024-03-21 20:15:45 +01:00
Zeno Rogue 6b723977dd in grid mode, don't try to draw greatwall lines outside of normal geometry pure/bitruncated 2024-03-21 19:40:07 +01:00
Zeno Rogue 1b3aecc10c better pseudohept in INVERSE tilings 2024-03-21 19:35:22 +01:00
Zeno Rogue e762da439c fixed the lack of non-trapdoors in Zebra 435 2024-03-21 19:17:12 +01:00
Zeno Rogue 7f023b2459 better Emerald in Octagon chamfered 2024-03-21 19:13:05 +01:00
Zeno Rogue 2a9ae3071d fixed Emerald Mine and Vineyard generating very bad in {n,oo} and binary tiling 2024-03-21 19:07:15 +01:00
Zeno Rogue de21375f40 clear more walls when generating Wild West in high GP 2024-03-21 18:56:12 +01:00
Zeno Rogue 7bc2715a43 debug_voronoi works in horo too 2024-03-21 18:44:28 +01:00
Zeno Rogue 04c15fc9c6 mapfontscale setting 2024-03-21 18:44:19 +01:00
Zeno Rogue 9430c26970 fixed a crash when running away from Clearing in single-land mode. 2024-03-21 18:19:28 +01:00
Zeno Rogue 616607dc8e hv:: fixed troll nests 2024-03-19 19:58:45 +01:00
Zeno Rogue 86f5a040c9 fixed dice hints over different heights 2024-03-19 19:36:28 +01:00
Zeno Rogue 37b498203c item movement animations for Orb of Space and Curse of Repulsion 2024-03-19 19:25:08 +01:00
Zeno Rogue 77a4bb4160 items moved by Orb of Water, Magnetism, and Winter are now animated 2024-03-19 19:19:23 +01:00
Zeno Rogue 5bdade94b6 Merge branch 'master' of https://github.com/zenorogue/hyperrogue 2024-03-19 18:54:04 +01:00
Zeno Rogue 0b526cbdfb rulegen:: no crash if no giver 2024-03-19 18:53:37 +01:00
Zeno Rogue a82d9b2266 rulegen:: optimize in 2D, also debug information during optimize is toggleable 2024-03-19 18:53:09 +01:00
Zeno Rogue 0e018df878 Void Beasts are now pulled by Orb of Air 2024-03-19 18:52:16 +01:00
Zeno Rogue 1c5709a3c9 slight change to Charged/Grounded wall temperature 2024-03-19 18:50:52 +01:00
Zeno Rogue c230e03a0a trees etc are now mentioned as blockers in YASC messages 2024-03-19 18:39:09 +01:00
Zeno Rogue b71cd1e44d
Merge pull request #365 from jlmjlm/ec-elec
Change some walls' electrical properties.
2024-03-14 20:41:21 +01:00
Zeno Rogue ef936d7b0e Merge branch 'master' of https://github.com/zenorogue/hyperrogue 2024-03-14 20:39:34 +01:00
Zeno Rogue 97f8c5ed72 CA does not count for hyperstones 2024-03-14 20:27:01 +01:00
Zeno Rogue 94bf06f7dc custom:: disable/enable all option, and don't srestart the game when customizing 2024-03-14 20:20:33 +01:00
Zeno Rogue 261800d765 Cellular Automaton now works when enabled in land_list 2024-03-14 20:20:01 +01:00
Zeno Rogue 2b2cc4e8a9 in getNewLand, do not freeze if no land is valid 2024-03-14 20:19:27 +01:00
Zeno Rogue cbccf4936d Asteroids now has some gameplay in non-shmup 2024-03-14 19:52:22 +01:00
Zeno Rogue 68f5ad6e92 custom: Wild West now enablable 2024-03-14 19:38:26 +01:00
Zeno Rogue 9f44f98b0a fixup to Halloween 2024-03-14 19:37:24 +01:00
Zeno Rogue 5bb4b69c23 fixup to Halloween 2024-03-14 19:36:21 +01:00
Zeno Rogue 9cc370a2d2 enabling Halloween in infinite geometries now produces something that makes sense 2024-03-14 19:34:51 +01:00
Zeno Rogue 26e61783b2 in getNewLand, both laMirrorOld and laMirror are now options, so both are supported in custom land list 2024-03-14 19:31:19 +01:00
Zeno Rogue d0d354b53a removed debug from intra 2024-03-14 19:29:36 +01:00
Zeno Rogue 78a1615c6c nicer boundaries used for archimedean 2024-03-14 19:29:10 +01:00
Zeno Rogue 125b271889 hooks for do_draw 2024-03-14 19:28:44 +01:00
Zeno Rogue c85b4d2f2b save/load mode data, via CLI 2024-03-14 19:28:33 +01:00
Zeno Rogue 424186b10d horodisk_from and randomwalk_size saved to save_mode_data 2024-03-14 19:27:50 +01:00
Zeno Rogue 4421143ae5 customize land mode 2024-03-14 19:27:08 +01:00
Jacob Mandelson ee293310b6 Consider red rock & rubble to electrically insulate. 2024-03-11 18:41:41 -07:00
Jacob Mandelson a40e72f1d8 Mark trees as grounded walls. 2024-03-11 18:41:33 -07:00
Jacob Mandelson 3bd67f466a Remove trees and red rock from conductive walls. 2024-03-11 18:41:26 -07:00
Zeno Rogue ddb9fbd58e
Merge pull request #363 from jlmjlm/save-xbow-reload
Record the ranged weapons' state in the savefile
2024-02-28 15:25:35 +01:00
Zeno Rogue b152bac377
Merge pull request #362 from jlmjlm/save_fa-so-fg
Track more missing game state in saves.
2024-02-28 15:25:26 +01:00
Jacob Mandelson a626ede2bf Record the amount of revolver ammunition in save file. 2024-02-27 21:31:57 -08:00
Jacob Mandelson 1f2692a4fb Record crossbow reload time in savefile. 2024-02-26 17:18:57 -08:00
Jacob Mandelson e31c9dc263 Record moFriendlyGhost kills in savefile. 2024-02-24 16:36:48 -08:00
Jacob Mandelson 7d04b0c717 Record snake oil in savefile. 2024-02-24 16:36:40 -08:00
Jacob Mandelson 0f84812d15 Track fatigue across save/load. 2024-02-24 16:36:33 -08:00
Jacob Mandelson 80f90dec52 Remove spurious semicolon. 2024-02-24 16:36:16 -08:00
Zeno Rogue e840e39ba0 13.0c 2024-02-24 09:56:30 +01:00
Zeno Rogue fa9c2da41d fixed tide/lava help counters 2024-02-24 09:53:31 +01:00
Zeno Rogue f291bbb1d1 fixed a bug with rusalka-cursing the first tile when you shoot 2024-02-24 09:47:53 +01:00
Zeno Rogue 2de61962f9 special YASC message for pinches 2024-02-24 03:19:38 +01:00
Zeno Rogue 43fc692b47 in YASC messages, 'on the Round Table' replaced by 'being polite' 2024-02-24 03:13:48 +01:00
Zeno Rogue 87ac19febe in YASC messages, mention the knights blocking the way, and also mention their names 2024-02-24 03:13:15 +01:00
Zeno Rogue 2379228ab4 display yasc message in gameover 2024-02-24 03:00:42 +01:00
Zeno Rogue 5aac5fd2a3 missing override added 2024-02-23 01:38:32 +01:00
Zeno Rogue 46eaee44ef 13.0b 2024-02-23 01:35:48 +01:00
Zeno Rogue 21d3f8bec4 IFINGAME is now undefined 2024-02-23 01:35:35 +01:00
Zeno Rogue c2d06dc05b missed offside parameters 2024-02-23 01:35:17 +01:00
Zeno Rogue 21a782cd28 improved in/on messages, also for Brownian III 2024-02-23 01:22:30 +01:00
Zeno Rogue bf512e39ce YASC messages in shmup 2024-02-23 01:09:22 +01:00
Zeno Rogue de5ddc3034 YASC messages in hardcore mode 2024-02-23 00:48:17 +01:00
Zeno Rogue b4b00baa5e apply_chaos removed baby tortoise move since we are using moveItem 2024-02-23 00:40:13 +01:00
Zeno Rogue 648dd67dc7 fixed Curse of Repulsion to use moveItem 2024-02-23 00:39:48 +01:00
Zeno Rogue 30f6fbc16c added A human to credits 2024-02-23 00:39:27 +01:00
Zeno Rogue 00b5fe3a22 save the YASC messages in save file, and display them in score list; also auto-width and zoom 2024-02-23 00:39:12 +01:00
Zeno Rogue 55493cc364 shmup:: boat can go thru non-adjacent using Orb of Warp 2024-02-23 00:37:41 +01:00
Zeno Rogue 3b1918535f fixed Orb of Chaos not calling moveItem 2024-02-22 21:08:39 +01:00
Zeno Rogue 650108bad3 gp:: goldberg x/y limit is now based on what the engine allows 2024-02-22 20:42:17 +01:00
Zeno Rogue 79e74e8d53 gp:: 'dual of current' no longer can circumvent the limits 2024-02-22 20:41:54 +01:00
Zeno Rogue 3ed43b8c7d fixed a freeze when computing distance in INVERSE 2024-02-22 20:30:35 +01:00
Zeno Rogue 5508fb7183 fixed sizes_known returning true incorrectly in INVERSE 2024-02-22 20:30:06 +01:00
Zeno Rogue 6c682510bc fixed the Yard bug 2024-02-22 20:21:08 +01:00
Zeno Rogue 6d9f7e791b Trollheim does not generate adjacent non-unlocked troll lands 2024-02-22 18:59:08 +01:00
Zeno Rogue e343ed9c3f alternative land unlock rules when monster/item requested is not available due to geometry etc 2024-02-22 18:57:41 +01:00
Zeno Rogue 8af2a43f5e fixed a crash with too large band 2024-02-22 18:41:52 +01:00
Zeno Rogue e33f26d51f opening inventory mode when you can just shoot should be fixed 2024-02-22 18:16:27 +01:00
Zeno Rogue 60980bcb8b bow:: rusalka curses now work 2024-02-22 18:11:12 +01:00
Zeno Rogue bcc026173e fixed tricking Pikemen with a bow 2024-02-22 18:03:50 +01:00
Zeno Rogue d86f70886d bow:: while rosed, you can now only shoot when this kills a monster at point blank in the rose direction 2024-02-22 17:49:45 +01:00
Zeno Rogue 2a7e2e96ca fixed crashes when e.g. entering 'ma' as a value 2024-02-22 17:29:58 +01:00
Zeno Rogue a91f74c86c fixed a crash bug when editing custom_settings 2024-02-22 17:21:57 +01:00
Zeno Rogue 285c71e10f yasc messages 2024-02-22 17:12:49 +01:00
Zeno Rogue a28c62416f restarting a race now resets pause counter 2024-02-22 16:47:20 +01:00
Zeno Rogue bfd1945d7b classified kills[moNone] 2024-02-22 12:33:49 +01:00
Zeno Rogue f271ba6b4d Merge branch 'master' of https://github.com/zenorogue/hyperrogue 2024-02-22 12:30:33 +01:00
Zeno Rogue f87a7c5f1c
Merge pull request #361 from jlmjlm/save-wtkill
Record World Turtle kills.
2024-02-22 12:30:13 +01:00
Zeno Rogue 9ce5c63708 new projection: polar coordinates 2024-02-22 01:16:43 +01:00
Jacob Mandelson 56c8838101 Record World Turtle kills. 2024-02-21 11:23:08 -08:00
Zeno Rogue 9a590ecc42 Merge branch 'master' of https://github.com/zenorogue/hyperrogue 2024-02-21 10:25:29 +01:00
Zeno Rogue eb1488b24f rogueviz:: updated reverb to compile 2024-02-21 10:24:46 +01:00
Zeno Rogue 26328f5493
Merge pull request #359 from jlmjlm/tidefix1
Calculate tidalsize before using it in mouseovers.
2024-02-19 14:22:49 +01:00
Zeno Rogue 52081a916a
Merge pull request #360 from jlmjlm/oofishfix
Record Orb of Fish in savefile.
2024-02-19 14:22:00 +01:00
Jacob Mandelson 08a774dfd4 Record Orb of Fish in savefile. 2024-02-17 20:50:10 -08:00
Jacob Mandelson acd88377a9 Calculate tidalsize before using it in mouseovers.
This way the game doesn't immediately crash when restoring a save
in tidal areas.
2024-02-14 11:13:16 -08:00
Zeno Rogue 51f59cc2fa version 13.0a 2024-01-13 09:03:12 +01:00
Zeno Rogue 5f552799e5 added fisheye_alpha to hyper.h 2024-01-13 09:02:57 +01:00
Zeno Rogue f883322ecd new Princess message 2024-01-13 08:56:41 +01:00
Zeno Rogue 8c06e184c8 added a message for not caring about roses 2024-01-11 17:51:18 +01:00
Zeno Rogue b8a5c7528b crossbow leaderboards should be fixed 2024-01-11 17:26:45 +01:00
Zeno Rogue 11aa7d5216 fixed button placement on Android once more 2024-01-11 17:23:01 +01:00
Zeno Rogue 0ea461fa7e fixed constant name 2024-01-11 17:22:20 +01:00
Zeno Rogue bdd2b5e9fd bow:: fixed mirrors in fire mode 2024-01-11 17:01:46 +01:00
Zeno Rogue 8ce805372d savemem:: larger allh array 2024-01-11 15:23:18 +01:00
Zeno Rogue 072041db06 savemem:: make sure it is not the same altmap 2024-01-11 15:23:05 +01:00
Zeno Rogue 4c6c44cc26 variant fisheye projection 2024-01-07 12:52:50 +01:00
Zeno Rogue 31471fc6c5 The bump_to_shoot flag now actually works 2024-01-07 12:52:11 +01:00
Zeno Rogue 7ad46d8e80 fixed tides in shmup and when scrolling 2024-01-07 09:33:29 +01:00
Zeno Rogue 34ab44d1e1 dipping rule no longer affects Tiger's Eyes 2024-01-07 09:23:14 +01:00
Zeno Rogue 66a3a3df6c screenshots centered 2024-01-07 09:13:44 +01:00
Zeno Rogue 0c34e9fd34 'cylidrical' stereo mode 2024-01-07 09:13:31 +01:00
Zeno Rogue cb8a3f5424 fixed changing the high-FOV mode to reset shaders 2024-01-07 09:09:18 +01:00
Zeno Rogue fc808d448b fixed FOV menu to automatically change its upper bound on high-fov modes 2024-01-07 09:08:44 +01:00
Zeno Rogue 7ad955dcff fixed two-eye rendering in stereo modes which should not cause that 2024-01-07 09:07:54 +01:00
Zeno Rogue 17b84bb4fb hyperroid updated to 13.0 2023-12-30 08:27:47 +01:00
Zeno Rogue 902986d473 vertical sliders work on Android 2023-12-30 08:10:52 +01:00
Zeno Rogue 9bc978ce16 added some CAP_ guards so Android compiles 2023-12-30 08:10:34 +01:00
Zeno Rogue 6f81743488 Android:: prevent android buttons from being too close from the center 2023-12-30 08:10:07 +01:00
Zeno Rogue f4607b63f4 moved game_keys_scroll so that it exists on Android 2023-12-30 08:08:33 +01:00
Zeno Rogue 6e3be8a92c version 13.0 2023-12-27 17:45:09 +01:00
Zeno Rogue 02efdec4b7 export daily::historical 2023-12-27 16:32:47 +01:00
Zeno Rogue 18247ec98f rogueviz:: made gobot compile without video 2023-12-27 16:32:36 +01:00
Zeno Rogue eb4b7177f3 rogueviz:: extra projection 2023-12-27 16:28:08 +01:00
Zeno Rogue 517f4af193 small fixes to gentrans 2023-12-27 16:27:05 +01:00
Zeno Rogue 2f1bb092b8 rogueviz:: list of portal scenes in portal collection 2023-12-27 16:25:33 +01:00
Zeno Rogue ffda562f7c geom3:: fixed Sol, NIH and SolN embeddings being always displayed as legal 2023-12-27 10:58:55 +01:00
Zeno Rogue c5a4cc2255 bow:: geometric crossbow can now hit monsters on the edge of vision 2023-12-27 10:50:01 +01:00
Zeno Rogue dbc51d2f94 bow:: fixed the geometric crossbow not hitting monsters inside walls 2023-12-27 10:45:24 +01:00
Zeno Rogue 3da65f4cd5 translation update: CZ 13.0 included and some fixes 2023-12-27 10:40:04 +01:00
Zeno Rogue 0c7aa7cbe3 fixed NUMLEADER in hyper.h 2023-12-27 10:23:26 +01:00
Zeno Rogue 79527688cf ls:: fixed Caribbean in ideal Voronoi 2023-12-22 11:30:09 +01:00
Zeno Rogue 364a563423 fixed the name displayed on mouseover for slime 2023-12-22 01:14:41 +01:00
Zeno Rogue a6b30fa564 fixed checkmove giving wrong answer when bow::fire_mode is active 2023-12-22 01:07:12 +01:00
Zeno Rogue eb3406d7dc fixed the bug where tides may move on orb use 2023-12-22 00:51:07 +01:00
Zeno Rogue 95ed035180 fixed typo in PL translation 2023-12-22 00:28:29 +01:00
Zeno Rogue 3d01ce808f bow:: disabled blade-only achievements 2023-12-22 00:28:11 +01:00
Zeno Rogue 558b8d7aff crossbow achievements 2023-12-21 19:51:05 +01:00
Zeno Rogue 0de012923a pressing ESC key while in fire mode now disables the fire mode 2023-12-21 19:50:01 +01:00
Zeno Rogue 7a352ccf43 in eligibility, mark that leaderboards are separate 2023-12-17 22:03:35 +01:00
Zeno Rogue 98831aff7e
Merge pull request #353 from jlmjlm/fproof_key
Make the Key fireproof.
2023-12-17 17:58:50 +01:00
Zeno Rogue 17c254e2b4
Merge pull request #352 from jlmjlm/gal21b
Make tortoise if first 21/21 tile created in > 100 turns.
2023-12-17 17:58:10 +01:00
Zeno Rogue 4fbce2ae5a a debug function added 2023-12-17 17:47:05 +01:00
Zeno Rogue cdc1696929 fixed the drawing of half-vines and mirror walls in spatial 2023-12-17 17:46:46 +01:00
Zeno Rogue 2fc42cb114 ls:: in Voronoi, made Rlyeh and Temple appear, and Haunted and Free Fall are now unavailable 2023-12-17 17:43:59 +01:00
Zeno Rogue 73884482aa using -lands option no longer enforces cheat mode 2023-12-17 17:42:47 +01:00
Zeno Rogue 8c57e8b746 in achievement eligiblity, a message if not in this version 2023-12-17 17:42:28 +01:00
Zeno Rogue f5c5a5f876 ls:: better land compatibility in Voronoi 2023-12-17 17:42:03 +01:00
Jacob Mandelson 12c464eb99 Make the Key fireproof. 2023-12-16 18:31:12 -08:00
Zeno Rogue 8e31c51bc9 achievement eligiblity added to translation 2023-12-15 11:04:47 +01:00
Zeno Rogue 71cbc8e221 achievement eligibility display 2023-12-15 11:00:41 +01:00
Zeno Rogue bce07e5914 hv:: fixed CR2 2023-12-15 11:00:41 +01:00
Zeno Rogue ed8b7d5d1d ls:: fixed Land of Storms in Horodisk and Voronoi 2023-12-15 11:00:41 +01:00
Zeno Rogue 5c24213092 fixed restoring golems in casual 2023-12-15 11:00:41 +01:00
Zeno Rogue a282ac314e shmup:: crossbow bolts now pierce multi-tile monsters 2023-12-15 11:00:41 +01:00
Zeno Rogue 5ab9bf8f11 shmup:: disabled fire-on-mouse 2023-12-15 11:00:41 +01:00
Zeno Rogue 61303fcab6 remove crossbow paths on orb use 2023-12-15 11:00:41 +01:00
Zeno Rogue 517f4a833c changelog/version number update to 12.1z was missing 2023-12-15 11:00:41 +01:00
Jacob Mandelson 27db11064c Make tortoise if first 21/21 tile created in > 100 turns. 2023-12-12 11:53:14 -08:00
Zeno Rogue 062fb577b2 fixed a bug with clicking lists in some dialogs 2023-12-12 20:09:19 +01:00
Zeno Rogue 4338ec2b43 racing:: exception on reading bad ghostmoments 2023-12-12 20:03:59 +01:00
Zeno Rogue cd7af38e2e fixed loading pre-bow character styles (fixes crashes on loading races) 2023-12-12 20:03:42 +01:00
Zeno Rogue 24c196db15 limit setland errors 2023-12-12 20:02:53 +01:00
Zeno Rogue 548e2609ce geom3:: fixed a bug with embedded maps being destroyed on restart 2023-12-12 19:18:26 +01:00
Zeno Rogue d2d6167eb9 updated Polish translation to 13.0 2023-12-03 14:50:06 +01:00
Zeno Rogue 86402cf979 fixup to honeycomb 2023-12-03 14:48:10 +01:00
Zeno Rogue 38825f3a31 added missing honeycombs to translations 2023-12-03 14:30:54 +01:00
Zeno Rogue 560cc91e95 fixed a translation bug with infinite squares 2023-12-03 14:30:08 +01:00
Zeno Rogue ffc06b981f used the same string in some places for easier translation 2023-12-03 14:29:50 +01:00
Zeno Rogue 0cdd6f8d5d hyperweb:: use XLAT1 not XLAT 2023-12-03 14:29:26 +01:00
Zeno Rogue c63969a21b fix typo 2023-12-03 14:29:08 +01:00
Zeno Rogue 7802194248 deconfused translation checker 2023-12-03 14:29:02 +01:00
Zeno Rogue a79a7f63a1 added XLAT in some places where it was missing 2023-12-03 14:28:30 +01:00
Zeno Rogue 928ab73fff menu_item_name_modified to help with translation 2023-12-03 14:10:03 +01:00
119 changed files with 4925 additions and 1872 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 {
#define NUMLEADER 87
#if HDR
#define NUMLEADER 90
#endif
EX bool test_achievements = false;
@ -80,12 +82,33 @@ EX const char* leadernames[NUMLEADER] = {
"Lazurite Figurines", // 83
"Water Lilies", // 84
"Capon Stones", // 85
"Crystal Dice" // 86
"Crystal Dice", // 86
"Crossbow (bull)", // 87
"Crossbow (geodesic)", // 88
"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);
@ -93,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];
@ -108,7 +131,7 @@ EX bool wrongMode(char flags) {
if(cheater) return true;
if(casual) return true;
if(flags == rg::global) return false;
if(bow::weapon) return true;
if(flags == rg::fail) return true;
if(flags != rg::special_geometry && flags != rg::special_geometry_nicewalls) {
if(!BITRUNCATED) return true;
@ -116,6 +139,7 @@ EX bool wrongMode(char flags) {
if(disksize) return true;
}
if(ineligible_starting_land && !flags) return true;
if(use_custom_land_list) return true;
if(shmup::on != (flags == rg::shmup || flags == rg::racing)) return true;
if(racing::on != (flags == rg::racing)) return true;
@ -131,6 +155,7 @@ EX bool wrongMode(char flags) {
if(tour::on) return true;
#endif
eLandStructure dls = lsNiceWalls;
if(flags == rg::princess && !princess::challenge) return true;
if(flags == rg::special_geometry || flags == rg::princess)
dls = lsSingle;
if(flags == rg::chaos)
@ -140,6 +165,7 @@ EX bool wrongMode(char flags) {
dls = land_structure;
if(land_structure != dls) return true;
if(shmup::on && vid.creature_scale != 1) return true;
if(numplayers() > 1 && !multi::friendly_fire) return true;
if(numplayers() > 1 && multi::pvp_mode) return true;
if(numplayers() > 1 && multi::split_screen) return true;
@ -160,6 +186,25 @@ EX void achievement_gain_once(const string& s, char flags IS(0)) {
achievement_gain(s.c_str(), flags);
}
namespace rg {
char check(bool b, char val = special_geometry) { return b ? val : fail; }
}
EX char specgeom_zebra() { return rg::check(geometry == gZebraQuotient && !disksize && BITRUNCATED && firstland == laDesert); }
EX char specgeom_lovasz() { return rg::check(geometry == gKleinQuartic && variation == eVariation::untruncated && gp::param == gp::loc(1,1) && !disksize && in_lovasz()); }
EX char specgeom_halloween() { return rg::check((geometry == gSphere || geometry == gElliptic) && BITRUNCATED && !disksize && firstland == laHalloween); }
EX char specgeom_heptagonal() { return rg::check(PURE && geometry == gNormal && !disksize, rg::special_geometry_nicewalls); }
EX char specgeom_euclid_gen() { return rg::check(geometry == gEuclid && !disksize && firstland == laMirrorOld); }
EX char specgeom_crystal1() { return rg::check(PURE && cryst && ginf[gCrystal].sides == 8 && ginf[gCrystal].vertex == 4 && !crystal::used_compass_inside && !disksize && firstland == laCamelot); }
EX char specgeom_crystal2() { return rg::check(BITRUNCATED && cryst && ginf[gCrystal].sides == 8 && ginf[gCrystal].vertex == 3 && !crystal::used_compass_inside && !disksize && firstland == laCamelot); }
EX vector<std::function<char()>> all_specgeom_checks = { specgeom_zebra, specgeom_lovasz, specgeom_halloween, specgeom_heptagonal, specgeom_crystal1, specgeom_crystal2, specgeom_euclid_gen };
EX char any_specgeom() {
for(auto chk: all_specgeom_checks) if(chk() != rg::fail) return chk();
return rg::fail;
}
EX void achievement_log(const char* s, char flags) {
if(wrongMode(flags)) {
@ -194,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'.
@ -230,11 +270,11 @@ EX void achievement_collection2(eItem it, int q) {
if(randomPatternsMode) return;
LATE( achievement_collection2(it, q); )
if(it == itTreat && q == 50 && (geometry == gSphere || geometry == gElliptic) && BITRUNCATED && !disksize)
achievement_gain("HALLOWEEN1", rg::special_geometry);
if(it == itTreat && q == 50)
achievement_gain("HALLOWEEN1", specgeom_halloween());
if(it == itTreat && q == 100 && (geometry == gSphere || geometry == gElliptic) && BITRUNCATED && !disksize)
achievement_gain("HALLOWEEN2", rg::special_geometry);
if(it == itTreat && q == 100)
achievement_gain("HALLOWEEN2", specgeom_halloween());
if(q == 1) {
if(it == itDiamond) achievement_gain("DIAMOND1");
@ -314,13 +354,10 @@ EX void achievement_collection2(eItem it, int q) {
// 32
if(it == itHolyGrail) {
if(q == 1) achievement_gain("GRAIL2");
if(PURE && geometry == gNormal && !disksize)
achievement_gain("GRAILH", rg::special_geometry_nicewalls);
achievement_gain("GRAILH", specgeom_heptagonal());
#if CAP_CRYSTAL
if(PURE && cryst && ginf[gCrystal].sides == 8 && ginf[gCrystal].vertex == 4 && !crystal::used_compass_inside && !disksize)
achievement_gain("GRAIL4D", rg::special_geometry);
if(BITRUNCATED && cryst && ginf[gCrystal].sides == 8 && ginf[gCrystal].vertex == 3 && !crystal::used_compass_inside && !disksize)
achievement_gain("GRAIL4D2", rg::special_geometry);
achievement_gain("GRAIL4D", specgeom_crystal1());
achievement_gain("GRAIL4D2", specgeom_crystal2());
#endif
if(q == 3) achievement_gain("GRAIL3");
if(q == 8) achievement_gain("GRAIL4");
@ -604,14 +641,18 @@ EX void achievement_count(const string& s, int current, int prev) {
achievement_gain("LIGHTNING2");
if(s == "LIGHTNING" && current-prev >= 10)
achievement_gain("LIGHTNING3");
if(s == "MIRAGE" && current >= 35 && geometry == gEuclid && !disksize)
achievement_gain("MIRAGE", rg::special_geometry);
if(s == "MIRAGE" && current >= 35)
achievement_gain("MIRAGE", specgeom_euclid_gen());
if(s == "ORB" && current >= 10)
achievement_gain("ORB3");
if(s == "BUG" && current >= 1000)
achievement_gain("BUG3");
if(s == "ELEC" && current >= 10)
achievement_gain("ELEC3");
if(s == "BOWVARIETY" && current >= 2)
achievement_gain("BOWVARIETY1");
if(s == "BOWVARIETY" && current >= 6)
achievement_gain("BOWVARIETY2");
}
int specific_improved = 0;
@ -620,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)) {
@ -634,10 +675,9 @@ 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;
if(bow::weapon) return;
LATE( achievement_score(cat, number); )
if(disksize) return;
if(cat == LB_HALLOWEEN) {
@ -656,6 +696,8 @@ EX void achievement_score(int cat, int number) {
if(tactic::on && cat != LB_PURE_TACTICS && cat != LB_PURE_TACTICS_SHMUP && cat != LB_PURE_TACTICS_COOP)
return;
if(racing::on && cat != LB_RACING) return;
if(bow::weapon) return;
if(use_custom_land_list) return;
upload_score(cat, number);
#endif
}
@ -739,14 +781,13 @@ 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;
}
if(cheater) return;
if(casual) return;
if(bow::weapon) return;
#if CAP_TOUR
if(tour::on) return;
@ -778,6 +819,10 @@ EX void achievement_final(bool really_final) {
if(PURE) specialcode+=4;
if(numplayers() > 1) specialcode+=8;
if(inv::on) specialcode+=16;
if(bow::crossbow_mode() && bow::style == bow::cbBull) specialcode += 32;
if(bow::crossbow_mode() && bow::style == bow::cbGeodesic) specialcode += 64;
if(bow::crossbow_mode() && bow::style == bow::cbGeometric) specialcode += 96;
if(shmup::on && vid.creature_scale != 1) return;
if(sphere && specialland == laHalloween) {
if(specialcode) return;
@ -788,6 +833,7 @@ EX void achievement_final(bool really_final) {
if(ineligible_starting_land) return;
if(geometry) return;
if(NONSTDVAR) return;
if(use_custom_land_list) return;
if(numplayers() > 1 && !multi::friendly_fire) return;
if(numplayers() > 1 && multi::pvp_mode) return;
@ -804,6 +850,9 @@ EX void achievement_final(bool really_final) {
case 8: sid = 61; break;
case 9: sid = 44; break;
case 16: sid = 69; break;
case 32: sid = 87; break;
case 64: sid = 88; break;
case 96: sid = 89; break;
default: return;
}
@ -867,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;
@ -880,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"))
@ -1000,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; }
@ -1036,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

@ -137,8 +137,8 @@ EX bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags)
else return false;
}
if(flags & AF_APPROACH) {
if(m2 == moLancer) ;
if(flags & (AF_APPROACH | AF_HORNS)) {
if(m2 == moLancer && (flags & AF_APPROACH)) ;
else if((flags & AF_HORNS) && checkOrb(m1, itOrbHorns)) { flags |= AF_IGNORE_UNARMED; }
else return false;
}
@ -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,6 +757,11 @@ 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 && c->land == laAsteroids) {
c->item = itAsteroid;
changes.value_add(splitrocks, 2);
}
if(m == moOutlaw && (c->item == itNone || c->item == itRevolver) && c->wall != waChasm)
c->item = itBounty;
// note: an Orb appears underwater!
@ -939,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
@ -1111,11 +1124,11 @@ EX bool should_switchplace(cell *c1, cell *c2) {
EX bool switchplace_prevent(cell *c1, cell *c2, struct pcmove& m) {
if(!should_switchplace(c1, c2)) return false;
if(peace::on && (isMultitile(c2->monst) || saved_tortoise_on(c2) || isDie(c2->monst))) {
if(m.vmsg(miRESTRICTED)) addMessage(XLAT("Cannot switch places with %the1!", c2->monst));
if(m.vmsg(miRESTRICTED, siMONSTER, c2, c2->monst)) addMessage(XLAT("Cannot switch places with %the1!", c2->monst));
return true;
}
if(c1->monst && c1->monst != moFriendlyIvy) {
if(m.vmsg(miRESTRICTED)) addMessage(XLAT("There is no room for %the1!", c2->monst));
if(m.vmsg(miRESTRICTED, siMONSTER, c1, c1->monst)) addMessage(XLAT("There is no room for %the1!", c2->monst));
return true;
}
if(passable(c1, c2, P_ISFRIEND | (c2->monst == moTameBomberbird ? P_FLYING : 0))) return false;
@ -1227,11 +1240,13 @@ EX void killThePlayer(eMonster m, int id, flagtype flags) {
}
else if(hardcore) {
addMessage(XLAT("You are killed by %the1!", m));
yasc_message = XLAT("killed by %the1", m);
killHardcorePlayer(id, flags);
}
else if(m == moLightningBolt && lastmovetype == lmAttack && isAlchAny(playerpos(id))) {
addMessage(XLAT("You are killed by %the1!", m));
addMessage(XLAT("Don't play with slime and electricity next time, okay?"));
yasc_message = XLAT("killed by %the1", m);
kills[moPlayer]++;
items[itOrbSafety] = 0;
}
@ -1346,9 +1361,10 @@ EX void stabbingAttack(movei mi, eMonster who, int bonuskill IS(0)) {
forCellIdEx(c, t, mt) {
if(!logical_adjacent(mt, who, c)) continue;
eMonster mm = c->monst;
int flag = AF_APPROACH;
int flag = 0;
if(!isUnarmed(who) && !out) flag |= AF_APPROACH;
if(proper(mt, backdir) && anglestraight(mt, backdir, t)) flag |= AF_HORNS;
if((isUnarmed(who) || out) && !(flag & AF_HORNS)) continue;
if(!flag) continue;
if(canAttack(mt,who,c,c->monst, flag)) {
changes.ccell(c);
if(attackMonster(c, flag | AF_MSG, who)) numlance++;
@ -1357,7 +1373,7 @@ EX void stabbingAttack(movei mi, eMonster who, int bonuskill IS(0)) {
}
}
if(who == moPlayer) {
if(who == moPlayer && !bow::crossbow_mode()) {
if(numsh) achievement_count("STAB", numsh, 0);
if(numlance && numflail && numsh) achievement_gain_once("MELEE3");

View File

@ -324,12 +324,15 @@ EX void setbarrier(cell *c) {
setbarrier(c, c->barleft, c->barright, ctof(c));
}
EX int setland_max = 5;
EX void setland(cell *c, eLand l) {
if(c->land != l) {
c->landparam = 0;
}
if(l == laNone) {
printf("setland\n"); // NONEDEBUG
if(l == laNone && setland_max > 0) {
setland_max--;
printf("error: set land to laNone\n"); // NONEDEBUG
}
c->land = l;
}
@ -556,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;
}
@ -612,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);
@ -677,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);
@ -721,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);
@ -749,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;
@ -871,6 +932,7 @@ EX void buildCrossroads2(cell *c) {
if(buggyGeneration) return;
if(!c) return;
if(ls::hv_structure()) return;
for(int i=0; i<c->type; i++)
if(c->move(i) && !c->move(i)->landparam && c->move(i)->mpdist < c->mpdist)

View File

@ -58,7 +58,7 @@ struct display_data {
transmatrix radar_transform_post;
ld eyewidth();
bool stereo_active();
bool separate_eyes();
bool in_anaglyph();
void set_viewport(int ed);
@ -108,7 +108,7 @@ EX int get_sightrange_ambush() {
}
bool display_data::in_anaglyph() { return vid.stereo_mode == sAnaglyph; }
bool display_data::stereo_active() { return vid.stereo_mode != sOFF; }
bool display_data::separate_eyes() { return among(vid.stereo_mode, sAnaglyph, sLR); }
ld display_data::eyewidth() {
switch(vid.stereo_mode) {

View File

@ -219,7 +219,7 @@ void hrmap::extend_altmap(heptagon *h, int levs, bool link_cdata) {
}
}
void new_voronoi_root(heptagon *h, int dist, int dir, eLand next, eLand last) {
void new_voronoi_root(heptagon *h, int dist, int dir, eLand next) {
heptagon *alt = init_heptagon(h->type);
allmaps.push_back(newAltMap(alt));
alt->s = hsA;
@ -231,7 +231,6 @@ void new_voronoi_root(heptagon *h, int dist, int dir, eLand next, eLand last) {
altmap::relspin(alt) = dir;
hv_land[alt] = next;
hv_last_land[alt] = last;
while(alt->distance > -100) {
auto alt1 = createStep(alt, 0);
@ -291,13 +290,41 @@ cand_info voronoi_candidate(heptagon *h) {
return ci;
}
vector<eLand> list_adjacent_lands(heptagon *h) {
vector<eLand> res;
for(int i=0; i<h->type; i++) {
heptspin hs = heptspin(h, i);
hs += wstep;
auto alt = hs.at->alt;
if(!alt) continue;
alt = alt->alt;
res.push_back(hv_land.at(alt));
// go arround the region of alt using the 'butterfly' method, to find the other two lands which seem adjacent
for(int d: {-1, 1}) {
auto hs1 = hs;
for(int i=0; i<100; i++) {
hs1 += d;
hs1 += wstep;
if(!hs1.at->alt) { hs1 += wstep; continue; }
auto alt1 = hs1.at->alt->alt;
if(alt1 != alt) {
res.push_back(hv_land.at(alt1)); break;
}
hs1 += d;
}
}
}
if(res.empty()) return { laBarrier };
return res;
}
void extend_altmap_voronoi(heptagon *h) {
if(h->alt) return;
auto ci = voronoi_candidate(h);
if(ci.bqty == 0) {
new_voronoi_root(h, -30, hrand(h->type), firstland, laBarrier);
new_voronoi_root(h, -30, hrand(h->type), firstland);
return;
}
else if(ci.bqty > 0 && isize(ci.free_dirs)) {
@ -305,15 +332,15 @@ void extend_altmap_voronoi(heptagon *h) {
ld growth = expansion.get_growth();
ld odds = pow(growth, ci.candidate->distance) * isize(ci.free_dirs);
if(hrandf() < odds / (1 + odds)) {
eLand last = hv_land[ci.candidate->alt];
eLand last2 = hv_last_land[ci.candidate->alt];
vector<eLand> lands_list = list_adjacent_lands(h);
auto dist = ci.candidate->distance;
// in PURE, could be a tie, or the new root could win
if(PURE) dist -= hrand(2);
// in BITRUNCATED, it could change too.. need a better formula probably
if(BITRUNCATED) dist += hrand(3) - 1;
// do not care about others...
new_voronoi_root(h, dist, hrand_elt(ci.free_dirs), getNewLand(last, last2), last);
new_voronoi_root(h, dist, hrand_elt(ci.free_dirs), getNewLand2(lands_list));
return;
}
}
@ -502,13 +529,18 @@ EX void generateTreasureIsland(cell *c) {
for(int i=0; i<c->type; i++) {
cell *c2 = createMov(c, i);
if(!eubinary) currentmap->extend_altmap(c2->master);
if(greater_alt(c, c2)) {
auto ok = [&] (cell *c2) {
if(ls::hv_structure() && get_voronoi_winner(c2).first != get_voronoi_winner(c).first) return false;
return true;
};
if(ok(c2) && greater_alt(c, c2)) {
ctab.push_back(c2);
qlo = i; qhi = i;
while(true && isize(ctab) < c->type) {
qlo--;
c2 = c->cmodmove(qlo);
if(!have_alt(c2)) break;
if(!ok(c2)) break;
if(celldistAlt(c2) >= celldistAlt(c)) break;
ctab.push_back(c2);
}
@ -516,6 +548,7 @@ EX void generateTreasureIsland(cell *c) {
qhi++;
c2 = c->cmodmove(qhi);
if(!have_alt(c2)) break;
if(!ok(c2)) break;
if(celldistAlt(c2) >= celldistAlt(c)) break;
ctab.push_back(c2);
}
@ -529,6 +562,7 @@ EX void generateTreasureIsland(cell *c) {
return;
}
cell* c2 = c->cmodmove((qlo+qhi)/2);
if(ls::voronoi_structure() && c2->land != laCaribbean) c2->land = laCaribbean;
generateTreasureIsland(c2);
if(!src) {
c->wall = c2->wall;
@ -669,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)
@ -971,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);
}
@ -1098,6 +1135,7 @@ EX void setLandSphere(cell *c) {
vector<eLand> euland;
map<int, eLand> euland3;
map<int, eLand> euland3_hash;
EX map<array<int, 3>, eLand> landscape_lands;
EX eLand& get_euland(int c) {
euland.resize(max_vec);
@ -1110,6 +1148,8 @@ EX void clear_euland(eLand first) {
if(!nonisotropic) euland[0] = euland[1] = euland[max_vec-1] = first;
euland3.clear();
euland3[0] = first;
landscape_lands.clear();
landscape_lands[make_array(0,0,0)] = first;
}
bool valid_wall_at(int c) {
@ -1289,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;
@ -1734,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;
@ -1755,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 &&
@ -1819,7 +1874,6 @@ EX void start_camelot(cell *c) {
EX bool debug_voronoi;
EX map<heptagon*, eLand> hv_land;
EX map<heptagon*, eLand> hv_last_land;
EX void build_horocycles(cell *c, cell *from) {
@ -1840,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;
}
@ -1858,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
@ -1883,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);
@ -2282,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

@ -1469,14 +1469,15 @@ EX int celldistance(cell *c1, cell *c2) {
if(hyperbolic && WDIM == 3) return reg3::celldistance(c1, c2);
#endif
if(INVERSE) {
/* if(INVERSE) {
c1 = gp::get_mapped(c1);
c2 = gp::get_mapped(c2);
return UIU(celldistance(c1, c2)) / 2;
/* TODO */
}
// that does not seem to work
} */
if(euclid) return clueless_celldistance(c1, c2);
if(INVERSE) return clueless_celldistance(c1, c2);
return hyperbolic_celldistance(c1, c2);
}

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) {
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;
@ -971,7 +969,7 @@ void celldrawer::draw_halfvine() {
}
else if(wmspatial || GDIM == 3) {
floorshape& shar = *((wmplain || GDIM == 3) ? (floorshape*)&cgi.shFloor : (floorshape*)&cgi.shFeatherFloor);
floorshape& shar = *(GDIM == 3 ? (floorshape*)&cgi.shFullFloor : wmplain ? (floorshape*)&cgi.shFloor : (floorshape*)&cgi.shFeatherFloor);
set_floor(shar);
@ -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, 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);
}
}
@ -2029,6 +2061,7 @@ void celldrawer::bookkeeping() {
modist2 = modist; mouseover2 = mouseover;
modist = dist;
mouseover = c;
mouseoverV = V;
}
else if(dist < modist2) {
modist2 = dist;
@ -2078,7 +2111,7 @@ void celldrawer::draw_cellstat() {
if(c->land == laMirrored || c->land == laMirrorWall2 || c->land == laMirrored2) {
string label = its(c->landparam);
queuestr(V, 1 * .2, label, 0xFFFFFFFF, 1);
queuestr(V, mapfontscale / 500, label, 0xFFFFFFFF, 1);
}
if(debug_tiles && mod_allowed()) {
@ -2104,22 +2137,22 @@ void celldrawer::draw_cellstat() {
#endif
else
label = its(shvid(c));
queuestr(V, .5, label, 0xFFFFFFFF, 1);
queuestr(V, mapfontscale / 200, label, 0xFFFFFFFF, 1);
for(int i=0; i<c->type; i++) {
queuestr(V * rgpushxto0(currentmap->get_corner(c, i, 4)), .2, its(i), 0xFFFFFFFF, 1);
queuestr(V * rgpushxto0(mid(currentmap->get_corner(c, i, 4), currentmap->get_corner(c, i+1, 5))), .2, its(i), 0xFFFFFFFF, 1);
queuestr(V * rgpushxto0(currentmap->get_corner(c, i, 4)), mapfontscale / 500, its(i), 0xFFFFFFFF, 1);
queuestr(V * rgpushxto0(mid(currentmap->get_corner(c, i, 4), currentmap->get_corner(c, i+1, 5))), mapfontscale / 500, its(i), 0xFFFFFFFF, 1);
}
}
if(debug_voronoi && ls::voronoi_structure() && mod_allowed()) {
if(debug_voronoi && ls::hv_structure() && mod_allowed()) {
auto p = get_voronoi_winner(c);
queuestr(V, .2, its(p.second), index_pointer_int(p.first) * 0x7F3015, 1);
queuestr(V, mapfontscale / 500, its(p.second), index_pointer_int(p.first) * 0x7F3015, 1);
}
if(cmode & sm::TORUSCONFIG) {
auto p = euc::coord_display(V, c);
if(p.second != "")
queuestr(V, p.first ? .2 : .6, p.second, p.first ? 0xFFFFFFD0 : 0xFFFF0040, 1);
queuestr(V, (p.first ? .2 : .6) * mapfontscale / 100, p.second, p.first ? 0xFFFFFFD0 : 0xFFFF0040, 1);
}
#if CAP_EDIT
@ -2134,13 +2167,13 @@ void celldrawer::draw_cellstat() {
string label = its(si.id & 255);
color_t col = forecolor ^ colorhash(si.id >> 8);
queuestr(V, .5, label, 0xFF000000 + col);
queuestr(V, mapfontscale / 200, label, 0xFF000000 + col);
}
#endif
if(debug_cellnames && pointer_indices.count(c)) {
shstream ss; print(ss, c);
queuestr(V, .5, ss.s, 0xFFFFFFFF);
queuestr(V, mapfontscale / 200, ss.s, 0xFFFFFFFF);
queuepoly(V * ddspin(c, 0), cgi.shAsymmetric, darkena(0x000000, 0, 0xC0));
}
}
@ -2232,9 +2265,6 @@ void celldrawer::draw_wall_full() {
else if(patterns::whichShape == '2')
set_floor(cgi.shMFloor3);
else if(embedded_plane && qfi.fshape == &cgi.shFloor)
set_floor(cgi.shFullFloor);
#if CAP_TEXTURE
else if(GDIM == 2 && texture::config.apply(c, Vf, darkena(fcol, fd, 0xFF))) ;
#endif
@ -2271,6 +2301,8 @@ void celldrawer::draw_wall_full() {
else set_land_floor(Vf);
if(embedded_plane && qfi.fshape == &cgi.shFloor) set_floor(cgi.shFullFloor);
// actually draw the floor
if(chasmg == 2) ;
@ -2497,20 +2529,13 @@ void celldrawer::draw_item_full() {
if(doHighlight()) asciiborder = kind_outline(it) >> 8;
if(it == itCompass && isPlayerOn(c)) {
cell *c1 = c ? findcompass(c) : NULL;
if(c1) {
shiftmatrix P = ggmatrix(c1);
shiftpoint P1 = tC0(P);
queuestr(P1, 2*vid.fsize, "X", 0x10100 * int(128 + 100 * sintick(150)));
queuestr(P1, vid.fsize, its(-compassDist(c)), 0x10101 * int(128 - 100 * sintick(150)));
addauraspecial(P1, 0xFF0000, 0);
}
shiftpoint dummy;
mark_compass(c, dummy);
}
}
if(it) {
if((c->land == laWhirlwind || c->item == itBabyTortoise || c->land == laWestWall) && c->wall != waBoat) {
if(c->wall != waBoat) {
double footphase = 0;
applyAnimation(c, Vboat, footphase, LAYER_BOAT);
}
@ -2581,7 +2606,7 @@ void celldrawer::draw_monster_full() {
bool dm = drawMonster(V, c->type, c, moncol, asciicol);
if(dm) onradar = false;
#if CAP_SHAPES
if(isize(ptds) != q) {
if(isize(ptds) != q && !(c == lmouseover_distant && isDie(c->monst))) {
if(WDIM == 2 && GDIM == 3 && abs(cgi.SLEV[sl] - cgi.FLOOR) > 1e-6)
pushdown(c, q, V, cgi.SLEV[sl] - cgi.FLOOR, false, false);
if(GDIM ==2 && abs(geom3::factor_to_lev(zlevel(tC0(Vboat.T)))) > 1e-6)
@ -2855,7 +2880,7 @@ void celldrawer::draw() {
if(callhandlers(false, hooks_drawcell, c, V)) return;
if(history::on || inHighQual || WDIM == 3 || sightrange_bonus > gamerange_bonus) checkTide(c);
checkTide(c);
if(1) {
@ -2962,7 +2987,7 @@ void celldrawer::draw() {
string s = s0+asciichar;
dynamicval<color_t> p(poly_outline, asciiborder << 8);
if(!wmascii3)
queuestrn(V, 1, s, darkenedby(asciicol, darken), 2);
queuestrn(V, mapfontscale / 100, s, darkenedby(asciicol, darken), 2);
else if(highwall(c) && conegraph(c)) {
const int layers = 1 << detaillevel;
string s1 = s0+asciichar1;
@ -2970,7 +2995,7 @@ void celldrawer::draw() {
for(int z=0; z<layers; z++)
queuestrn(orthogonal_move_fol(V, zgrad0(0, geom3::actual_wall_height(), z, layers)), 1. - z * .5 / layers, s1, darkenedby(gradient(bordcolor, asciicol1, -layers, z, layers), darken), 1);
poly_outline = asciiborder << 8;
queuestrn(orthogonal_move_fol(V, cgi.WALL), asciicol == asciicol1 && asciichar == asciichar1 ? .5 : 1, s, darkenedby(asciicol, darken), 2);
queuestrn(orthogonal_move_fol(V, cgi.WALL), (asciicol == asciicol1 && asciichar == asciichar1 ? .5 : 1) * mapfontscale / 100, s, darkenedby(asciicol, darken), 2);
}
else if(highwall(c)) {
const int layers = 1 << detaillevel;
@ -2979,15 +3004,15 @@ void celldrawer::draw() {
for(int z=0; z<layers; z++)
queuestrn(orthogonal_move_fol(V, zgrad0(0, geom3::actual_wall_height(), z, layers)), 1, s1, darkenedby(gradient(bordcolor, asciicol1, -layers, z, layers), darken), 1);
poly_outline = asciiborder << 8;
queuestrn(orthogonal_move_fol(V, cgi.WALL), 1, s, darkenedby(asciicol, darken), 2);
queuestrn(orthogonal_move_fol(V, cgi.WALL), mapfontscale / 100, s, darkenedby(asciicol, darken), 2);
}
else if((sl = snakelevel(c))) {
string s1 = s0+asciichar1;
poly_outline = bordcolor << 8;
for(int z=0; z<sl*4; z++) if(z%4 == 0)
queuestrn(orthogonal_move_fol(V, zgrad0(0, cgi.slev * sl, z, sl*4)), 1, s1, darkenedby(gradient(bordcolor, asciicol1, -sl, z, sl*4), darken), 1);
queuestrn(orthogonal_move_fol(V, zgrad0(0, cgi.slev * sl, z, sl*4)), mapfontscale / 100, s1, darkenedby(gradient(bordcolor, asciicol1, -sl, z, sl*4), darken), 1);
poly_outline = asciiborder << 8;
queuestrn(orthogonal_move_fol(V, cgi.SLEV[sl]), 1, s, darkenedby(asciicol, darken), 2);
queuestrn(orthogonal_move_fol(V, cgi.SLEV[sl]), mapfontscale / 100, s, darkenedby(asciicol, darken), 2);
}
// else if(c->wall == waChasm) {
// const int layers = 1 << detaillevel;
@ -2996,12 +3021,12 @@ void celldrawer::draw() {
else if(chasmgraph(c)) {
string s1 = s0+asciichar1;
poly_outline = bordcolor << 8;
queuestrn(orthogonal_move_fol(V, cgi.BOTTOM), 1, s1, darkenedby(gradient(bordcolor, asciicol1, 0, 0.3, 1), darken), 2);
queuestrn(orthogonal_move_fol(V, cgi.BOTTOM), mapfontscale / 100, s1, darkenedby(gradient(bordcolor, asciicol1, 0, 0.3, 1), darken), 2);
poly_outline = asciiborder << 8;
queuestrn(V, 1, s, darkenedby(asciicol, darken), 2);
queuestrn(V, mapfontscale / 100, s, darkenedby(asciicol, darken), 2);
}
else
queuestrn(V, 1, s, darkenedby(asciicol, darken), 2);
queuestrn(V, mapfontscale / 100, s, darkenedby(asciicol, darken), 2);
}
draw_grid();

View File

@ -5039,3 +5039,213 @@ Updates to the crossbow mode:
- fixed crossbow mode not changing the PTM/etc. scoreboards
- mode change confirmation is now only required when actually changing a relevant option
- new aim style 'geometric'
2023-12-02 12:54 Update 12.1z:
Gameplay (mostly crossbow modes)
- an option to automatically shoot when clicking a tile with mouse
- press 'f' + direction for auto fire at distant enemies in the given direction
- bulls are now enraged by crossbow shots
- ratlings no longer move when shooting pointlessly
- the warped space distracts you from reloading while staying in place
- Warped Coast/Sea now prevents crossbow bolts from moving between triangles
- clarified that only direct melee attacks trigger Storms/Flash
- fixed Horns in the crossbow mode; the unarmed Princess is now also able to use Empathy+Thorns and Empathy+Horns
- reduced CR3 land requirement to 20 in casual
Other
- fixed the drawing mode on quotient spaces (including torus display)
- fixed point recognition in rug mode
- cleaned up high-FOV and stereo modes into one setting
2023-12-27 12:54 Update 13.0:
Summary post: https://zenorogue.blogspot.com/2023/12/hyperrogue-130.html
Voronoi mode fixes:
- fixed Caribbean
- made Rlyeh and Temple appear, and Haunted and Free Fall are now unavailable
- better land compatibility
- fixed CR2
- fixed Land of Storms (in Horodisk and Voronoi)
Crossbow fixes:
- in shmup, crossbow bolts now pierce multi-tile monsters, and fire-on-mouse is disabled
- remove crossbow paths on orb use
- pressing ESC key while in fire mode now disables the fire mode
- geometric crossbow can now hit monsters on the edge of vision and inside walls
- crossbow achievements and leaderboards
- fixed false game over messages after shooting a bow
other updates:
- updated the Czech and Polish translations
- display achievement eligiblity
- make the Key fireproof; make tortoise if first 21/21 tile created in > 100 turns (thanks to jlm)
Other fixes:
- fixed restoring golems in casual mode
- fixed a crash while loading races
- fixed a bug with embedded maps (i.e., 2D maps in 3D) being destroyed when the game is restarted
- fixed the drawing of half-vines and mirror walls in spatial
- fixed the bug where tides may move on orb use
- fixed Sol, NIH and SolN embeddings being always displayed as legal
- fixed the name displayed on mouseover for slime
2024-01-12 08:59 Update 13.0a:
- fixed some bugs with high-FOV modes (reset shaders, show upper FOV ranges correctly, buggy two-eye rendering)
- as a new positive, the Curse of Fatigue makes you not care about roses when very fatigued
- changed one Prince(ss) message
- crossbow leaderboards should be fixed
- fixed button placement on Android once more
- fixed mirrors in crossbow fire mode
- the bump-to-shoot flag now actually works
- fixed a bug in "memory saving" mode to not remove the current altmap
- variant fisheye projection
- fixed tides in shmup and when scrolling
- the dipping rule no longer affects Tiger's Eyes
- screenshots were sometimes not correctly centered
2024-02-23 01:34 Update 13.0b:
When you are checkmated or die, a message explaining the cause is now displayed in the quit screen and saved in the local score file.
Crossbow fixes:
- opening inventory mode when you can just shoot should be fixed
- rusałka curses now work
- fixed tricking Pikemen with a bow
- while rosed, you can now only shoot when this kills a monster at point blank in the rose direction
Crash fixes:
- fixed crash when e.g. entering 'ma' as a value, or when editing some settings such as sight range bonus
- fixed a crash when viewing help on tide tiles (thanks to jlm)
- fixed a crash with too large band
- fixed some cases where untruncated/unrectified/warped maps would freeze when computing distances or crash due to trees are not known
Gameplay fixes:
- restarting a race now resets pause counter
- World Turtle kills are recorded (thanks to jlm)
- boat can go thru non-adjacent using Orb of Warp in shmup
- fixed the items (key, OoY, baby tortoise) moved by the Orb of Chaos and Curse of Repulsion
- fixed the Yard bug (graveless graveyard when you somehow used Orb of Safety in the Haunted Woods strip)
- Trollheim no longer generates adjacent non-unlocked troll lands
- alternative land unlock rules when monster/item requested is not available due to geometry etc
Other:
- in Goldberg variation, x/y limit is now based on what the engine allows, and 'dual of current' no longer can circumvent the limits
- New projection: polar coordinates
2024-02-24 09:54 Update 13.0c:
- fixed the off-by-one error in thehelp line displayed for tides and lava
- fixed a bug with rusalka-cursing the first tile when you shoot
- when you press ESC in the gameover screen, the YASC message is displayed
- special YASC message for pinches, and being on the Round Table
- in YASC messages, mention the knights blocking the way, and also mention their names
2024-03-24 11:32 Update 13.0d:
System:
* itch.io Windows binaries and Steam Windows/Linux binaries now use SDL2 instead of SDL1.2
Custom mode:
* A new mode where you can select the lands to be used.
* Another menu can be used to save a mode to a file.
* Enabling Halloween or Space Rocks in infinite geometries now produces something that makes sense.
* Previously changing the creature scale was disabled in non-cheat shmup. Now it can be changed (but it counts as a cheat).
* New land structure 'landscape'.
Graphics:
* Font scale used in ASCII maps now can be changed.
* Items moved by Orb of Water, Magnetism, Winter, Space, and Repulsion are now animated.
* VR: fixed items, Ivy, compasses, etc. being placed incorrectly in 2.5D.
* VR: compass/Yendor targets now should be displayed.
Gameplay:
* Void Beasts are now pulled by Orb of Air.
* Changed the electrical properties of some walls to make Eclectic City more friendly.
* Trees etc are now mentioned as blockers in YASC messages.
* YASC codes work better if killed on a 10+ tile.
Alternate geometries:
* Clear more walls when generating Wild West in high GP.
* Better Emerald in Octagon chamfered.
* Fixed Emerald Mine and Vineyard generating very bad in {n,oo} and binary tiling.
* Fixed the lack of non-trapdoors in Zebra 435.
* Better 'pseudohept' tiles in INVERSE tilings.
* In grid mode, don't try to draw greatwall lines outside of normal geometry pure/bitruncated.
* Nicer cell boundaries used in Archimedean and irregular tilings.
* When you save an irregular map using Orb of Safety or map editor (or custom mode), it should now save the irregular map used.
Bug fixes:
* Fixed dice hints over different heights.
* 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

@ -27,29 +27,49 @@ EX bool canmove = true;
// how many monsters are near
EX eMonster who_kills_me;
EX cell *who_kills_me_cell;
EX int lastkills;
EX vector<bool> legalmoves;
/* why is a move illegal */
EX vector<int> move_issues;
#if HDR
struct moveissue {
int type;
int subtype;
eMonster monster;
cell *where;
};
static constexpr int miVALID = 10000;
static constexpr int miENTITY = 11000;
static constexpr int miRESTRICTED = 10100;
static constexpr int miTHREAT = 10010;
static constexpr int miWALL = 10001;
static constexpr int siWALL = 1;
static constexpr int siMONSTER = 2;
static constexpr int siGRAVITY = 3;
static constexpr int siROSE = 4;
static constexpr int siITEM = 5;
static constexpr int siWIND = 6;
static constexpr int siCURRENT = 7;
static constexpr int siFATIGUE = 8;
static constexpr int siWARP = 9;
static constexpr int siUNKNOWN = 10;
#endif
EX int checked_move_issue;
/* why is a move illegal */
EX vector<moveissue> move_issues;
EX moveissue checked_move_issue;
EX moveissue stay_issue;
EX int yasc_code;
EX void check_if_monster() {
eMonster m = cwt.peek()->monst;
if(m && m != passive_switch && !isFriendly(m))
checked_move_issue = miENTITY;
checked_move_issue = moveissue { miENTITY, siMONSTER, m, cwt.peek() };
}
EX bool hasSafeOrb(cell *c) {
@ -108,14 +128,14 @@ EX bool monstersnear(cell *c, eMonster who) {
bool kraken_will_destroy_boat = false;
elec::builder b;
if(elec::affected(c)) { who_kills_me = moLightningBolt; res++; }
if(elec::affected(c)) { who_kills_me = moLightningBolt; who_kills_me_cell = nullptr; res++; }
if(c->wall == waArrowTrap && c->wparam == 2) {
who_kills_me = moArrowTrap; res++;
who_kills_me = moArrowTrap; who_kills_me_cell = nullptr; res++;
}
for(auto c1: crush_now) if(c == c1) {
who_kills_me = moCrusher; res++;
who_kills_me = moCrusher; who_kills_me_cell = nullptr; res++;
}
if(who == moPlayer || items[itOrbEmpathy]) {
@ -126,7 +146,7 @@ EX bool monstersnear(cell *c, eMonster who) {
if(havewhat&HF_OUTLAW) {
for(cell *c1: gun_targets(c))
if(c1->monst == moOutlaw && !c1->stuntime) {
res++; who_kills_me = moOutlaw;
res++; who_kills_me = moOutlaw; who_kills_me_cell = c1;
}
}
@ -157,13 +177,11 @@ EX bool monstersnear(cell *c, eMonster who) {
}
// flashwitches cannot attack if it would kill another enemy
if(c3->monst == moWitchFlash && flashWouldKill(c3, 0)) continue;
res++, who_kills_me = c3->monst;
res++, who_kills_me = c3->monst; who_kills_me_cell = c3;
}
// 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;
@ -179,12 +197,12 @@ EX bool monstersnear(cell *c, eMonster who) {
eaten = true;
else if(c2->monst != moHexSnake) continue;
}
res++, who_kills_me = m;
res++, who_kills_me = m; who_kills_me_cell = c2;
}
}
if(kraken_will_destroy_boat && !krakensafe(c) && warningprotection(XLAT("This move appears dangerous -- are you sure?"))) {
if (res == 0) who_kills_me = moWarning;
if (res == 0) who_kills_me = moWarning; who_kills_me_cell = nullptr;
res++;
} else {
if(who == moPlayer && res && (markOrb2(itOrbShield) || markOrb2(itOrbShell)) && !eaten)
@ -239,7 +257,7 @@ EX bool monstersnear_aux() {
/** like monstersnear but add the potential moves of other players into account */
EX bool monstersnear_add_pmi(player_move_info pmi0) {
if(suicidal) {
who_kills_me = moPlayer;
who_kills_me = moPlayer; who_kills_me_cell = nullptr;
return true;
}
pmi.push_back(pmi0);
@ -280,6 +298,110 @@ EX bool swordConflict(const player_move_info& sm1, const player_move_info& sm2)
return false;
}
EX string yasc_message;
EX string blocking_monster_name(const moveissue& mi) {
if(mi.monster == moKnight && mi.where)
return XLAT("%1 the Knight", camelot::knight_name(mi.where));
else
return dnameof(mi.monster);
}
EX void create_yasc_message() {
set<pair<cell*, string>> captures;
auto all = move_issues;
all.push_back(stay_issue);
for(auto c: all) if(c.type == miTHREAT) captures.emplace(c.where, blocking_monster_name(c));
vector<string> context;
if(!captures.empty()) {
string msg = "captured by ";
map<string, int> qties;
for(auto ca: captures) qties[ca.second]++;
int iqties = 0;
for(auto q: qties) {
if(iqties && iqties == isize(qties) - 1) msg += " and ";
else if(iqties) msg += ", ";
msg += q.first;
if(q.second > 1) msg += " (x" + its(q.second) + ")";
iqties++;
}
context.push_back(msg);
}
int idx = 0;
for(auto c: all) if(idx == 0 && c.subtype == siROSE) context.push_back("rosed"), idx = 1;
for(auto c: all) if(idx < 2 && c.subtype == siWIND) context.push_back("blown away"), idx = 2;
for(auto c: all) if(idx < 3 && c.subtype == siGRAVITY) context.push_back("falling"), idx = 3;
for(auto c: all) if(idx < 4 && c.subtype == siFATIGUE) context.push_back("fatigued"), idx = 4;
for(auto c: all) if(idx < 5 && c.subtype == siCURRENT) context.push_back("whirled"), idx = 5;
bool in_ctx = true;
set<string> blocks;
int index = 0;
for(auto c: all) {
if(c.type == miENTITY && !captures.count({c.where, blocking_monster_name(c)})) blocks.insert(blocking_monster_name(c));
else if(c.type == miWALL && c.subtype == siMONSTER && !captures.count({c.where, blocking_monster_name(c)})) blocks.insert(blocking_monster_name(c));
else if(c.subtype == siITEM) blocks.insert("item");
else if(c.subtype == siWALL) {
if(c.where == cwt.at) {
if(in_ctx) {
if(c.where->wall == waNone && c.where->land == laBrownian)
context.push_back("on level 3");
else if(c.where->wall == waRoundTable)
context.push_back("being polite");
else
context.push_back(winf[c.where->wall].flags & WF_ON ? XLAT("on %the1", c.where->wall) : XLAT("in %the1", c.where->wall));
}
in_ctx = false;
}
else if(c.where && c.where->wall != cwt.at->wall) blocks.insert(dnameof(c.where->wall));
}
else if(c.type == siWARP) blocks.insert("warp");
index++;
}
if(!blocks.empty()) {
string block = "blocked by ";
int iqties = 0;
for(auto& q: blocks) {
if(iqties && iqties == isize(blocks) - 1) block += " and ";
else if(iqties) block += ", ";
block += q;
iqties++;
}
context.push_back(block);
}
yasc_message = "";
int iqties = 0;
for(auto& ctx: context) {
if(iqties == 0) ;
else if(iqties == 1) yasc_message += " while ";
else if(iqties == isize(context) - 1) yasc_message += " and ";
else yasc_message += ", ";
yasc_message += ctx;
iqties++;
}
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(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);
}
}
println(hlog, "YASC_MESSAGE: ", yasc_message);
}
int yasc_recode(int x) {
if(cwt.at->type < 10 || x == 0) return x;
return yasc_recode(x / 10) * 100 + (x % 10);
};
EX void checkmove() {
if(dual::state == 2) return;
@ -295,15 +417,17 @@ EX void checkmove() {
if(hardcore) return;
legalmoves.clear(); legalmoves.resize(cwt.at->type+1, false);
move_issues.clear(); move_issues.resize(cwt.at->type, 0);
move_issues.clear(); move_issues.resize(cwt.at->type);
canmove = haveRangedTarget();
items[itWarning]+=2;
if(movepcto(-1, 0, true))
canmove = legalmoves[cwt.at->type] = true;
stay_issue = checked_move_issue;
if(true) {
for(int i=0; i<cwt.at->type; i++) {
dynamicval<bool> fm(bow::fire_mode, false);
if(movepcto(1, -1, true)) {
canmove = legalmoves[cwt.spin] = true;
}
@ -322,7 +446,9 @@ EX void checkmove() {
yasc_code = 0;
for(int i=0; i<cwt.at->type; i++)
yasc_code += move_issues[i];
yasc_code += yasc_recode(move_issues[i].type);
if(!canmove && bow::crossbow_mode() && !items[itCrossbow]) canmove = bow::have_bow_target();
#if CAP_INV
if(inv::on && !canmove && !inv::incheck) {
@ -338,12 +464,12 @@ EX void checkmove() {
}
#endif
if(!canmove && bow::crossbow_mode() && !items[itCrossbow]) canmove = bow::have_bow_target();
if(!canmove) {
create_yasc_message();
achievement_final(true);
if(cmode & sm::NORMAL) showMissionScreen();
}
else yasc_message = "";
if(canmove && timerstopped) {
timerstart = time(NULL);

View File

@ -601,6 +601,7 @@ static constexpr flagtype WF_CISLAND = Flag(19);
static constexpr flagtype WF_SULPHURIC = Flag(20);
static constexpr flagtype WF_HALFVINE = Flag(21);
static constexpr flagtype WF_NONBLOCK = Flag(22);
static constexpr flagtype WF_ON = Flag(23); // just for grammar: 'on' not 'in'
struct walltype {
char glyph;
@ -1031,7 +1032,7 @@ enum eModel : int {
// 39..48
mdPoorMan, mdPanini, mdRetroCraig, mdRetroLittrow, mdRetroHammer, mdThreePoint, mdLiePerspective, mdLieOrthogonal, mdRelPerspective, mdRelOrthogonal,
// 49..50
mdHorocyclicEqa, mdConformalSquare,
mdHorocyclicEqa, mdConformalSquare, mdFisheye2, mdPolar,
// 51..
mdGUARD, mdPixel, mdHyperboloidFlat, mdPolynomial, mdManual
};
@ -1095,6 +1096,8 @@ EX vector<modelinfo> mdinf = {
{X3("relativistic orthogonal"), mf::euc_boring},
{X3("horocyclic equal-area"), mf::euc_boring | mf::equiarea | mf::orientation | mf::horocyclic},
{X3("conformal square"), mf::orientation | mf::broken | mf::transition},
{X3("variant fisheye"), 0},
{X3("polar coordinates"), mf::orientation},
{X3("guard"), mf::technical},
{X3("pixel"), mf::technical},
{X3("hypflat"), mf::technical},

View File

@ -335,6 +335,19 @@ int arg::readCommon() {
clearMessages();
}
else if(argis("-save-mode")) {
save_mode_to_file(shift_args());
}
else if(argis("-load-mode")) {
try {
load_mode_from_file(shift_args());
}
catch(hstream_exception& e) {
println(hlog, "exception!");
}
}
// informational
else if(argis("-version") || argis("-v")) {
printf("HyperRogue version " VER "\n");

View File

@ -215,10 +215,14 @@ EX namespace elec {
if(c->wall == waSea || c->wall == waGrounded) return ecGrounded;
if(c->wall == waSandstone || c->wall == waDeadTroll ||
c->wall == waDeadTroll2 ||
among(c->wall, waBigTree, waSmallTree, waExplosiveBarrel, waRed1, waRed2, waRed3) ||
c->wall == waExplosiveBarrel ||
c->wall == waVinePlant ||
c->wall == waMetal || isAlchAny(c))
return isElectricLand(c) ? ecConductor : ecGrounded;
if(c->wall == waBigTree || c->wall == waSmallTree)
return ecGrounded;
if(among(c->wall, waRed1, waRed2, waRed3, waRubble, waDeadfloor2))
return ecIsolator;
if(c->wall == waBarrier)
return ecIsolator;
if(c->wall == waChasm)
@ -644,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(); )
}
}
@ -738,7 +742,7 @@ struct info {
if(m == moPrincess)
addMessage(XLAT("\"I want my revenge. Stun a guard and leave him for me!\"", m));
else
addMessage(XLAT("\"That felt great. Thanks!\"", m));
addMessage(XLAT("\"I wouldn't say killing that guard was not pleasant...\"", m));
}
else if(msgid == 2 && d >= 70 && inpalace) {
addMessage(XLAT("\"Bring me out of here please!\"", m));
@ -2126,6 +2130,8 @@ EX namespace heat {
if(c->monst == moDesertman) hmod += 4 * xrate;
if(c->monst == moAngryDie) hmod += 4 * xrate;
if(c->monst == moMonkey) hmod += xrate;
if(c->wall == waCharged) hmod += xrate * .25;
if(c->wall == waGrounded) hmod -= xrate * .25;
if(c->wall == waDeadTroll) hmod -= 2 * xrate;
if(c->wall == waDeadTroll2) hmod -= 1.5 * xrate;
if(c->wall == waBigStatue) hmod -= .5 * xrate;
@ -2478,7 +2484,9 @@ EX void livecaves() {
if(hv > 0 && c->wall == waNone) {
if(c->item && c->cpdist == 1 && markOrb(itOrbWater)) {
bool saf = c->item == itOrbSafety;
eItem it = c->item;
collectItem(c, c);
if(it && !c->item) animate_item_throw(c, cwt.at, it);
if(saf) return;
}
c->wall = waSea;
@ -2513,6 +2521,7 @@ EX namespace tortoise {
EX map<cell*, int> emap;
EX map<cell*, int> babymap;
EX int last;
EX int last21tort;
#if HDR
enum tflag {
@ -2943,6 +2952,8 @@ EX }
EX namespace kraken {
EX map<cell*, bool> half_killed;
EX cell *head(cell *c) {
if(c->monst == moKrakenH) return c;
if(c->monst == moKrakenT) return c->move(c->mondir);
@ -3044,6 +3055,7 @@ EX namespace kraken {
c3->monst = moNone;
}
c->monst = moKrakenH;
if(half_killed.count(c2)) { half_killed[c] = half_killed[c2]; half_killed.erase(c2); }
vector<pair<cell*, cell*> > acells;
acells.push_back(make_pair(c2, c));
forCellIdEx(c3, i, c) {
@ -3494,6 +3506,7 @@ EX namespace ca {
}
for(int i=0; i<dcs; i++) {
cell *c = allcells[i];
if(c->land != laCA) continue;
auto last = c->wall;
c->wall = willlive[i] ? wlive : waNone;
if(c->wall != last) {
@ -3515,6 +3528,7 @@ auto ccm = addHook(hooks_clearmemory, 0, [] () {
clearing::stats.clear();
clearing::score.clear();
tortoise::emap.clear();
kraken::half_killed.clear();
tortoise::babymap.clear();
dragon::target = NULL;
#if CAP_FIELD
@ -3547,6 +3561,7 @@ auto ccm = addHook(hooks_clearmemory, 0, [] () {
addHook(hooks_removecells, 0, [] () {
for(cell *c: removed_cells) clearing::score.erase(c);
for(auto& am: adj_memo) am.clear();
for(cell *c: removed_cells) kraken::half_killed.erase(c);
eliminate_if(heat::offscreen_heat, is_cell_removed);
eliminate_if(heat::offscreen_fire, is_cell_removed);
eliminate_if(princess::infos, [] (princess::info*& i) {

View File

@ -166,11 +166,11 @@ EX namespace brownian {
ONEMPTY {
if(hrand(10000) < min(250, 100 + 2 * PT(kills[moAcidBird] + kills[moBrownBug], 50)) * (25 + min(items[itBrownian], 100)) / 25 && c->landparam >= 4 && c->landparam < 24)
c->item = itBrownian;
if(hrand_monster(8000) < 15 + items[itBrownian])
if(hrand_monster_in(laBrownian, 8000) < 15 + items[itBrownian])
c->monst = moAcidBird;
else if(hrand_monster(8000) < 15)
else if(hrand_monster_in(laBrownian, 8000) < 15)
c->monst = moAlbatross;
else if(hrand_monster(8000) < 15 + items[itBrownian]) {
else if(hrand_monster_in(laBrownian, 8000) < 15 + items[itBrownian]) {
c->monst = moBrownBug;
c->hitpoints = 3;
}
@ -291,7 +291,7 @@ extern array<feature, 21> features;
#define VF [] (cell *c)
bool hrand_var(int i) { return hrand_monster(i) < 25 + items[itVarTreasure] + yendor::hardness(); }
bool hrand_var(int i) { return hrand_monster_in(laVariant, i) < 25 + items[itVarTreasure] + yendor::hardness(); }
array<feature, 21> features {{
feature{(color_t)(-0x202020), 5, moNecromancer, VF {
@ -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

@ -43,6 +43,7 @@ struct setting {
string parameter_name;
string config_name;
string menu_item_name;
bool menu_item_name_modified;
string help_text;
reaction_t reaction;
char default_key;
@ -110,6 +111,7 @@ struct list_setting : setting {
is_editable = true;
options = o;
this->menu_item_name = menu_item_name;
menu_item_name_modified = true;
default_key = key;
return this;
}
@ -167,6 +169,7 @@ template<class T> struct enum_setting : list_setting {
needs_confirm = true;
return this;
}
virtual cld get_cld() override { return get_value(); }
};
/** transmatrix with equality, so we can construct val_setting<matrix_eq> */
@ -222,6 +225,7 @@ struct float_setting : public val_setting<ld> {
this->min_value = min_value;
this->max_value = max_value;
this->menu_item_name = menu_item_name;
menu_item_name_modified = true;
this->help_text = help_text;
this->step = step;
default_key = key;
@ -254,6 +258,7 @@ struct int_setting : public val_setting<int> {
this->min_value = min_value;
this->max_value = max_value;
this->menu_item_name = menu_item_name;
menu_item_name_modified = true;
this->help_text = help_text;
this->step = step;
default_key = key;
@ -280,6 +285,7 @@ struct color_setting : public val_setting<color_t> {
color_setting *editable(string menu_item_name, string help_text, char key) {
this->is_editable = true;
this->menu_item_name = menu_item_name;
menu_item_name_modified = true;
this->help_text = help_text;
default_key = key;
return this;
@ -295,6 +301,7 @@ struct matrix_setting : public val_setting<matrix_eq> {
matrix_setting *editable(string menu_item_name, string help_text, char key) {
this->is_editable = true;
this->menu_item_name = menu_item_name;
menu_item_name_modified = true;
this->help_text = help_text;
default_key = key;
return this;
@ -318,7 +325,9 @@ struct bool_setting : public val_setting<bool> {
reaction_t switcher;
bool_setting* editable(string cap, char key ) {
is_editable = true;
menu_item_name = cap; default_key = key; return this;
menu_item_name = cap; default_key = key;
menu_item_name_modified = true;
return this;
}
void show_edit_option(int key) override;
@ -332,6 +341,8 @@ struct custom_setting : public setting {
function<void(char)> custom_viewer;
function<cld()> custom_value;
function<bool(void*)> custom_affect;
function<void(const string&)> custom_load;
void show_edit_option(int key) override { custom_viewer(key); }
supersaver *make_saver() override { throw hr_exception("make_saver for custom_setting"); }
bool affects(void *v) override { return custom_affect(v); }
@ -341,6 +352,15 @@ struct custom_setting : public setting {
add_to_changed(this);
}
}
virtual void load_from(const string& s) override {
if(saver) { saver->load(s); return; }
if(!custom_load) {
println(hlog, "cannot load parameter: ", parameter_name, " from: ", s);
throw hr_exception("parameter cannot be loaded");
}
custom_load(s);
}
virtual cld get_cld() override { return custom_value(); }
};
struct local_parameter_set {
@ -682,6 +702,7 @@ EX int_setting *param_i(int& val, const string s, int dft) {
u->parameter_name = param_esc(s);
u->config_name = s;
u->menu_item_name = s;
u->menu_item_name_modified = false;
u->value = &val;
u->last_value = dft;
u->dft = dft;
@ -707,6 +728,7 @@ EX bool_setting *param_b(bool& val, const string s, bool dft) {
u->parameter_name = param_esc(s);
u->config_name = s;
u->menu_item_name = s;
u->menu_item_name_modified = false;
u->value = &val;
u->last_value = dft;
u->dft = dft;
@ -723,6 +745,7 @@ EX color_setting *param_color(color_t& val, const string s, bool has_alpha, colo
u->parameter_name = param_esc(s);
u->config_name = s;
u->menu_item_name = s;
u->menu_item_name_modified = false;
u->value = &val;
u->last_value = dft;
u->dft = dft;
@ -740,6 +763,7 @@ EX matrix_setting *param_matrix(transmatrix& val0, const string s, int dim) {
u->parameter_name = param_esc(s);
u->config_name = s;
u->menu_item_name = s;
u->menu_item_name_modified = false;
u->value = &val;
u->last_value = val;
u->dft = val;
@ -755,6 +779,7 @@ EX char_setting *param_char(char& val, const string s, char dft) {
u->parameter_name = param_esc(s);
u->config_name = s;
u->menu_item_name = s;
u->menu_item_name_modified = false;
u->value = &val;
u->last_value = dft;
u->dft = dft;
@ -782,6 +807,7 @@ template<class T> enum_setting<T> *param_enum(T& val, const string p, const stri
u->parameter_name = p;
u->config_name = s;
u->menu_item_name = s;
u->menu_item_name_modified = false;
u->value = &val;
u->dft = dft;
val = dft;
@ -813,10 +839,12 @@ custom_setting* param_custom(T& val, const string& s, function<void(char)> menui
u->parameter_name = param_esc(s);
u->config_name = s;
u->menu_item_name = s;
u->menu_item_name_modified = false;
u->last_value = (int) val;
u->custom_viewer = menuitem;
u->custom_value = [&val] () { return (int) val; };
u->custom_affect = [&val] (void *v) { return &val == v; };
u->custom_load = [&val] (const string& s) { val = (T) parseint(s); };
u->default_key = key;
u->is_editable = true;
auto f = &*u;
@ -861,6 +889,12 @@ struct charstyle_old {
bool lefthanded;
};
struct charstyle_prebow {
int charid;
color_t skincolor, haircolor, dresscolor, swordcolor, dresscolor2, uicolor, eyecolor;
bool lefthanded;
};
EX void hread(hstream& hs, charstyle& cs) {
// before 0xA61A there was no eyecolor
if(hs.get_vernum() < 0xA61A) {
@ -874,7 +908,21 @@ EX void hread(hstream& hs, charstyle& cs) {
if(cs.charid < 4) cs.eyecolor = 0;
cs.dresscolor2 = cso.dresscolor2;
cs.uicolor = cso.uicolor;
cs.lefthanded = cso.lefthanded;
cs.lefthanded = cso.lefthanded;
}
else if(hs.get_vernum() < 0xA938) {
charstyle_prebow cso;
hread_raw(hs, cso);
cs.charid = cso.charid;
cs.skincolor = cso.skincolor;
cs.haircolor = cso.haircolor;
cs.dresscolor = cso.dresscolor;
cs.eyecolor = cso.eyecolor;
cs.swordcolor = cs.bowcolor = cs.bowcolor2 = cso.swordcolor;
if(cs.charid < 4) cs.eyecolor = 0;
cs.dresscolor2 = cso.dresscolor2;
cs.uicolor = cso.uicolor;
cs.lefthanded = cso.lefthanded;
}
else hread_raw(hs, cs);
}
@ -980,6 +1028,8 @@ EX void savecolortable(colortable& ct, string name) {
EX purehookset hooks_configfile;
EX ld mapfontscale = 100;
EX void initConfig() {
// basic config
@ -1000,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);
@ -1032,6 +1082,13 @@ EX void initConfig() {
-> set_reaction(compute_fsize)
-> set_sets([] { dialog::bound_low(0); });
param_f(mapfontscale, "mapfontscale", 100)
-> editable(-400, 400, 10, "map font scale",
"This affects the size of the characters on the ASCII map. This includes ASCII walls/monster display mode, the minimap, minefield values, and various debug features.", 'B')
->set_extra([] {
dialog::get_di().extra_options = [] () { draw_radar(true); };
});
param_i(vid.abs_fsize, "fsize", 12)
-> editable(1, 72, 1, "font size", "", 'b')
-> set_reaction(compute_fsize)
@ -1116,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; });
@ -1290,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);
@ -1302,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
@ -1331,7 +1390,7 @@ EX void initConfig() {
addsaverenum(variation, "mode-variation", eVariation::bitruncated);
addsaver(peace::on, "mode-peace");
addsaver(peace::otherpuzzles, "mode-peace-submode");
addsaverenum(specialland, "land for special modes");
param_enum(specialland, "specialland", "land for special modes", specialland);
addsaver(viewdists, "expansion mode");
param_f(backbrightness, "back", "brightness behind sphere");
@ -1350,8 +1409,10 @@ EX void initConfig() {
{"ODS", "for rendering 360° VR videos (implemented only in raycaster and some other parts)"},
{"Panini", "Projection believed to be used by Italian painters. Allows very high FOV angles while rendering more straight lines as straight than the stereographic projection."},
{"stereographic", "Stereographic projection allows very high FOV angles."},
{"equirectangular", "for rendering 360° videos (implemented only in raycaster)"}
}, "stereo/high-FOV mode", 'm');
{"equirectangular", "for rendering 360° videos (implemented only in raycaster)"},
{"cylindrical", "full vertical (not implemented in raycaster)"}
}, "stereo/high-FOV mode", 'm')
->set_reaction(reset_all_shaders);
param_f(vid.plevel_factor, "plevel_factor", 0.7);
@ -1613,6 +1674,18 @@ EX void initConfig() {
param_i(stamplen, "stamplen");
param_f(anims::period, "animperiod");
addsaver(use_custom_land_list, "customland_use");
for(int i=0; i<landtypes; i++) {
custom_land_list[i] = true;
custom_land_treasure[i] = 100;
custom_land_difficulty[i] = 100;
custom_land_wandering[i] = 100;
addsaver(custom_land_list[i], "customland" + its(i) + "i", true);
addsaver(custom_land_treasure[i], "customland" + its(i) + "t", 100);
addsaver(custom_land_difficulty[i], "customland" + its(i) + "d", 100);
addsaver(custom_land_wandering[i], "customland" + its(i) + "w", 100);
}
}
EX bool inSpecialMode() {
@ -1863,7 +1936,7 @@ EX void menuitem_sightrange_bonus(char c) {
}
EX void edit_sightrange_3d(char key, bool fog) {
dialog::addSelItem(XLAT(fog ? "3D sight range for the fog effect" : "3D sight range"), fts(sightranges[geometry]), key);
dialog::addSelItem(fog ? XLAT("3D sight range for the fog effect") : ("3D sight range"), fts(sightranges[geometry]), key);
dialog::add_action([] {
dialog::editNumber(sightranges[geometry], 0, TAU, 0.5, M_PI, XLAT("3D sight range"),
XLAT(
@ -2174,6 +2247,7 @@ EX void showGraphConfig() {
add_edit(vid.fontscale);
else
add_edit(vid.abs_fsize);
add_edit(mapfontscale);
dialog::addSelItem(XLAT("vector settings"), XLAT("width") + " " + fts(vid.linewidth), 'w');
dialog::add_action_push(show_vector_settings);
@ -2371,6 +2445,7 @@ EX void configureInterface() {
};
});
add_edit(show_turns);
add_edit(menu_darkening);
add_edit(centered_menus);
add_edit(startanims::enabled);
@ -2486,6 +2561,29 @@ EX ld max_fov_angle() {
return acos(-p) * 2 / degree;
}
EX void edit_fov_screen() {
dialog::editNumber(vid.fov, 1, max_fov_angle(), 1, 90, "field of view",
XLAT(
"Horizontal field of view, in angles. "
"This affects the Hypersian Rug mode (even when stereo is OFF) "
"and non-disk models.") + "\n\n" +
XLAT(
"Must be less than %1°. Panini projection can be used to get higher values.",
fts(max_fov_angle())
)
);
dialog::bound_low(1e-8);
dialog::bound_up(max_fov_angle() - 0.01);
dialog::get_di().extra_options = [] {
auto ptr = dynamic_cast<dialog::number_dialog*> (screens.back().target_base());
if(ptr && ptr->vmax != max_fov_angle()) { popScreen(); edit_fov_screen(); return; }
add_edit(vid.stereo_mode, 'M');
if(among(vid.stereo_mode, sPanini, sStereographic)) {
add_edit(vid.stereo_param, 'P');
}
};
}
EX void add_edit_fov(char key IS('f')) {
string sfov = fts(vid.fov) + "°";
@ -2493,26 +2591,7 @@ EX void add_edit_fov(char key IS('f')) {
sfov += " / " + fts(max_fov_angle()) + "°";
}
dialog::addSelItem(XLAT("field of view"), sfov, key);
dialog::add_action([=] {
dialog::editNumber(vid.fov, 1, max_fov_angle(), 1, 90, "field of view",
XLAT(
"Horizontal field of view, in angles. "
"This affects the Hypersian Rug mode (even when stereo is OFF) "
"and non-disk models.") + "\n\n" +
XLAT(
"Must be less than %1°. Panini projection can be used to get higher values.",
fts(max_fov_angle())
)
);
dialog::bound_low(1e-8);
dialog::bound_up(max_fov_angle() - 0.01);
dialog::get_di().extra_options = [] {
add_edit(vid.stereo_mode, 'M');
if(among(vid.stereo_mode, sPanini, sStereographic)) {
add_edit(vid.stereo_param, 'P');
}
};
});
dialog::add_action(edit_fov_screen);
}
bool supported_ods() {
@ -2840,7 +2919,7 @@ EX void show3D() {
#if MAXMDIM >=4
if(WDIM == 2) {
dialog::addSelItem("3D style", geom3::spatial_embedding_options[shown_spatial_embedding()].first, 'E');
dialog::addSelItem(XLAT("3D style"), XLAT(geom3::spatial_embedding_options[shown_spatial_embedding()].first), 'E');
dialog::add_action_push(show_spatial_embedding);
display_embedded_errors();
@ -2876,11 +2955,10 @@ EX void show3D() {
dialog::addBreak(50);
add_edit(vid.wall_height);
dialog::addSelItem("height details", "", 'D');
dialog::addSelItem(XLAT("3D detailed settings"), "", 'D');
dialog::add_action_push(show3D_height_details);
if(scale_used())
add_edit(vid.creature_scale);
add_edit(vid.creature_scale);
}
else {
add_edit(vid.creature_scale);
@ -3029,7 +3107,9 @@ EX int config3 = addHook(hooks_configfile, 100, [] {
}, "context help", 'H');
param_f(vid.creature_scale, "creature_scale", "3d-creaturescale", 1)
->editable(0, 1, .1, "Creature scale", "", 'C');
->editable(0, 1, .1, "Creature scale", "", 'C')
->set_extra([] { dialog::addInfo(XLAT("changing this during shmup is counted as cheating")); })
->set_reaction([] { if(shmup::on) cheater++; });
param_f(vid.height_width, "heiwi", "3d-heightwidth", 1.5)
->editable(0, 1, .1, "Height to width", "", 'h');
param_f(vid.yshift, "yshift", "Y shift", 0)
@ -3044,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)
@ -3182,7 +3270,7 @@ EX int config3 = addHook(hooks_configfile, 100, [] {
);
});
string unitwarn =
"The unit this is value is given in is wall height. "
"The unit this value is given in is wall height. "
"Note that, in exponentially expanding spaces, too high values could cause rendering issues. So "
"if you want infinity, values of 5 or similar should be used -- there is no visible difference "
"from infinity and glitches are avoided.";
@ -3254,7 +3342,19 @@ EX int config3 = addHook(hooks_configfile, 100, [] {
"larger values might produce horodisks with errors or crashing into each other.", 'H');
param_i(randomwalk_size, "randomwalk_size", 10)->editable(2, 100, 1,
"land size in randomwalk mode",
"The average size of a land in randomwalk mode.", 'R');
"The average size of a land in randomwalk mode.", 'R')
->set_reaction([] { if(game_active) { stop_game(); start_game(); } });
param_i(landscape_div, "landscape_div")->editable(1, 100, 1,
"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")
->editable(0, 5, 0.1, "Width of cell boundaries",
@ -3300,7 +3400,7 @@ EX void showCustomizeChar() {
dialog::addColorItem(XLAT("hair color"), cs.haircolor, 'h');
if(bow::crossbow_mode()) {
dialog::addColorItem(XLAT("bow color"), cs.bowcolor, 'b');
dialog::addColorItem(XLAT("boswtring color"), cs.bowcolor2, 'c');
dialog::addColorItem(XLAT("bowstring color"), cs.bowcolor2, 'c');
}
if(cs.charid >= 1) dialog::addColorItem(XLAT("dress color"), cs.dresscolor, 'd');
@ -3367,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);
@ -3389,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;
});
@ -3399,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();
});
}
@ -3458,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); });
}
}
@ -3806,7 +3906,8 @@ void list_setting::show_edit_option(int key) {
dialog::addBreak(100);
if(need_list >= 1 && options[get_value()].second != "") {
dialog::addHelp(XLAT(options[get_value()].second));
string text = options[get_value()].second;
dialog::addHelp(XLAT(text));
dialog::addBreak(100);
}
dialog::addBack();
@ -3880,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

@ -458,7 +458,7 @@ ITEM( '*', 0x8080FF, "Ice Sapphire", itSapphire, IC_TREASURE, ZERO, RESERVED, os
ITEM( '*', 0xEEFF20, "Hyperstone", itHyperstone, IC_TREASURE, ZERO, RESERVED, osNone,
"These bright yellow gems can be found only by those who have mastered the Crossroads."
)
ITEM( '[', 0x8080FF, "Key", itKey, IC_OTHER, ZERO, RESERVED, osNone,
ITEM( '[', 0x8080FF, "Key", itKey, IC_OTHER, ZERO | IF_FIREPROOF, RESERVED, osNone,
"That's all you need to unlock the Orb of Yendor! Well... as long as you are able to return to the Orb that this key unlocks...\n\n"
"Each key unlocks only the Orb of Yendor which led you to it."
)
@ -873,8 +873,8 @@ WALL( '#', 0x8080FF, "ice wall", waIcewall, WF_WALL | WF_HIGHWALL | WF_HEATCOLOR
"Ice Walls melt after some time has passed."
)
WALL( '#', 0xC06000, "great wall", waBarrier, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, barrierhelp)
WALL( '+', 0x900030, "red slime", waFloorA, ZERO | WF_ALCHEMY, RESERVED, 0, sgFloorA, slimehelp )
WALL( '+', 0x300090, "blue slime", waFloorB, ZERO | WF_ALCHEMY, RESERVED, 0, sgFloorB, slimehelp )
WALL( '+', 0x900030, "red slime", waFloorA, ZERO | WF_ALCHEMY | WF_ON, RESERVED, 0, sgFloorA, slimehelp )
WALL( '+', 0x300090, "blue slime", waFloorB, ZERO | WF_ALCHEMY | WF_ON, RESERVED, 0, sgFloorB, slimehelp )
WALL( '#', 0xA0D0A0, "living wall", waCavewall, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgCave, cavehelp)
WALL( '.', 0x306060, "living floor", waCavefloor, ZERO, RESERVED, 0, sgNone,cavehelp)
WALL( '#', 0xD03030, "dead rock troll", waDeadTroll, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, trollhelp)
@ -888,7 +888,7 @@ WALL( '%', 0xFFC0C0, "Cloud of Mirage", waCloud, WF_WALL, RESERVED, 0, sgNone,
"Tiny droplets of magical water. You see images of yourself inside them. "
"Go inside the cloud, to make these images help you.")
WALL( '^', 0x8D694F, "Thumper", waThumperOff, WF_WALL | WF_ACTIVABLE | WF_THUMPER, RESERVED, 0, sgNone, thumpdesc)
WALL( '^', 0x804000, "Fire", waFire, WF_FIRE | WF_TIMEOUT, RESERVED, 0, sgNone,
WALL( '^', 0x804000, "Fire", waFire, WF_FIRE | WF_TIMEOUT | WF_ON, RESERVED, 0, sgNone,
"This cell is on fire. Most beings and items cannot survive."
)
WALL( '+', 0xC0C0C0, "ancient grave", waAncientGrave, WF_WALL | WF_HIGHWALL | WF_GRAVE | WF_NONBLOCK, RESERVED, 0, sgNone,
@ -917,10 +917,10 @@ WALL( '#', 0x006000, "tree", waSmallTree, WF_WALL | WF_HIGHWALL | WF_STDTREE | W
WALL( '#', 0x421C52*2, "vine", waVinePlant, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgVine, vinehelp)
WALL( ':', 0x006000, "vine", waVineHalfA, ZERO | WF_NOFLIGHT | WF_HALFVINE, RESERVED, 0, sgVine, hvinehelp)
WALL( ';', 0x006000, "vine", waVineHalfB, ZERO | WF_NOFLIGHT | WF_HALFVINE, RESERVED, 0, sgVine, hvinehelp)
WALL( '^', 0x804000, "partial fire", waPartialFire, WF_FIRE | WF_TIMEOUT, RESERVED, 0, sgNone, "This cell is partially on fire.")
WALL( '#', 0xA07070, "dead wall", waDeadwall, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgCave, deadcavehelp)
WALL( '.', 0x401010, "dead floor", waDeadfloor, ZERO, RESERVED, 0, sgNone,deadcavehelp)
WALL( '.', 0x905050, "rubble", waDeadfloor2, ZERO, RESERVED, 1, sgNone, "Dead floor, with some rubble.")
WALL( '^', 0x804000, "partial fire", waPartialFire, WF_FIRE | WF_TIMEOUT | WF_ON, RESERVED, 0, sgNone, "This cell is partially on fire.")
WALL( '#', 0xA07070, "dead wall", waDeadwall, WF_WALL | WF_HIGHWALL | WF_ON, RESERVED, 0, sgCave, deadcavehelp)
WALL( '.', 0x401010, "dead floor", waDeadfloor, ZERO | WF_ON, RESERVED, 0, sgNone,deadcavehelp)
WALL( '.', 0x905050, "rubble", waDeadfloor2, ZERO | WF_ON, RESERVED, 1, sgNone, "Dead floor, with some rubble.")
WALL( '#', 0xD0D010, "weird rock", waWaxWall, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone,
"A weirdly colored rock. Hyperentomologists claim that the "
"Hyperbug armies use these rocks to navigate back home after a victorious battle."
@ -932,7 +932,7 @@ WALL( '#', 0x8080C0, "crystal cabinet", waGlass, WF_WALL, RESERVED, 0, sgNone,
"using an Orb of Aether, your Aether power will be completely drained."
)
WALL( '#', 0xC0C0C0, "wall of Camelot", waCamelot, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, camelothelp )
WALL( '+', 0xA06000, "Round Table", waRoundTable, WF_WALL | WF_NONBLOCK, RESERVED, 1, sgNone, camelothelp )
WALL( '+', 0xA06000, "Round Table", waRoundTable, WF_WALL | WF_NONBLOCK | WF_ON, RESERVED, 1, sgNone, camelothelp )
WALL( '=', 0x0000A0, "moat of Camelot", waCamelotMoat, WF_WATER, RESERVED, 0, sgWater, camelothelp)
WALL( '+', 0x606060, "big statue of Cthulhu", waBigStatue, WF_WALL, RESERVED, 0, sgNone,
"These statues of Cthulhu are too large to carry, and they don't look too "
@ -941,24 +941,24 @@ WALL( '+', 0x606060, "big statue of Cthulhu", waBigStatue, WF_WALL, RESERVED, 0,
"a statue, you push the statue to the cell you left.\n"
)
WALL( '=', 0x0000A0, "sea", waSea, WF_WATER, RESERVED, 0, sgWater, caribbeanhelp)
WALL( '+', 0x0000A0, "boat", waBoat, ZERO | WF_BOAT | WF_NOFLIGHT, RESERVED, 0, sgNone,
WALL( '+', 0x0000A0, "boat", waBoat, ZERO | WF_BOAT | WF_NOFLIGHT | WF_ON, RESERVED, 0, sgNone,
"Hyperbolic pirates do not need huge ships, since so many lands to conquest "
"are so close. These small boats are enough for them.\n\n"
"Boats allow you to go through water. If you are in a boat, you can move into "
"a water cell (and the boat will come with you)."
)
WALL( '.', 0x00FF00, "island", waCIsland, ZERO | WF_CISLAND, RESERVED, 0, sgNone, cislandhelp)
WALL( '.', 0x80C060, "island", waCIsland2, ZERO | WF_CISLAND, RESERVED, 0, sgNone, cislandhelp)
WALL( '.', 0x00FF00, "island", waCIsland, ZERO | WF_CISLAND | WF_ON, RESERVED, 0, sgNone, cislandhelp)
WALL( '.', 0x80C060, "island", waCIsland2, ZERO | WF_CISLAND | WF_ON, RESERVED, 0, sgNone, cislandhelp)
WALL( '#', 0x006000, "tree", waCTree, WF_WALL | WF_HIGHWALL | WF_CONE | WF_CISLAND, RESERVED, 0, sgTree,
"The forests of Caribbean are too dense to be traversed by humans, "
"and they are hard to burn. Many colorful parrots can be found there."
)
WALL( ',', 0x800000, "rock I", waRed1, ZERO | WF_RED, RESERVED, 1, sgNone, redrockhelp)
WALL( ':', 0xC00000, "rock II", waRed2, ZERO | WF_RED, RESERVED, 2, sgNone, redrockhelp)
WALL( ';', 0xFF0000, "rock III", waRed3, ZERO | WF_RED, RESERVED, 3, sgNone, redrockhelp)
WALL( ',', 0x800000, "rock I", waRed1, ZERO | WF_RED | WF_ON, RESERVED, 1, sgNone, redrockhelp)
WALL( ':', 0xC00000, "rock II", waRed2, ZERO | WF_RED | WF_ON, RESERVED, 2, sgNone, redrockhelp)
WALL( ';', 0xFF0000, "rock III", waRed3, ZERO | WF_RED | WF_ON, RESERVED, 3, sgNone, redrockhelp)
WALL( '.', 0xD0D0D0, "minefield", waMineUnknown, ZERO, RESERVED, 0, sgNone, minedesc)
WALL( '.', 0xD0D0D0, "minefield", waMineMine, ZERO, RESERVED, 0, sgNone, minedesc)
WALL( '.', 0x909090, "cell without mine", waMineOpen, ZERO, RESERVED, 0, sgNone, minedesc)
WALL( '.', 0x909090, "cell without mine", waMineOpen, ZERO | WF_ON, RESERVED, 0, sgNone, minedesc)
WALL( '+', 0x808000, "stranded boat", waStrandedBoat, ZERO | WF_BOAT | WF_NOFLIGHT, RESERVED, 0, sgNone,
"This boat cannot go through the sand. But if you sit inside and "
"wait for the tide, you will be able to use it to travel through the Ocean."
@ -966,17 +966,17 @@ WALL( '+', 0x808000, "stranded boat", waStrandedBoat, ZERO | WF_BOAT | WF_NOFLIG
WALL( '#', 0xFFD500, "palace wall", waPalace, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, palacedesc )
WALL( '+', 0xFFFFFF, "closed gate", waClosedGate, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, gatedesc )
WALL( '-', 0x404040, "open gate", waOpenGate, ZERO, RESERVED, 0, sgNone, gatedesc )
WALL( '_', 0xC00000, "closing plate", waClosePlate, ZERO, RESERVED, 0, sgNone, gatedesc )
WALL( '_', 0x00C050, "opening plate", waOpenPlate, ZERO, RESERVED, 0, sgNone, gatedesc )
WALL( '_', 0x202020, "trapdoor", waTrapdoor, ZERO, RESERVED, 0, sgNone, "This floor will fall after someone goes there. Go quickly!" )
WALL( '+', 0xFF0000, "giant rug", waGiantRug, ZERO, RESERVED, 0, sgNone,
WALL( '_', 0xC00000, "closing plate", waClosePlate, ZERO | WF_ON, RESERVED, 0, sgNone, gatedesc )
WALL( '_', 0x00C050, "opening plate", waOpenPlate, ZERO | WF_ON, RESERVED, 0, sgNone, gatedesc )
WALL( '_', 0x202020, "trapdoor", waTrapdoor, ZERO | WF_ON, RESERVED, 0, sgNone, "This floor will fall after someone goes there. Go quickly!" )
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( '.', 0xB0B0B0, "stone gargoyle floor", waGargoyleFloor, ZERO, RESERVED, 1, sgNone, gargdesc)
WALL( '.', 0x909090, "rubble", waRubble, ZERO, RESERVED, 1, sgNone, "Some rubble.")
WALL( '+', 0x804000, "ladder", waLadder, ZERO, RESERVED, 0, sgNone,
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,
"You can use this ladder to climb the Tower."
)
WALL( '#', 0xC0C0C0, "limestone wall", waStone, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, "Simply a wall. Mostly.")
@ -985,13 +985,13 @@ WALL( '^', 0x804000, "Bonfire", waBonfireOff, WF_WALL | WF_ACTIVABLE, RESERVED,
)
WALL( '^', 0x8D694F, "Thumper", waThumperOn, WF_WALL | WF_TIMEOUT | WF_PUSHABLE | WF_THUMPER, RESERVED, 0, sgNone,
"A device that attracts sandworms and other enemies. You need to activate it.")
WALL( '^', 0x804000, "Eternal Fire", waEternalFire, WF_FIRE, RESERVED, 0, sgNone,
WALL( '^', 0x804000, "Eternal Fire", waEternalFire, WF_FIRE | WF_ON, RESERVED, 0, sgNone,
"This fire never burns out."
)
WALL( '.', 0x909090, "stone gargoyle bridge", waGargoyleBridge, ZERO, RESERVED, 1, sgNone, gargdesc)
WALL( '.', 0x909090, "stone gargoyle bridge", waGargoyleBridge, ZERO | WF_ON, RESERVED, 1, sgNone, gargdesc)
WALL( '#', 0x309060, "temporary wall", waTempWall, WF_WALL | WF_HIGHWALL | WF_TIMEOUT, RESERVED, 0, sgNone, twdesc)
WALL( '.', 0x309060, "temporary floor", waTempFloor, ZERO | WF_TIMEOUT, RESERVED, 1, sgNone, twdesc)
WALL( '.', 0x309060, "temporary bridge", waTempBridge, ZERO | WF_TIMEOUT, RESERVED, 1, sgNone, twdesc)
WALL( '.', 0x309060, "temporary floor", waTempFloor, ZERO | WF_TIMEOUT | WF_ON, RESERVED, 1, sgNone, twdesc)
WALL( '.', 0x309060, "temporary bridge", waTempBridge, ZERO | WF_TIMEOUT | WF_ON, RESERVED, 1, sgNone, twdesc)
WALL( '#', 0x3030FF, "charged wall", waCharged, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, elecdesc)
WALL( '#', 0xFF3030, "grounded wall", waGrounded, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, elecdesc)
WALL( '#', 0xA0A060, "sandstone wall", waSandstone, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, elecdesc)
@ -1009,8 +1009,8 @@ WALL( '#', 0x764e7c, "rosebush", waRose, WF_WALL | WF_HIGHWALL | WF_THORNY, RESE
WALL( '#', 0xC0C000, "warp gate", waWarpGate, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone,
"This gate separates the warped area from the normal land.")
WALL( '+', 0x804000, "trunk", waTrunk, ZERO | WF_NOFLIGHT, RESERVED, 0, sgNone, "The skeleton of a tree.")
WALL( '-', 0x402000, "solid branch", waSolidBranch, ZERO, RESERVED, 0, sgNone, "Branches here could bear your weight easily.")
WALL( ':', 0x804000, "weak branch", waWeakBranch, ZERO, RESERVED, 0, sgNone,
WALL( '-', 0x402000, "solid branch", waSolidBranch, ZERO | WF_ON, RESERVED, 0, sgNone, "Branches here could bear your weight easily.")
WALL( ':', 0x804000, "weak branch", waWeakBranch, ZERO | WF_ON, RESERVED, 0, sgNone,
"Branches here will bear you weight, but if you use them to move (not fall) to an unstable place, they will break.")
WALL( '+', 0x60C060, "canopy", waCanopy, ZERO, RESERVED, 0, sgNone,
"Only thin twigs and leaves here. They may bear fruits, but for you, these cells count "
@ -1018,33 +1018,33 @@ 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, RESERVED, 0, sgNone,
WALL( '-', 0x402000, "big bush", waBigBush, ZERO | WF_NOFLIGHT | WF_ON, RESERVED, 0, sgNone,
"You can hold this bush to climb the Lost Mountain. "
"Bushes block the movement of birds."
)
WALL( ':', 0x804000, "small bush", waSmallBush, ZERO | WF_NOFLIGHT, RESERVED, 0, sgNone,
WALL( ':', 0x804000, "small bush", waSmallBush, ZERO | WF_NOFLIGHT | WF_ON, RESERVED, 0, sgNone,
"You can hold this bush to climb the Lost Mountain, "
"but it is not very strong -- it will get destroyed "
"if you climb from it into an unstable location. "
"Bushes block the movement of birds.")
WALL( '.', 0xFFFF00, "Reptile floor", waReptile, ZERO | WF_REPTILE, RESERVED, 0, sgNone, reptiledesc)
WALL( '.', 0xFFFF00, "Reptile bridge", waReptileBridge, ZERO | WF_REPTILE, RESERVED, 0, sgNone, reptiledesc)
WALL( '.', 0xFFFF00, "invisible floor", waInvisibleFloor, ZERO, RESERVED, 0, sgNone, NODESCYET)
WALL( '.', 0xFFFF00, "Reptile floor", waReptile, ZERO | WF_REPTILE | WF_ON, RESERVED, 0, sgNone, reptiledesc)
WALL( '.', 0xFFFF00, "Reptile bridge", waReptileBridge, ZERO | WF_REPTILE | WF_ON, RESERVED, 0, sgNone, reptiledesc)
WALL( '.', 0xFFFF00, "invisible floor", waInvisibleFloor, ZERO | WF_ON, RESERVED, 0, sgNone, NODESCYET)
WALL( '#', 0xC0C0FF, "mirror wall", waMirrorWall, WF_WALL, RESERVED, 0, sgNone, mirroreddesc)
WALL( '.', 0xE0E0E0, "stepping stones", waPetrifiedBridge, ZERO, RESERVED, 1, sgNone, "A petrified creature.")
WALL( '.', 0xE0E0E0, "stepping stones", waPetrifiedBridge, WF_ON, RESERVED, 1, sgNone, "A petrified creature.")
WALL( '#', 0x309060, "temporary wall", waTempBridgeBlocked, WF_WALL | WF_HIGHWALL | WF_TIMEOUT, RESERVED, 0, sgNone, twdesc)
WALL( 'S', 0xB0B0B0, "warrior statue", waTerraWarrior, WF_WALL, RESERVED, 0, sgNone, terradesc)
WALL( '=', 0xB0B0B0, "bubbling slime", waBubble, ZERO | WF_CHASM, RESERVED, 0, sgNone, NODESC)
WALL( '^', 0xD00000, "arrow trap", waArrowTrap, ZERO, RESERVED, 0, sgNone, arrowtrapdesc)
WALL( '^', 0xD00000, "arrow trap", waArrowTrap, WF_ON, RESERVED, 0, sgNone, arrowtrapdesc)
WALL( '=', 0xE2E2E2, "mercury river", waMercury, ZERO | WF_CHASM, RESERVED, 0, sgNone, "A river of mercury.")
WALL( '&', 0xD00000, "lava", waMagma, ZERO, RESERVED, 1, sgNone, lavadesc)
WALL( '=', 0x804000, "dock", waDock, ZERO, RESERVED, 0, sgNone, "A dock.")
WALL( '^', 0xFF8000, "burning dock", waBurningDock, WF_FIRE | WF_TIMEOUT, RESERVED, 0, sgNone, "A burning dock.")
WALL( '=', 0x804000, "dock", waDock, ZERO | WF_ON, RESERVED, 0, sgNone, "A dock.")
WALL( '^', 0xFF8000, "burning dock", waBurningDock, WF_FIRE | WF_TIMEOUT | WF_ON, RESERVED, 0, sgNone, "A burning dock.")
WALL( '#', 0xE04030, "ruin wall", waRuinWall, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, ruindesc)
WALL( '#', 0xA04060, "Brownian generator", waBrownian, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, NODESC)
WALL( '^', 0xC05000, "fire trap", waFireTrap, ZERO, RESERVED, 0, sgNone,
WALL( '^', 0xC05000, "fire trap", waFireTrap, ZERO | WF_ON, RESERVED, 0, sgNone,
"This trap will explode when stepped on, setting all the adjacent cells on fire. However, this happens on the next turn, "
"so you can safely escape if you are fast enough.")
WALL( '^', 0xFD692F, "Explosive Barrel", waExplosiveBarrel, WF_WALL | WF_PUSHABLE, RESERVED, 0, sgNone,
@ -1285,7 +1285,12 @@ LAND( 0x4040C0, "Sea Border", laOceanWall, ZERO | LF_TECHNICAL | LF_SEA, itNone,
LAND( 0x4040C0, "Elemental Planes", laElementalWall, ZERO | LF_ELEMENTAL, itElemental, RESERVED, elemdesc)
NATIVE((m == moAirElemental || m == moEarthElemental || m == moWaterElemental || m == moFireElemental) ? 1 : 0)
REQ(KILL(moAirElemental, laWhirlwind) KILL(moWaterElemental, laLivefjord) KILL(moEarthElemental, laDeadCaves) KILL(moFireElemental, laDragon))
REQ(
IFINGAME(laWhirlwind, KILL(moAirElemental, laWhirlwind), ITEMS(itDiamond, U10))
IFINGAME(laLivefjord, KILL(moWaterElemental, laLivefjord), ITEMS(itElixir, U10))
IFINGAME(laDeadCaves, KILL(moEarthElemental, laDeadCaves), ITEMS(itGold, U10))
IFINGAME(laDragon, KILL(moFireElemental, laDragon), ITEMS(itSpice, U10))
)
LAND( 0xE08020, "Canvas", laCanvas, ZERO | LF_TECHNICAL, itNone, RESERVED, "A fake Land with colored floors.")
NATIVE(0)
@ -1293,11 +1298,11 @@ 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)
REQ( NEVER )
REQ( ALWAYS )
LAND( 0x80A080, "Land of Storms", laStorms, ZERO | LF_TROLL | LF_ELECTRIC, itFulgurite, RESERVED, elecdesc)
NATIVE((m == moMetalBeast || m == moMetalBeast2 || m == moStormTroll) ? 1 : 0)
@ -1388,7 +1393,14 @@ LAND( 0x90A548, "Trollheim", laTrollheim, ZERO, itTrollEgg, RESERVED,
"these Trolls yourself?"
)
NATIVE(isTroll(m) ? 1 : 0)
REQ( KILL(moTroll, laCaves) KILL(moDarkTroll, laDeadCaves) KILL(moRedTroll, laRedRock) KILL(moStormTroll, laStorms) KILL(moForestTroll, laOvergrown) KILL(moFjordTroll, laLivefjord) )
REQ(
IFINGAME(laCaves, KILL(moTroll, laCaves), ITEMS(itSpice, 10))
IFINGAME(laDeadCaves, KILL(moDarkTroll, laDeadCaves), ITEMS(itGold, 10))
IFINGAME(laRedRock, KILL(moRedTroll, laRedRock), ITEMS(itSpice, 10))
IFINGAME(laStorms, KILL(moStormTroll, laStorms), ITEMS(itElixir, 10))
IFINGAME(laOvergrown, KILL(moForestTroll, laOvergrown), ITEMS(itRuby, 10))
IFINGAME(laLivefjord, KILL(moFjordTroll, laLivefjord), ITEMS(itGold, 10))
)
LAND( 0xFF7518, "Halloween", laHalloween, ZERO, itTreat, RESERVED, halloweendesc)
NATIVE((m == moGhost || m == moZombie || m == moWitch ||
@ -1400,13 +1412,16 @@ LAND( 0xFF7518, "Halloween", laHalloween, ZERO, itTreat, RESERVED, halloweendesc
m == moLancer || m == moFireFairy ||
m == moBomberbird || m == moRatlingAvenger ||
m == moVineBeast || m == moDragonHead || m == moDragonTail) ? 1 : 0)
REQ( NEVER )
REQ( ALWAYS )
LAND( 0x605040, "Dungeon", laDungeon, ZERO | LF_GRAVITY | LF_EQUI, itSlime, RESERVED,
"The result of a collaboration of the Great Vizier and the Wizard of the Ivory Tower."
)
NATIVE(m == moBat ? 2 : m == moSkeleton || m == moGhost ? 1 : 0)
REQ(ITEMS(itPalace, U5) ITEMS(itIvory, U5))
REQ(
IFINGAME(laPalace, ITEMS(itPalace, U5), ITEMS(itDiamond, U10))
IFINGAME(laIvoryTower, ITEMS(itIvory, U5), ITEMS(itElixir, U10))
)
LAND( 0x603000, "Lost Mountain", laMountain, ZERO | LF_GRAVITY | LF_CYCLIC, itAmethyst, RESERVED,
"Gravitational anomalies in the Jungle create mountains "
@ -1415,7 +1430,11 @@ LAND( 0x603000, "Lost Mountain", laMountain, ZERO | LF_GRAVITY | LF_CYCLIC, itAm
"Cells adjacent to Ivies count as stable (but Ivies "
"cannot climb themselves or other Ivies).")
NATIVE(m == moEagle || m == moMonkey || isIvy(m) || m == moFriendlyIvy ? 1 : 0)
REQ(ITEMS(itRuby, U5) ITEMS(itIvory, U5) ACCONLY(laJungle))
REQ(
ITEMS(itRuby, U5)
IFINGAME(laIvoryTower, ITEMS(itIvory, U5), ITEMS(itElixir, U10))
ACCONLY(laJungle)
)
LAND( 0xFFFF00, "Reptiles", laReptile, ZERO, itDodeca, RESERVED, reptiledesc)
NATIVE(m == moReptile ? 1 : 0)
@ -1435,7 +1454,7 @@ LAND( 0xC000C0, "Crossroads V", laCrossroads5, ZERO, itHyperstone, RESERVED, "Ex
LAND( 0xC0C0C0, "Cellular Automaton", laCA, ZERO | LF_TECHNICAL, itNone, RESERVED, cadesc)
NATIVE(0)
REQ(NEVER)
REQ(ALWAYS)
LAND( 0xC0C0FF, "Mirror Wall", laMirrorWall, ZERO | LF_TECHNICAL | LF_INMIRRORORWALL, itShard, RESERVED, mirroreddesc)
NATIVE(isNative(laMirror, m))
@ -1463,7 +1482,7 @@ LAND( 0xA06000, "Volcanic Wasteland", laVolcano, ZERO, itLavaLily, RESERVED, lav
LAND( 0x8080FF, "Blizzard", laBlizzard, ZERO | LF_ICY, itBlizzard, RESERVED, blizzarddesc)
NATIVE((m == moVoidBeast || m == moIceGolem) ? 2 : 0)
REQ(ITEMS(itDiamond, U5) ITEMS(itWindstone, U5))
REQ(IFINGAME(laWhirlwind, ITEMS(itDiamond, U5) ITEMS(itWindstone, U5), ITEMS(itDiamond, 10) GOLD(R60)))
LAND( 0x207068, "Hunting Ground", laHunting, ZERO, itHunting, RESERVED, huntingdesc)
NATIVE(m == moHunterDog ? 1 : 0)
@ -1491,7 +1510,9 @@ LAND( 0x80FF00, "Docks", laDocks, ZERO | LF_SEA, itDock, RESERVED, NODESCYET)
LAND( 0x306030, "Ruined City", laRuins, ZERO, itRuins, RESERVED, ruindesc)
NATIVE(among(m, moPair, moHexDemon, moAltDemon, moMonk, moCrusher) ? 2 : m == moSkeleton ? 1 : 0)
REQ(KILL(moSkeleton, laPalace))
REQ(
IFINGAME(laPalace, KILL(moSkeleton, laPalace), ITEMS(itRuby, U10))
)
LAND( 0x306030, "Magnetosphere", laMagnetic, ZERO, itMagnet, RESERVED, NODESCYET)
NATIVE(isMagneticPole(m) ? 2 : 0)
@ -1548,9 +1569,9 @@ LAND( 0x30FF30, "Irradiated Field", laVariant, ZERO, itVarTreasure, RESERVED,
LAND( 0x202020, "Space Rocks", laAsteroids, ZERO, itAsteroid, RESERVED, rock_description)
ITEM( '!', 0xFFD0D0, "Fuel", itAsteroid, IC_TREASURE, ZERO, RESERVED, osNone, rock_description)
MONSTER('A', 0x606040, "Space Rock", moAsteroid, ZERO, RESERVED, moAsteroid, rock_description)
MONSTER('A', 0x606040, "Space Rock", moAsteroid, ZERO, RESERVED, moYeti, rock_description)
NATIVE(m == moAsteroid ? 2 : 0)
REQ( NEVER )
REQ( ALWAYS )
LAND( 0x00C0C0, "Wetland", laWet, ZERO, itWet, RESERVED,
"Some people have definitely drowned in this treacherous area. Better be careful!"
@ -1638,7 +1659,7 @@ WALL( '$', 0xFD692F, "Crate", waCrateCrate, WF_WALL | WF_PUSHABLE, RESERVED, 0,
"These crates can be pushed."
)
WALL( '.', 0x40FD40, "Target", waCrateTarget, 0, RESERVED, 0, sgNone,
WALL( '.', 0x40FD40, "Target", waCrateTarget, 0 | WF_ON, RESERVED, 0, sgNone,
"Push all your crates on targets."
)
@ -1776,3 +1797,5 @@ MONSTER( '*', 0, "vertex", moRogueviz, ZERO | CF_TECHNICAL, RESERVED, moN
#undef ACCONLY2
#undef ACCONLY3
#undef ACCONLYF
#undef IFINGAME
#undef INMODE

View File

@ -67,6 +67,7 @@ EX ld shiftmul = 1;
EX cell *mouseover, *mouseover2, *lmouseover, *lmouseover_distant;
EX ld modist, modist2;
EX shiftmatrix mouseoverV;
EX int lastt;
@ -375,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;
@ -523,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);
}
@ -574,7 +576,9 @@ EX void handleKeyNormal(int sym, int uni) {
}
if(sym == SDLK_ESCAPE) {
if(viewdists)
if(bow::fire_mode)
bow::switch_fire_mode();
else if(viewdists)
viewdists = false;
else
showMissionScreen();
@ -680,6 +684,9 @@ EX void resize_screen_to(int x, int y);
EX void mainloopiter() { printf("(compiled without SDL -- no action)\n"); quitmainloop = true; }
#endif
/* visualization only -- the HyperRogue movement keys should move the camera */
EX bool game_keys_scroll;
#if CAP_SDL
// Warning: a very long function! todo: refactor
@ -711,9 +718,6 @@ EX bool mouseaiming(bool shmupon) {
(GDIM == 3 && !shmupon) || (rug::rugged && (lctrlclick ^ rug::mouse_control_rug)) || (cmode & sm::MOUSEAIM);
}
/* visualization only -- the HyperRogue movement keys should move the camera */
EX bool game_keys_scroll;
EX purehookset hooks_control;
EX void mainloopiter() {
@ -869,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 {
@ -954,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.;
@ -1301,7 +1305,10 @@ EX void displayabutton(int px, int py, string s, int col) {
int rad = (int) realradius();
if(vid.stereo_mode == sLR) rad = 99999;
int vrx = min(rad, vid.xres/2 - 40);
int vry = min(rad, min(current_display->ycenter, vid.yres - current_display->ycenter) - 20);
int maxy = min(current_display->ycenter, vid.yres - current_display->ycenter);
int vry = min(rad, maxy - 20);
vrx = max(vrx, vid.xres/3);
vry = max(vry, maxy * 2/3);
int x = current_display->xcenter + px * vrx;
int y = current_display->ycenter + py * (vry - siz/2);
int vrr = int(hypot(vrx, vry) * sqrt(2.));

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;
@ -190,12 +191,15 @@ EX vector<int> create_dirseq_geometric() {
if(GDIM == 3) y = hypot(U0[1], U0[2]); else y = abs(U0[1]) + (U0[1] > 0 ? 1e-6 : 0);
if(y < best_y) { best_y = y; best_i = i; }
}
if(best_i < 0) break;
if(best_i < 0) {
dirseq.push_back(NODIR);
break;
}
at = at + best_i;
int bonus = bolt_score(at + wstep);
if(bonus < 0) break;
best_score_res += bonus;
dirseq.push_back(best_i);
if(bonus < 0) break;
T = T * currentmap->adj(at.at, at.spin);
at = at + wstep;
}
@ -298,7 +302,7 @@ EX void add_fire(cell *c) {
return;
}
clear_bowpath();
checked_move_issue = miVALID;
checked_move_issue.type = miVALID;
pcmove pcm;
pcm.checkonly = false;
changes.init(false);
@ -336,6 +340,7 @@ EX bool fire_on_mouse(cell *c) {
if(mouse_fire_mode == mfmNone) return false;
if(!mouseover) return false;
if(!mouseover->monst) return false;
if(shmup::on) return false;
if(items[itCrossbow]) {
if(mouse_fire_mode == mfmAlways) {
addMessage(XLAT("Cannot fire again yet. Turns to reload: %1.", its(items[itCrossbow])));
@ -354,7 +359,7 @@ EX bool fire_on_mouse(cell *c) {
return false;
}
gen_bowpath_map();
checked_move_issue = miVALID;
checked_move_issue.type = miVALID;
pcmove pcm;
pcm.checkonly = false;
changes.init(false);
@ -365,6 +370,8 @@ EX bool fire_on_mouse(cell *c) {
return b;
}
EX int rusalka_curses = 0;
EX void shoot() {
flagtype attackflags = AF_BOW;
if(items[itOrbSpeed]&1) attackflags |= AF_FAST;
@ -373,6 +380,34 @@ EX void shoot() {
vector<bowpoint> pushes;
// for achievements
set<eMonster> kills;
vector<pair<cell*, int>> healthy_dragons;
map<cell*, pair<int, int>> kraken_hits;
int dragon_hits = 0;
rusalka_curses = 0;
// for achievements
for(auto& mov: bowpath) {
cell *c = mov.prev.at;
if(c->monst == moDragonHead) {
bool healthy = true;
cell *c1 = c;
int qty = 0;
for(int i=0; i<iteration_limit; i++) {
if(!isDragon(c1)) break;
if(!c1->hitpoints) { healthy = false; break; }
if(c1->mondir == NODIR) break;
c1 = c1->move(c1->mondir);
qty++;
}
if(healthy) healthy_dragons.emplace_back(c, qty);
}
if(c->monst == moKrakenT && c->hitpoints) {
kraken_hits[kraken::head(c)].first++;
}
}
for(auto& mov: bowpath) {
cell *c = mov.prev.at;
cell *cf = mov.prev.cpeek();
@ -391,6 +426,7 @@ EX void shoot() {
changes.ccell(c1);
eMonster m = c->monst;
if(attackMonster(c1, AF_STAB | AF_MSG, who)) {
achievement_count("STAB", 1, 0);
spread_plague(c1, cf, t, moPlayer);
produceGhost(c, m, moPlayer);
}
@ -400,6 +436,7 @@ EX void shoot() {
mirror::breakMirror(mov.next, -1);
eMonster m = c->monst;
if(!m || isMimic(m)) continue;
if(m == moKrakenH) continue;
if(!canAttack(cf, who, c, m, attackflags)) {
if(among(m, moSleepBull, moHerdBull)) {
@ -419,11 +456,18 @@ EX void shoot() {
bool push = (items[itCurseWeakness] || (isStunnable(c->monst) && c->hitpoints > 1));
push = push && (!(mov.flags & bpLAST) && monsterPushable(c));
// for achievements
if(isDragon(m)) dragon_hits++;
if(m == moKrakenT && c->hitpoints) kraken_hits[kraken::head(c)].second++;
if(m && attackMonster(c, attackflags | AF_MSG, who)) hit_anything = true;
if(m == moRusalka) rusalka_curses++;
if(!c->monst || isAnyIvy(m)) {
spread_plague(cf, c, movei(mov.prev).rev().d, moPlayer);
produceGhost(c, m, moPlayer);
kills.insert(m);
}
if(push) pushes.push_back(mov);
@ -445,6 +489,22 @@ EX void shoot() {
reverse(bowpath.begin(), bowpath.end());
// three achievements:
achievement_count("BOWVARIETY", kills.size(), 0);
for(auto p: healthy_dragons) {
cell *c = p.first;
if(c->monst != moDragonHead && dragon_hits >= p.second)
achievement_gain_once("BOWDRAGON");
}
for(auto kh: kraken_hits) {
if(kh.second.first == 3 && kh.second.second == 3) {
if(kraken::half_killed[kh.first]) achievement_gain_once("BOWKRAKEN");
else kraken::half_killed[kh.first] = true;
}
}
gen_bowpath_map();
}
@ -460,7 +520,7 @@ EX bool have_bow_target() {
int res = create_path();
if(res == -1) continue;
checked_move_issue = miVALID;
checked_move_issue.type = miVALID;
pcmove pcm;
pcm.checkonly = true;
changes.init(true);

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);
@ -812,7 +815,6 @@ int read_cheat_args() {
}
else if(argis("-lands")) {
PHASEFROM(2);
cheat();
stop_game();
shift(); land_structure = (eLandStructure) (argi());
}

View File

@ -191,7 +191,7 @@ void gentrans() {
DIR *d;
struct dirent *dir;
println(hlog, "// checking all the files");
println(hlog, "\n\n// checking all the files");
d = opendir(".");
@ -204,11 +204,11 @@ void gentrans() {
closedir(d);
}
println(hlog, "// checking configurables");
println(hlog, "\n\n// checking configurables");
for(auto& fs: params) {
auto& sett = fs.second;
if(sett->menu_item_name != sett->config_name)
if(sett->menu_item_name_modified)
check_ex(sett->menu_item_name, "menu_item_name for " + sett->parameter_name);
check_ex(sett->help_text, "help_text for " + sett->parameter_name);
auto ls = dynamic_cast<list_setting*> ( (setting*) &*sett);
@ -222,6 +222,6 @@ void gentrans() {
exit(0);
}
auto ar = arg::add3("-gentrans", gentrans);
auto gtar = arg::add3("-gentrans", gentrans);
}

View File

@ -791,7 +791,7 @@ EX namespace dialog {
continue;
}
else list_left -= size;
if(list_next_key) { key_actions[list_next_key] = key_actions[I.key]; I.key = list_next_key++; }
if(list_next_key) { if(key_actions.count(I.key)) key_actions[list_next_key] = key_actions[I.key]; I.key = list_next_key++; }
}
top = tothei;
@ -1201,6 +1201,7 @@ EX namespace dialog {
rot_but(0, 1, "rotate in XY", 'z');
}
#if !ISMOBILE
addBoolItem("mouse control", dialogflags & sm::MOUSEAIM, 'm');
dialog::add_action([this] { dialogflags ^= sm::MOUSEAIM; });
if(dialogflags & sm::MOUSEAIM) {
@ -1208,6 +1209,7 @@ EX namespace dialog {
*edit_matrix = cspin(1, 2, mouseaim_y) * *edit_matrix;
mouseaim_x = mouseaim_y = 0;
}
#endif
static string formula;
formula = "?";

View File

@ -229,7 +229,7 @@ EX void glflush() {
else
#endif
for(int ed = (current_display->stereo_active() && text_shift)?-1:0; ed<2; ed+=2) {
for(int ed = (current_display->separate_eyes() && text_shift)?-1:0; ed<2; ed+=2) {
glhr::set_modelview(glhr::translate(-ed*text_shift-current_display->xcenter,-current_display->ycenter, 0));
current_display->set_mask(ed);
drawer();
@ -237,7 +237,7 @@ EX void glflush() {
GLERR("print");
}
if(current_display->stereo_active() && text_shift && !svg::in) current_display->set_mask(0);
if(current_display->separate_eyes() && text_shift && !svg::in) current_display->set_mask(0);
texts_merged = 0;
text_vertices.clear();
@ -474,7 +474,7 @@ void addpoint(const shiftpoint& H) {
void coords_to_poly() {
polyi = isize(glcoords);
for(int i=0; i<polyi; i++) {
if(!current_display->stereo_active()) glcoords[i][2] = 0;
if(!current_display->separate_eyes()) glcoords[i][2] = 0;
polyx[i] = current_display->xcenter + glcoords[i][0] - glcoords[i][2];
polyxr[i] = current_display->xcenter + glcoords[i][0] + glcoords[i][2];
@ -663,7 +663,7 @@ void dqi_poly::gldraw() {
int ioffset = offset;
#if MINIMIZE_GL_CALLS
if(current_display->stereo_active() == 0 && !tinf && (color == 0 || ((flags & (POLY_VCONVEX | POLY_CCONVEX)) && !(flags & (POLY_INVERSE | POLY_FORCE_INVERTED))))) {
if(current_display->separate_eyes() == 0 && !tinf && (color == 0 || ((flags & (POLY_VCONVEX | POLY_CCONVEX)) && !(flags & (POLY_INVERSE | POLY_FORCE_INVERTED))))) {
if(lprio != prio || texts_merged || m_shift != V.shift) {
glflush();
lprio = prio;
@ -717,7 +717,7 @@ void dqi_poly::gldraw() {
next_slr:
for(int ed = current_display->stereo_active() ? -1 : 0; ed<2; ed+=2) {
for(int ed = current_display->separate_eyes() ? -1 : 0; ed<2; ed+=2) {
if(global_projection && global_projection != ed) continue;
if(min_slr < max_slr) {
@ -1975,7 +1975,7 @@ void dqi_poly::draw() {
if(isize(glcoords) <= 1) return;
cyl::loop_min = cyl::loop_max = 0;
if(sphere && mdBandAny())
if((sphere && mdBandAny()) || pmodel == mdPolar)
cyl::adjust(tinf);
int poly_limit = max(vid.xres, vid.yres) * 2;
@ -2136,10 +2136,10 @@ void dqi_poly::draw() {
else
filledPolygonColorI(srend, polyx, polyy, polyi, color);
if(current_display->stereo_active()) filledPolygonColorI(auxrend, polyxr, polyy, polyi, color);
if(current_display->separate_eyes()) filledPolygonColorI(auxrend, polyxr, polyy, polyi, color);
((vid.antialias & AA_NOGL) ?aapolylineColor:polylineColor)(srend, polyx, polyy, polyi, outline);
if(current_display->stereo_active()) aapolylineColor(auxrend, polyxr, polyy, polyi, outline);
if(current_display->separate_eyes()) aapolylineColor(auxrend, polyxr, polyy, polyi, outline);
if(vid.xres >= 2000 || fatborder) {
int xmi = 3000, xma = -3000;
@ -2623,7 +2623,7 @@ EX void drawqueue() {
}
#if CAP_SDL
if(current_display->stereo_active() && !vid.usingGL) {
if(current_display->separate_eyes() && !vid.usingGL) {
if(aux && (aux->w != s->w || aux->h != s->h)) {
SDL_FreeSurface(aux);
@ -2651,7 +2651,7 @@ EX void drawqueue() {
reset_projection();
#if CAP_GL
if(model_needs_depth() && current_display->stereo_active()) {
if(model_needs_depth() && current_display->separate_eyes()) {
global_projection = -1;
draw_main();
#if CAP_GL

View File

@ -90,7 +90,7 @@ EX namespace geom3 {
ans += " torus";
}
if(among(sp, seSol, seNIH, seSolN)) {
if((meuclid && !PURE) && !bt::in()) ans += " pure or bin";
if((meuclid && !PURE) || !bt::in()) ans += " pure or bin";
}
return ans;
}
@ -543,7 +543,7 @@ struct emb_same_in_same : emb_actual {
for(int i=0; i<4; i++) T[i][2] = T[i][3], T[i][3] = 0;
for(int i=0; i<4; i++) T[2][i] = T[3][i], T[3][i] = 0;
T[3][3] = 1;
fixmatrix(T);
if(MDIM == 3) fixmatrix(T); else IPF(fixmatrix(T));
for(int i=0; i<MDIM; i++) for(int j=0; j<MDIM; j++) if(isnan(T[i][j])) return Id;
return T;
}
@ -1389,7 +1389,9 @@ geom3::eSpatialEmbedding embed_by_name(string ss) {
return seNone;
}
#if CAP_COMMANDLINE
auto ah_embed = arg::add2("-seo", [] { arg::shift(); invoke_embed(embed_by_name(arg::args())); })
+ arg::add2("-never-invert", [] { never_invert = true; });
#endif
}

View File

@ -304,8 +304,6 @@ EX vector<int> bfs_reachedfrom;
/** calculate cpdist, 'have' flags, and do general fixings */
EX void bfs() {
calcTidalPhase();
yendor::onpath();
int dcs = isize(dcal);
@ -330,12 +328,9 @@ EX void bfs() {
dcal.clear(); bfs_reachedfrom.clear();
recalcTide = false;
for(cell *c: player_positions()) {
if(c->cpdist == 0) continue;
c->cpdist = 0;
checkTide(c);
dcal.push_back(c);
bfs_reachedfrom.push_back(hrand(c->type));
if(!invismove) targets.push_back(c);
@ -373,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;
}
@ -381,7 +376,7 @@ EX void bfs() {
// remove treasures
if(!peace::on && c2->item && c2->cpdist == distlimit && itemclass(c2->item) == IC_TREASURE &&
c2->item != itBabyTortoise && WDIM != 3 &&
!among(c2->item, itBrownian, itBabyTortoise) && WDIM != 3 &&
(items[c2->item] >= (ls::any_chaos()?10:20) + currentLocalTreasure || getGhostcount() >= 2)) {
c2->item = itNone;
if(c2->land == laMinefield) { c2->landparam &= ~3; }
@ -436,8 +431,6 @@ EX void bfs() {
dcal.push_back(c2);
bfs_reachedfrom.push_back(c->c.spin(i));
checkTide(c2);
if(c2->wall == waBigStatue && c2->land != laTemple)
statuecount++;
@ -548,11 +541,6 @@ EX void bfs() {
if(c2->wall == waThumperOn) {
targets.push_back(c2);
}
while(recalcTide) {
recalcTide = false;
for(int i=0; i<isize(dcal); i++) checkTide(dcal[i]);
}
for(auto& t: tempmonsters) t.first->monst = t.second;
@ -831,7 +819,16 @@ EX void findWormIvy(cell *c) {
else break;
}
}
EX void advance_tides() {
calcTidalPhase();
recalcTide = true;
while(recalcTide) {
recalcTide = false;
for(int i=0; i<isize(dcal); i++) checkTide(dcal[i]);
}
}
EX void monstersTurn() {
reset_spill();
checkSwitch();
@ -869,6 +866,8 @@ EX void monstersTurn() {
if(!phase1) livecaves();
if(!phase1) ca::simulate();
if(!phase1) heat::processfires();
// this depends on turncount, so we do it always
advance_tides();
for(cell *c: crush_now) {
changes.ccell(c);

View File

@ -409,7 +409,8 @@ EX bool sizes_known() {
if(aperiodic) return false;
if(currentmap->strict_tree_rules()) return true;
if(arb::in()) return false;
return true;
if(INVERSE) return false;
return true;
}
EX bool trees_known() {
@ -654,7 +655,7 @@ void celldrawer::do_viewdist() {
if(!dist_label_colored) dc = dist_label_color;
if(label != "")
queuestr(V, (isize(label) > 1 ? .6 : 1), label, 0xFF000000 + dc, 1);
queuestr(V, (isize(label) > 1 ? .6 : 1) * mapfontscale / 100, label, 0xFF000000 + dc, 1);
}
EX void viewdist_configure_dialog() {

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;
}
@ -724,11 +725,12 @@ EX void configure() {
underlying_cgip = cgip;
around = around_orig();
}
dialog::editNumber(around, 2.01, 10, 1, around, "fake curvature",
dialog::editNumber(around, 2.01, 10, 1, around, XLAT("fake curvature"),
XLAT(
"This feature lets you construct the same tiling, but "
"from shapes of different curvature.\n\n"
"The number you give here is (2D) vertex degree or (3D) "
"the number of cells around an edge.\n\n"
"the number of cells around an edge.\n\n")
);
if(fake::in())
dialog::get_di().reaction = change_around;
@ -736,33 +738,33 @@ EX void configure() {
dialog::get_di().reaction_final = change_around;
dialog::get_di().extra_options = [] {
ld e = compute_euclidean();
dialog::addSelItem("Euclidean", fts(e), 'E');
dialog::addSelItem(XLAT("Euclidean"), fts(e), 'E');
dialog::add_action([e] {
around = e;
popScreen();
change_around();
});
dialog::addSelItem("original", fts(around_orig()), 'O');
dialog::addSelItem(XLAT("original"), fts(around_orig()), 'O');
dialog::add_action([] {
around = around_orig();
popScreen();
change_around();
});
dialog::addSelItem("double original", fts(2 * around_orig()), 'D');
dialog::addSelItem(XLAT("double original"), fts(2 * around_orig()), 'D');
dialog::add_action([] {
around = 2 * around_orig();
popScreen();
change_around();
});
dialog::addBoolItem_action("draw all if multiple of original", multiple_special_draw, 'M');
dialog::addBoolItem_action("draw copies (2D only)", recursive_draw, 'C');
dialog::addBoolItem_action(XLAT("draw all if multiple of original"), multiple_special_draw, 'M');
dialog::addBoolItem_action(XLAT("draw copies (2D only)"), recursive_draw, 'C');
dialog::addBoolItem_choice("unordered", ordered_mode, 0, 'U');
dialog::addBoolItem_choice("pre-ordered", ordered_mode, 1, 'P');
dialog::addBoolItem_choice("post-ordered", ordered_mode, 2, 'Q');
dialog::addBoolItem_choice(XLAT("unordered"), ordered_mode, 0, 'U');
dialog::addBoolItem_choice(XLAT("pre-ordered"), ordered_mode, 1, 'P');
dialog::addBoolItem_choice(XLAT("post-ordered"), ordered_mode, 2, 'Q');
};
}

View File

@ -507,7 +507,7 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i
}
}
else if(arb::in() || aperiodic) {
else if(arb::in() || aperiodic || arcm::in() || IRREGULAR) {
vector<hyperpoint> actual;
for(int j=0; j<cor; j++)
actual.push_back(get_corner_position(c, j));

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

@ -152,11 +152,8 @@ void validity_info() {
EX bool showquotients;
string validclasses[4] = {" (X)", " (½)", "", " (!)"};
EX void ge_land_selection() {
cmode = sm::SIDE | sm::MAYDARK;
gamescreen();
EX void gen_landvisited() {
if(cheater) for(int i=0; i<landtypes; i++) landvisited[i] = true;
for(int i=0; i<landtypes; i++)
@ -177,6 +174,13 @@ EX void ge_land_selection() {
landvisited[laCamelot] |= hiitemsMax(treasureType(laCamelot)) >= 1;
landvisited[laCA] = true;
landvisited[laAsteroids] = true;
}
EX void ge_land_selection() {
cmode = sm::SIDE | sm::MAYDARK;
gamescreen();
gen_landvisited();
dialog::init(XLAT("select the starting land"));
if(dialog::infix != "") mouseovers = dialog::infix;
@ -1109,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

@ -576,8 +576,6 @@ EX void add_wall(int i, const vector<hyperpoint>& h) {
static constexpr ld hcrossf7 = 0.620672, hexf7 = 0.378077, tessf7 = 1.090550, hexhexdist7 = 0.566256;
#endif
EX bool scale_used() { return (shmup::on && geometry == gNormal && BITRUNCATED) ? (cheater || autocheat) : true; }
EX bool is_subcube_based(eVariation var) {
return among(var, eVariation::subcubes, eVariation::dual_subcubes, eVariation::bch, eVariation::bch_oct);
}
@ -784,13 +782,13 @@ void geometry_information::prepare_basics() {
if(msphere && geuclid) scalefactor *= (1 + vid.depth);
if(msphere && ghyperbolic) scalefactor *= sinh(1 + vid.depth);
if(scale_used()) {
if(true) {
scalefactor *= vid.creature_scale;
orbsize *= vid.creature_scale;
}
zhexf = BITRUNCATED ? hexf : crossf* .55;
if(scale_used()) zhexf *= vid.creature_scale;
zhexf *= vid.creature_scale;
if(WDIM == 2 && GDIM == 3) zhexf *= 1.5, orbsize *= 1.2;
if(cgi.emb->is_euc_in_hyp()) {
@ -1314,7 +1312,7 @@ EX string cgi_string() {
V("RS:", fts(geom3::euclid_embed_rotate));
}
if(scale_used()) V("CS", fts(vid.creature_scale));
if(vid.creature_scale != 1) V("CS", fts(vid.creature_scale));
if(WDIM == 3) V("HTW", fts(vid.height_width));

View File

@ -813,6 +813,15 @@ EX namespace gp {
screens = g;
}
EX bool check_whirl_set(loc xy) {
if(!check_limits(xy)) {
addMessage(XLAT("Outside of the supported limits"));
return false;
}
whirl_set(xy);
return true;
}
string helptext() {
return XLAT(
"Goldberg polyhedra are obtained by adding extra hexagons to a dodecahedron. "
@ -887,10 +896,11 @@ EX namespace gp {
}
dialog::addBreak(100);
int max_goldberg = (1<<GOLDBERG_BITS)/2 - 1;
dialog::addSelItem("x", its(config.first), 'x');
dialog::add_action([] { dialog::editNumber(config.first, 0, 8, 1, 1, "x", helptext()); });
dialog::add_action([max_goldberg] { dialog::editNumber(config.first, 0, max_goldberg, 1, 1, "x", helptext()); });
dialog::addSelItem("y", its(config.second), 'y');
dialog::add_action([] { dialog::editNumber(config.second, 0, 8, 1, 1, "y", helptext()); });
dialog::add_action([max_goldberg] { dialog::editNumber(config.second, 0, max_goldberg, 1, 1, "y", helptext()); });
if(!check_limits(config))
dialog::addInfo(XLAT("Outside of the supported limits"));
@ -973,24 +983,24 @@ EX namespace gp {
auto p = univ_param();
if(S3 == 3 && !UNTRUNCATED) {
println(hlog, "set param to ", p * loc(1,1));
whirl_set(p * loc(1, 1));
if(!check_whirl_set(p * loc(1, 1))) return;
set_variation(eVariation::untruncated);
start_game();
config = human_representation(univ_param());
}
else if(S3 == 4 && !UNRECTIFIED) {
whirl_set(p * loc(1, 1));
if(!check_whirl_set(p * loc(1, 1))) return;
set_variation(eVariation::unrectified);
start_game();
config = human_representation(univ_param());
}
else if(S3 == 3 && UNTRUNCATED) {
println(hlog, "whirl_set to ", (p * loc(1,1)) / 3);
whirl_set((p * loc(1,1)) / 3);
if(!check_whirl_set((p * loc(1,1)) / 3)) return;
config = human_representation(univ_param());
}
else if(S3 == 4 && UNRECTIFIED) {
whirl_set((p * loc(1,1)) / 2);
if(!check_whirl_set((p * loc(1,1)) / 2)) return;
config = human_representation(univ_param());
}
});
@ -1259,6 +1269,7 @@ EX namespace gp {
}
hrmap_inverse() {
underlying_map = nullptr;
if(0) {
println(hlog, "making ucgi");
dynamicval<eVariation> gva(variation, variation_for(param));
@ -1431,11 +1442,17 @@ EX namespace gp {
return C0;
}
};
EX hrmap* new_inverse() { return new hrmap_inverse; }
hrmap_inverse* inv_map() { return (hrmap_inverse*)currentmap; }
EX bool inverse_pseudohept(cell *c) {
cell *c1 = inv_map()->mapping[c];
if(!c1) return false;
return UIU(pseudohept(c1));
}
EX hrmap* get_underlying_map() { return inv_map()->underlying_map; }
EX cell* get_mapped(cell *c) { return inv_map()->get_mapped(c, 0); }
EX int untruncated_shift(cell *c) { return inv_map()->shift[c]; }

109
graph.cpp
View File

@ -769,11 +769,12 @@ EX shiftmatrix face_the_player(const shiftmatrix V) {
if(nonisotropic) return shiftless(spin_towards(unshift(V), dummy, C0, 2, 0));
#if CAP_VR
if(vrhr::enabled) {
shiftpoint h = tC0(V);
shiftpoint h = tC0(V);
hyperpoint uh = unshift(h);
return shiftless(cspin90(1, 2) * lrspintox(cspin90(2, 1) * uh) * xpush(hdist0(uh)) * cspin90(0, 2) * spin270());
return shiftless(cspin90(1, 2) * rspintox(cspin90(2, 1) * uh) * xpush(hdist0(uh)) * cspin90(0, 2) * spin270());
}
#endif
return rgpushxto0(tC0(V));
}
@ -846,12 +847,42 @@ EX void draw_ascii(const shiftmatrix& V, char glyph, color_t col, ld size) {
string s = s0 + glyph;
int id = isize(ptds);
if(WDIM == 2 && GDIM == 3)
queuestrn(V * lzpush(cgi.FLOOR - cgi.scalefactor * size / 4), size, s, darkenedby(col, darken), 0);
queuestrn(V * lzpush(cgi.FLOOR - cgi.scalefactor * size / 4), size * mapfontscale / 100, s, darkenedby(col, darken), 0);
else
queuestrn(V, 1, s, darkenedby(col, darken), GDIM == 3 ? 0 : 2);
queuestrn(V, mapfontscale / 100, s, darkenedby(col, darken), GDIM == 3 ? 0 : 2);
while(id < isize(ptds)) ptds[id++]->prio = PPR::MONSTER_BODY;
}
EX void queue_goal_text(shiftpoint P1, ld sizemul, const string& s, color_t color) {
#if CAP_VR
if(vrhr::enabled) {
auto e = inverse_exp(P1);
e = e * 3 / hypot_d(GDIM, e);
auto T = face_the_player(shiftless(rgpushxto0(direct_exp(e))));
queuestrn(T, sizemul * mapfontscale / 100, s, color);
return;
}
#endif
queuestr(P1, vid.fsize * sizemul, s, color);
}
EX bool mark_compass(cell *c, shiftpoint& P1) {
cell *c1 = c ? findcompass(c) : NULL;
if(!c1) return false;
shiftmatrix P = ggmatrix(c1);
P1 = tC0(P);
if(isPlayerOn(c)) {
queue_goal_text(P1, 2, "X", 0x10100 * int(128 + 100 * sintick(150)));
// 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;
}
EX bool drawItemType(eItem it, cell *c, const shiftmatrix& V, color_t icol, int pticks, bool hidden) {
if(!it) return false;
char xch = iinf[it].glyph;
@ -953,18 +984,8 @@ EX bool drawItemType(eItem it, cell *c, const shiftmatrix& V, color_t icol, int
else
#endif
if(1) {
cell *c1 = c ? findcompass(c) : NULL;
if(c1) {
shiftmatrix P = ggmatrix(c1);
shiftpoint P1 = tC0(P);
if(isPlayerOn(c)) {
queuestr(P1, 2*vid.fsize, "X", 0x10100 * int(128 + 100 * sintick(150)));
// queuestr(V, 1, its(compassDist(c)), 0x10101 * int(128 - 100 * sin(ticks / 150.)), 1);
queuestr(P1, vid.fsize, its(-compassDist(c)), 0x10101 * int(128 - 100 * sintick(150)));
addauraspecial(P1, 0xFF0000, 0);
}
shiftpoint P1;
if(mark_compass(c, P1)) {
V2 = V * lrspintox(inverse_shift(V, P1));
}
else V2 = V;
@ -3103,15 +3124,15 @@ EX bool drawMonster(const shiftmatrix& Vparam, int ct, cell *c, color_t col, col
col = mirrorcolor(geometry == gElliptic ? det(Vs.T) < 0 : mirr);
if(!mouseout() && !nospins && GDIM == 2) {
shiftpoint P2 = Vs * inverse_shift(inmirrorcount ? ocwtV : cwtV, mouseh);
queuestr(P2, 10, "x", 0xFF00);
}
queuestr(P2, 10*mapfontscale/100, "x", 0xFF00);
}
if(!nospins && flipplayer) Vs = Vs * lpispin();
res = res && drawMonsterType(moMimic, c, Vs, col, footphase, asciicol);
drawPlayerEffects(Vs, Vparam, c, c->monst);
}
}
// illusions face randomly
else if(c->monst == moIllusion) {
@ -3235,7 +3256,7 @@ EX bool drawMonster(const shiftmatrix& Vparam, int ct, cell *c, color_t col, col
hyperpoint h = inverse_shift(ocwtV, mouseh);
if(flipplayer) h = lpispin() * h;
shiftpoint P2 = Vs * h;
queuestr(P2, 10, "x", 0xFF00);
queuestr(P2, mapfontscale / 10, "x", 0xFF00);
}
if(hide_player()) {
@ -3273,7 +3294,7 @@ EX int haveaura() {
if(sphere && mdAzimuthalEqui()) return 0;
if(among(pmodel, mdJoukowsky, mdJoukowskyInverted) && hyperbolic && pconf.model_transition < 1)
return 2;
if(pmodel == mdFisheye) return 1;
if(among(pmodel, mdFisheye, mdFisheye2)) return 1;
return pmodel == mdDisk && (!sphere || pconf.alpha > 10) && !euclid;
}
@ -3573,7 +3594,7 @@ void draw_movement_arrows(cell *c, const transmatrix& V, int df) {
transmatrix T = iso_inverse(Centered) * rgpushxto0(Centered * tC0(V)) * lrspintox(Centered*tC0(V)) * spin(-sd * M_PI/S7) * xpush(0.2);
if(vid.axes >= 5)
queuestr(shiftless(T), keysize, s0 + key, col >> 8, 1);
queuestr(shiftless(T), keysize * mapfontscale / 100, s0 + key, col >> 8, 1);
else
queuepoly(shiftless(T), cgi.shArrow, col);
@ -3581,7 +3602,7 @@ void draw_movement_arrows(cell *c, const transmatrix& V, int df) {
else if(!confusingGeometry()) break;
}
}
if(keylist != "") queuestr(shiftless(V), keysize, keylist, col >> 8, 1);
if(keylist != "") queuestr(shiftless(V), keysize * mapfontscale / 100, keylist, col >> 8, 1);
}
EX int celldistAltPlus(cell *c) { return 1000000 + celldistAlt(c); }
@ -4008,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;
}
@ -4056,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;
}
@ -4119,7 +4146,7 @@ EX ld threshold, xyz_threshold;
EX bool clip_checked = false;
EX bool other_stereo_mode() {
return among(vid.stereo_mode, sODS, sPanini, sStereographic, sEquirectangular);
return vid.stereo_mode != sOFF;
}
void make_clipping_planes() {
@ -4761,7 +4788,7 @@ EX void drawMarkers() {
#if CAP_QUEUE
if(haveMount())
for (const shiftmatrix& V : hr::span_at(current_display->all_drawn_copies, dragon::target)) {
queuestr(V, 1, "X",
queuestr(V, mapfontscale/100, "X",
gradient(0, iinf[itOrbDomination].color, -1, sintick(dragon::whichturn == turncount ? 75 : 150), 1));
}
#endif
@ -4773,31 +4800,31 @@ 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;
}
shiftpoint H = tC0(ggmatrix(keycell));
#if CAP_QUEUE
queuestr(H, 2*vid.fsize, "X", 0x10101 * int(128 + 100 * sintick(150)));
queue_goal_text(H, 2, "X", 0x10101 * int(128 + 100 * sintick(150)));
int cd = celldistance(yi[yii].key(), cwt.at);
if(cd == DISTANCE_UNKNOWN) for(int i2 = 0; i2<YDIST; i2++) {
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));
}
}
queuestr(H, vid.fsize, its(cd), 0x10101 * int(128 - 100 * sintick(150)));
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);
}
}
}
@ -4930,9 +4957,10 @@ EX void drawMarkers() {
}
if(items[itOrbAir] && mouseover->cpdist > 1) {
cell *c1 = mouseover;
int dir = c1->monst == moVoidBeast ? -1 : 1;
for(int it=0; it<10; it++) {
int di;
auto mib = blowoff_destination(c1, di);
auto mib = blowoff_destination_dir(c1, di, dir);
if(!mib.proper()) break;
auto& c2 = mib.t;
shiftmatrix T1 = ggmatrix(c1);
@ -4993,12 +5021,12 @@ EX void draw_flash(struct flashdata& f, const shiftmatrix& V, bool& kill) {
int r = 2;
apply_neon(col, r);
if(GDIM == 3 || sphere)
queuestr(V, (1 - tim * 1. / f.size) * f.angle, f.text, col, r);
queuestr(V, (1 - tim * 1. / f.size) * f.angle * mapfontscale / 100, f.text, col, r);
else if(!kill) {
shiftpoint h = tC0(V);
if(hdist0(h) > .1) {
transmatrix V2 = rspintox(h.h) * xpush(hdist0(h.h) * (1 / (1 - tim * 1. / f.size)));
queuestr(shiftless(V2, h.shift), f.angle, f.text, col, r);
queuestr(shiftless(V2, h.shift), f.angle * mapfontscale / 100, f.text, col, r);
}
}
if(static_bubbles) {
@ -5644,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() {
@ -5770,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,11 +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"
"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, Pasu4"
);
#ifdef EXTRALICENSE
help += EXTRALICENSE;
@ -552,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(
@ -567,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) {
@ -699,10 +714,12 @@ 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);
#define ACCONLYF(z) s += XLAT("Accessible only from %the1 (until finished).\n", z);
#define IFINGAME(land, ok, fallback) if(isLandIngame(land)) { ok } else { s += XLAT("Alternative rule when %the1 is not in the game:\n", land); fallback }
#include "content.cpp"
case landtypes: return;
@ -880,9 +897,9 @@ EX void describeMouseover() {
if(shmup::on)
out += " (" + its(c->landparam)+")";
else {
bool b = c->landparam >= tide[(turncount-1) % tidalsize];
bool b = c->landparam >= tide[turncount % tidalsize];
int t = 1;
for(; t < 1000 && b == (c->landparam >= tide[(turncount+t-1) % tidalsize]); t++) ;
for(; t < 1000 && b == (c->landparam >= tide[(turncount+t) % tidalsize]); t++) ;
if(b)
out += " (" + turnstring(t) + XLAT(" to surface") + ")";
else
@ -891,7 +908,7 @@ EX void describeMouseover() {
}
#if CAP_FIELD
else if(c->land == laVolcano) {
int id = lavatide(c, -1)/4;
int id = lavatide(c, 0)/4;
if(id < 96/4)
out += " (" + turnstring(96/4-id) + XLAT(" to go cold") + ")";
else
@ -964,7 +981,12 @@ EX void describeMouseover() {
if(c->wall && !(c->wall == waChasm && c->land == laDual && ctof(c)) &&
!(c->land == laMemory) &&
!((c->wall == waFloorA || c->wall == waFloorB) && c->item)) {
out += ", "; out += XLAT1(winf[c->wall].name);
eWall w = c->wall;
if(isAlch(w))
w = conditional_flip_slime(mousing ? det(mouseoverV.T) < 0 : det(View) < 0, w);
out += ", "; out += XLAT1(winf[w].name);
if(c->wall == waRose) out += " (" + its(7-rosephase) + ")";
if(c->wall == waTerraWarrior) out += " (" + its(c->wparam) + ")";
@ -1081,16 +1103,7 @@ EX void describeMouseover() {
#endif
}
EX void showHelp() {
cmode = sm::HELP | sm::DOTOUR | sm::DARKEN;
getcstat = SDLK_ESCAPE;
if(help == "HELPFUN") {
help_delegate();
return;
}
gamescreen();
string help2;
EX void addHelpWithTitle() {
if(help[0] == '@') {
int iv = help.find("\t");
int id = help.find("\n");
@ -1101,6 +1114,19 @@ EX void showHelp() {
dialog::init("help", forecolor, 120, 100);
dialog::addHelp(help);
}
}
EX void showHelp() {
cmode = sm::HELP | sm::DOTOUR | sm::DARKEN;
getcstat = SDLK_ESCAPE;
if(help == "HELPFUN") {
help_delegate();
return;
}
gamescreen();
string help2;
addHelpWithTitle();
bool in_list = false;

View File

@ -457,6 +457,11 @@ EX namespace history {
dynamicval<bool> di(inHighQual, true);
renderbuffer glbuf(bandfull, bandfull, vid.usingGL);
glbuf.make_surface(); if(!glbuf.srf) {
addMessage(XLAT("Could not create an image of that size."));
return;
}
vid.xres = vid.yres = bandfull;
glbuf.enable(); current_display->radius = bandhalf;
calcparam();
@ -480,7 +485,8 @@ EX namespace history {
};
if(!band) {
addMessage("Could not create an image of that size.");
addMessage(XLAT("Could not create an image of that size."));
return;
}
else {
@ -528,6 +534,10 @@ EX namespace history {
len -= bandsegment; xpos -= bandsegment;
seglen = min(int(len), bandsegment);
band = SDL_CreateRGBSurface(SDL_SWSURFACE, seglen, bandfull,32,0,0,0,0);
if(!band) {
addMessage(XLAT("Could not create an image of that size."));
return;
}
goto drawsegment;
}
xpos += bwidth;

View File

@ -144,7 +144,10 @@ template<class T, class U> void hread(hstream& hs, map<T,U>& a) {
template<class C, class C1, class... CS> void hwrite(hstream& hs, const C& c, const C1& c1, const CS&... cs) { hwrite(hs, c); hwrite(hs, c1, cs...); }
template<class C, class C1, class... CS> void hread(hstream& hs, C& c, C1& c1, CS&... cs) { hread(hs, c); hread(hs, c1, cs...); }
struct hstream_exception : hr_exception {};
struct hstream_exception : hr_exception {
hstream_exception() : hr_exception("hstream_exception") {}
hstream_exception(const std::string &s) : hr_exception(s) {}
};
struct fhstream : hstream {
FILE *f;
@ -555,4 +558,12 @@ template<class... T> string lalign(int len, T... t) {
return hs.s;
}
#endif
map<string, string> last;
EX void debug_view(string context, string s) {
string& old = last[context];
if(s != old) { old = s; println(hlog, s); }
}
}

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,10 +132,8 @@
#include "rogueviz/rogueviz-all.cpp"
#endif
#if CAP_DAILY
#include "private/daily.cpp"
#else
namespace hr { namespace daily { bool on; } }
#if !CAP_DAILY
namespace hr { namespace daily { bool on; int historical; } }
#endif
#include "mobile.cpp"

22
hyper.h
View File

@ -13,8 +13,8 @@
#define _HYPER_H_
// version numbers
#define VER "12.1y"
#define VERNUM_HEX 0xA939
#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 87
#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"
@ -250,7 +241,7 @@ struct charstyle {
bool lefthanded;
};
enum eStereo { sOFF, sAnaglyph, sLR, sODS, sPanini, sStereographic, sEquirectangular };
enum eStereo { sOFF, sAnaglyph, sLR, sODS, sPanini, sStereographic, sEquirectangular, sCylindrical };
enum eModel : int;
@ -258,10 +249,11 @@ enum eModel : int;
struct projection_configuration {
eModel model; /**< which projection, see classes.cpp */
ld xposition, yposition; /**< move the center to another position */
ld scale, alpha, fisheye_param, twopoint_param, axial_angle, stretch, ballproj, euclid_to_sphere;
ld scale, alpha, fisheye_param, fisheye_alpha, twopoint_param, axial_angle, stretch, ballproj, euclid_to_sphere;
ld clip_min, clip_max;
ld halfplane_scale;
ld collignon_parameter;
ld offside, offside2;
ld aitoff_parameter, miller_parameter, loximuthal_parameter, winkel_parameter;
bool show_hyperboloid_flat;
bool collignon_reflected;
@ -565,7 +557,7 @@ typedef function<int(struct cell*)> cellfunction;
// passable flags
#define SAGEMELT .1
#define PT(x, y) ((tactic::on || quotient == 2 || daily::on) ? (y) : inv::on ? min(2*(y),x) : (x))
#define PT(x, y) rebalance_treasure(x, y, c->land)
#define ROCKSNAKELENGTH 50
#define WORMLENGTH 15
#define PRIZEMUL 7
@ -779,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));
@ -887,6 +880,7 @@ template<class T> T& atmod(vector<T>& container, int index) {
namespace daily {
extern bool on;
extern int historical;
extern int daily_id;
void setup();
void split();

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.roguetemple.hyperroid"
android:versionCode="12080" android:versionName="12.0v"
android:versionCode="13001" android:versionName="13.0a"
android:installLocation="auto">
<!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> -->
<!-- <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="9" /> -->

View File

@ -50,7 +50,7 @@ void gdpush(int t);
void shareScore(MOBPAR_FORMAL);
const char *scorefile;
std::string scorefile;
bool settingsChanged = false;
@ -203,14 +203,13 @@ extern "C" void
Java_com_roguetemple_hyperroid_HyperRogue_setFilesDir(MOBPAR_FORMAL, jstring dir)
{
const char *nativeString = env->GetStringUTFChars(dir, 0);
sscorefile = nativeString; sscorefile += "/hyperrogue.log";
scorefile = nativeString; scorefile += "/hyperrogue.log";
sconffile = nativeString; sconffile += "/hyperrogue.ini";
scachefile = nativeString; scachefile += "/scorecache.txt";
levelfile = nativeString; levelfile += "/hyperrogue.lev";
picfile = nativeString; picfile += "/hyperrogue.pic";
scorefile = sscorefile.c_str();
conffile = sconffile.c_str();
chmod(scorefile, 0777);
chmod(scorefile.c_str(), 0777);
chmod(conffile, 0777);
chmod(nativeString, 0777);
chmod((string(nativeString)+"/..").c_str(), 0777);

View File

@ -151,9 +151,9 @@ void showDemo() {
dialog::addBreak(100);
dialog::addTitle("highlights", 0xC00000, 120);
dialog::addItem(XLAT("Temple of Cthulhu"), 't');
dialog::addItem(XLAT("Land of Storms"), 'l');
dialog::addItem(XLAT("Burial Grounds"), 'b');
dialog::addItem(XLAT1("Temple of Cthulhu"), 't');
dialog::addItem(XLAT1("Land of Storms"), 'l');
dialog::addItem(XLAT1("Burial Grounds"), 'b');
dialog::display();

View File

@ -167,7 +167,7 @@ bool use_z_coordinate() {
#if CAP_VR
if(vrhr::rendering()) return true;
#endif
return current_display->stereo_active();
return current_display->separate_eyes();
}
void apply_depth(hyperpoint &f, ld z) {
@ -1055,6 +1055,27 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
break;
}
case mdFisheye2: {
ld zlev;
if(nonisotropic) {
H = lp_apply(inverse_exp(H_orig));
zlev = 1;
}
else {
zlev = find_zlev(H);
H = space_to_perspective(H);
}
H /= pconf.fisheye_param;
auto H1 = perspective_to_space(H, pconf.fisheye_alpha, gcSphere);
auto H2 = perspective_to_space(hyperpoint(1e6, 0, 0, 0), pconf.fisheye_alpha, gcSphere);
H1[2] += 1;
H1 /= H1[2];
H1 /= H2[0] / (H2[2]+1);
ret = H1;
if(GDIM == 3) ret[LDIM] = zlev;
break;
}
case mdSimulatedPerspective: {
models::scr_to_ori(H);
auto yz = move_z_to_y(H);
@ -1341,6 +1362,21 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
makeband(H_orig, ret, [] (ld& x, ld& y) { x *= cos_auto(y); });
break;
case mdPolar: {
models::scr_to_ori(H);
H = xpush(pconf.offside) * H;
ld zlev = find_zlev(H);
ld d = hdist0(H);
ld df, zf;
hypot_zlev(zlev, d, df, zf);
ret[0] = -atan2(H) / M_PI;
ret[1] = (d - pconf.offside2) / M_PI;
ret[2] = zf;
ret[3] = 1;
models::ori_to_scr(ret);
break;
}
case mdEquidistant: case mdEquiarea: case mdEquivolume: {
if(vrhr::rendering() && GDIM == 3 && pmodel == mdEquidistant) {
ret = inverse_exp(H_orig);
@ -1431,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;
@ -1456,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;
}
@ -2475,7 +2515,7 @@ EX transmatrix atscreenpos(ld x, ld y, ld size) {
void circle_around_center(ld radius, color_t linecol, color_t fillcol, PPR prio) {
#if CAP_QUEUE
if(among(pmodel, mdDisk, mdEquiarea, mdEquidistant, mdFisheye) && !(pmodel == mdDisk && hyperbolic && pconf.alpha <= -1) && models::camera_straight) {
if(among(pmodel, mdDisk, mdEquiarea, mdEquidistant, mdFisheye, mdFisheye2) && !(pmodel == mdDisk && hyperbolic && pconf.alpha <= -1) && models::camera_straight) {
hyperpoint ret;
applymodel(shiftless(xpush0(radius)), ret);
ld r = hypot_d(2, ret);
@ -2733,7 +2773,7 @@ EX void draw_boundary(int w) {
}
if(w == 1) return;
if(nonisotropic || (euclid && !among(pmodel, mdFisheye, mdConformalSquare, mdHemisphere)) || gproduct) return;
if(nonisotropic || (euclid && !among(pmodel, mdFisheye, mdFisheye2, mdConformalSquare, mdHemisphere)) || gproduct) return;
#if CAP_VR
if(vrhr::active() && pmodel == mdHyperboloid) return;
#endif
@ -2783,7 +2823,7 @@ EX void draw_boundary(int w) {
switch(pmodel) {
case mdTwoPoint: {
if(twopoint_do_flips || current_display->stereo_active() || !sphere) return;
if(twopoint_do_flips || current_display->separate_eyes() || !sphere) return;
queuereset(mdPixel, p);
for(int b=-1; b<=1; b+=2)
@ -2983,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;
@ -3176,7 +3217,7 @@ EX bool do_draw(cell *c) {
EX ld extra_generation_distance = 99;
// returns false if limited
bool limited_generation(cell *c) {
EX bool limited_generation(cell *c) {
if(c->mpdist <= 7) return true;
if(cells_generated > vid.cells_generated_limit) return false;
setdist(c, 7, c);
@ -3186,7 +3227,11 @@ bool limited_generation(cell *c) {
EX int min_cells_drawn = 50;
EX hookset<int(cell*,const shiftmatrix&)> hooks_do_draw;
EX bool do_draw(cell *c, const shiftmatrix& T) {
int h = callhandlers(0, hooks_do_draw, c, T);
if(h) return h > 0;
if(WDIM == 3) {
// do not care about cells outside of the track

View File

@ -538,7 +538,7 @@ EX void shift_view_portal(hyperpoint H) {
if(b) maxv = t; else minv = t;
shift_view(H * -t * scale);
}
println(hlog, "maxv = ", maxv);
// println(hlog, "maxv = ", maxv);
shift_view(H * maxv * scale);
check_portal_movement();
shift_view_portal(H * (1 - maxv) * scale);
@ -668,7 +668,7 @@ EX string portal_help =
EX void become_menu() {
cmode = sm::SIDE | sm::MAYDARK;
gamescreen();
dialog::init(XLAT("Become a portal map"));
dialog::init(XLAT("become a portal map"));
dialog::addHelp(XLAT(portal_help));
dialog::addItem(XLAT("yes, that's what I want"), 'y');
dialog::add_action([] {
@ -788,7 +788,7 @@ EX void show_portals() {
dialog::add_action([cw] { unconnected.push_back(cw); });
dialog::start_list(500, 500, '1');
for(auto p: unconnected) {
dialog::addItem(XLAT("connect " + lalign(0, p)), dialog::list_fake_key++);
dialog::addItem(XLAT("connect ") + lalign(0, p), dialog::list_fake_key++);
dialog::add_action([p, cw] {
connect_portal(cw, p, edit_spin);
mapeditor::map_version++;

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));
@ -770,7 +767,7 @@ EX int celldist(cell *c, bool alts) {
return hi.celldists[alts][cells[cellindex[c]].localindex];
}
eGeometry orig_geometry;
eGeometry orig_geometry, base_geometry;
void start_game_on_created_map() {
popScreen();
@ -807,6 +804,47 @@ 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();
int origcells = 0;
for(cellinfo& ci: cells)
if(ci.generation == 0)
origcells++;
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;
for(auto i: cells_of_heptagon[h->master])
if(cells[i].generation == 0)
origcells++;
f.write<short> (origcells);
for(auto i: cells_of_heptagon[h->master]) if(cells[i].generation == 0) {
auto &ci = cells[i];
check_float_order(ci.p[0]);
check_float_order(ci.p[1]);
check_float_order(ci.p[LDIM]);
}
}
}
bool load_map(const string &fname) {
fhstream f(fname, "rt");
if(!f.f) return false;
@ -839,6 +877,52 @@ bool load_map(const string &fname) {
return true;
}
EX void load_map_bin(hstream& f) {
auto& all = base->allcells();
eGeometry g = (eGeometry) f.get<short>();
if(int(g) == -1) return;
int sa = f.get<short>();
cellcount = f.get<short>();
if(g != geometry) throw hstream_exception("bad geometry");
if(sa != isize(all)) throw hstream_exception("bad size of all");
density = cellcount * 1. / isize(all);
cells.clear();
float_order.clear();
for(auto h: all) {
int q = f.get<short>();
if(q < 0 || q > cellcount) throw hstream_exception("incorrect quantity");
while(q--) {
cells.emplace_back();
cellinfo& s = cells.back();
s.patterndir = -1;
double a, b, c;
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);
s.owner = h;
}
}
make_cells_of_heptagon();
runlevel = 2;
}
EX void load_map_full(hstream& f) {
init();
load_map_bin(f);
while(runlevel < 10) step(1000);
start_game_on_created_map();
}
void cancel_map_creation() {
base = NULL;
runlevel = 0;
@ -950,7 +1034,7 @@ void show_gridmaker() {
};
}
EX void visual_creator() {
EX void init() {
stop_game();
orig_geometry = geometry;
switch(geometry) {
@ -966,13 +1050,19 @@ EX void visual_creator() {
break;
}
base_geometry = geometry;
variation = eVariation::pure;
start_game();
if(base) delete base;
base = currentmap;
base_config = euc::eu;
drawthemap();
cellcount = int(isize(base->allcells()) * density + .5);
gridmaking = true;
drawthemap();
}
EX void visual_creator() {
init();
pushScreen(show_gridmaker);
runlevel = 0;
gridmaking = true;
@ -1015,7 +1105,7 @@ int readArgs() {
else if(argis("-irrload")) {
PHASE(3);
restart_game();
visual_creator();
init();
showstartmenu = false;
shift();
load_map(args());

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) {
@ -39,9 +44,9 @@ EX bool doPickupItemsWithMagnetism(cell *c) {
if(!isNeighbor(c, c4) && c3->item && !c4->item && passable(c4, c3, ZERO)) {
changes.ccell(c3);
changes.ccell(c4);
c4->item = c3->item;
moveEffect(movei(c3, c4, (cw+j).spin), moDeadBird);
c3->item = itNone;
moveItem(c3, c4, false);
animateMovement(match(c3, c4), LAYER_BOAT);
moveEffect(movei(c4, c4, NODIR), moDeadBird);
markOrb(itCurseRepulsion);
}
}
@ -57,8 +62,12 @@ EX bool doPickupItemsWithMagnetism(cell *c) {
}
else if(c3->item == itOrbSafety || c3->item == itBuggy || c3->item == itBuggy2)
csaf = c3;
else if(markOrb(itOrbMagnetism))
else if(markOrb(itOrbMagnetism)) {
eItem it = c3->item;
collectItem(c3, c3, false);
if(!c3->item)
animate_item_throw(c3, c, it);
}
}
if(csaf)
return collectItem(csaf, csaf, false);
@ -733,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

@ -171,8 +171,8 @@ EX void place_elemental_wall(cell *c) {
else if(c->land == laEEarth) c->wall = waStone;
}
// automatically adjust monster generation for 3D geometries
EX int hrand_monster(int x) {
// automatically adjust monster generation for 3D geometries and custom difficulty
EX int hrand_monster_in(eLand l, int x) {
// dual geometry mode is much harder, so generate less monsters to balance it
if(dual::state) x *= 3;
// in 3D monster generation depends on the sight range
@ -180,9 +180,15 @@ EX int hrand_monster(int x) {
int t = isize(gmatrix);
if(t > 500) x = int(((long long)(x)) * t / 500);
}
if(use_custom_land_list) {
x = x * 100 / custom_land_difficulty[l];
if(x == 0) x = 1;
}
return hrand(x);
}
#define hrand_monster(x) hrand_monster_in(c->land, x)
EX bool is_zebra_trapdoor(cell *c) {
if(euclid && closed_or_bounded) return false;
#if CAP_ARCM
@ -195,7 +201,6 @@ EX bool is_zebra_trapdoor(cell *c) {
else if(PURE && reg3::exact_rules()) switch(geometry) {
case gSpace534: {
if(c->master->fieldval == 0) return true;
forCellCM(c1, c) if(c1->master->fieldval == 0) return true;
return false;
}
case gSpace435: {
@ -280,6 +285,23 @@ EX void gen_baby_tortoise(cell *c) {
tortoise::babymap[c] = tortoise::getb(c) ^ tortoise::getRandomBits();
}
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) {
@ -536,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;
@ -634,9 +656,9 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
c->wall = waCavewall;
else c->wall = waCavefloor;
}
else if(a4 || arcm::in() || cryst)
else if(a4 || arcm::in() || cryst || bt::in() || S3 >= OINF)
c->wall = hrand(100) < 50 ? waCavefloor : waCavewall;
else if(!BITRUNCATED) {
else if(!BITRUNCATED && geometry != gOctagon) {
if(polarb50(c))
c->wall = waCavewall;
else c->wall = waCavefloor;
@ -743,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;
@ -753,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] = {
@ -811,7 +836,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
}
else if(WDIM == 3 && hyperbolic && !bt::in())
c->wall = (c->master->zebraval & 2) ? waVinePlant : waNone;
else if(a4 || sphere || arcm::in())
else if(a4 || sphere || arcm::in() || bt::in() || S3 >= OINF)
c->wall = hrand(100) < 50 ? waNone : waVinePlant;
else {
int v = emeraldval(c);
@ -832,6 +857,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
forCellCM(c2, c) if(emeraldval(c2) == (v^1))
c->wall = waVinePlant;
}
if(weirdhyperbolic && cellHalfvine(c)) c->wall = waNone;
}
}
}
@ -924,11 +950,17 @@ 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;
if(cx->land != laTrollheim && cx->land != laNone)
if(cx->land != laTrollheim && cx->land != laNone && !ls::hv_structure())
okay = false;
if(cx->bardir != NODIR) okay = false;
}
@ -1226,7 +1258,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
if(fargen) {
if(hrand(500) < 15)
createArrowTrapAt(c, laTerracotta);
if(pseudohept(c) && hrand(100) < 40 && c->wall == waNone && !racing::on) {
if(pseudohept_r(c) && hrand(100) < 40 && c->wall == waNone && !racing::on) {
c->wall = waTerraWarrior;
c->wparam = terracotta::randterra ? 0 : 3 + hrand(3);
if(hrand(100) < items[itTerra]-10)
@ -1268,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;
@ -1296,6 +1328,12 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
break;
case laHalloween:
if(!closed_or_bounded) {
ONEMPTY {
if(hrand(1000) < PT(20, 20)) c->item = itTreat;
if(hrand(1000) < 20) c->wall = waChasm;
}
}
break;
case laWildWest:
@ -1440,13 +1478,23 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
c->wall = waSandstone;
}
for(int i=0; i<c->type; i++)
if(c->move(i) && c->move(i)->land != laStorms && c->move(i)->land != laNone)
c->wall = waNone;
if(ls::horodisk_structure()) {
if(celldistAlt(c) >= horodisk_from) c->wall = waNone;
}
else if(!ls::voronoi_structure()) {
for(int i=0; i<c->type; i++)
if(c->move(i) && c->move(i)->land != laStorms && c->move(i)->land != laNone)
c->wall = waNone;
}
}
if(d == BARLEV && randstorm) {
c->landparam = hrand(1000000);
}
if(d == 7 && ls::voronoi_structure()) {
for(int i=0; i<c->type; i++)
if(c->move(i) && c->move(i)->land != laStorms)
c->wall = waNone;
}
if(d == BARLEV-1 && randstorm) {
/* static int stormlevel, stormgroup;
if(!stormlevel) stormgroup = 0;
@ -1493,7 +1541,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
if(fargen) {
if(randomPatternsMode)
c->wall = RANDPAT ? ((RANDPATV(laCrossroads) || RANDPATV(laCrossroads2)) ? waAncientGrave : waFreshGrave) : waNone;
else if(pseudohept(c))
else if(pseudohept_r(c))
c->wall = hrand(5) ? waAncientGrave : waFreshGrave;
}
ONEMPTY {
@ -1526,7 +1574,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
c->move(i)->wall = waNone;
}
}
if(pseudohept(c) && hrand(2)) c->wall = waColumn;
if(pseudohept_r(c) && hrand(2)) c->wall = waColumn;
}
}
ONEMPTY {
@ -1791,11 +1839,13 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
}
}
ONEMPTY {
if(hrand_monster(ls::hv_structure() ? 8000 : 4000) < (peace::on ? 750 : 50 + items[itBabyTortoise]*2 + yendor::hardness() * 6) && !safety) {
bool mk21tor = (tortoise::seek() && !((tortoise::getb(c) ^ tortoise::seekbits) & tortoise::mask) && (turncount > tortoise::last21tort + 100));
if((mk21tor || hrand_monster(ls::hv_structure() ? 8000 : 4000) < (peace::on ? 750 : 50 + items[itBabyTortoise]*2 + yendor::hardness() * 6)) && !safety) {
c->monst = moTortoise;
c->hitpoints = 3;
auto val = tortoise::getb(c);
tortoise::emap[c] = val;
if (mk21tor) tortoise::last21tort = turncount;
}
else if(ls::hv_structure() && hrand(10000) <= 250) {
c->item = itCompass;
@ -2035,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]) {
@ -2243,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(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;
}
}
@ -2287,7 +2337,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
int d = -celldistAlt(c);
if(hrand_monster(2500) < items[itMutant2] + yendor::hardness() - 10 && !reptilecheat)
c->monst = moRedFox;
else if(hrand(100 + d) < d && !reptilecheat)
else if(d > 0 && hrand(100 + d) < d && !reptilecheat)
c->item = itMutant2;
}
}
@ -2366,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);
@ -2504,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;
@ -2545,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) {
@ -2616,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) {
@ -2652,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;
}
@ -2870,13 +2920,37 @@ EX void share_land(cell *c, cell *c2) {
c->land = c2->land;
}
EX void set_land_for_geometry(cell *c) {
// odd landscape_div are better
EX int landscape_div = 25;
EX void set_land_for_geometry(cell *c) {
if(!c->land && isize(currentlands)) {
if(land_structure == lsTotalChaos) {
setland(c, random_land());
return;
}
if(land_structure == lsLandscape) {
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;
auto ld2 = ld * 2;
int sh = 0;
for(int i=0; i<3; i++) {
int x = a[i];
x = gmod(x, ld2);
if(x >= ld) sh += x - ld;
else sh += ld - 1 - x;
}
for(int i=0; i<3; i++) {
if(sh * 2 < ld * 3) a[i] = gdiv(a[i], ld2)*2+1;
else a[i] = gdiv(a[i]+ld, ld2)*2;
}
eLand& l = landscape_lands[make_array(a[0], a[1], a[2])];
if(l == laNone) l = random_land();
setland(c, l);
return;
}
/* note: Nil patched chaos done in setLandNil */
if(ls::patched_chaos() && (cgflags & qFRACTAL)) {
share_land(c, fractal_rep(c));
@ -2978,7 +3052,7 @@ EX void setdist(cell *c, int d, cell *from) {
}
#endif
if(!c->land && from && (WDIM == 3 || !among(from->land, laBarrier, laElementalWall, laHauntedWall, laOceanWall)) && !quotient && ls::chaoticity() < 60) {
if(!c->land && from && (WDIM == 3 || !among(from->land, laBarrier, laElementalWall, laHauntedWall, laOceanWall)) && !quotient && ls::chaoticity() < 60 && land_structure != lsLandscape) {
if(!hasbardir(c)) setland(c, from->land);
}
if(c->land == laTemple && ls::any_order()) setland(c, laRlyeh);
@ -3001,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;
@ -3127,4 +3201,6 @@ EX void setdist(cell *c, int d, cell *from) {
#endif
}
#undef hrand_monster
}

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, 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); }
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); }
@ -110,12 +110,33 @@ EX int chaoticity() {
if(land_structure == lsChaosRW) return 80;
if(land_structure == lsPatchedChaos) return 60;
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 }
@ -139,8 +160,16 @@ EX string land_structure_name(bool which) {
return XLAT("horodisks");
case lsVoronoi:
return XLAT("ideal Voronoi");
case lsLandscape:
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";
}
@ -151,6 +180,8 @@ EX void fix_land_structure_choice() {
if(land_structure != lsTotalChaos && land_structure != lsChaosRW)
land_structure = lsSingle;
}
if(land_structure == lsLandscape && !geometry_supports_cdata())
land_structure = lsChaosRW;
if(tactic::on || princess::challenge)
land_structure = lsSingle;
if(yendor::on)
@ -159,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))
@ -224,6 +261,8 @@ EX bool landUnlocked(eLand l) {
#define ACCONLY2(x,y)
#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;
@ -245,6 +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++;
@ -266,6 +309,20 @@ EX int isRandland(eLand l) {
return 0;
}
EX int voronoi_sea_category(eLand l) {
if(l == laRlyeh) return rlyehComplete() ? 0 : 2;
if(among(l, laOcean, laWarpCoast, laLivefjord, laDocks)) return 1;
if(among(l, laWhirlpool, laKraken, laWarpSea, laCaribbean)) return 2;
return 0;
}
EX bool voronoi_sea_incompatible(eLand l1, eLand l2) {
int c1 = voronoi_sea_category(l1);
int c2 = voronoi_sea_category(l2);
if(c1+c2 == 2 && c1 != c2) return true;
return false;
}
EX bool incompatible1(eLand l1, eLand l2) {
if(isCrossroads(l1) && isCrossroads(l2)) return true;
if(l1 == laJungle && l2 == laMotion) return true;
@ -362,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;
@ -371,6 +428,7 @@ EX eLand getNewSealand(eLand old) {
if(!isLandIngame(p)) continue;
return p;
}
return old;
}
EX bool createOnSea(eLand old) {
@ -387,7 +445,7 @@ EX bool all_unlocked = false;
EX vector<eLand> cheatdest_list;
EX eLand getNewLand(eLand old, eLand old2 IS(laBarrier)) {
EX eLand getNewLand(eLand old) {
#if CAP_LEGACY
if(legacy_racing()) {
@ -399,7 +457,7 @@ EX eLand getNewLand(eLand old, eLand old2 IS(laBarrier)) {
eLand l = callhandlers(laNone, hooks_nextland, old);
if(l) return l;
if(cheatdest != old && cheatdest != old2 && cheatdest != laElementalWall) if(!isCyclic(cheatdest) && !isTechnicalLand(cheatdest)) return cheatdest;
if(cheatdest != old && cheatdest != laElementalWall) if(!isCyclic(cheatdest) && !isTechnicalLand(cheatdest)) return cheatdest;
if(cheatdest_list.size()) {
eLand l = cheatdest_list[0];
@ -413,9 +471,7 @@ EX eLand getNewLand(eLand old, eLand old2 IS(laBarrier)) {
while(true) {
eLand n = eLand(hrand(landtypes));
if(n == old) continue;
if(n == old2) continue;
if(incompatible(n,old)) continue;
if(incompatible(n,old2)) continue;
if(!isLandIngame(n)) continue;
if(n == laElementalWall || isTechnicalLand(n)) continue;
if(n == laWildWest) continue;
@ -427,9 +483,9 @@ EX eLand getNewLand(eLand old, eLand old2 IS(laBarrier)) {
if(markOrb(itOrbLuck)) {
int i = items[itOrbLuck];
items[itOrbLuck] = 0;
eLand l1 = getNewLand(old, old2);
eLand l1 = getNewLand(old);
for(int i=1; i<3; i++)
l1 = pickluck(l1, getNewLand(old, old2));
l1 = pickluck(l1, getNewLand(old));
items[itOrbLuck] = i;
return l1;
}
@ -453,9 +509,9 @@ EX eLand getNewLand(eLand old, eLand old2 IS(laBarrier)) {
#endif
if(tactic::on) return specialland;
if(specialland != old && specialland != old2 && easy_to_find_specialland && specialland != laElementalWall) return specialland;
if(specialland != old && easy_to_find_specialland && specialland != laElementalWall) return specialland;
if(specialland != old && specialland != old2 && easy_specialland && specialland != laElementalWall) {
if(specialland != old && easy_specialland && specialland != laElementalWall) {
easy_specialland--;
return specialland;
}
@ -539,7 +595,8 @@ EX eLand getNewLand(eLand old, eLand old2 IS(laBarrier)) {
// the intermediate lands
if(all_unlocked || gold() >= R30) {
tab[cnt++] = laCrossroads;
tab[cnt++] = (geometry || ls::hv_structure()) ? laMirrorOld : laMirror;
tab[cnt++] = laMirrorOld;
tab[cnt++] = laMirror;
tab[cnt++] = laOcean;
tab[cnt++] = laLivefjord;
if(all_unlocked || kills[moVizier]) tab[cnt++] = laEmerald;
@ -548,6 +605,11 @@ EX eLand getNewLand(eLand old, eLand old2 IS(laBarrier)) {
tab[cnt++] = laDocks;
}
tab[cnt++] = laHalloween;
tab[cnt++] = laWildWest;
tab[cnt++] = laAsteroids;
tab[cnt++] = laCA;
// the advanced lands
if(all_unlocked || gold() >= R60) {
tab[cnt++] = laCrossroads;
@ -587,12 +649,14 @@ EX eLand getNewLand(eLand old, eLand old2 IS(laBarrier)) {
if(ls::hv_structure() && landUnlocked(laMountain)) tab[cnt++] = laMountain;
if(ls::hv_structure() && landUnlocked(laClearing)) tab[cnt++] = laClearing;
if(ls::voronoi_structure() && landUnlocked(laRlyeh) && !rlyehComplete()) LIKELY tab[cnt++] = laRlyeh;
if(ls::hv_structure() && landUnlocked(laTemple)) tab[cnt++] = laTemple;
if(landUnlocked(laTrollheim)) {
if(isTrollLand(old)) LIKELY tab[cnt++] = laTrollheim;
if(old == laTrollheim) for(int i=0; i<landtypes; i++) {
eLand l2 = eLand(i);
if(isTrollLand(l2)) LIKELY tab[cnt++] = l2;
if(isTrollLand(l2) && landUnlocked(l2)) LIKELY tab[cnt++] = l2;
}
}
@ -611,16 +675,41 @@ EX eLand getNewLand(eLand old, eLand old2 IS(laBarrier)) {
if(ls::horodisk_structure() && tortoise::seek()) LIKELY tab[cnt++] = laTortoise;
eLand n = old;
while(incompatible(n, old) || incompatible(n, old2) || !isLandIngame(n)) {
n = tab[hrand(cnt)];
if(weirdhyperbolic && specialland == laCrossroads4 && isCrossroads(n))
n = laCrossroads4;
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;
}
EX eLand getNewLand2(vector<eLand> olds) {
for(int i=0;; i++) {
auto old = hrand_elt(olds);
eLand l = getNewLand(old);
// how bad it is
int err = 0;
for(auto o: olds) if(l == o) err += 2000;
for(auto o: olds) if(incompatible(l, o)) err += 1000;
for(auto o: olds) if(voronoi_sea_incompatible(l, o)) err += 100;
// we still allow bad choices if we cannot obtain a good one
if(err <= i) return l;
}
}
EX vector<eLand> land_over = {
laIce, laCaves, laDesert, laHunting, laMotion, laJungle, laAlchemist,
laCrossroads,
@ -683,14 +772,26 @@ EX eLand getLandForList(cell *c) {
return l;
}
EX bool use_custom_land_list;
EX array<bool, landtypes> custom_land_list;
EX array<int, landtypes> custom_land_treasure;
EX array<int, landtypes> custom_land_difficulty;
EX array<int, landtypes> custom_land_wandering;
EX bool isLandIngame(eLand l) {
if(isElemental(l)) l = laElementalWall;
if(use_custom_land_list) return custom_land_list[l];
if(dual::state == 2 && !dual::check_side(l)) return false;
if((eubinary || sol) && isCyclic(l) && l != specialland) return false;
if(l == laCamelot && hyperbolic && WDIM == 3) return false;
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;
@ -716,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." };
@ -773,6 +875,132 @@ EX const int cursed_when = 386;
EX const int walls_when = 388;
EX void mark_tamper() { cheater++; }
EX void customize_land_in_list(eLand l) {
cmode = sm::SIDE | sm::MAYDARK; gamescreen();
dialog::init(XLATN(linf[l].name), linf[l].color);
help = generateHelpForLand(l);
addHelpWithTitle();
dialog::addBreak(100);
dialog::addBoolItem(XLAT("land in game"), custom_land_list[l], 'a');
dialog::add_action([l] {
custom_land_list[l] = !custom_land_list[l];
cheater++;
});
dialog::addSelItem(XLAT("treasure rate"), its(custom_land_treasure[l]), 't');
dialog::add_action([l] {
dialog::editNumber(custom_land_treasure[l], 0, 1000, 10, 100, XLAT("treasure rate in %the1", linf[l].name), "");
dialog::get_ne().reaction = mark_tamper;
});
dialog::addSelItem(XLAT("difficulty"), its(custom_land_difficulty[l]), 'd');
dialog::add_action([l] {
dialog::editNumber(custom_land_difficulty[l], 0, 1000, 10, 100, XLAT("difficulty of %the1", linf[l].name), "");
dialog::get_ne().reaction = mark_tamper;
});
dialog::addSelItem(XLAT("wandering"), its(custom_land_wandering[l]), 'w');
dialog::add_action([l] {
dialog::editNumber(custom_land_wandering[l], 0, 1000, 10, 100, XLAT("difficulty of %the1", linf[l].name), "");
dialog::get_ne().reaction = mark_tamper;
});
gen_landvisited();
if(landvisited[l]) {
dialog::addItem(XLAT("test"), 'T');
dialog::add_action([l] {
stop_game(); firstland = specialland = l; start_game();
});
}
dialog::addBack();
dialog::display();
}
EX void customize_land_list() {
cmode = sm::SIDE | sm::MAYDARK; gamescreen();
dialog::init(XLAT("custom land list"));
if(dialog::infix != "") mouseovers = dialog::infix;
generateLandList([] (eLand l) {
if(!use_custom_land_list) {
custom_land_list[l] = isLandIngame(l);
custom_land_treasure[l] = 100;
custom_land_difficulty[l] = 100;
custom_land_wandering[l] = 100;
}
if(dialog::infix != "" && !dialog::hasInfix(linf[l].name)) return false;
if(l == laCanvas) return true;
return !!(land_validity(l).flags & lv::appears_in_geom_exp);
});
stable_sort(landlist.begin(), landlist.end(), [] (eLand l1, eLand l2) { return land_validity(l1).quality_level > land_validity(l2).quality_level; });
dialog::start_list(900, 900, '1');
for(eLand l: landlist) {
dialog::addBoolItem(XLAT1(linf[l].name), custom_land_list[l], dialog::list_fake_key++);
string s;
if(custom_land_treasure[l] != 100) s += "$" + its(custom_land_treasure[l]) + " ";
if(custom_land_difficulty[l] != 100) s += "!" + its(custom_land_difficulty[l]) + " ";
if(custom_land_wandering[l] != 100) s += "^" + its(custom_land_wandering[l]) + " ";
if(s != "") dialog::lastItem().value = s;
dialog::add_action_confirmed([l] {
if(!use_custom_land_list) {
stop_game();
use_custom_land_list = true;
start_game();
}
pushScreen([l] { customize_land_in_list(l); });
});
}
dialog::end_list();
dialog::addInfo(XLAT("press letters to search"));
dialog::addBoolItem("custom land list mode", use_custom_land_list, 'U');
dialog::add_action_confirmed([] {
stop_game();
use_custom_land_list = !use_custom_land_list;
start_game();
});
if(use_custom_land_list) {
dialog::addItem("disable/enable all", 'D');
dialog::add_action([] {
int qty = 0;
for(int i=0; i<landtypes; i++) if(custom_land_list[i]) qty++;
for(int i=0; i<landtypes; i++) custom_land_list[i] = !qty;
});
}
else dialog::addBreak(100);
dialog::addHelp();
dialog::add_action([] {
gotoHelp(XLAT(
"In this mode, you can choose the lands you want to be in game. You can also customize their treasure rate and difficulty.\n\n"
"While the game automatically selects a list of lands by default, "
"based on whether it thinks they work well in the currently selected tiling, "
"you might not agree with this selection.\n\n"
"Note that, often, lands are enabled or disabled for a GOOD reason! Use at your own risk.\n\n"
"Just click on a land to configure it. If you are not in the custom land list mode, "
"this will restart the game. You can change the settings during a custom game, but it counts as a cheat."
));
});
dialog::addBack();
dialog::display();
keyhandler = [] (int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(dialog::editInfix(uni)) dialog::list_skip = 0;
else if(doexiton(sym, uni)) popScreen();
};
}
// check if the given land should appear in lists
EX land_validity_t& land_validity(eLand l) {
@ -882,7 +1110,7 @@ EX land_validity_t& land_validity(eLand l) {
}
if(ls::hv_structure() && among(l, laDungeon, laEndorian, laBrownian, laPrincessQuest)) return not_in_hv;
if(ls::voronoi_structure() && among(l, laPrairie, laCamelot, laWhirlpool, laClearing)) return not_in_hv;
if(ls::voronoi_structure() && among(l, laPrairie, laCamelot, laWhirlpool, laClearing, laHaunted, laWestWall)) return not_in_hv;
if(ls::horodisk_structure() && l != laCrossroads && isCrossroads(l)) return not_in_hv;
if(l == laBrownian) {
@ -966,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();
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)
@ -987,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

@ -7935,6 +7935,7 @@ Cell("{3,3,3} 5") Cell("{4,3,3} 8") Cell("{3,3,4} 16") Cell("{3,4,3} 24") Cell("
S(x " field quotient space", x " prostor s tělesovým kvocientem")
Honeycomb("{5,3,4}") Honeycomb("{4,3,5}") Honeycomb("{3,3,6}") Honeycomb("{3,4,4}") Honeycomb("{5,3,5}") Honeycomb("{5,3,6}") Honeycomb("{4,3,6}") Honeycomb("{5,3,6}")
Honeycomb("{3,4,5}") Honeycomb("{3,5,3}") Honeycomb("{3,5,4}") Honeycomb("{3,5,5}")
#undef Honeycomb
// new or previously untranslated options
@ -8425,7 +8426,7 @@ S("stretched hyperbolic", "natažené hyperbolické")
S("stretched Solv", "natažený Solv")
S("{3,∞} (infinite triangles)", "{3,∞} (nekonečné trojúhelníky)")
S("{4,∞} (infinite triangles)", "{4,∞} (nekonečné čtverce)")
S("{4,∞} (infinite squares)", "{4,∞} (nekonečné čtverce)")
S("{3/4,∞} (infinite triangles and squares)", "nekonečné trojúhelníky a čtverce")
S("4D crystal in H3", "4D krystal v H3")
@ -9692,3 +9693,662 @@ S(
"* na Prérii poté, co ji odemkneš (%3 pokladů)\n\n"
)
// 13.0
// gameplay
//==========
// these were missing somehow
N("Palace Quest", GEN_F, "Palácová mise", "Palácové mise", "Palácovou misi", "na Palácové misi")
N("Pike", GEN_F, "Štika", "Štiky", "Štiku", "Štikou")
// crossbow
S("The warped space distracts you from reloading while staying in place!",
"Pokřivený prostor ti brání nabíjet na místě!")
S("Fire!", "Hoří!")
S("(shooting while unstable -- no turn passes)", "(střelba z nestabilní polohy -- bez spotřeby kola)")
S("Stab them by shooting around them.", "(Bodni je tím, že střelíš kolem nich.)")
S("You are too weakened to attack %the1!", "Jsi příliš slab%ý0 na útok proti %a2!")
S("You cannot attack your own mount!", "Nemůžeš útočit na vlastní jízdní zvíře!")
S("A magical shield protects %the1!", "%a1 chrání magický štít!")
S("You have no melee weapon!", "Nemáš žádnou zbraň pro boj na blízko!")
S("Your crossbow is still reloading!", "Tvá kuše se stále ještě nabíjí!")
S("Trying to fire.", "Pokoušíš se vystřelit.")
S(" (turns to reload: %1)", " (počet kol do nabití: %1)")
S(" (fire mode on / turns to reload: %1)", " (palebný mód / počet kol do nabití: %1)")
S(" (fire mode on)", " (palebný mód)")
S(" (click to fire)", " (střílej kliknutím)")
S("You fire an angry glance at your enemies.", "Věnuješ nepřátelům ošklivý pohled.")
S("Note: cannot fire again yet. Turns to reload: %1.", "Poznámka: ještě nemůžeš střílet. Počet kol do nabití: %1")
S("Fire crossbow! Click to aim, click again to confirm.", "Vystřel! Klikni pro zamíření, a znovu pro potvrzení.")
S("Fire mode disabled.", "Palebný mód vypnut.")
S("Firing cancelled.", "Střelba zrušena.")
S("Cannot fire again yet. Turns to reload: %1.", "Ještě nemůžeš znovu střílet. Počet kol do nabití: %1")
S("No way to hit this place.", "To se nedá zasáhnout.")
S("Shooting impossible.", "Nemůžeš střílet.")
S("%The1 is enraged!", "%1 se rozzuři%l1!")
S("weapon selection", "výběr zbraně")
S("Cannot hit anything by shooting this direction!", "Tímhle směrem nemůžeš nic trefit!")
S("Welcome to HyperRanger!", "Vítej v HyperRanger!")
S("bow color", "barva kuše")
S("bowstring color", "barva tětivy")
S("%The1 alarms other dogs as it dies!", "Umírající %1 burcuje ostatní!")
S("crossbow straight line style", "styl střelných čar")
S("bull line", "býčí čára")
S("Can go in either direction on odd shapes. 3 turns to reload.", "Na lichých tvarech můžeš jít kterýmkoli směrem. Nabíjení trvá 3 kola.")
S("Graph geodesic: any sequence of tiles is OK as long as there are no shortcuts. 4 turns to reload.", "Grafová geodetika: jakákoli sekvence políček je v pořáídku, pokud neexistují zkratky. Nabíjení trvá 4 kola.")
S("geometric", "geometrické čáry")
S("Approximations of geometric straight lines.", "Aproximace geometrických přímek")
S("bump to shoot", "střílej naběhnutím")
S("mouse auto-fire mode", "mód automatické střelby myší")
S("explicit", "explicitní")
S("You need to click crossbow or be close to fire.", "Na výstřel musíš kliknout na kuši nebo být blízko.")
S("priority", "prioritní")
S("Click on a faraway monster to fire if possible, or move if not.", "Klikni na vzdáleného netvora, abys vystřelil, je-li to možné, nebo se pohnul, pokud není.")
S("Clicking on a faraway monster always means an attempt to fire.", "Kliknutí na vzdáleného netvora vždy znamená pokus o výstřel.")
S("blade", "čepel")
S("Standard Rogue weapon. Bump into a monster to hit. Most monsters attack you the same way.",
"Standardní zbraň. Naběhni do netvora, abys na něj zaútočil. Většina netvorů na tebe útočí stejným způsobem.")
S("crossbow", "kuše")
S("Hits all monsters in a straight line, but slow to reload. Press 'f' or click the crossbow icon to target.",
"Zasáhne všechny netvory v přímé linii, chvíli však trvá, než se znovu nabije. Cíluj klávesou 'f' nebo kliknutím na ikonu kuše.")
// 'click to use orb' errors
S("You have no ranged Orbs!", "Nemáš žádné dálkové Sféry!")
S("Strong wind can only take you to a specific place!", "Silný vítr tě může odnést pouze na určité místo!")
S("%The1 can only be used on items!", "%1 se dá použít pouze na předměty!")
S("Nothing to blow here!", "Tady není co odfouknout!")
S("Cannot be used in multiplayer", "Toto nelze použít v módu pro více hráčů")
S("You cannot grow on yourself!", "Nemůžeš růst na sobě!")
S("Cannot attack there!", "Tam nemůžeš útočit!")
S("Cannot grow there!", "Tam nemůžeš růst!")
S("Cannot grow against gravity!", "Nemůžeš růst proti gravitaci!")
S("You cannot grow there from any adjacent cell!", "Tam nemůžeš vyrůst z žádného sousedního políčka!")
S("Cannot vault that far!", "Tak daleko nedoskočíš!")
S("ERROR: No common neighbor to vault through!", "CHYBA: Není žádný společné sousední políčko, přes které bys mohl přeskočit!")
S("Can only vault in a roughly straight line!", "Skoky lze provádět pouze (zhruba) přímo!")
S("Nothing to vault over!", "Není přes co přeskočit!")
S("Cannot pass through %the1 while vaulting!", "Při přeskoku nemůžeš projít skrz %a1!")
S("Cannot vault onto %the1!", "Nemůžeš skočit na %a1!")
S("Cannot vault to %the1!", "Nemůžeš skočit do %a1!")
S("Cannot attack %the1 while vaulting!", "Nemůžeš útočit během skoku!")
S("Cannot jump that far!", "Tak daleko nedoskočíš!")
S("Cannot jump onto %the1!", "Nemůžeš vyskočit na %a1!")
S("Cannot phase that far!", "Nemůžeš fázovat tak daleko!")
S("Cannot phase onto %the1!", "Nemůžeš fázovat na %a1!")
S("Cannot phase to %the1!", "Nemůžeš fázovat do %a1!")
S("Nothing to phase through!", "Není tu nic, skrz co by se dalo fázovat!")
S("Can only use %the1 on a monster!", "%a1 můžeš použít pouze na netvory!")
S("%The1 is immune to %the2!", "%1 je proti %a2 imunní!")
S("%The1 can only be used on monsters.", "%1 se dá používat pouze na netvory.")
S("%The1 cannot be used on big monsters.", "%1 se nedá používat na velké netvory.")
S("%The1 cannot be used on %the2.", "%1 se nedá použít na %abl2.")
S("%The1 is already stunned!", "%1 už je omráčen%ý1!")
// multiplayer settings
S("friendly fire", "přátelská palba")
S("friendly fire off -- achievements disabled", "přátelská palba vypnutá -- achievementy také")
S("player vs player", "hráč proti hráči")
S("PvP available only in shmup", "mód 'hráč proti hráči' je dostupný pouze ve střílečkovém módu")
S("PvP grants infinite lives -- achievements disabled", "v módu 'hráč proti hráči' máš nekonečné životy -- achievementy jsou vypnuté")
S("split screen mode", "mód rozdělené obrazovky")
S("achievements disabled in split screen", "mód rozdělené obrazovky -- achievementy jsou vypnuté")
S("auto-adjust dual-focus projections", "automatické přizpůsobení projekcí s dvojím zaostřením")
S("autoscale dual focus", "automatické škálování dvojího zaostření")
S("self hits", "útoky do sebe")
S(" (%1 $$$, %2 kills, %3 deaths)", "(%1 $$$, zabitých nepřátel: %2, smrtí: %3)")
S(" (%1 pkills)", " (%1 zabitých hráčů)")
S(" (%1 self)", " (%1 sebe)")
// racing mode
S("play on an official track", "hraj na oficiální dráze")
S("generate a random track", "vygeneruj náhodnou dráhu")
S("Too many pauses!", "Příliš mnoho pauz!")
S("Pauses: %1 of %2 allowed", "Pauzy: %1 z %2 povolených")
// new land structures
S("horodisks", "horodisky")
S("land size in horodisk mode", "velikost krajů v horodiskovém módu")
S("Set this to -2 to get perfect horodisks. Smaller values yield less dense horodisks, and larger values might produce horodisks with errors or crashing into each other.",
"Dokonalé horodisky získáš na hodnotě -2. Nižší hodnoty vedou k menší hustotě horodisků; vyšší hodnoty mohou vést k horodiskům, které obsahují chyby nebo do sebe narážejí.")
S("ideal Voronoi", "ideální Voronoi")
S("display Voronoi tie debug values", "zobrazit debugové hodnoty pro Voronoiova políčka")
S("land size in randomwalk mode", "velikost krajů v módu náhodné procházky")
S("The average size of a land in randomwalk mode.", "Průměrná velikost kraje v módu náhodné procházky.")
S("this starting land is not eligible for achievements", "s tímto počátečním krajem není možné získat achievementy")
S("eligible for most achievements", "lze získat většinu achievementů")
S("eligible for Chaos mode achievements", "lze získat achievementy v chaotickém módu")
S("eligible for special achievements", "lze získat speciální achievementy")
S("not eligible for achievements", "nelze získat achievementy")
S("(but the cheat mode is on)", "(ale je zapnutý cheat mód)")
S("(but the casual mode is on)", "(ale je zapnutý neformální mód)")
// other gameplay
S("There should be a Palace somewhere nearby...", "Někde tady by měl být Palác...")
S("The following Orbs act an extra lives in the shmup mode:", "Následující Sféry fungují ve střílečkovém módu jako životy navíc:")
S("\n\nThis Orb is triggered on your first direct melee attack or illegal move.", /* 'direct melee' added to an earlier version of this message */
"\n\nTato Sféra se spustí při tvém prvním přímém útoku nablízko nebo ilegálním tahu.")
S("\n\nOrb unlocked: %1", "\n\nSféra odemčena: %1")
S("toggle numerical display", "přepnutí číselného displeje") // in help
S("display mine counts numerically", "zobrazuj počet min číslem")
S("Accessible only from %the1, %2, or %3.\n", "Kraj je přístupný pouze z: %1, %2, %3.\n")
S("Cannot switch places with %the1!", "Nemůžeš si vyměnit místo s %abl1!")
S("d%1 rolled %2", "d%1 hodila %2")
S("orb display mode", "mód zobrazení Sfér")
S("icons", "ikony")
// menu & configuration
//======================
S("default: ", "standardní: ")
S("use the default value", "použij standardní hodnotu")
S("pick scores", "vyber skóre")
S("Angle to rotate by.", "Úhel rotace")
S("dxy(n) = rotate n degrees from x to y\n\nd-degree, r-radian, t-turn\n\nexample: dxy(30)*dyz(45)",
"dxy(n) = otočení o n stupňů od x do y\n\nd-stupeň (degree), r-radián, t-otočka (turn)\n\například: dxy(30)*dyz(45)")
S("no filters", "bez filtrů")
S("yet another classic game", "další klasická hra") // hyperbolic Minesweeper
S("context help", "kontextová nápověda")
S("all context help/welcome messages", "plná kontextová nápověda")
S("no context help/welcome messages", "bez kontextové nápovědy")
S("I know I can press F1 for help", "vím, že mohu získat nápovědu stisknutím klávesy F1")
S("menu map darkening", "ztmavování mapy v menu")
S("A larger number means darker game map in the background. Set to 8 to disable the background.",
"Vyšší číslo znamená tmavší herní mapu na pozadí. Hodnota 8 pozadí úplně vypne.")
S("centered menus in widescreen", "vycentrované menu na širokých obrazovkách")
S("less items/kills in landscape", "méně předmětů/zabití v orientaci na šířku")
S("less items/kills in portrait", "méně předmětů/zabití v orientaci na výšku")
S("forced center down", "vynucený střed níže")
S("make the center not the actual screen center", "způsobí, že střed herní plochy není skutečným středem obrazovky")
// animations
S("idle animation speed", "rychlost nečinné animace")
S("flashing effects", "bleskové efekty")
S("Disable if you are photosensitive. Replaces flashing effects such as Orb of Storms lightning with slow, adjustable animations.",
"Vypni, pokud máš citlivost na světlo. Nahrazuje blikající efekty, jako je Sféra Bouří, pomalými, konfigurovatelnými animacemi.")
S("start animations", "startovní animace")
S("movement animation", "animace pohybu")
S("animation rug angle", "úhel animace koberce")
S("rug forward movement angle", "úhel pohybu koberce dopředu")
S("rug_camera angle", "úhel kamery koberce")
S("translation+rotation", "posunutí+otočení")
// save file selection
S("select the score/save file on startup", "vyber soubor se skóre/uloženou hrou při spuštění")
S("choose your score/save file", "vyber soubor se skóre/uloženou hrou")
S("Save the config and restart to select another score/save file.", "Ulož konfiguraci a restartuj hru pro vybrání jiného souboru se skóre/uloženou hrou.")
S("Save the config to always play without recording your progress.", "Ulož konfiguraci, aby se vždy hrálo bez zaznamenávání postupu.")
S("Save the config to always use %1.", "Ulož konfiguraci, aby se vždy používalo %1.")
S("Your progress will not be saved.", "Tvůj postup nebude uložen.")
// online demo (not translated but just in case)
S("HyperRogue %1: online demo", "HyperRogue %1: online demo")
S("play the game", "hraj")
S("learn about hyperbolic geometry", "nauč se něco o hyperbolické geometrii")
S("toggle high detail", "přepni vysokou úroveň detailů")
// other
S("wiki", "wiki")
S("highlight faraway monsters", "zvýrazni vzdálené netvory")
// map editor, line patterns, etc.
//=================================
S("hint: shift+A to enter the map editor", "nápověda: stiskem shift+A se dostaneš do mapového editoru")
S("z = set Shift+click", "z = nastav Shift+klik")
S("B = build on walls ", "B = stavění na zdech")
S("S = snap (%1)", "S = přicvaknutí (%1)")
S("Z =", "Z = ")
S("X =", "X = ")
S("Y =", "Y = ")
S("w: %1", "w: %1")
S("λ: %1°", "λ: %1°")
S("edit cell values", "editace hodnot políček")
S("canvas floor shape", "tvar podlahy Plátna")
S("canvas darkness", "tmavost Plátna")
S("die shape", "tvar kostky")
S("die face", "stěna kostky")
S("die direction", "směr kostky")
S("die mirror status", "zrcadlový status kostky")
S("mirrored", "zrcadlená")
// line patterns
S("parallel/meridian orientation", "orientace rovnoběžek/poledníků")
S("number of parallels drawn", "počet nakreslených rovnoběžek")
S("last parallel drawn", "poslední nakreslená rovnoběžka")
S("tree-drawing parameter", "parametr kreslení stromu")
S("How much of edges to draw for tree patterns (to show how the tree edges are oriented).",
"Jak velká část hran se má kreslit ve stromových vzorech (pro vyznačení jejich orientace).")
// debug tools
S("error", "chyba")
S("display tile debug values", "zobrazení debugových hodnot políček")
S("Display cell type IDs, as well as vertex and edge identifiers.\n\n"
"Setting 1 uses the internal shape IDs, while setting 2 in tes files uses the original IDs"
" in case if extra tile types were added to separate mirror images or different football types.",
"Zobrazuje ID typu políčka a identifikátory vrcholů a hran.\n\n"
"Hodnota 1 používá interní ID tvarů, zatímco hodnota 2 používá původní ID ze souborů *.tes "
"pro případ, že se přidaly další typy políček, aby se oddělily zrcadlové obrazy nebo různé fotbalové typy.")
// tessellations / honeycombs / projections / embeddings
//========================================================
// new geometry settings
S("projective Bring's Surface", "projektivní Bringův povrch")
S("aperiodic hat", "aperiodický klobouk")
S("Sierpiński triangle", "Sierpińského trojúhelník")
S("Sierpiński carpet", "Sierpińského koberec")
S("6-flake fractal", "6-vločkový fraktál")
S("Menger sponge", "Mengerova houba")
S("Sierpiński tetrahedron", "Sierpińského čtyřstěn")
S("aperiodic spectre", "aperiodický přízrak")
// inter-geometric portals
S("Welcome to a portal map! Press 'o' to configure.", "Vítej v portálové mapě! Stiskni 'o' pro konfiguraci.")
S("become a portal map", "změnit na portálovou mapu")
S("yes, that's what I want", "ano, to je to, co chci")
S("world list", "seznam světů")
S("manage portals", "správa portálů")
S("view another world", "podívat se na jiný svět")
S("connect ", "spojit ")
S("disconnect this portal", "odpojit tento portál")
S("remove %1 from the list", "odstranit %1 ze seznamu")
S("add to list", "přidat na seznam")
S("portal orientation", "orientace portálu")
S("mirror connection", "zrcadlové spojení")
S("test portal here", "otestovat portál zde")
S("set recommended settings", "zadat doporučené nastavení")
S("height-to-width ratio", "poměr výšky a šířky")
S("keep eye level when walking enabled", "udržovat výši oka při zapnuté chůzi")
S("walking eye angle", "úhel oka při chůzi")
S("0 = looking forward, 90 = looking upward. In VR this is adjusted automatically.",
"0 = dopředu, 90 = nahoru. Ve VR módu se upravuje automaticky.")
S("eye angle scale", "škálování úhlu oka")
S("1 = the angle can be changed with keyboard or mouse movements, 0 = the angle is fixed",
"1 = úhel je možné měnit klávesnicí nebo pohybem myši, 0 = úhel je pevně daný")
S("walking eye level", "výše oka při chůzi")
S("Distance from the floor to the eye in the walking mode, in absolute units. In VR this is adjusted automatically.",
"Vzdálenost oka od podlahy v módu chůze, vyjádřená v absolutních jednotkách. Ve VR módu se upravuje automaticky.")
S("move the camera with arrow keys and Home/End", "přesouvat kameru šipkami a klávesami home/End")
S("the map is fixed (improves performance)", "fixní mapa (zlepšuje výkon)")
S("You are currently in a visualization. Press wasd to scroll, qe to rotate. You can also use the arrow keys. ESC for menu.\n\n",
"Momentálně se nacházíš ve vizualizaci. Stiskni klávesy WASD pro pohyb, QE pro rotaci. Také můžeš používat šipky. ESC otvírá menu.\n\n")
S("You are currently in a visualization. Press wasdqe to rotate the camera, ijklyh to move. You can also use the arrow keys and Home/End and PgUp/PgDn. ESC for menu.\n\n",
"Momentálně se nacházíš ve vizualizaci. Stiskni klávesy WASDQE pro rotaci kamery, IJKLYH pro pohyb. Také můžeš používat šipky a klávesy Home/End a PgUp/PgDn. ESC otvírá menu.\n\n")
S("pure exploration (game keys scroll)", "čisté zkoumání světa (herní klávesy scrollují)")
// subdivisions of 3D honeycombs
S("sub-cubes", "podkrychle")
S("dual sub-cubes", "duální podkrychle")
S("bitruncated sub-cubes", "dvojseříznuté podkrychle")
S("note: more choices in cubic honeycombs", "poznámka: v krychlových dlážděních je více voleb")
S("subdivision", "poddělení")
S("split by original faces", "rozdělit podle původních stran")
S("split by vertex axes", "rozdělit podle vrcholových os")
S("split by midedges", "rozdělit podle středů hran")
S("Outside of the supported limits", "Mimo podporované hranice")
// let's just not translate this
S("subcubed", "subcubed")
S("dual-subcubed", "dual-subcubed")
S("bitruncated-subcubed", "bitruncated-subcubed")
S("subdivided", "subdivided")
// restrict map to disk
S("disk size", "rozměr disku")
S("Play on a disk. Enables the special game rules for small bounded spaces (especially relevant for e.g. Minefield and Halloween). "
"The number given is the number of tiles to use; it is not used exactly, actually the smallest disk above this size is used. Set to 0 to disable.",
"Hraj na disku. Aktivuje zvláštní herní pravidla pro malé, ohraničené prostory (zvláště relevantní pro např. Minové pole a Halloween). "
"Udané číslo je počet políček; nepoužívá se však přesně tato hodnota, ale nejmenší disk, který ji převyšuje. Nastavením na 0 se tato možnost vypne.")
S("disk shape", "tvar disku")
S("distance in tiles", "vzdálenost v políčkách")
S("distance in vertices", "vzdálenost ve vrcholech")
S("geometric distance", "geometrická vzdálenost")
S("fraction of mine in bounded minefield", "podíl min v ohraničeném minovém poli")
// tessellation tree generation
S("strict tree maps", "striktní stromové mapy")
S("display distances up to", "zobraz vzdálenosti až do")
S("extend automatically", "automatické rozšíření tabulky") // the table of tile count by distances
S("rules generated successfully: %1 states using %2-%3 cells", "pravidla úspěšně vygenerovaná: %1 stavů s využitím %2-%3 políček")
S("too difficult: %1", "příliš obtížné: %1")
S("bug: %1", "bug: %1")
S(
"Strict tree maps are generated using a more powerful algorithm.\n\nThis algorithm supports horocycles and knows the expansion rates of various "
"tessellations (contrary to the basic implementation of Archimedean, tes, and unrectified/warped/untruncated tessellations).\n\nYou can convert mostly any "
"non-spherical periodic 2D tessellation to strict tree based.\n\nSwitching the map format erases your map.",
"Striktní stromové mapy se vytvářejí pomocí silnějšího algoritmu.\n\nTento algoritmus podporuje horocykly a zná rychlost růstu různých "
"dláždění (oproti základní implementaci archimédovských dláždění, *.tes a nerektifikovaných/pokřivených/neseříznutých dláždění).\n\nTéměř jakékoli "
"nesférické periodické 2D dláždění je možné zkonvertovat na striktní stromovou mapu.\n\nZměna formátu mapy tvoji mapu vymaže."
)
S("in tes internal format", "v interním formátu *.tes")
S("converted successfully -- %1 cell types", "konverze úspěšná -- %1 typů políček")
S("cannot be disabled for this tiling", "v tomto dláždění nelze vypnout")
S("extended football colorability", "rozšířená obarvitelnost fotbalového míče")
S("consider all symmetries when converting", "ber při konverzi v úvahu všechny symetrie")
S("tes reverse order on convert", "obrácené pořadí *.tes při konverzi")
S("maximum cellcount", "maximální počet políček")
S("controls the max memory usage of conversion algorithm -- the algorithm fails if exceeded",
"ovládá maximální využití paměti konverzním algoritmem -- pokud se toto množství překročí, algoritmus skončí neúspěšně")
// hat tiling
S("hat/spectre/turtle parameter", "parametr hat/spectre/turtle")
S("Apeirodic hat tiling based on: https://arxiv.org/pdf/2303.10798.pdf\n\n"
"This controls the parameter discussed in Section 6. Parameter p is Tile(p, (2-p)√3), "
"scaled so that the area is the same for every p.\n\n"
"Aperiodic spectre tiling based on: https://arxiv.org/abs/2305.17743\n\n"
"In the spectre tiling, set the parameter to 'spectre' value to make all tiles have the same shape.",
"Aperiodické kloboukové (hat) dláždění založené na: https://arxiv.org/pdf/2303.10798.pdf\n\n"
"Toto ovládá parametr diskutovaná v Sekci 6. Parametr p znamená Tile(p, (2-p)√3), "
"škálovaný tak, aby měla pole pro všechna p stejný obsah.\n\n"
"Aperiodické přízrakové (spectre) dláždění založené na: https://arxiv.org/abs/2305.17743\n\n"
"Pokud v přízrakovém dláždění nastavíš parametr na hodnotu 'spectre', budou mít všechna políčka stejný tvar.")
S("Welcome to HatRogue!", "Vítej v HatRogue!")
S("hat in cluster", "klobouk ve shluku")
S("hat clusters", "shluky klobouků")
S("hat superclusters", "supershluky klobouků")
S("types (mark reverse)", "typy (označit převrácené)")
S("display small floors", "zobrazit malé podlahy")
S("chevron (periodic)", "chevron (periodický)")
S("hat", "klobouk ('hat')")
S("spectre", "přízrak ('spectre')")
S("turtle", "želva ('turtle')")
S("comma (periodic)", "čárka (periodická)")
S("hat parameter (imaginary)", "parametr 'hat' (imaginární)")
S("Imaginary part of the hat parameter. This corresponds to the usual interpretation of complex numbers in Euclidean planar geometry: "
"rather than shortened or lengthened, the edges are moved in the other dimension.",
"Imaginární část parametru 'hat'. Odpovídá obvyklé interpretaci komplexních čísel v eukleidovské rovinné geometrii: "
"místo aby se hrany zkracovaly nebo prodlužovaly, posouvají se ve druhém rozměru."
)
// fake curvature setting in experiments in geometry (some texts were not translated)
S(
"This feature lets you construct the same tiling, but "
"from shapes of different curvature.\n\n"
"The number you give here is (2D) vertex degree or (3D) "
"the number of cells around an edge.\n\n",
"Zde můžeš sestavit stejné dláždění, ale "
"z tvarů odlišné křivosti.\n\n"
"Číslo, které se zde zadává, udává (2D) stupeň vrcholu nebo (3D) "
"počet buněk kolem hrany.\n\n")
S("original", "originální")
S("double original", "dvojitá originální")
S("draw all if multiple of original", "vykresluj vše, je-li to násobkem originálu")
S("draw copies (2D only)", "vykresluj kopie (pouze 2D)")
S("unordered", "neuspořádané")
S("pre-ordered", "uspořádané 'před'")
S("post-ordered", "uspořádané 'po'")
// other tessellation-related
S("color by symmetries (reversed tiles marked)", "obarvi podle symetrií (s vyznačením převrácených dlaždic)")
S("unreversed colors", "nepřevrácené barvy")
S("symmetric subdivision", "symetrické poddělení")
S("simplified display of apeirogons", "zjednodušené zobrazení apeirogonů")
S("Width of cell boundaries", "šířka hranic políček")
S("How wide should the cell boundaries be.", "Jak široké by měly být hranice políček.")
S("the following sliders will restart the game", "následující slidery restartují hru")
// new projections and parameters
S("horocyclic equal-area", "horocyklická rovnoplochá")
S("conformal square", "konformální čtverec")
S("Lie perspective", "perspektiva v Lieově grupě")
S("Lie orthogonal", "ortogonální projekce v Lieově grupě")
S("relativistic perspective", "relativistická perspektiva")
S("relativistic orthogonal", "relativistická ortogonální projekce")
S("angle between the axes", "úhel mezi osami")
S("In two-axe-based models, this parameter gives the angle between the two axes.", "V modelech založených na dvou osách tento parametr udává úhel mezi nimi.")
S("model orientation 3D", "orientace modelu ve 3D")
S("semidirect_rendering (perspective on GPU)", "polopřímé renderování (perspektiva v GPU)")
S("this is not a Lie group", "toto není Lieova grupa")
S("not implemented", "není implementováno")
S("auto rotation", "automatická rotace")
S("auto rotation in 3D", "automatická rotace ve 3D")
// alternative screen projections
S("stereo/high-FOV mode", "mód stereo / velký zorný úhel")
S("linear perspective", "lineární perspektiva")
S("for red-cyan glasses", "pro červeno-tyrkysové 3D brýle")
S("for mobile VR", "pro mobilní VR")
S("ODS", "projekce ODS")
S("for rendering 360° VR videos (implemented only in raycaster and some other parts)",
"pro renderování 360° VR videí (implementováno pouze v raycasteru a některých jiných částech)")
S("Panini", "Panini")
S("Projection believed to be used by Italian painters. Allows very high FOV angles while rendering more straight lines as straight than the stereographic projection.",
"Domníváme se, že tuto projekci používali italští malíři. Umožňuje opravdu velké zorné úhly, a přitom vykresluje více přímek jako přímky než stereografická projekce.")
S("stereographic", "stereografická projekce")
S("Stereographic projection allows very high FOV angles.", "Stereografická projekce umožňuje opravdu velké zorné úhly.")
S("equirectangular", "rovnoobdélníková projekce")
S("for rendering 360° videos (implemented only in raycaster)", "pro renderování 360° videí (implementováno pouze v raycasteru)")
S("stereographic/Panini parameter", "parametr stereografické/Paniniho projekce")
S("1 for full stereographic/Panini projection. Lower values reduce the effect.\n\n"
"HyperRogue uses a quick implementation, so parameter values too close to 1 may be buggy (outside of raycasting); try e.g. 0.9 instead.",
"1 pro plnou stereografickou/Paniniho projekci. Nižší hodnoty účinek oslabují.\n\n"
"HyperRogue používá rychlou implementaci, takže hodnoty parametrů, které se příliš blíží jedné, mohou vést k chybám (s výjimkou raycastingu); zkus raději např. hodnotu 0.9."
)
// embeddings
//============
S("3D embedding method", "metoda vnoření do 3D")
S("3D style", "3D styl")
S("2D engine", "2D engine")
S("Use HyperRogue's 2D engine to simulate same curvature. Works well in top-down and third-person perspective. The Hypersian Rug mode can be used to project this to a surface.",
"Použij 2D engine HyperRogue k simulování stejné křivosti. Dobře to funguje v pohledu seshora nebo třetí osoby. Můžeš použít mód Hyperského koberce, abys výsledek promítl na nějaký povrch.")
S("same curvature", "stejná křivost")
S("Embed as an equidistant surface in the 3D version of the same geometry.",
"Vnoř jako ekvidistantní povrch ve 3D verzi stejné geometrie.")
S("lower curvature", "menší křivost")
S("Embed as a surface in a space of lower curvature.", "Vnoř jako povrch v prostoru s menší křivostí.")
S("much lower curvature", "mnohem menší křivost")
S("Embed sphere as a sphere in hyperbolic space.", "Vnoř kouli jako kouli v hyperbolickém prostoru.")
S("product", "součin")
S("Add one extra dimension in the Euclidean way.", "Přidej jeden rozměr navíc eukleidovským způsobem.")
S("Embed Euclidean plane into Nil.", "Vnoř eukleidovskou rovinu do Nil.")
S("Embed Euclidean or hyperbolic plane into Sol.", "Vnoř eukleidovskou rovinu do Sol.")
S("Embed Euclidean or hyperbolic plane into stretched hyperbolic geometry.", "Vnoř eukleidovskou nebo hyperbolickou rovinu do natažené hyperbolické geometrie.")
S("stretched Sol", "natažený Sol.")
S("Embed Euclidean or hyperbolic plane into stretched Sol geometry.", "Vnoř eukleidovskou nebo hyperbolickou rovinu do natažené geometrie Sol.")
S("Clifford Torus", "Cliffordův torus")
S("Embed Euclidean rectangular torus into S3.", "Vnoř eukleidovský obdélníkový torus do S3.")
S("hyperbolic product", "hyperbolický součin")
S("Embed Euclidean or hyperbolic plane in the H2xR product space.", "Vnoř eukleidovskou nebo hyperbolickou rovinu do součinového prostoru H2xR")
S("spherical product", "sférický součin")
S("Embed Euclidean cylinder or spherical plane in the H2xR product space.", "Vnoř eukleidovský válec nebo sférickou rovinu do součinového prostoru S2xR")
S("Embed Euclidean plane in twisted product geometry.", "Vnoř eukleidovskou rovinu do zkroucené součinové geometrie.")
S("Embed Euclidean cylinder in Euclidean space.", "Vnoř eukleidovský válec do eukleidovského prostoru.")
S("hyperbolic cylinder", "hyperbolický válec")
S("Embed Euclidean cylinder in hyperbolic space.", "Vnoř eukleidovský válec do hyperbolického prostoru.")
S("product cylinder", "součinový válec")
S("Embed Euclidean cylinder in H2xR space.", "Vnoř eukleidovský válec do prostoru H2xR.")
S("Nil cylinder", "Nil válec")
S("Embed Euclidean cylinder in Nil.", "Vnoř eukleidovský válec do Nil.")
S("horocylinder", "horoválec")
S("Embed Euclidean as a horocylinder in H2xR space.", "Vnoř eukleidovskou rovinu do prostoru H2xR jako horoválec.")
S("SL2 cylinder", "SL2 válec")
S("Embed Euclidean as a cylinder in twisted product geometry.", "Vnoř eukleidovský válec do zkroucené součinové geometrie.")
// embedding settings
S("flat, not equidistant", "ploché, nikoli ekvidistantní")
S("invert convex/concave", "převrať konvexní/konkávní")
// embedding errors
S("set square tiling", "nastav čtvercové dláždění")
S("set hex tiling", "nastav šestiúhelníkové dláždění")
S("error: currently works only in PURE Euclidean regular square or hex tiling", "chyba: momentálně funguje pouze v ČISTÉM eukleidovském pravidelném čtvercovém nebo šestiúhelníkovém dláždění")
S("error: currently works only in pure Euclidean, or binary tiling and similar", "chyba: momentálně funguje pouze v čistých eukleidovských dlážděních nebo v binárním dláždění a jemu podobným")
S("set binary tiling variant", "nastav variantu binárního dláždění")
S("set ternary tiling", "nastav ternární dláždění")
S("set binary tiling", "nastav binární dláždění")
S("error: this embedding does not work in shmup", "chyba: toto vnoření nefunguje ve střílečkovém módu")
S("error: this method works only in rectangular torus", "chyba: tato metoda funguje pouze v obdélníkovém torusu")
S("set 20x20 torus", "nastav torus 20x20")
S("error: this method works only in cylinder", "chyba: tato metoda funguje pouze ve válci")
S("set cylinder", "nastav válec")
S("error: not supported", "chyba: není podporováno")
S("error: this method does not work in spherical geometry", "chyba: tato metoda nefunguje ve sférické geometrii")
S("error: this method does not work in hyperbolic geometry", "chyba: tato metoda nefunguje v hyperbolické geometrii")
S("3D styles", "styly 3D")
S("3D detailed settings", "detailní nastavení 3D")
S("more options in 3D engine", "více možností v 3D enginu")
S("configure Hypersian Rug", "konfiguruj Hyperský koberec")
S("view shift for embedded planes", "změna pohledu pro vnořené roviny")
S("always move on geodesics", "vždy se pohybuj po geodetikách")
S("keep levels", "udržuj úrovně")
S("keep the vertical angle of the camera", "udržuj vertikální úhel kamery")
S("mixed", "smíšený mód")
S("on geodesics when moving camera manually, keep level when auto-centering", "udržuj úroveň při automatickém centrování během ručního pohybu kamery po geodetikách")
S("Euclidean embedding rotation", "rotace eukleidovského vnoření")
S("How to rotate the Euclidean embedding, in degrees.", "O kolik stupňů otočit eukleidovské vnoření.")
S("Euclidean embedding scale", "škála eukleidovského vnoření")
S("How to scale the Euclidean map, relatively to the 3D absolute unit.", "Jak škálovat eukleidovskou mapu v poměru ke 3D absolutní jednotce.")
S("Euclidean embedding scale Y/X", "škála eukleidovského vnoření Y/X")
S("This scaling factor affects only the Y coordinate.", "Tento škálovací faktor ovlivňuje pouze souřadnici Y.")
S("(fix errors)", "(oprav chyby)")
S("reset view", "vyresetuj pohled")
S("needs", "potřebuje: ")
// embeddings: detailed 3D parameters
S("set 3D settings automatically", "nastav 3D možnosti automaticky")
S("draw plain floors in 3D", "vykresluj v 3D módu prostou podlahu")
S("floor alpha", "průhlednost podlahy")
S("255 = opaque", "255 = neprůhledné")
S("altitude of the stars", "výška hvězd")
S("star probability", "pravděpodobnost hvězdy")
S("probability of star per tile", "pravděpodobnost hvězdy na jednu dlaždici")
S("night star size (relative to item sizes)", "velikost nočních hvězd (v poměru k velikosti předmětů)")
S("sun size (relative to item sizes)", "velikost slunce (v poměru k velikosti předmětů)")
S("infinite sky", "nekonečná obloha")
S("ratio of high walls to normal walls", "poměr vysokých a normálních stěn")
S("ratio of very high walls to normal walls", "poměr velmi vysokých a normálních stěn")
S("altitude of the sky", "výška oblohy")
S("sky fake height", "falešná výška oblohy")
S("Sky is rendered at the distance computed based on the sky height, "
"which might be beyond the range visible in fog. To prevent this, "
"the intensity of the fog effect depends on the value here rather than the actual distance. Stars are affected similarly.",
"Nebe se renderuje ve vzdálenosti vypočtené na základě výšky oblohy, "
"což může být dál, než činí viditelnost v mlze. Aby se tomu zabránilo, "
"závisí intenzita efektu mlhy na této hodnotě a ne na skutečné vzdálenosti. Hvězdy jsou ovlivněny podobným způsobem."
)
S("sky rendering", "renderování oblohy")
S("do not draw sky", "nevykresluj oblohu")
S("skybox", "skybox")
S("infinite depth", "nekonečná hloubka")
S("The unit this value is given in is wall height. "
"Note that, in exponentially expanding spaces, too high values could cause rendering issues. "
"So if you want infinity, values of 5 or similar should be used -- there is no visible difference from infinity and glitches are avoided.",
"Tato hodnota je udávaná v jednotkách výšky stěny. "
"Pozor -- v exponenciálně se zvětšujících prostorech by příliš vysoká hodnota mohla způsobit problémy při renderování. "
"Chceš-li tedy nekonečno, použij hodnotu 5 nebo něco podobného -- vizuálně tam žádný rozdíl oproti nekonečnu není a vyhneš se chybám.")
S("Level of shallow water", "Úroveň mělké vody")
S("do not render higher levels if camera too high", "nerenderuj vyšší úrovně, je-li kamera příliš vysoko")
S("works only in Euclidean", "toto funguje pouze v eukleidovském prostoru")
S("always", "vždy")
S("might be glitched in some settings", "s některými nastaveními může dělat chyby")
S("prevent exceeding recommended altitudes", "nepřekračuj doporučenou výšku")
S("camera angle", "úhel kamery")
S("render behind the camera", "renderuj za kamerou")
// embeddings: pseudohedral setting
S("make the tiles flat", "ploché dlaždice")
S("the tiles are curved", "dlaždice jsou zakřivené")
S("inscribed", "vepsané")
S("the tiles are inscribed", "dlaždice jsou vepsané")
S("circumscribed", "opsané")
S("the tiles are circumscribed", "dlaždice jsou opsané")
S("depth bonus in pseudohedral", "bonus na hloubku v pseudohedrálním módu")
// embeddings: geodesic movement in Solv etc
S("straight lines", "přímky")
S("Lie group", "Lieova grupa")
S("light, camera, and objects move in lines of constant direction, in the Lie group sense", "světlo, kamera a předměty se pohybují po čarách konstantního směru ve smyslu Lieovy grupy")
S("geodesics", "geodetiky")
S("light, camera, and objects always take the shortest path", "světlo, kamera a objekty se vždy pohybují po nejkratší dráze")
// achievement eligiblity
S("achievement/leaderboard eligiblity:", "dostupnost achievementů/leaderboardů:")
S("eligible for most", "většina achievementů/leaderboardů dostupná")
S("eligible for most -- leaderboards separate", "většina achievementů dostupná -- leaderboardy oddělené")
S("eligible for racing", "závodní achievementy/leaderboardy dostupné")
S("eligible for shmup", "střílečkové achievementy/leaderboardy dostupné")
S("eligible for multiplayer", "multiplayerové achievementy/leaderboardy dostupné")
S("eligible for Chaos mode", "achievementy/leaderboardy chaotického módu dostupné")
S("eligible for Princess Challenge", "achievementy/leaderboardy Mise: Princezna dostupné")
S("eligible for heptagonal", "achievementy/leaderboardy sedmiúhelníkového módu dostupné")
S("eligible for special geometry", "achievementy/leaderboardy speciální geometrie dostupné")
S("eligible for Strange Challenge", "achievementy/leaderboardy Podivné mise dostupné")
S("disabled in cheat mode", "v cheat módu jsou achievementy/leaderboardy nedostupné")
S("disabled in casual mode", "v neformálním módu jsou achievementy/leaderboardy nedostupné")
S("not eligible due to current mode settings", "achievementy/leaderboardy nejsou dostupné díky současnému nastavení módu")
S("no achievements/leaderboards in this version", "v této verzi žádné achievementy/leaderboardy nejsou")

View File

@ -7540,6 +7540,7 @@ Cell("{3,3,3} 5") Cell("{4,3,3} 8") Cell("{3,3,4} 16") Cell("{3,4,3} 24") Cell("
S(x " field quotient space", x " champ d'espace quotient")
Honeycomb("{5,3,4}") Honeycomb("{4,3,5}") Honeycomb("{3,3,6}") Honeycomb("{3,4,4}") Honeycomb("{5,3,5}") Honeycomb("{5,3,6}") Honeycomb("{4,3,6}") Honeycomb("{5,3,6}")
Honeycomb("{3,4,5}") Honeycomb("{3,5,3}") Honeycomb("{3,5,4}") Honeycomb("{3,5,5}")
#undef Honeycomb

View File

@ -7657,6 +7657,7 @@ Cell("{3,3,3} 5") Cell("{4,3,3} 8") Cell("{3,3,4} 16") Cell("{3,4,3} 24") Cell("
S(x " field quotient space", x " przestrzeń ilorazowa ciała")
Honeycomb("{5,3,4}") Honeycomb("{4,3,5}") Honeycomb("{3,3,6}") Honeycomb("{3,4,4}") Honeycomb("{5,3,5}") Honeycomb("{5,3,6}") Honeycomb("{4,3,6}") Honeycomb("{5,3,6}")
Honeycomb("{3,4,5}") Honeycomb("{3,5,3}") Honeycomb("{3,5,4}") Honeycomb("{3,5,5}")
#undef Honeycomb
@ -8144,7 +8145,7 @@ S("stretched hyperbolic", "rozciągnięta hiperboliczna")
S("stretched Solv", "rozciągnięta geometria Solv")
S("{3,∞} (infinite triangles)", "{3,∞} (nieskończone trójkąty)")
S("{4,∞} (infinite triangles)", "{4,∞} (nieskończone kwadraty)")
S("{4,∞} (infinite squares)", "{4,∞} (nieskończone kwadraty)")
S("{3/4,∞} (infinite triangles and squares)", "nieskończone trójkąty i kwadraty")
S("4D crystal in H3", "4D kryształ w H3")
@ -9407,6 +9408,663 @@ S(
"* na Prerii po jej odblokowaniu (%3 skarbów)\n\n"
)
N("Palace Quest", GEN_O, "Misja w Pałacu", "Misje w Pałacu", "Misję w Pałacu", "na Misji w Pałacu")
// 13.0
// gameplay
//==========
// these were missing somehow
N("Palace Quest", GEN_O, "Misja w Pałacu", "Misje w Pałacu", "Misję w Pałacu", "na Misji w Pałacu")
N("Pike", GEN_F, "Szczupak", "Szczupaki", "Szczupaka", "Szczupakiem")
// crossbow
S("The warped space distracts you from reloading while staying in place!",
"Zakrzywiona przestrzeń nie pozwala Ci ładować broni bez ruszania się!")
S("Fire!", "Ognia!")
S("(shooting while unstable -- no turn passes)", "(Strzał z niestabilnej pozycji -- tura nie mija)")
S("Stab them by shooting around them.", "(Dźgnij ich poprzez strzelanie wokół nich.)")
S("You are too weakened to attack %the1!", "Jesteś za słab%y0, by zaatakować %a2!")
S("You cannot attack your own mount!", "Nie można atakować swojego własnego wierzchowca!")
S("A magical shield protects %the1!", "Magiczna tarcza chroni %a1!")
S("You have no melee weapon!", "Nie masz broni do walki wręcz!")
S("Your crossbow is still reloading!", "Twoja kusza wciąż się ładuje!")
S("Trying to fire.", "Próbujesz strzelać.")
S(" (turns to reload: %1)", " (kolejki do naładowania: %1)")
S(" (fire mode on / turns to reload: %1)", " (tryb strzału / kolejki do naładowania: %1)")
S(" (fire mode on)", " (tryb strzału)")
S(" (click to fire)", " (kliknij by strzelać)")
S("You fire an angry glance at your enemies.", "Strzelasz focha.")
S("Note: cannot fire again yet. Turns to reload: %1.", "Uwaga: jeszcze za wcześnie, by strzelać. Liczba kolejek do naładowania: %1")
S("Fire crossbow! Click to aim, click again to confirm.", "Strzał! Kliknij cel, a następnie jeszcze raz, by potwierdzić.")
S("Fire mode disabled.", "Tryb strzału wyłączony.")
S("Firing cancelled.", "Strzał anulowany.")
S("Cannot fire again yet. Turns to reload: %1.", "Wciąż nie możesz strzelać. Liczba kolejek do naładowania: %1")
S("No way to hit this place.", "Nie da się tam trafić.")
S("Shooting impossible.", "Strzał niemożliwy.")
S("%The1 is enraged!", "%1 jest wściekł%y1!")
S("weapon selection", "wybór broni")
S("Cannot hit anything by shooting this direction!", "Nic nie trafisz strzelając w tym kierunku!")
S("Welcome to HyperRanger!", "Witaj w HyperRanger!")
S("bow color", "kolor kuszy")
S("bowstring color", "kolor cięciwy")
S("%The1 alarms other dogs as it dies!", "Umierając%y1 %1 podnosi alarm!")
S("crossbow straight line style", "styl linii strzału")
S("bull line", "linie byka")
S("Can go in either direction on odd shapes. 3 turns to reload.", "Na polach nieparzystych może lekko skręcić w lewo lub prawo. 3 kolejki do przeładowania.")
S("Graph geodesic: any sequence of tiles is OK as long as there are no shortcuts. 4 turns to reload.", "Geodezyjna grafowa: każdy ciąg pól dobry o ile nie ma skrótów. 4 kolejki do przeładowania.")
S("geometric", "linie geometryczne")
S("Approximations of geometric straight lines.", "Przybliżenia geometrycznych linii prostych")
S("bump to shoot", "uderz by strzelać")
S("mouse auto-fire mode", "tryb auto-strzału dla myszy")
S("explicit", "kategoryczny")
S("You need to click crossbow or be close to fire.", "By strzelać, musisz nacisnąć kuszę, albo być blisko.")
S("priority", "priorytetowy")
S("Click on a faraway monster to fire if possible, or move if not.", "Klikając odległego przeciwnika strzelasz jeśli to możliwe, ruszasz się jeśli nie.")
S("Clicking on a faraway monster always means an attempt to fire.", "Kliknięcie przeciwnika zawsze jest rozumiane jako próba strzału.")
S("blade", "broń biała")
S("Standard Rogue weapon. Bump into a monster to hit. Most monsters attack you the same way.",
"Standardowa broń. Uderz potwora, by go zaatakować. Większość potworów atakuję Cię w ten sposób.")
S("crossbow", "kusza")
S("Hits all monsters in a straight line, but slow to reload. Press 'f' or click the crossbow icon to target.",
"Rani wszystkich przeciwników w linii prostej, ale przeładowanie zajmuje dużo czasu. Naciśnij 'f' lub kliknij ikonę kuszy, by celować.")
// 'click to use orb' errors
S("You have no ranged Orbs!", "Nie masz Sfer działających na odległość!")
S("Strong wind can only take you to a specific place!", "Silny wiatr może przenieść Cię tylko w konkretne miejsce!")
S("%The1 can only be used on items!", "%1 może być używan%y1 tylko na przedmiotach!")
S("Nothing to blow here!", "Tu nic nie można zdmuchnąć!")
S("Cannot be used in multiplayer", "Nie można używać w grze na wielu graczy")
S("You cannot grow on yourself!", "Nie możesz rosnąć na sobie!")
S("Cannot attack there!", "Nie można tam zaatakować!")
S("Cannot grow there!", "Nie można tam rosnąć!")
S("Cannot grow against gravity!", "Nie można rosnąć wbrew grawitacji!")
S("You cannot grow there from any adjacent cell!", "Nie można tam wyrosnąć z żadnego sąsiedniego pola!")
S("Cannot vault that far!", "Nie można przeskoczyć tak daleko!")
S("ERROR: No common neighbor to vault through!", "BŁĄD: brak wspólnego sąsiada do przeskoku!")
S("Can only vault in a roughly straight line!", "Przeskok można wykonać tylko w (mniej więcej) prostej linii!")
S("Nothing to vault over!", "Nie ma przez co przeskoczyć!")
S("Cannot pass through %the1 while vaulting!", "Nie można przejść przez %a1 podczas przeskoku!")
S("Cannot vault onto %the1!", "Nie można przeskoczyć na %a1!")
S("Cannot vault to %the1!", "Nie można przeskoczyć do %a1!")
S("Cannot attack %the1 while vaulting!", "Nie można zaatakować %a1 podczas przeskoku!")
S("Cannot jump that far!", "Nie można skoczyć tak daleko!")
S("Cannot jump onto %the1!", "Nie można wskoczyć na %a1!")
S("Cannot phase that far!", "Nie można fazować tak daleko!")
S("Cannot phase onto %the1!", "Nie można fazować na %a1!")
S("Cannot phase to %the1!", "Nie można fazować do %a1!")
S("Nothing to phase through!", "Nie ma nic przez co można fazować!")
S("Can only use %the1 on a monster!", "Można użyć %a1 tylko na potworze!")
S("%The1 is immune to %the2!", "%1 jest odporn%y1 na %a2!")
S("%The1 can only be used on monsters.", "%1 może być użyt%y1 tylko na potworach.")
S("%The1 cannot be used on big monsters.", "%1 nie może być użyt%y1 na dużych potworach.")
S("%The1 cannot be used on %the2.", "%1 nie może być użyt%y1 na %abl2.")
S("%The1 is already stunned!", "%1 już jest ogłuszon%y1!")
// multiplayer settings
S("friendly fire", "bratobójczy ogień")
S("friendly fire off -- achievements disabled", "bratobójczy ogień wyłączony -- osiągnięcia wyłączone")
S("player vs player", "gracz vs gracz")
S("PvP available only in shmup", "tryb gracz vs gracz dostępny tylko w trybie strzelanki")
S("PvP grants infinite lives -- achievements disabled", "gracz vs gracz daje nieskończenie wiele żyć -- osiągnięcia wyłączone")
S("split screen mode", "tryb podzielonego ekranu")
S("achievements disabled in split screen", "podzielony ekran -- osiągnięcia wyłączone")
S("auto-adjust dual-focus projections", "automatycznie dostosuj projekcje podwójnie zogniskowane")
S("autoscale dual focus", "automatyczne skalowanie przy podwójnym ogniskowaniu")
S("self hits", "atakowanie siebie")
S(" (%1 $$$, %2 kills, %3 deaths)", "(%1 $$$, pokonanych: %2, śmierci: %3)")
S(" (%1 pkills)", " (%1 pokonanych graczy)")
S(" (%1 self)", " (%1 siebie)")
// racing mode
S("play on an official track", "graj na torze oficjalnym")
S("generate a random track", "generuj tor losowy")
S("Too many pauses!", "za dużo pauz!")
S("Pauses: %1 of %2 allowed", "Pauzy: %1 dozwolone: %2")
// new land structures
S("horodisks", "horodyski")
S("land size in horodisk mode", "wielkość krainy w trybie horodysków")
S("Set this to -2 to get perfect horodisks. Smaller values yield less dense horodisks, and larger values might produce horodisks with errors or crashing into each other.",
"Ustaw -2 by horodyski były dokładne. Mniejsze wartości to rzadsze horodyski; większe wartości mogą powodować, że horodyski się zderzają, i inne błędy.")
S("ideal Voronoi", "idealne Voronoi")
S("display Voronoi tie debug values", "wartości do debugowania Voronoi")
S("land size in randomwalk mode", "wielkość krainy w trybie błądzenia losowego")
S("The average size of a land in randomwalk mode.", "Średnia wielkość krainy w trybie błądzenia losowego.")
S("this starting land is not eligible for achievements", "ta kraina startu wyłącza osiągnięcia")
S("eligible for most achievements", "większość osiągnięć legalna")
S("eligible for Chaos mode achievements", "osiągnięcia trybu Chaosu legalne")
S("eligible for special achievements", "osiągnięcia spejalne legalne")
S("not eligible for achievements", "osiągnięcia nielegalne")
S("(but the cheat mode is on)", "(ale włączono tryb oszusta)")
S("(but the casual mode is on)", "(ale włączono tryb niezobowiązujący)")
// other gameplay
S("There should be a Palace somewhere nearby...", "Gdzieś tu powinien być Pałac...")
S("The following Orbs act an extra lives in the shmup mode:", "Następujące sfery w trybie strzelanki dają dodatkowe życie:")
S("\n\nThis Orb is triggered on your first direct melee attack or illegal move.", /* 'direct melee' added to an earlier version of this message */
"\n\nTa Sfera się aktywuje automatycznie, gdy wykonasz bezpośredni atak wręcz lub nielegalny ruch.")
S("\n\nOrb unlocked: %1", "\n\nSfera odblokowana: %1")
S("toggle numerical display", "przestaw tryb numeryczny") // in help
S("display mine counts numerically", "pokazuj liczby min cyframi")
S("Accessible only from %the1, %2, or %3.\n", "Kraina dostępna jedynie z: %1, %2, %3.\n")
S("Cannot switch places with %the1!", "Nie można się zamienić miejscami z %abl1!")
S("d%1 rolled %2", "d%1 wyrzuciła %2")
S("orb display mode", "tryb pokazywania sfer")
S("icons", "ikony")
// menu & configuration
//======================
S("default: ", "domyślne: ")
S("use the default value", "użyj wartości domyślnych")
S("pick scores", "wybór wyników")
S("Angle to rotate by.", "O jaki kąt obrócić")
S("dxy(n) = rotate n degrees from x to y\n\nd-degree, r-radian, t-turn\n\nexample: dxy(30)*dyz(45)",
"dxy(n) = obróć n stopni od x do y\n\nd-stopeń (degree), r-radian, t-obrót (turn)\n\nprzykład: dxy(30)*dyz(45)")
S("no filters", "bez filtrów")
S("yet another classic game", "kolejna klasyczna gra") // hyperbolic Minesweeper
S("context help", "pomoc kontekstowa")
S("all context help/welcome messages", "pełna pomoc kontekstowa")
S("no context help/welcome messages", "bez pomocy kontekstowej")
S("I know I can press F1 for help", "wiem, że mogę nacisnąć F1 by dostać pomoc")
S("menu map darkening", "przyciemnianie mapy w menu")
S("A larger number means darker game map in the background. Set to 8 to disable the background.",
"Większa liczba to ciemniejsze tło z mapą gry. Ustaw 8, by całkowicie wyłączyć tło.")
S("centered menus in widescreen", "wycentrowane menu przy szerokim ekranie")
S("less items/kills in landscape", "mniej przedmiotów/zabić w trybie pejzażu")
S("less items/kills in portrait", "mniej przedmiotów/zabić w trybie portretu")
S("forced center down", "centrum niżej")
S("make the center not the actual screen center", "umieść centrum mapy poniżej centrum ekranu")
// animations
S("idle animation speed", "prędkość animacji własnej")
S("flashing effects", "efekty rozbłysku")
S("Disable if you are photosensitive. Replaces flashing effects such as Orb of Storms lightning with slow, adjustable animations.",
"Wyłącz jeśli jesteś czuł%y0 na światło. Zamienia rozbłyski takie, jak efekt błyskawicy, na powolne, konfigurowalne animacje.")
S("start animations", "animacje podczas startu gry")
S("movement animation", "animacja ruchu")
S("animation rug angle", "kąt animacji dywanu")
S("rug forward movement angle", "kąt ruchu wprost dywanu")
S("rug_camera angle", "kąt kamery dywanu")
S("translation+rotation", "translacja+rotacja")
// save file selection
S("select the score/save file on startup", "wybierz plik postępów podczas uruchamiania")
S("choose your score/save file", "Wybierz plik z zapisanymi stanami gry i wynikami")
S("Save the config and restart to select another score/save file.", "Zapisz konfigurację i zrestartuj, by użyć innego pliku postępów.")
S("Save the config to always play without recording your progress.", "Zapisz konfigurację, by zawsze grać bez zapisu postępów.")
S("Save the config to always use %1.", "Zapisz konfigurację by zawsze używać pliku postępów %1.")
S("Your progress will not be saved.", "Twoje postępy nie będą zapisywane.")
// online demo (not translated but just in case)
S("HyperRogue %1: online demo", "HyperRogue %1: demo online")
S("play the game", "gramy")
S("learn about hyperbolic geometry", "nauka o geometrii hiperbolicznej")
S("toggle high detail", "przestaw wysoki poziom szczegółów")
// other
S("wiki", "wiki")
S("highlight faraway monsters", "podświetlaj odległe potwory")
// map editor, line patterns, etc.
//=================================
S("hint: shift+A to enter the map editor", "wskazówka: shift+A uruchamia edytor map")
S("z = set Shift+click", "z = ustaw Shift+klik")
S("B = build on walls ", "B = budowa na ścianie")
S("S = snap (%1)", "S = przyciąganie (%1)")
S("Z =", "Z = ")
S("X =", "X = ")
S("Y =", "Y = ")
S("w: %1", "w: %1")
S("λ: %1°", "λ: %1°")
S("edit cell values", "edytuj zmienne w polach")
S("canvas floor shape", "kształt podłogi płotna")
S("canvas darkness", "przyciemnianie płótna")
S("die shape", "kształt kostki")
S("die face", "ścianka kostki")
S("die direction", "kierunek kostki")
S("die mirror status", "stan lustrzanego odbicia kostki")
S("mirrored", "lustrzane")
// line patterns
S("parallel/meridian orientation", "orientacja równoleżników i południków")
S("number of parallels drawn", "liczba rysowanych równoleżników")
S("last parallel drawn", "ostatni równoleżnik rysowany")
S("tree-drawing parameter", "parametr rysowania drzew")
S("How much of edges to draw for tree patterns (to show how the tree edges are oriented).",
"Jaką część krawędzi rysować (by pokazać, w którą stronę zorientowane są krawędzie drzewa).")
// debug tools
S("error", "błąd")
S("display tile debug values", "pokaż wartości do debugowania kafelków")
S("Display cell type IDs, as well as vertex and edge identifiers.\n\n"
"Setting 1 uses the internal shape IDs, while setting 2 in tes files uses the original IDs"
" in case if extra tile types were added to separate mirror images or different football types.",
"Typy komórek, numery krawędzi i wierzchołków. Ustaw 1 = wewnętrzne IDy kształtów, 2 = oryginalne IDy, "
"o ile dodatkowe typy zostały dodane, by odseparować odbicia lustrzane lub dodatkowe typy wprowadzone w celu uzyskania kolorowalności piłki nożnej.")
// tessellations / honeycombs / projections / embeddings
//========================================================
// new geometry settings
S("projective Bring's Surface", "rzutowa powierzchnia Bringa")
S("aperiodic hat", "aperiodyczny kapelusz (hat)")
S("Sierpiński triangle", "trójkąt Sierpińskiego")
S("Sierpiński carpet", "dywan Sierpińskiego")
S("6-flake fractal", "fraktal 6-płatek")
S("Menger sponge", "gąbka Mengera")
S("Sierpiński tetrahedron", "czworościan Sierpińskiego")
S("aperiodic spectre", "aperiodyczny spektr (spectre)")
// inter-geometric portals
S("Welcome to a portal map! Press 'o' to configure.", "Witaj w mapie portalowej! Naciśnij 'o', by skonfigurować.")
S("become a portal map", "Przekształć na mapę portalową")
S("yes, that's what I want", "Tak, tego chcę")
S("world list", "lista światów")
S("manage portals", "zarządzanie portalami")
S("view another world", "pokaż inny świat")
S("connect ", "połącz ")
S("disconnect this portal", "rozłącz ten portal")
S("remove %1 from the list", "usuń %1 z listy")
S("add to list", "dodaj do listy")
S("portal orientation", "orientacja portalu")
S("mirror connection", "połączenie lustrzane")
S("test portal here", "testuj portal tutaj")
S("set recommended settings", "ustaw zalecane ustawienia")
S("height-to-width ratio", "stosunek wysokości do szerokości")
S("keep eye level when walking enabled", "trzymaj poziom oka podczas chodzenia")
S("walking eye angle", "chodzenie: kąt widzenia")
S("0 = looking forward, 90 = looking upward. In VR this is adjusted automatically.",
"0 = wprost, 90 = do góry. W VR to jest dostosowywane automatycznie.")
S("eye angle scale", "skalowanie kąta widzenia")
S("1 = the angle can be changed with keyboard or mouse movements, 0 = the angle is fixed",
"1 = kąt widzenia można zmieniać klawiaturą lub myszą, 0 = kąt jest sztywno ustalony")
S("walking eye level", "chodzenie: poziom oka")
S("Distance from the floor to the eye in the walking mode, in absolute units. In VR this is adjusted automatically.",
"Odległość od podłogi do oka w trybie chodzenia, w jednostkach bezwzględnych. W trybie VR jest to dobierane automatycznie.")
S("move the camera with arrow keys and Home/End", "strzałki i Home/End by ruszać kamerą")
S("the map is fixed (improves performance)", "stała mapa (lepsza wydajność)")
S("You are currently in a visualization. Press wasd to scroll, qe to rotate. You can also use the arrow keys. ESC for menu.\n\n",
"Jesteś w wizualizacji. Klawisze: wasd by przesuwać, qe by obracać. Można też używać strzałek. ESC by wyjść do menu.\n\n")
S("You are currently in a visualization. Press wasdqe to rotate the camera, ijklyh to move. You can also use the arrow keys and Home/End and PgUp/PgDn. ESC for menu.\n\n",
"Jesteś w wizualizacji. Klawisze: wasdqe by obracać kamerę, ijklyh by poruszać. Można też używać strzałek, Home/End, i PgUp/PgDn. ESC by wyjść do menu.\n\n")
S("pure exploration (game keys scroll)", "czysta eksploracja (klawisze gry przewijają)")
// subdivisions of 3D honeycombs
S("sub-cubes", "pod-kostki")
S("dual sub-cubes", "dualne pod-kostki")
S("bitruncated sub-cubes", "przycięte pod-kostki")
S("note: more choices in cubic honeycombs", "uwaga: w teselacjach 3D kubicznych jest więcej możliwości")
S("subdivision", "podział")
S("split by original faces", "podziel według ścian oryginalnych komórek")
S("split by vertex axes", "podziel według osi wierzchołków")
S("split by midedges", "podziel według środków krawędzi")
S("Outside of the supported limits", "przekraczasz dozwolone limity")
// let's just not translate this
S("subcubed", "subcubed")
S("dual-subcubed", "dual-subcubed")
S("bitruncated-subcubed", "bitruncated-subcubed")
S("subdivided", "subdivided")
// restrict map to disk
S("disk size", "rozmiar dysku")
S("Play on a disk. Enables the special game rules for small bounded spaces (especially relevant for e.g. Minefield and Halloween). "
"The number given is the number of tiles to use; it is not used exactly, actually the smallest disk above this size is used. Set to 0 to disable.",
"Graj na dysku. Uruchamia specjalne reguły gry dla małych, ograniczonych przestrzeni, które są szczególnie ważne dla Pola Minowego i Halloween. "
"Podaj, ile ma być pól; zwykle nie będzie dokładnie tyle, najmniejszy dysk ponad ten rozmiar będzie użyty. Ustaw 0 by wyłączyć.")
S("disk shape", "kształt dysku")
S("distance in tiles", "odległość w polach")
S("distance in vertices", "odległość w wierzchołkach")
S("geometric distance", "odległość geometryczna")
S("fraction of mine in bounded minefield", "frakcja min w ograniczonym polu minowym")
// tessellation tree generation
S("strict tree maps", "ściśle drzewiaste mapy")
S("display distances up to", "pokazuj odległości aż do")
S("extend automatically", "automatycznie rozszerzaj tablicę") // the table of tile count by distances
S("rules generated successfully: %1 states using %2-%3 cells", "reguły wygenerowane, liczba stanów: %1, liczba pól: %2-%3")
S("too difficult: %1", "za trudne: %1")
S("bug: %1", "bug: %1")
S(
"Strict tree maps are generated using a more powerful algorithm.\n\nThis algorithm supports horocycles and knows the expansion rates of various "
"tessellations (contrary to the basic implementation of Archimedean, tes, and unrectified/warped/untruncated tessellations).\n\nYou can convert mostly any "
"non-spherical periodic 2D tessellation to strict tree based.\n\nSwitching the map format erases your map.",
"Ściśle drzewiaste mapy używają mocniejsego algorytmu.\n\n"
"W tym algorytmie działają horocykle i obliczanie stopnia ekspansji dla różnych teselacji (w przeciwieństwie do podstawowej implementacji map archimedesowych, "
".tes, i teselacji unrectified/warped/untruncated).\n\n"
"Można skonwertować prawie dowolną niesferyczną okresową teselację 2D do ściśle drzewiastej mapy.\n\n"
"Ta konwersja powoduje wykasowanie Twojej obecnej mapy gry."
)
S("in tes internal format", "w formacie wewnętrznym .tes")
S("converted successfully -- %1 cell types", "konwersja udana -- liczba typów pól: %1")
S("cannot be disabled for this tiling", "nie da się wyłączyć dla tej teselacji")
S("extended football colorability", "rozszerzona kolorowalność w stylu piłki nożnej")
S("consider all symmetries when converting", "przy konwersji uwzględniaj wszystkie symetrie")
S("tes reverse order on convert", "odwrócona kolejność tes przy konwersji")
S("maximum cellcount", "max liczba pól")
S("controls the max memory usage of conversion algorithm -- the algorithm fails if exceeded",
"steruje maksymalnym zużyciem pamięci algorytmu konwersji -- jeśli przekroczymy podaną wartość, algorytm jest przerywany")
// hat tiling
S("hat/spectre/turtle parameter", "parametr hat/spectre/turtle")
S("Apeirodic hat tiling based on: https://arxiv.org/pdf/2303.10798.pdf\n\n"
"This controls the parameter discussed in Section 6. Parameter p is Tile(p, (2-p)√3), "
"scaled so that the area is the same for every p.\n\n"
"Aperiodic spectre tiling based on: https://arxiv.org/abs/2305.17743\n\n"
"In the spectre tiling, set the parameter to 'spectre' value to make all tiles have the same shape.",
"Hat: aperiodyczny parkietaż oparty na: https://arxiv.org/pdf/2303.10798.pdf\n\n"
"Tu możemy sterować parametrem opisanym w Sekcji 6. Parametr p to Tile(p, (2-p)√3), "
"przeskalowany tak, by pole było takie samo dla każdego p.\n\n"
"Spectre: aperiodyczny parkietaż oparty na: https://arxiv.org/abs/2305.17743\n\n"
"W tym parkietażu ustaw parametr na 'spectre' by wszystkie kafelki miały ten sam kształt.")
S("Welcome to HatRogue!", "Witaj w HatRogue!")
S("hat in cluster", "kapelusz w klastrze")
S("hat clusters", "klastry kapeluszy")
S("hat superclusters", "superklastry")
S("types (mark reverse)", "typy (zaznacz odwrócone)")
S("display small floors", "małe podłogi")
S("chevron (periodic)", "szewron")
S("hat", "kapelusz ('hat')")
S("spectre", "spektr ('spectre')")
S("turtle", "żółw ('turtle')")
S("comma (periodic)", "przecinek")
S("hat parameter (imaginary)", "parametr hat (część urojona)")
S("Imaginary part of the hat parameter. This corresponds to the usual interpretation of complex numbers in Euclidean planar geometry: "
"rather than shortened or lengthened, the edges are moved in the other dimension.",
"Część urojona parametru hat. Odpowiada ona standardowej interpretacji liczb zespolonych w geometrii płaskiej: "
"zamiast skracać czy wydłużać, krawędzie są przemieszczane w drugim wymiarze."
)
// fake curvature setting in experiments in geometry (some texts were not translated)
S(
"This feature lets you construct the same tiling, but "
"from shapes of different curvature.\n\n"
"The number you give here is (2D) vertex degree or (3D) "
"the number of cells around an edge.\n\n",
"Ta funkcja pozwala skonstruować ten sam parkietaż, ale z kształów pochodzących z geometrii o innej krzywiźnie.\n\n"
"Podana liczba to (w 2D) stopień wierczhołka lub (w 3D) liczba komórek wokół krawędzi.\n\n")
S("original", "oryginalna")
S("double original", "podwójna oryginalna")
S("draw all if multiple of original", "rysuj wszystkie jeśli wielokrotność oryginalnej")
S("draw copies (2D only)", "rysuj kopie (tylko 2D)")
S("unordered", "nieuporządkowane")
S("pre-ordered", "uporządkowane przed")
S("post-ordered", "uporządkowane po")
// other tessellation-related
S("color by symmetries (reversed tiles marked)", "koloruj po symetriach (zaznacz odwrócone kafelki)")
S("unreversed colors", "kolory nie odwrócone")
S("symmetric subdivision", "symetryczny podział")
S("simplified display of apeirogons", "uproszczone pokazywanie apeirogonów")
S("Width of cell boundaries", "szerokość brzegów pól")
S("How wide should the cell boundaries be.", "Jak szerokie powinny być brzegi pól.")
S("the following sliders will restart the game", "te suwaki restartują grę")
// new projections and parameters
S("horocyclic equal-area", "horocykliczny, równe pola")
S("conformal square", "kwadrat konforemny")
S("Lie perspective", "perspektywa w grupie Liego")
S("Lie orthogonal", "rzut ortogonalny w grupie Liego")
S("relativistic perspective", "perspektywa relatywistyczna")
S("relativistic orthogonal", "rzut ortogonalny relatywistyczny")
S("angle between the axes", "kąt między osiami")
S("In two-axe-based models, this parameter gives the angle between the two axes.", "W modelach opartych na dwóch osiach ten parametr określa kąt między osiami.")
S("model orientation 3D", "orientacja modelu w 3D")
S("semidirect_rendering (perspective on GPU)", "półbezpośrednie (perspektywa na GPU)")
S("this is not a Lie group", "to nie grupa Liego")
S("not implemented", "nie zaimplementowane")
S("auto rotation", "automatyczne obracanie")
S("auto rotation in 3D", "automatyczne obracanie w 3D")
// alternative screen projections
S("stereo/high-FOV mode", "tryb stereo / duże pole widzenia")
S("linear perspective", "perspektywa liniowa")
S("for red-cyan glasses", "do użycia z czerowno-turkusowymi okularami 3D")
S("for mobile VR", "do mobilnego VR")
S("ODS", "rzut ODS")
S("for rendering 360° VR videos (implemented only in raycaster and some other parts)",
"do renderowania filmów VR w 360° stopniach (zaimplementowane jedynie w raycasterze i innych szczególnych przypadkach)")
S("Panini", "Panini")
S("Projection believed to be used by Italian painters. Allows very high FOV angles while rendering more straight lines as straight than the stereographic projection.",
"Rekonstrukcja rzutu używanego przez włoskich malarzy. Bardzo duże pole widzenia, ale więcej linii prostych niż w rzucie stereograficznym.")
S("stereographic", "rzut stereograficzny")
S("Stereographic projection allows very high FOV angles.", "Rzut stereograficzny pozwala na bardzo duże pole widzenia.")
S("equirectangular", "rzut równoprostokątny")
S("for rendering 360° videos (implemented only in raycaster)", "do filmów w 360° (zaimplementowany tylko w raycasterze)")
S("stereographic/Panini parameter", "parametr rzutu stereograficznego/Paniniego")
S("1 for full stereographic/Panini projection. Lower values reduce the effect.\n\n"
"HyperRogue uses a quick implementation, so parameter values too close to 1 may be buggy (outside of raycasting); try e.g. 0.9 instead.",
"1 to pełny rzut stereograficzny/Paniniego; mniejsze wartości to efekt pośredni.\n\n"
"Obecna implementacja jest uproszczona, także wartości parametru zbytnio bliskie 1 mogą powodować błędy graficzne (poza trybem raycastingu), "
"także zaleca się używać mniejszych wartości, przykładowo 0.9."
)
// embeddings
//============
S("3D embedding method", "metoda zanurzenia w 3D")
S("3D style", "styl 3D")
S("2D engine", "silnik 2D")
S("Use HyperRogue's 2D engine to simulate same curvature. Works well in top-down and third-person perspective. The Hypersian Rug mode can be used to project this to a surface.",
"Używamy silnika 2D by symulować tą samą krzywiznę w trzecim wymiarze. Działa dobrze przy widoku z góry i z perspektywy trzeciej osoby. Tryb Hiperskiego Dywanu "
"może być użyty, by zrobić rzut na powierzchnię w trzech wymiarach.")
S("same curvature", "ta sama krzywizna")
S("Embed as an equidistant surface in the 3D version of the same geometry.",
"Zanurz jako powierzchnia ekwidystantna w trójwymiarowej wersji tej samej geometrii.")
S("lower curvature", "niższa krzywizna")
S("Embed as a surface in a space of lower curvature.", "Zanurz jako powierzchnia w przestrzeni o niższej krzywiźnie.")
S("much lower curvature", "o wiele niższa krzywizna")
S("Embed sphere as a sphere in hyperbolic space.", "Zanurz sferę w przestrzeni hiperbolicznej.")
S("product", "produkt")
S("Add one extra dimension in the Euclidean way.", "Dodaje dodatkowy wymiar w sposób Euklidesowy.")
S("Embed Euclidean plane into Nil.", "Zanurz płaszczyznę euklidesową w geometrię Nil.")
S("Embed Euclidean or hyperbolic plane into Sol.", "Zanurz płaszczyznę euklidesową w geometrię Sol.")
S("Embed Euclidean or hyperbolic plane into stretched hyperbolic geometry.", "Zanurz płaszczyznę euklidesową lub hiperboliczną w rozciągniętą geometrię hiperboliczną.")
S("stretched Sol", "rozciągnięte Sol.")
S("Embed Euclidean or hyperbolic plane into stretched Sol geometry.", "Zanurz płaszczyznę euklidesową lub hiperboliczną w rozciągniętą geometrię Sol.")
S("Clifford Torus", "torus Clifforda")
S("Embed Euclidean rectangular torus into S3.", "Zanurz prostokątny torus w geometrię sferyczną.")
S("hyperbolic product", "produkt hiperboliczny")
S("Embed Euclidean or hyperbolic plane in the H2xR product space.", "Zanurz płaszczyznę euklidesową lub hiperboliczną w przestrzeń produktową H2xR")
S("spherical product", "produkt sferyczny")
S("Embed Euclidean cylinder or spherical plane in the H2xR product space.", "Zanurz płaszczyznę euklidesową lub sferę w przestrzeń produktową H2xR")
S("Embed Euclidean plane in twisted product geometry.", "Zanurz płaszczyznę euklidesową w skręconą geometrię produktową.")
S("Embed Euclidean cylinder in Euclidean space.", "Zanurz walec euklidesowy w przestrzeń euklidesową.")
S("hyperbolic cylinder", "walec hiperboliczny")
S("Embed Euclidean cylinder in hyperbolic space.", "Zanurz walec euklidesowy w przestrzeń hiperboliczną.")
S("product cylinder", "walec produktowy")
S("Embed Euclidean cylinder in H2xR space.", "Zanurz walec euklidesowy w przestrzeń produktową H2xR.")
S("Nil cylinder", "walec Nil")
S("Embed Euclidean cylinder in Nil.", "Zanurz walec euklidesowy w Nil.")
S("horocylinder", "horowalec")
S("Embed Euclidean as a horocylinder in H2xR space.", "Zanurz płaszczyznę euklidesową jako horowalec w H2xR.")
S("SL2 cylinder", "walec SL2")
S("Embed Euclidean as a cylinder in twisted product geometry.", "Zanurz walec euklidesowy w poskręcaną przestrzeń produktową.")
// embedding settings
S("flat, not equidistant", "płaskie, a nie ekwidystantny")
S("invert convex/concave", "odwróć wypukły/wklęsły")
// embedding errors
S("set square tiling", "ustaw parkietaż kwadratowy")
S("set hex tiling", "ustaw parkietaż sześciokątny")
S("error: currently works only in PURE Euclidean regular square or hex tiling", "błąd: obecnie działa tylko w CZYSTYM parkietażu euklidesowym kwadratowym lub sześciokątnym")
S("error: currently works only in pure Euclidean, or binary tiling and similar", "błąd: obecnie działa tylko w czystym parkietażu euklidesowym, lub podobnym do parkietażu binarnego")
S("set binary tiling variant", "ustaw wariant parkietażu binarnego")
S("set ternary tiling", "ustaw parkietaż ternarny")
S("set binary tiling", "ustaw parkietaż binarny")
S("error: this embedding does not work in shmup", "błąd: to zanurzenie nie działa w trybie strzelanki")
S("error: this method works only in rectangular torus", "błąd: ta metoda działa tylko dla torusu prostokątnego")
S("set 20x20 torus", "ustaw torus 20x20")
S("error: this method works only in cylinder", "błąd: ta metoda działa tylko dla walcowej mapy")
S("set cylinder", "ustaw walec")
S("error: not supported", "błąd: nie działa")
S("error: this method does not work in spherical geometry", "błąd: ta metoda nie działa w geometrii sferycznej")
S("error: this method does not work in hyperbolic geometry", "błąd: ta metoda nie działa w geometrii hiperbolicznej")
S("3D styles", "style 3D")
S("3D detailed settings", "szczegółowe ustawienia 3D")
S("more options in 3D engine", "więcej opcji przy użyciu silnika 3D")
S("configure Hypersian Rug", "konfiguruj Hiperski Dywan")
S("view shift for embedded planes", "zmiana kamery dla zanurzonych płaszczyzn")
S("always move on geodesics", "ruch zawsze po geodezyjnych")
S("keep levels", "trzymaj poziom")
S("keep the vertical angle of the camera", "trzymaj pionowy kąt kamery")
S("mixed", "tryb mieszany")
S("on geodesics when moving camera manually, keep level when auto-centering", "geodezyjne przy ręcznym ruchu kamerą, trzymaj poziom przy auto-centrowaniu")
S("Euclidean embedding rotation", "obrót zanurzenia euklidesowego")
S("How to rotate the Euclidean embedding, in degrees.", "O ile obrócić zanurzoną płaszczyznę euklidesową, w stopniach.")
S("Euclidean embedding scale", "skala zanurzenia euklidesowego")
S("How to scale the Euclidean map, relatively to the 3D absolute unit.", "Jak przeskalować mapę euklidesową, w stosunku do jednostki absolutnej 3D.")
S("Euclidean embedding scale Y/X", "skala Y/X zanurzenia euklidesowego")
S("This scaling factor affects only the Y coordinate.", "Ten współczynnik skali wpływa jedynie na współrzędną Y.")
S("(fix errors)", "(popraw błędy)")
S("reset view", "zresetuj obraz")
S("needs", "potrzeba: ")
// embeddings: detailed 3D parameters
S("set 3D settings automatically", "ustaw 3D automatycznie")
S("draw plain floors in 3D", "w trybie 3D rysuj zwykłe podłogi")
S("floor alpha", "przezroczystość podłóg")
S("255 = opaque", "255 = nieprzejrzyste")
S("altitude of the stars", "wysokość gwiazd")
S("star probability", "prawdopodobieństwo gwiazdy")
S("probability of star per tile", "prawdopodobieństwo gwiazdy na kafelek")
S("night star size (relative to item sizes)", "rozmiar gwiazd nocnych (w stosunku do wielkości przedmiotów)")
S("sun size (relative to item sizes)", "rozmiar słońca (w stosunku do wielkości przedmiotów)")
S("infinite sky", "nieskończone niebo")
S("ratio of high walls to normal walls", "stosunek wysokich ścian do normalnych")
S("ratio of very high walls to normal walls", "stosunek bardzo wysokich ścian do normalnych")
S("altitude of the sky", "wysokość nieba")
S("sky fake height", "fałszywa wysokość nieba")
S("Sky is rendered at the distance computed based on the sky height, "
"which might be beyond the range visible in fog. To prevent this, "
"the intensity of the fog effect depends on the value here rather than the actual distance. Stars are affected similarly.",
"Niebo jest renderowane w odległości obliczanej na podstawie parametru, "
"co może być dalej, niż zasięg widoczny we mgle. By tego uniknąć, "
"intensywność mgły zależy od tej wartości zamiast faktycznej odległości. Ten sam efekt wpływa na gwiazdy."
)
S("sky rendering", "renderowanie powietrza")
S("do not draw sky", "nie rysuj powietrza")
S("skybox", "skybox")
S("infinite depth", "nieskończona głębokość")
S("The unit this value is given in is wall height. "
"Note that, in exponentially expanding spaces, too high values could cause rendering issues. "
"So if you want infinity, values of 5 or similar should be used -- there is no visible difference from infinity and glitches are avoided.",
"Ta wartość jest podawana w jednostkach wysokości ściany. "
"W przestrzeniach rosnących wykładniczo, zbyt wysokie wartości mogą powodować błędy. "
"Także sugerujemy użycie wartości około 5 dla nieskończoności -- nie ma widocznych różnic i te błędy nie wystąpią.")
S("Level of shallow water", "poziom płytkiej wody")
S("do not render higher levels if camera too high", "nie renderuj wyższych poziomów jeśli kamera jest ponad nimi")
S("works only in Euclidean", "działa tylko w przestrzeni euklidesowej")
S("always", "zawsze")
S("might be glitched in some settings", "w niektórych ustawieniach źle działa")
S("prevent exceeding recommended altitudes", "nie przekraczaj rekomendowanych wysokości")
S("camera angle", "kąt kamery")
S("render behind the camera", "renderuj za kamerą")
// embeddings: pseudohedral setting
S("make the tiles flat", "płaskie kafelki")
S("the tiles are curved", "kafelki są zakrzywione")
S("inscribed", "wpisane")
S("the tiles are inscribed", "kafelki są wpisane")
S("circumscribed", "opisane")
S("the tiles are circumscribed", "kafelki są opisane")
S("depth bonus in pseudohedral", "bonus do głębokości")
// embeddings: geodesic movement in Solv etc
S("straight lines", "linie proste")
S("Lie group", "grupy Liego")
S("light, camera, and objects move in lines of constant direction, in the Lie group sense", "światło, kamera, i obiekty ruszają się w liniach o stałym kierunku w sensie group Liego")
S("geodesics", "geodezyjne")
S("light, camera, and objects always take the shortest path", "światło, kamera, i obiekty ruszają się po najkrótszej ścieżce")
// achievement eligiblity
S("achievement/leaderboard eligiblity:", "legalność osiągnięć i rankingów:")
S("eligible for most", "większość legalna")
S("eligible for most -- leaderboards separate", "większość legalna -- osobne rankingi")
S("eligible for racing", "legalne dla wyścigu")
S("eligible for shmup", "legalne dla strzelanki")
S("eligible for multiplayer", "legalne dla wielu graczy")
S("eligible for Chaos mode", "legalne dla trybu Chaosu")
S("eligible for Princess Challenge", "legalne dla misji Księżniczka")
S("eligible for heptagonal", "legalne dla trybu siedmiokątów")
S("eligible for special geometry", "legalne dla geometrii specjalnych")
S("eligible for Strange Challenge", "legalne dla Dziwnej Misji")
S("disabled in cheat mode", "wyłączone w trybie oszusta")
S("disabled in casual mode", "wyłączone w trybie niezobowiązującym")
S("not eligible due to current mode settings", "nielegalne w obecnych trybach")
S("no achievements/leaderboards in this version", "brak osiągnięć i rankingów w tej wersji")

View File

@ -206,6 +206,7 @@ EX modecode_t legacy_modecode() {
if(int(geometry) > 3 || int(variation) > 1) return UNKNOWN;
if(casual) return UNKNOWN;
if(bow::weapon) return UNKNOWN;
if(use_custom_land_list) return UNKNOWN;
bool is_default_land_structure =
(princess::challenge || tactic::on) ? ls::single() :

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

@ -491,6 +491,9 @@ EX namespace mapstream {
f.write(gp::param.second);
}
#endif
#if CAP_IRR
if(IRREGULAR) irr::save_map_bin(f);
#endif
#if MAXMDIM >= 4
if(variation == eVariation::coxeter) {
f.write(reg3::coxeter_param);
@ -587,6 +590,9 @@ EX namespace mapstream {
f.read(gp::param.second);
}
#endif
#if CAP_IRR
if(IRREGULAR) { irr::load_map_full(f); stop_game(); }
#endif
#if MAXMDIM >= 4
if(variation == eVariation::coxeter && vernum >= 0xA908) {
f.read(reg3::coxeter_param);
@ -740,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);
@ -940,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);
@ -2588,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;
}
@ -2625,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);
@ -2738,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;
@ -640,7 +641,7 @@ EX bool cellEdgeUnstable(cell *c, flagtype flags IS(0)) {
return true;
}
int tidalphase;
EX int tidalphase;
EX int tidalsize, tide[200];
@ -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) ;
@ -814,10 +824,12 @@ EX bool makeEmpty(cell *c) {
}
if(c->land == laWildWest) {
forCellEx(c2, c)
forCellEx(c3, c2)
if(c3->wall != waBarrier)
c3->wall = waNone;
celllister cl(cwt.at, 100, 1000000, NULL);
for(cell *c: cl.lst) {
if(c == cwt.at) continue;
if(c->wall != waSaloon) break;
c->wall = waNone;
}
}
return true;

127
menus.cpp
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);
@ -381,6 +384,43 @@ EX void showCreative() {
dialog::display();
}
EX void show_achievement_eligibility() {
#if CAP_ACHIEVE
dialog::addBreak(100);
dialog::addInfo(XLAT("achievement/leaderboard eligiblity:"), 0xFF8000);
if(!wrongMode(0)) {
if(inv::on || bow::crossbow_mode()) dialog::addInfo(XLAT("eligible for most -- leaderboards separate"), 0x80FF00);
else dialog::addInfo(XLAT("eligible for most"), 0x00FF00);
}
else if(!wrongMode(rg::racing))
dialog::addInfo(XLAT("eligible for racing"), 0xFFFF00);
else if(!wrongMode(rg::shmup))
dialog::addInfo(XLAT("eligible for shmup"), 0xFFFF00);
else if(!wrongMode(rg::multi))
dialog::addInfo(XLAT("eligible for multiplayer"), 0xFFFF00);
else if(!wrongMode(rg::chaos))
dialog::addInfo(XLAT("eligible for Chaos mode"), 0xFFFF00);
else if(!wrongMode(rg::princess))
dialog::addInfo(XLAT("eligible for Princess Challenge"), 0xFFFF00);
else if(!wrongMode(specgeom_heptagonal()))
dialog::addInfo(XLAT("eligible for heptagonal"), 0xFFFF00);
else if(!wrongMode(any_specgeom())) /* the player probably knows what they are aiming at */
dialog::addInfo(XLAT("eligible for special geometry"), 0xFFFF00);
#if CAP_DAILY
else if(daily::on && !daily::historical)
dialog::addInfo(XLAT("eligible for Strange Challenge"), 0xFFFF00);
#endif
else if(cheater) dialog::addInfo(XLAT("disabled in cheat mode"), 0xC00000);
else if(casual) dialog::addInfo(XLAT("disabled in casual mode"), 0xC00000);
else if(ineligible_starting_land)
dialog::addInfo(XLAT("this starting land is not eligible for achievements"), 0xC00000);
else
dialog::addInfo(XLAT("not eligible due to current mode settings"), 0XC00000);
#else
dialog::addInfo(XLAT("no achievements/leaderboards in this version"), 0XFF8000);
#endif
}
EX void show_chaos() {
cmode = sm::SIDE | sm::MAYDARK;
gamescreen();
@ -388,10 +428,10 @@ EX void show_chaos() {
chaosUnlocked = chaosUnlocked || autocheat;
dialog::addHelp(
"In the Chaos mode, lands change very often, and "
XLAT("In the Chaos mode, lands change very often, and "
"there are no walls between them. "
"Some lands are incompatible with this."
"\n\nYou need to reach Crossroads IV to unlock the Chaos mode."
"\n\nYou need to reach Crossroads IV to unlock the Chaos mode.")
);
dialog::addBreak(100);
@ -420,31 +460,76 @@ EX void show_chaos() {
dialog::addSelItem(XLAT("land"), XLAT1(linf[specialland].name), 'l');
dialog::add_action(activate_ge_land_selection);
dialog::addBreak(100);
if(ineligible_starting_land)
dialog::addInfo("this starting land is not eligible for achievements");
else if(land_structure == lsNiceWalls)
dialog::addInfo("eligible for most achievements");
else if(land_structure == lsChaos)
dialog::addInfo("eligible for Chaos mode achievements");
else if(land_structure == lsSingle)
dialog::addInfo("eligible for special achievements");
else
dialog::addInfo("not eligible for achievements");
if(cheater) dialog::addInfo("(but the cheat mode is on)");
if(casual) dialog::addInfo("(but the casual mode is on)");
show_achievement_eligibility();
dialog::addBreak(100);
if(ls::horodisk_structure())
add_edit(horodisk_from);
else if(land_structure == lsChaosRW)
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();
dialog::display();
}
EX string custom_welcome;
string customfile = "custom.hrm";
EX void show_custom() {
cmode = sm::SIDE | sm::MAYDARK;
gamescreen();
dialog::init(XLAT("custom mode"));
if(custom_welcome != "") {
dialog::addInfo("custom welcome message:");
dialog::addInfo(custom_welcome);
dialog::addItem("edit", '/');
}
else {
dialog::addItem("custom welcome message", '/');
}
dialog::add_action([] () {
dialog::edit_string(custom_welcome, "custom welcome message", "");
});
dialog::addBreak(100);
dialog::addItem("save custom mode", 's');
dialog::add_action([] {
dialog::openFileDialog(customfile, XLAT("file to save:"), ".hrm", [] () {
try {
save_mode_to_file(customfile);
addMessage(XLAT("Mode saved to %1", customfile));
return true;
}
catch(hstream_exception& e) {
addMessage(XLAT("Failed to save mode to %1", customfile));
return false;
}
});
});
dialog::addItem("load custom mode", 'l');
dialog::add_action([] {
dialog::openFileDialog(customfile, XLAT("file to load:"), ".hrm", [] () {
try {
load_mode_from_file(customfile);
addMessage(XLAT("Loaded mode from %1", customfile));
return true;
}
catch(hstream_exception& e) {
addMessage(XLAT("Failed to load mode from %1", customfile));
return false;
}
});
});
dialog::addBack();
dialog::display();
}
EX void mode_higlights() {
cmode = sm::NOSCR;
gamescreen();
@ -660,6 +745,9 @@ EX void showChangeMode() {
multi::cpid = 0;
menuitem_land_structure('l');
dialog::addBoolItem(XLAT("custom land list"), use_custom_land_list, 'L');
dialog::add_action_push(customize_land_list);
dialog::addBoolItem(XLAT("weapon selection"), bow::weapon, 'b');
dialog::add_action_push(bow::showMenu);
@ -697,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);
});
@ -716,10 +804,13 @@ EX void showChangeMode() {
dialog::add_action(racing::configure_race);
#endif
dialog::addBreak(50);
show_achievement_eligibility();
dialog::addBreak(50);
dialog::addItem(XLAT("highlights & achievements"), 'h');
dialog::add_action_push(mode_higlights);
dialog::addItem(XLAT("custom mode manager"), 'm');
dialog::add_action_push(show_custom);
dialog::addBack();
dialog::display();
@ -921,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

@ -92,6 +92,11 @@ void handleclick(MOBPAR_FORMAL) {
getcstat = 0;
}
else if(statkeys && getcstat == 'f') {
bow::switch_fire_mode();
getcstat = 0;
}
else if(getcstat != SDLK_F1 && getcstat != 'i' && getcstat != 't') {
int px = mousex < current_display->xcenter ? 0 : 1;
int py = mousey < current_display->ycenter ? 0 : 1;
@ -289,6 +294,8 @@ EX void mobile_draw(MOBPAR_FORMAL) {
if(lclicked && !clicked && !inmenu) handleclick(MOBPAR_ACTUAL);
if(inmenu && !clicked && !lclicked) inmenu = false;
if(!clicked && !lclicked) invslider = false;
bool keyreact = lclicked && !clicked;
@ -302,6 +309,7 @@ EX void mobile_draw(MOBPAR_FORMAL) {
#endif
if(inslider) keyreact = true;
if(invslider || getcstat == PSEUDOKEY_LIST_SLIDER) keyreact = true;
#if CAP_ANDROIDSHARE
if(getcstat == 's'-96 && keyreact) {

View File

@ -139,6 +139,7 @@ projection_configuration::projection_configuration() {
ptr_ball = new transmatrix;
*ptr_ball = cspin(1, 2, 20._deg);
ptr_camera = new transmatrix; *ptr_camera = Id;
offside = 0; offside2 = M_PI;
}
EX namespace models {
@ -619,6 +620,11 @@ EX namespace models {
if(vpmodel == mdFisheye)
add_edit(vpconf.fisheye_param);
if(vpmodel == mdFisheye2) {
add_edit(vpconf.fisheye_param);
add_edit(vpconf.fisheye_alpha);
}
if(is_hyperboloid(vpmodel))
add_edit(pconf.show_hyperboloid_flat);
@ -638,6 +644,11 @@ EX namespace models {
if(among(vpmodel, mdLoximuthal, mdRetroHammer, mdRetroCraig))
add_edit(vpconf.loximuthal_parameter);
if(among(vpmodel, mdPolar)) {
add_edit(vpconf.offside);
add_edit(vpconf.offside2);
}
if(among(vpmodel, mdAitoff, mdHammer, mdWinkelTripel))
add_edit(vpconf.aitoff_parameter);
@ -974,6 +985,13 @@ EX namespace models {
-> editable(1e-3, 10, .1, "fisheye parameter", "Size of the fish eye.", 'b')
-> set_sets(dialog::scaleLog);
param_f(p.fisheye_alpha, pp+"fishalpha", sp+"off-center parameter", 0)
-> editable(1e-1, 10, .1, "off-center parameter",
"This projection is obtained by composing gnomonic projection and inverse stereographic projection. "
"This parameter changes the center of the first projection (0 = gnomonic, 1 = stereographic). Use a value closer to 1 "
"to make the projection more conformal.",
'o');
param_f(p.stretch, pp+"stretch", 1)
-> editable(0, 10, .1, "vertical stretch", "Vertical stretch factor.", 's')
-> set_extra(stretch_extra);
@ -997,6 +1015,12 @@ EX namespace models {
"The Aitoff projection is obtained by multiplying the longitude by 1/2, using azimuthal equidistant projection, and then dividing X by 1/2. "
"Hammer projection is similar but equi-area projection is used instead. "
"Here you can change this parameter.", 'b');
param_f(p.offside, sp+"offside")
-> editable(0, TAU, TAU/10, "offside parameter",
"Do not center the projection on the player -- move the center offside. Useful in polar, where the value equal to offside2 can be used to center the projection on the player.", 'o');
param_f(p.offside2, sp+"offside2")
-> editable(0, TAU, TAU/10, "offside parameter II",
"In polar projection, what distance to display in the center. Use asinh(1) (in hyperbolic) to make it conformal in the center, and pi to have the projection extend the same distance to the left, right, and upwards.", 'O');
param_f(p.miller_parameter, sp+"miller");
param_f(p.loximuthal_parameter, sp+"loximuthal")
-> editable(-90._deg, 90._deg, .1, "loximuthal parameter",

View File

@ -8,7 +8,7 @@
#include "hyper.h"
namespace hr {
EX int avengers, mirrorspirits, wandering_jiangshi, jiangshi_on_screen;
EX int avengers, mirrorspirits, wandering_jiangshi, jiangshi_on_screen, splitrocks;
EX bool timerghost = true;
EX bool gen_wandering = true;
@ -192,7 +192,7 @@ EX int reptilemax() {
return r;
}
bool wchance(int a, int of, int reduction = 0) {
bool wchance_in(eLand l, int a, int of, int reduction = 0) {
of *= 10;
a += yendor::hardness() + 1;
if(isCrossroads(cwt.at->land))
@ -206,6 +206,11 @@ bool wchance(int a, int of, int reduction = 0) {
a -= reduction;
if(a < 0) return false;
if(use_custom_land_list) {
of *= 100;
a *= custom_land_wandering[l];
}
return hrand(a+of) < a;
}
@ -337,7 +342,7 @@ EX void wandering() {
if(closed_or_bounded && specialland == laClearing)
clearing::new_root();
if(cwt.at->land == laZebra && cwt.at->wall == waNone && wchance(items[itZebra], 20))
if(cwt.at->land == laZebra && cwt.at->wall == waNone && wchance_in(laZebra, items[itZebra], 20))
wanderingZebra(cwt.at);
bool smallbounded_generation = smallbounded || (closed_manifold && specialland == laClearing);
@ -370,6 +375,8 @@ EX void wandering() {
cell *c = dcal[i];
if(!valid(c)) continue;
if(isPlayerOn(c)) break;
auto wchance = [c] (int a, int of, int reduction = 0) { return wchance_in(c->land, a, of, reduction); };
if(specialland == laStorms) {
// place the sandstone wall completely randomly (but not on the player)
@ -555,6 +562,12 @@ EX void wandering() {
else if(c->monst || c->pathdist == PINFD) break;
else if(c->land == laAsteroids && splitrocks && canReachPlayer(c, moYeti)) {
c->monst = moAsteroid;
splitrocks--;
continue;
}
else if(c->land == laAsteroids) {
int gen = 0;
if(asteroids_generated * 12 <= items[itAsteroid]) gen = 2;

View File

@ -887,8 +887,7 @@ EX void moveWorm(cell *c) {
else
addMessage(XLAT("The sandworm explodes!"));
playSound(NULL, "explosion");
if(geometry == gZebraQuotient)
achievement_gain_once("ZEBRAWORM", rg::special_geometry);
achievement_gain_once("ZEBRAWORM", specgeom_zebra());
}
return;
}

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; });
@ -2358,7 +2359,7 @@ EX namespace rots {
ptds.clear();
drawthemap();
drawqueue();
displaychr(current_display->xcenter, current_display->ycenter, 0, 24, '+', 0xFFFFFFFF);
displaychr(current_display->xcenter, current_display->ycenter, 0, 24 * mapfontscale / 100, '+', 0xFFFFFFFF);
glflush();
});
gmatrix = std::move(g);

View File

@ -597,6 +597,7 @@ EX bool haveRangedTarget() {
}
void checkmoveO() {
bow::bowpath_map.clear();
if(multi::players > 1 && multi::activePlayers() == 1)
multi::checklastmove();
if(multi::players == 1) checkmove();
@ -628,6 +629,7 @@ EX void teleportTo(cell *dest) {
playerMoveEffects(movei(cwt.at, dest, TELEPORT));
afterplayermoved();
bfs();
advance_tides();
}
return;
}
@ -646,6 +648,7 @@ EX void teleportTo(cell *dest) {
afterplayermoved();
bfs();
advance_tides();
sword::reset();
items[itOrbSword2] = 0;
@ -661,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);
@ -680,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);
@ -738,6 +744,7 @@ EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMons
if(from) movecost(from, dest, 2);
createNoise(1);
bow::bowpath_map.clear();
if(shmup::on)
shmup::teleported();
@ -818,7 +825,14 @@ 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 if(!saf)
animate_item_throw(dest, cwt.at, it);
useupOrb(itOrbSpace, cost.first);
if(cost.second)
markOrb(itOrbMagnetism);
@ -870,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)
@ -1132,8 +1150,10 @@ void blowoff(const movei& mi) {
auto& ct = mi.t;
bool die = cf->wall == waRichDie;
playSound(ct, "orb-ranged");
if(cf->monst)
addMessage(XLAT("You blow %the1 away!", cf->monst));
if(cf->monst == moVoidBeast)
addMessage(XLAT("You blow %the1 closer!", cf->monst));
else if(cf->monst)
addMessage(XLAT("You blow %the1 away!", cf->monst));
if(cf->wall == waThumperOff) activateActiv(cf, false);
if(isPushable(cf->wall) || cf->wall == waBigStatue)
pushThumper(mi);
@ -1201,9 +1221,9 @@ EX bool monstersnearO(orbAction a, cell *c) {
EX bool isCheck(orbAction a) { return a == roCheck || a == roMultiCheck; }
EX bool isWeakCheck(orbAction a) { return a == roCheck || a == roMultiCheck || a == roMouse; }
EX movei blowoff_destination(cell *c, int& di) {
EX movei blowoff_destination_dir(cell *c, int& di, int rev) {
int d = 0;
for(; d<c->type; d++) if(c->move(d) && c->move(d)->cpdist < c->cpdist) break;
for(; d<c->type; d++) if(c->move(d) && rev*c->move(d)->cpdist < rev*c->cpdist) break;
if(d<c->type) for(int e=d; e<d+c->type; e++) {
int di = e % c->type;
cell *c2 = c->move(di);
@ -1211,11 +1231,16 @@ EX movei blowoff_destination(cell *c, int& di) {
if(dice::on(c) && !dice::can_roll(movei(c, di)))
continue;
#endif
if(c2 && c2->cpdist > c->cpdist && passable(c2, c, P_BLOW)) return movei(c, c2, di);
if(c2 && rev*c2->cpdist > rev*c->cpdist && passable(c2, c, P_BLOW)) return movei(c, c2, di);
}
return movei(c, c, NO_SPACE);
}
EX movei blowoff_destination(cell *c, int& di) {
int rev = c->monst == moVoidBeast ? -1 : 1;
return blowoff_destination_dir(c, di, rev);
}
EX int check_jump(cell *cf, cell *ct, flagtype flags, cell*& jumpthru) {
int partial = 1;
forCellCM(c2, cf) {
@ -1506,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

@ -118,8 +118,9 @@ bool pcmove::checkNeedMove(bool checkonly, bool attacking) {
if(items[itOrbDomination] > ORBBASE && cwt.at->monst)
return false;
int flags = 0;
bool drown = false;
if(cwt.at->monst) {
if(vmsg(miRESTRICTED)) {
if(vmsg(miRESTRICTED, siMONSTER, cwt.at, cwt.at->monst)) {
if(isMountable(cwt.at->monst))
addMessage(XLAT("You need to dismount %the1!", cwt.at->monst));
else
@ -128,60 +129,75 @@ bool pcmove::checkNeedMove(bool checkonly, bool attacking) {
}
else if(cwt.at->wall == waRoundTable) {
if(markOrb2(itOrbAether)) return false;
if(vmsg(miRESTRICTED))
if(vmsg(miRESTRICTED, siWALL, cwt.at, moNone))
addMessage(XLAT("It would be impolite to land on the table!"));
}
else if(cwt.at->wall == waLake) {
drown = true;
if(markOrb2(itOrbAether)) return false;
if(markOrb2(itOrbFish)) return false;
if(in_gravity_zone(cwt.at) && passable(cwt.at, NULL, P_ISPLAYER)) return false;
flags |= AF_FALL;
if(vmsg(miWALL)) addMessage(XLAT("Ice below you is melting! RUN!"));
if(vmsg(miWALL, siWALL, cwt.at, moNone)) addMessage(XLAT("Ice below you is melting! RUN!"));
}
else if(!attacking && cellEdgeUnstable(cwt.at)) {
if(markOrb2(itOrbAether)) return false;
if(in_gravity_zone(cwt.at) && passable(cwt.at, NULL, P_ISPLAYER)) return false;
if(vmsg(miRESTRICTED)) addMessage(XLAT("Nothing to stand on here!"));
if(vmsg(miRESTRICTED, siGRAVITY, cwt.at, moNone)) addMessage(XLAT("Nothing to stand on here!"));
return true;
}
else if(among(cwt.at->wall, waSea, waCamelotMoat, waLake, waDeepWater)) {
drown = true;
if(markOrb(itOrbFish)) return false;
if(markOrb2(itOrbAether)) return false;
if(in_gravity_zone(cwt.at) && passable(cwt.at, NULL, P_ISPLAYER)) return false;
if(vmsg(miWALL)) addMessage(XLAT("You have to run away from the water!"));
if(vmsg(miWALL, siWALL, cwt.at, moNone)) addMessage(XLAT("You have to run away from the water!"));
}
else if(cwt.at->wall == waClosedGate) {
if(markOrb2(itOrbAether)) return false;
if(vmsg(miWALL)) addMessage(XLAT("The gate is closing right on you! RUN!"));
if(vmsg(miWALL, siWALL, cwt.at, moNone)) addMessage(XLAT("The gate is closing right on you! RUN!"));
}
else if(isFire(cwt.at) && !markOrb(itOrbWinter) && !markOrb(itCurseWater) && !markOrb2(itOrbShield)) {
if(markOrb2(itOrbAether)) return false;
if(vmsg(miWALL)) addMessage(XLAT("This spot will be burning soon! RUN!"));
if(vmsg(miWALL, siWALL, cwt.at, moNone)) addMessage(XLAT("This spot will be burning soon! RUN!"));
}
else if(cwt.at->wall == waMagma && !markOrb(itOrbWinter) && !markOrb(itCurseWater) && !markOrb2(itOrbShield)) {
if(markOrb2(itOrbAether)) return false;
if(in_gravity_zone(cwt.at) && passable(cwt.at, cwt.at, P_ISPLAYER)) return false;
if(vmsg(miWALL)) addMessage(XLAT("Run away from the lava!"));
if(vmsg(miWALL, siWALL, cwt.at, moNone)) addMessage(XLAT("Run away from the lava!"));
}
else if(cwt.at->wall == waChasm) {
if(markOrb2(itOrbAether)) return false;
if(in_gravity_zone(cwt.at) && passable(cwt.at, cwt.at, P_ISPLAYER)) return false;
flags |= AF_FALL;
if(vmsg(miWALL)) addMessage(XLAT("The floor has collapsed! RUN!"));
if(vmsg(miWALL, siWALL, cwt.at, moNone)) addMessage(XLAT("The floor has collapsed! RUN!"));
}
else if(items[itOrbAether] > ORBBASE && !passable(cwt.at, NULL, P_ISPLAYER | P_NOAETHER)) {
if(markOrb2(itOrbAether)) return false;
vmsg(miWALL);
vmsg(miWALL, siWALL, cwt.at, moNone);
return true;
}
else if(!passable(cwt.at, NULL, P_ISPLAYER)) {
if(isFire(cwt.at)) return false; // already checked: have Shield
if(markOrb2(itOrbAether)) return false;
if(vmsg(miWALL)) addMessage(XLAT("Your Aether power has expired! RUN!"));
if(vmsg(miWALL, siWALL, cwt.at, moNone)) addMessage(XLAT("Your Aether power has expired! RUN!"));
}
else return false;
if(hardcore && !checkonly)
if(hardcore && !checkonly) {
if(cwt.at->monst)
yasc_message = XLAT("did not leave %the1", cwt.at->monst);
else if(cwt.at->wall == waChasm)
yasc_message = XLAT("fell into a chasm");
else if(cwt.at->wall == waRoundTable)
yasc_message = XLAT("died by politeness");
else if(cwt.at->wall == waClosedGate)
yasc_message = XLAT("crushed by a gate");
else if(drown)
yasc_message = XLAT("drowned in %the1", cwt.at->wall);
else
yasc_message = XLAT("did not leave %the1", cwt.at->wall);
killHardcorePlayer(multi::cpid, flags);
}
return true;
}
@ -198,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;
@ -226,16 +243,33 @@ struct pcmove {
movei mi, mip;
pcmove() : mi(nullptr, nullptr, 0), mip(nullptr, nullptr, 0) {}
bool vmsg(int code);
bool vmsg(moveissue mi);
bool vmsg(int code, int subissue_code, cell *where, eMonster m) {
moveissue mi;
mi.type = code;
mi.subtype = subissue_code;
mi.monster = m;
mi.where = where;
return vmsg(mi);
}
bool vmsg_threat() {
return vmsg(miTHREAT, siMONSTER, who_kills_me_cell, who_kills_me);
}
};
#endif
EX cell *global_pushto;
bool pcmove::vmsg(int code) { checked_move_issue = code; changes.rollback(); return errormsgs && !checkonly; }
bool pcmove::vmsg(moveissue mi) {
checked_move_issue = mi;
changes.rollback();
return errormsgs && !checkonly;
}
EX bool movepcto(int d, int subdir IS(1), bool checkonly IS(false)) {
checked_move_issue = miVALID;
checked_move_issue.type = miVALID;
pcmove pcm;
pcm.checkonly = checkonly;
pcm.d = d; pcm.subdir = subdir;
@ -258,6 +292,9 @@ bool pcmove::try_shooting(bool auto_target) {
addMessage(XLAT("Fire!"));
}
items[itCrossbow] = bow::loading_time();
cell *fst = cwt.peek();
if(bow::bowpath.size() >= 1) fst = bow::bowpath[1].prev.at;
eMonster blocked = fst->monst;
bow::shoot();
int v = -1; for(auto p: bow::bowpath) if(p.next.at == cwt.at && (p.flags & bow::bpFIRST)) v = p.next.spin;
@ -268,6 +305,13 @@ bool pcmove::try_shooting(bool auto_target) {
if(gravity_state) markOrb(itOrbGravity);
}
if(againstRose(cwt.at, nullptr) && !scentResistant() && (againstRose(cwt.at, fst) || blocked == fst->monst)) {
if(vmsg(miRESTRICTED, siROSE, nullptr, moNone)) {
addMessage(XLAT("You cannot stay in place and shoot, those roses smell too nicely.") + its(celldistance(cwt.at, fst)));
}
return false;
}
if(cellEdgeUnstable(cwt.at) || cwt.at->land == laWhirlpool) {
if(checkonly) return true;
if(changes.on) changes.commit();
@ -282,12 +326,14 @@ bool pcmove::try_shooting(bool auto_target) {
nextmovetype = hit_anything ? lmAttack : lmSkip;
lastmovetype = hit_anything ? lmAttack : lmSkip; lastmove = NULL;
while(bow::rusalka_curses--) rusalka_curse();
mi = movei(cwt.at, STAY);
if(last_gravity_state && !gravity_state)
playerMoveEffects(mi);
if(monstersnear_add_pmi(mi)) {
if(vmsg(miTHREAT)) wouldkill("%The1 would catch you!");
if(vmsg_threat()) wouldkill("%The1 would catch you!");
return false;
}
if(checkonly) return true;
@ -325,10 +371,15 @@ bool pcmove::movepcto() {
else
lastmountpos[0] = cwt.at;
bool fatigued = false;
if(againstRose(cwt.at, NULL) && d<0 && !scentResistant()) {
if(vmsg(miRESTRICTED))
addMessage("You just cannot stand in place, those roses smell too nicely.");
return false;
fatigued = items[itFatigue] >= 8;
if(!fatigued) {
if(vmsg(miRESTRICTED, siROSE, nullptr, moNone))
addMessage(XLAT("You just cannot stand in place, those roses smell too nicely."));
return false;
}
}
gravity_state = gsNormal;
@ -340,13 +391,19 @@ bool pcmove::movepcto() {
changes.init(checkonly);
changes.value_keep(bow::bowpath_map);
bow::bowpath_map.clear();
bool b = (d >= 0 && bow::fire_mode) ? (origd = d, cwt += d, false) : (d >= 0) ? actual_move() : stay();
if(fatigued) addMessage(XLAT("The roses smell nicely, but you are just too tired to care."));
bool b = (d >= 0 && bow::fire_mode) ? false : (d >= 0) ? actual_move() : stay();
if(checkonly || !b) {
changes.rollback();
if(!checkonly) flipplayer = false;
if(!b && items[itCrossbow] == 0 && bow::crossbow_mode() && d >= 0 && !checkonly) {
if(!b && items[itCrossbow] == 0 && bow::crossbow_mode() && bow::bump_to_shoot && d >= 0 && !checkonly) {
changes.init(checkonly);
if(bow::fire_mode) {
origd = d;
cwt += d;
mirror::act(d, mirror::SPINSINGLE);
}
changes.value_keep(bow::bowpath_map);
b = try_shooting(true);
if(checkonly || !b) changes.rollback();
@ -433,7 +490,7 @@ bool pcmove::swing() {
mirror::act(origd, mirror::SPINMULTI | mirror::ATTACK);
if(monstersnear_add_pmi(movei(cwt.at, STAY))) {
if(vmsg(miTHREAT))
if(nextmovetype == lmAttack ? vmsg(miWALL, siWALL, mi.t, who_kills_me) : vmsg_threat())
wouldkill("You would be killed by %the1!");
return false;
}
@ -659,6 +716,11 @@ void apply_chaos() {
markOrb(itOrbChaos);
copy_metadata(ca, &cob);
copy_metadata(cb, &coa);
ca->item = coa.item;
cb->item = cob.item;
moveItem(ca, cb, false);
if(!switch_lhu_in(ca->land)) ca->LHU = coa.LHU;
if(!switch_lhu_in(cb->land)) cb->LHU = cob.LHU;
if(ca->monst && !(isFriendly(ca) && markOrb(itOrbEmpathy))) {
@ -683,9 +745,6 @@ void apply_chaos() {
if(dice::on(ca) || dice::on(cb)) {
dice::chaos_swap(wa, wb);
}
if(ca->item == itBabyTortoise || cb->item == itBabyTortoise) {
tortoise::move_baby(ca, cb);
}
}
bool pcmove::actual_move() {
@ -713,7 +772,7 @@ bool pcmove::actual_move() {
}
if(againstRose(cwt.at, c2) && !scentResistant()) {
if(vmsg(miRESTRICTED)) addMessage("Those roses smell too nicely. You have to come towards them.");
if(vmsg(miRESTRICTED, siROSE, nullptr, moNone)) addMessage("Those roses smell too nicely. You have to come towards them.");
return false;
}
@ -744,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
@ -752,7 +821,7 @@ bool pcmove::actual_move() {
mip = determinePush(cwt, subdir, [] (movei mi) { return canPushThumperOn(mi, cwt.at); });
if(mip.t) changes.ccell(mip.t);
if(mip.d == NO_SPACE) {
if(vmsg(miWALL)) addMessage(XLAT("No room to push %the1.", c2->wall));
if(vmsg(miWALL, siWALL, c2, moNone)) addMessage(XLAT("No room to push %the1.", c2->wall));
return false;
}
nextmovetype = lmMove;
@ -764,7 +833,7 @@ bool pcmove::actual_move() {
}
if(c2->item == itHolyGrail && roundTableRadius(c2) < newRoundTableRadius()) {
if(vmsg(miRESTRICTED)) addMessage(XLAT("That was not a challenge. Find a larger castle!"));
if(vmsg(miRESTRICTED, siITEM, c2, moNone)) addMessage(XLAT("That was not a challenge. Find a larger castle!"));
return false;
}
@ -776,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();
}
@ -804,21 +870,21 @@ bool pcmove::boat_move() {
cell *& c2 = mi.t;
if(againstWind(c2, cwt.at)) {
if(vmsg(miRESTRICTED)) blowaway_message(c2);
if(vmsg(miRESTRICTED, siWIND, c2, moNone)) blowaway_message(c2);
return false;
}
if(againstCurrent(c2, cwt.at) && !markOrb(itOrbWater)) {
if(markOrb(itOrbFish) || markOrb(itOrbAether) || gravity_state)
return after_escape();
if(vmsg(miRESTRICTED)) addMessage(XLAT("You cannot go against the current!"));
if(vmsg(miRESTRICTED, siCURRENT, c2, moNone)) addMessage(XLAT("You cannot go against the current!"));
return false;
}
if(cwt.at->item == itOrbYendor) {
if(markOrb(itOrbFish) || markOrb(itOrbAether) || gravity_state)
return after_escape();
if(vmsg(miRESTRICTED)) addMessage(XLAT("The Orb of Yendor is locked in with powerful magic."));
if(vmsg(miRESTRICTED, siITEM, c2, moNone)) addMessage(XLAT("The Orb of Yendor is locked in with powerful magic."));
return false;
}
@ -863,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))
@ -893,7 +957,7 @@ bool pcmove::after_escape() {
if(push_behind && !c2->monst && !nonAdjacentPlayer(c2, cwt.at) && fmsMove) {
eWall what = c2->wall;
if(!thruVine(c2, cwt.at) && !canPushStatueOn(cwt.at, P_ISPLAYER)) {
if(vmsg(miRESTRICTED)) {
if(vmsg(miRESTRICTED, siWALL, c2, moNone)) {
if(isFire(cwt.at))
addMessage(XLAT("You have to escape first!"));
else
@ -977,7 +1041,7 @@ bool pcmove::after_escape() {
}
else if(c2->monst == moKnight) {
#if CAP_COMPLEX2
if(vmsg(miWALL)) camelot::knightFlavorMessage(c2);
if(vmsg(miWALL, siMONSTER, c2, c2->monst)) camelot::knightFlavorMessage(c2);
#endif
return false;
}
@ -988,7 +1052,7 @@ bool pcmove::after_escape() {
return false;
}
else if(markOrb(itCurseFatigue) && items[itFatigue] + fatigue_cost(mi) > 10) {
if(vmsg(miRESTRICTED))
if(vmsg(miRESTRICTED, siFATIGUE, nullptr, moNone))
addMessage(XLAT("You are too fatigued!"));
return false;
}
@ -1024,45 +1088,51 @@ bool pcmove::move_if_okay() {
void pcmove::tell_why_impassable() {
cell*& c2 = mi.t;
if(nonAdjacentPlayer(cwt.at,c2)) {
if(vmsg(miRESTRICTED)) addMessage(geosupport_football() < 2 ?
if(vmsg(miRESTRICTED, siWARP, c2, moNone)) addMessage(geosupport_football() < 2 ?
XLAT("You cannot move between the cells without dots here!") :
XLAT("You cannot move between the triangular cells here!")
);
}
else if(againstWind(c2, cwt.at)) {
if(vmsg(miRESTRICTED))
if(vmsg(miRESTRICTED, siWIND, c2, moNone))
blowaway_message(c2);
}
else if(anti_alchemy(c2, cwt.at)) {
if(vmsg(miRESTRICTED))
if(vmsg(miRESTRICTED, siWALL, c2, moNone))
addMessage(XLAT("Wrong color!"));
}
else if(c2->wall == waRoundTable) {
if(vmsg(miRESTRICTED))
if(vmsg(miRESTRICTED, siWALL, c2, moNone))
addMessage(XLAT("It would be impolite to land on the table!"));
}
else if(snakelevel(cwt.at) >= 3 && snakelevel(c2) == 0 && !isWall(c2)) {
if(vmsg(miRESTRICTED))
if(vmsg(miRESTRICTED, siWALL, cwt.at, moNone))
addMessage(XLAT("You would get hurt!", c2->wall));
}
else if(cellEdgeUnstable(cwt.at) && cellEdgeUnstable(c2)) {
if(vmsg(miRESTRICTED))
if(vmsg(miRESTRICTED, siGRAVITY, c2, moNone))
addMessage(XLAT("Gravity does not allow this!"));
}
else if(c2->wall == waChasm && c2->land == laDual) {
if(vmsg(miRESTRICTED))
if(vmsg(miRESTRICTED, siWALL, c2, moNone))
addMessage(XLAT("You cannot move there!"));
}
else if(!c2->wall) {
if(vmsg(miRESTRICTED))
if(vmsg(miRESTRICTED, siUNKNOWN, c2, moNone))
addMessage(XLAT("You cannot move there!"));
}
else {
if(vmsg(miWALL))
if(vmsg(miWALL, siWALL, c2, moNone))
addMessage(XLAT("You cannot move through %the1!", c2->wall));
}
}
EX void rusalka_curse() {
changes.ccell(cwt.at);
if(cwt.at->wall == waNone) cwt.at->wall = waShallow;
else if(cwt.at->wall == waShallow || isAlch(cwt.at->wall)) cwt.at->wall = waDeepWater;
}
bool pcmove::attack() {
auto& c2 = mi.t;
if(!fmsAttack) return false;
@ -1080,14 +1150,14 @@ bool pcmove::attack() {
if(!ca) {
if(forcedmovetype == fmAttack) {
if(monstersnear_add_pmi(movei(cwt.at, STAY))) {
if(vmsg(miTHREAT)) wouldkill("%The1 would get you!");
if(vmsg_threat()) wouldkill("%The1 would get you!");
return false;
}
nextmovetype = lmSkip;
addMessage(XLAT("You swing your sword at %the1.", c2->monst));
return swing();
}
if(vmsg(miENTITY)) tell_why_cannot_attack();
if(vmsg(miENTITY, siMONSTER, c2, c2->monst)) tell_why_cannot_attack();
return false;
}
@ -1139,11 +1209,7 @@ bool pcmove::attack() {
changes.value_add(wandering_jiangshi, 1);
}
attackMonster(c2, attackflags | AF_MSG, moPlayer);
if(m == moRusalka) {
changes.ccell(cwt.at);
if(cwt.at->wall == waNone) cwt.at->wall = waShallow;
else if(cwt.at->wall == waShallow || isAlch(cwt.at->wall)) cwt.at->wall = waDeepWater;
}
if(m == moRusalka) rusalka_curse();
changes.ccell(c2);
// salamanders are stunned for longer time when pushed into a wall
if(c2->monst == moSalamander && (mip.t == c2 || !mip.t)) c2->stuntime = 10;
@ -1161,7 +1227,7 @@ bool pcmove::attack() {
swordAttackStatic();
if(monstersnear_add_pmi(movei(cwt.at, STAY))) {
if(vmsg(miTHREAT)) wouldkill("You would be killed by %the1!");
if(vmsg_threat()) wouldkill("You would be killed by %the1!");
return false;
}
if(checkonly) return true;
@ -1225,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)) {
@ -1251,7 +1311,11 @@ bool pcmove::perform_actual_move() {
forCellEx(c3, c2) if(c3->wall == waIcewall && c3->item) {
changes.ccell(c3);
markOrb(itOrbWinter);
if(collectItem(c3, cwt.at)) return true;
eItem it = c3->item;
if(collectItem(c3, cwt.at))
return true;
if(!c3->item)
animate_item_throw(c3, c2, it);
}
movecost(cwt.at, c2, 2);
@ -1301,7 +1365,7 @@ bool pcmove::perform_move_or_jump() {
if(mi.t->monst == moFriendlyIvy) changes.ccell(mi.t), mi.t->monst = moNone;
if(monstersnear_add_pmi(pmi)) {
if(vmsg(miTHREAT)) wouldkill("%The1 would kill you there!");
if(vmsg_threat()) wouldkill("%The1 would kill you there!");
return false;
}
@ -1346,7 +1410,7 @@ bool pcmove::stay() {
items[itFatigue] = 0;
if(monstersnear_add_pmi(mi)) {
if(vmsg(miTHREAT)) wouldkill("%The1 would get you!");
if(vmsg_threat()) wouldkill("%The1 would get you!");
return false;
}
if(checkonly) return true;

View File

@ -32,6 +32,17 @@ EX string getgametime_s(int timespent IS(getgametime())) {
EX bool display_yasc_codes;
string formatted_yasc_code() {
if(yasc_code < 100000) return its(yasc_code);
int y = yasc_code;
string out;
while(y >= 100) {
out = "-" + its(y%100) + out;
y /= 100;
}
return its(y) + out;
}
string timeline() {
string s;
if(shmup::on)
@ -39,7 +50,7 @@ string timeline() {
else {
s = XLAT("%1 turns (%2)", its(turncount), getgametime_s());
if(display_yasc_codes)
s+= XLAT(" YASC code: ") + its(yasc_code);
s += XLAT(" YASC code: ") + formatted_yasc_code();
}
return s;
}
@ -321,13 +332,14 @@ 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") :
XLAT("GAME OVER"),
0xC00000, 200, 100
);
if(!canmove && yasc_message != "") dialog::addInfo(yasc_message);
#if CAP_COMPLEX2
bool sweeper = mine::in_minesweeper();
@ -369,8 +381,7 @@ EX void showGameMenu() {
}
dialog::addInfo(XLAT("Dropped floors: %1/%2", its(score), its(all)));
if(score == all) dialog::addInfo(XLAT("CONGRATULATIONS!"), iinf[itOrbYendor].color);
if(score == all && geometry == gKleinQuartic && variation == eVariation::untruncated && gp::param == gp::loc(1,1) && !disksize)
achievement_gain_once("LOVASZ", rg::special_geometry);
if(score == all) achievement_gain_once("LOVASZ", specgeom_lovasz());
}
else {
if(0)
@ -434,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);
}
@ -615,6 +626,7 @@ EX void handleKeyQuit(int sym, int uni) {
stop_game();
load_last_save();
start_game();
restore_all_golems();
}
else
gotoHelp(safety_help());
@ -638,7 +650,8 @@ EX void handleKeyQuit(int sym, int uni) {
popScreen();
msgs.clear();
if(!canmove) {
addMessage(XLAT("GAME OVER"));
if(yasc_message != "") addMessage(XLAT("GAME OVER") + ": " + yasc_message);
else addMessage(XLAT("GAME OVER"));
addMessage(timeline());
}
}

View File

@ -88,6 +88,7 @@ string ghost_prefix = "default";
void hread(hstream& hs, ghostmoment& m) {
int id;
hread(hs, m.step, id, m.alpha, m.distance, m.beta, m.footphase);
if(id < 0 || id >= isize(mapstream::cellbyid)) throw hr_exception("error reading a ghost moment");
m.where_cell = mapstream::cellbyid[id];
}
@ -924,7 +925,7 @@ EX void load_official_track() {
void track_chooser(bool official) {
cmode = sm::NOSCR;
gamescreen();
dialog::init(XLAT(official ? "Official tracks" : "Generate a racing track"));
dialog::init(official ? XLAT("play on an official track") : XLAT("generate a random track"));
map<char, eLand> landmap;
@ -1038,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});
}
@ -146,7 +151,7 @@ EX void draw_radar(bool cornermode) {
auto compassdir = [&] (char dirname, hyperpoint h) {
h = NLP * h * .8;
queueline(sId*atscreenpos(cx+rad * h[0], cy - rad * h[2] * si + rad * h[1] * co, 0)*C0, sId*atscreenpos(cx+rad*h[0], cy - rad*h[2] * si, 0)*C0, 0xA0401040, -1);
displaychr(int(cx+rad * h[0]), int(cy - rad * h[2] * si + rad * h[1] * co), 0, 8, dirname, 0xA04010);
displaychr(int(cx+rad * h[0]), int(cy - rad * h[2] * si + rad * h[1] * co), 0, 8 * mapfontscale / 100, dirname, 0xA04010);
};
compassdir('E', point3(+1, 0, 0));
compassdir('N', point3(0, +1, 0));
@ -180,10 +185,10 @@ EX void draw_radar(bool cornermode) {
glflush();
for(auto& r: cd->radarpoints) {
if(d3) displaychr(int(cx + rad * r.h[0]), int(cy - rad * r.h[2] * si + rad * r.h[1] * co), 0, 8, r.glyph, r.color);
if(d3) displaychr(int(cx + rad * r.h[0]), int(cy - rad * r.h[2] * si + rad * r.h[1] * co), 0, 8 * mapfontscale / 100, r.glyph, r.color);
else {
hyperpoint h = locate(r.h);
displaychr(int(h[0]), int(h[1]), 0, int(h[2]) / divby, r.glyph, r.color);
displaychr(int(h[0]), int(h[1]), 0, int(h[2]) * mapfontscale / divby / 100, r.glyph, r.color);
}
}
#endif

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

@ -211,7 +211,26 @@ void add_extra_projections() {
ret[1] = H[1] / H[0] * x;
if(GDIM == 2) ret[2] = H[2] / H[0] * x;
ret[LDIM] = 1;
models::ori_to_scr(H);
models::ori_to_scr(ret);
});
add_extra("point-ideal-point equidistant", mf::horocyclic | mf::orientation, [] (shiftpoint& H_orig, hyperpoint& H, hyperpoint& ret) {
find_zlev(H);
models::scr_to_ori(H);
ld d0 = hdist0(H);
ld x = deparabolic13(H)[0];
ld y2 = d0*d0 - x*x;
ld y = y2 > 0 ? sqrt(y2) : 0;
ret[0] = x;
if(GDIM == 2) ret[1] = H[1] > 0 ? y : -y;
else if(GDIM == 3) {
ld r = hypot(H[1], H[2]);
if(r == 0) ret[1] = ret[2] = 0;
else ret[1] = y * H[1] / r, ret[2] = y * H[2] / r;
}
models::ori_to_scr(ret);
});
}

View File

@ -901,6 +901,7 @@ int rugArgs() {
else if(argis("-go-save")) save_go();
#if CAP_VIDEO
else if(argis("-go-video")) {
save_backup();
shift(); string s = args();
@ -918,6 +919,7 @@ int rugArgs() {
delHook(anims::hooks_anim, a);
undo();
}
#endif
else return 1;
return 0;

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

@ -234,7 +234,7 @@ struct hrmap_notknot : hrmap {
heptagon* at(int x, int y, int z) {
dynamicval<eGeometry> g(geometry, base);
dynamicval<hrmap*> m(currentmap, euc);
euc::coord co = euc::basic_canonicalize({x, y, z});
euc::coord co = euc::basic_canonicalize(euc::coord{x, y, z});
return euc::get_at(co);
}
@ -1429,7 +1429,13 @@ void portal_slideshow(tour::ss::slideshow_callback cb) {
"This is a collection of portals. We start with knotted portals in Euclidean geometry, "
"then we visit portals in other geometries, and finally, we explore portals between different "
"geometries.\n\nLoading these may take some time, so you need to press 'r' to run them. In most slides you can also press '5' to change various parameters.",
[] (presmode mode) {}
[] (presmode mode) {
slide_action(mode, '9', "list of portal scenes", [=] {
popScreenAll();
ss::current_folder = get_foldername(slides[currentslide].name);
pushScreen(ss::showMenu);
});
}
});
auto add = [&] (string s, string text, string youtube, reaction_t act) {

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
}
}

Some files were not shown because too many files have changed in this diff Show More