Compare commits

...

317 Commits

Author SHA1 Message Date
Zeno Rogue 7af403490a fixed the bug with smart range 2024-05-31 19:18:08 +02:00
Zeno Rogue 2314eaba29 fixed non-enterable characters 2024-05-29 14:22:44 +02:00
Zeno Rogue 5d34760290 v13.0l 2024-05-29 13:58:21 +02:00
Zeno Rogue 50d70097cb fixup to another fix 2024-05-29 13:52:12 +02:00
Zeno Rogue c16c064b21 fixed loading used model 2024-05-29 13:52:02 +02:00
Zeno Rogue 448397ab1d fixed Orb Energy orb desc and Air charges 2024-05-29 13:51:53 +02:00
Zeno Rogue b482dabb84 fixed crashes when apply_settings_light with no cgip 2024-05-29 13:51:35 +02:00
Zeno Rogue 478be692de do not exit on sfc if save not even loaded 2024-05-29 13:51:20 +02:00
Zeno Rogue dda979ad14 delayed start in config file 2024-05-29 13:51:09 +02:00
Zeno Rogue 9485495e48 v13.0k 2024-05-28 20:21:45 +02:00
Zeno Rogue d4a610c2b6 fixed orb change display 2024-05-28 20:21:07 +02:00
Zeno Rogue 003ca36ee5 fixed backward incompatible color reading from config 2024-05-28 20:20:56 +02:00
Zeno Rogue 9752cdede1 fixed symbol changed enable archimedean unexpectedly 2024-05-28 20:20:28 +02:00
Zeno Rogue fbd2cc6b9d v13.0j 2024-05-28 19:35:48 +02:00
Zeno Rogue 5324d3d068 fixed parameters in VR 2024-05-28 18:55:22 +02:00
Zeno Rogue d34070f709 fixed atomic 2024-05-28 17:18:39 +02:00
Zeno Rogue 5d576c3344 display charge count for all orbs, and activation costs for frog-like orbs 2024-05-28 15:45:31 +02:00
Zeno Rogue c6c040eead testing in menu_format 2024-05-28 15:35:42 +02:00
Zeno Rogue aec2463f2f more explanation to menu format 2024-05-28 15:26:45 +02:00
Zeno Rogue ba44e111ca fixed string_parameter editors forgetting the edited text 2024-05-28 15:26:10 +02:00
Zeno Rogue 43d1fd3db8 known keynames for all F1-F10 2024-05-28 15:15:41 +02:00
Zeno Rogue 727ae8a260 gametime available in formulas 2024-05-28 15:09:18 +02:00
Zeno Rogue 99bc842c57 generalized show_turns to menu_format 2024-05-28 15:09:00 +02:00
Zeno Rogue a9d6def718 string parameters are now correctly editable 2024-05-28 15:08:30 +02:00
Zeno Rogue 0d5723dd69 config:: pre reactions 2024-05-28 15:07:29 +02:00
Zeno Rogue ab0ca74328 fixed the font file name, also fixed the problem in rawdisplaystr 2024-05-28 13:41:30 +02:00
Zeno Rogue e66f071521
Merge pull request #378 from jlmjlm/fakemob-font
Make fake-mobile fail cleanly if font missing.
2024-05-28 13:36:01 +02:00
Zeno Rogue b7bfe746cb updated the font name in fake-mobile 2024-05-28 13:34:42 +02:00
Zeno Rogue 093044ba83 Orb of Luck now removes the blue bug bias 2024-05-28 13:33:19 +02:00
Zeno Rogue 3c29b987ce fixup to shape pattern 2024-05-28 13:08:08 +02:00
Zeno Rogue a755f26075 make exception text available for parse errors 2024-05-28 13:05:55 +02:00
Zeno Rogue c1bacb0695 catch exception in case if failed to convert 2024-05-28 13:05:07 +02:00
Zeno Rogue e2c81eeae7 size of the world in arcm now can be pressed just like in geom_exp 2024-05-28 13:04:52 +02:00
Zeno Rogue fcc3cae938 fixed the shape pattern for converted tilings 2024-05-28 13:04:24 +02:00
Zeno Rogue 3b3e9e2de6 fixed arb::convert to take 'step' into account, not only 'next' 2024-05-28 13:02:12 +02:00
Zeno Rogue 5901d9598d faster joystick intiialization 2024-05-28 11:59:03 +02:00
Zeno Rogue 6bf198946c chainspilling lava slimes 2024-05-28 11:58:41 +02:00
Zeno Rogue a3261b21da throw color parse error if wrong length 2024-05-27 22:24:20 +02:00
Zeno Rogue 3da7e4c020 removed debug spam 2024-05-27 20:29:31 +02:00
Zeno Rogue ce09e4910e display smaller mouseover help if there is too much text 2024-05-27 15:54:12 +02:00
Zeno Rogue 95d7ffee08 provided some more help to bool parameters 2024-05-27 15:53:59 +02:00
Zeno Rogue 82a7077019 in bool dialog items, display help text as mouseover 2024-05-27 15:53:37 +02:00
Zeno Rogue 1cc90a6f76 added help to some bool parameters 2024-05-27 15:21:57 +02:00
Zeno Rogue 1323ec446a fixed a crash when changing 3D always 2024-05-27 15:21:44 +02:00
Zeno Rogue 8db11dc683 bool dialogs 2024-05-27 15:21:31 +02:00
Zeno Rogue 502469a54a innerwall is now a param 2024-05-27 14:38:29 +02:00
Zeno Rogue 0df75589ca phi now available in formulas 2024-05-27 14:20:54 +02:00
Zeno Rogue 358554d60e sides and shape now available in color formula 2024-05-27 14:20:54 +02:00
Zeno Rogue c594aea40e windmap and cdata available in color formula 2024-05-27 14:20:54 +02:00
Zeno Rogue 03c549b010 hsv color definition 2024-05-27 14:20:54 +02:00
Zeno Rogue 937a291485 atan2 function in parser 2024-05-27 14:20:54 +02:00
Zeno Rogue 0e09775669 clamp function 2024-05-27 14:20:54 +02:00
Zeno Rogue 5c03f9c7fe fixed wallif 2024-05-27 14:20:54 +02:00
Zeno Rogue 8321751cb0 'single color' now works better with live canvas 2024-05-27 14:20:54 +02:00
Zeno Rogue bfacda7207 ccolor:: live_canvas feature 2024-05-27 14:20:54 +02:00
Zeno Rogue 4f761c70cb Wax walls in Canvas now not only in 3D 2024-05-27 14:20:53 +02:00
Zeno Rogue 3ca75bec8e parsecolortable 2024-05-27 14:20:53 +02:00
Zeno Rogue 54443e365d argcolor now uses parsecolor 2024-05-27 14:20:53 +02:00
Zeno Rogue 6ca2051c96 bugfix in parsecolor 2024-05-27 14:20:53 +02:00
Zeno Rogue e5e89c4800 all color names are now accepted in parsecolor 2024-05-27 14:20:53 +02:00
Zeno Rogue bb6df35bf2 moved wallif to parsecolor from general parse 2024-05-27 14:20:53 +02:00
Zeno Rogue ba05c94d7b parse color: fixed color formula doc 2024-05-27 14:20:53 +02:00
Zeno Rogue 90c7f6e927 fixed 'formula' pattern to use RGB correctly 2024-05-27 14:20:53 +02:00
Zeno Rogue e6417951de fixed rgb color passing 2024-05-27 14:20:53 +02:00
Zeno Rogue f823a53f84 fixed hex color parsing 2024-05-27 14:20:53 +02:00
Zeno Rogue 83575d9d7d color parser 2024-05-27 14:20:53 +02:00
Zeno Rogue d381caba1f better a/b anim pars 2024-05-27 14:20:53 +02:00
Zeno Rogue 78cd26f456 fixed char_paremeter edit_option, added edit_option for string_parameters, improved warning for lack of edit_option 2024-05-27 14:20:53 +02:00
Zeno Rogue 96be05484a tau can be now used in formulas 2024-05-27 14:20:53 +02:00
Zeno Rogue 4d57041c9f angles now can be given in quarterturns 2024-05-27 14:20:53 +02:00
Zeno Rogue 5022b76d75 use turncount, framecount and illegal_moves in formulas 2024-05-27 14:20:53 +02:00
Zeno Rogue 8caf343390 track illegal moves 2024-05-27 14:20:53 +02:00
Zeno Rogue 203c11f6e1 fixed used_model parameter 2024-05-27 14:20:53 +02:00
Zeno Rogue 322b21e999 hardcore now can use a formula 2024-05-27 14:20:53 +02:00
Zeno Rogue f445d02707 specialized exceptions for param errors 2024-05-27 02:18:22 +02:00
Zeno Rogue 888a34dea6 fixed unused lambda capture 2024-05-26 23:26:49 +02:00
Zeno Rogue a20158ab65 fixed overzealous override 2024-05-26 23:22:40 +02:00
Zeno Rogue a703448144 added missing override 2024-05-26 23:20:50 +02:00
Zeno Rogue 480916e4db added missing split_string to repo 2024-05-26 23:19:19 +02:00
Zeno Rogue 998a74800c colortables are now saved correctly 2024-05-26 21:15:26 +02:00
Zeno Rogue f4796a10f4 config:: provided custom_reset 2024-05-26 20:57:32 +02:00
Zeno Rogue aa4bf4d818 removed set_default method from parameters 2024-05-26 20:55:39 +02:00
Zeno Rogue ff8bb20a55 config:: custom parameters now have custom_do_save 2024-05-26 20:51:33 +02:00
Zeno Rogue 57691737f0 fixed rwalls not being set in nilrider 2024-05-26 20:42:47 +02:00
Zeno Rogue a4b9b9b0a5 ccolor::which is now a parameter 2024-05-26 20:38:31 +02:00
Zeno Rogue 1c74774bfa refactored the parameter (saver/setting) system 2024-05-26 20:22:29 +02:00
Zeno Rogue a80a73458a fixed product rendering 2024-05-25 22:46:47 +02:00
Zeno Rogue d7bde6f175 fixup to CR 2024-05-25 12:04:11 +02:00
Zeno Rogue 9f711627f1 export to_square 2024-05-25 11:46:53 +02:00
Zeno Rogue 89763be7d2 when drawing circle_around_center, be more precise, and also use POLY_FORCEWIDE 2024-05-25 11:46:37 +02:00
Zeno Rogue 03b89f053b do not draw Safety in high-qual screenshots 2024-05-25 11:46:11 +02:00
Zeno Rogue 441f825566 export achievement data 2024-05-25 11:45:47 +02:00
Zeno Rogue f2d8b4d95e Merge branch 'master' of https://github.com/zenorogue/hyperrogue 2024-05-24 20:58:32 +02:00
Zeno Rogue 73dbccbb0e made Bringris, Nil Rider, and Relative Hell compile after changes 2024-05-24 20:57:53 +02:00
Jacob Mandelson efc2ce90e0 Make fake-mobile fail cleanly if font missing. 2024-05-16 19:33:24 -07:00
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
111 changed files with 3901 additions and 2470 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: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, macos-latest] # os: [ubuntu-latest, macos-latest]
# macos is broken for now
os: [ubuntu-latest]
compiler: [gcc, clang] compiler: [gcc, clang]
build_system: [makefile, mymake] build_system: [makefile, mymake]
hyper_use_rviz: [rviz_1, rviz_0] hyper_use_rviz: [rviz_1, rviz_0]
@ -71,13 +73,15 @@ jobs:
- name: Do a simple test - name: Do a simple test
run: .github/workflows/test_simple.sh run: .github/workflows/test_simple.sh
emscripten: # broken for now
runs-on: ubuntu-latest
steps: # emscripten:
- uses: actions/checkout@v2 # runs-on: ubuntu-latest
- name: Build # steps:
run: | # - uses: actions/checkout@v2
docker run --rm -v $(pwd):/src trzeci/emscripten make emscripten # - name: Build
- name: Do a simple test # run: |
run: | # docker run --rm -v $(pwd):/src trzeci/emscripten make emscripten
ls -lAF hyper.html hyper.js hyper.wasm # - 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 exit 1
ENDOFCMDS 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 else
./hyperrogue --version ./hyperrogue --version
fi 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. # 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: # For Mac OS X:
# Run "brew install sdl" to install SDL in /usr/local. # Run `brew install sdl12-compat sdl_gfx sdl_mixer sdl_ttf`
# Run "brew install sdl_gfx". # Run `brew install glew libpng` to install the optional dependencies
# Run "brew install sdl_mixer". # Run `make` to build HyperRogue as `./hyperrogue`.
# Run "brew install sdl_ttf".
# Run "make" to build HyperRogue as ./hyperrogue.
# #
# For MSYS2 and MinGW-w64: # 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 these commands
# to install SDL and other required libraries. # from the MSYS2 shell:
# Run "make" to build HyperRogue as ./hyperrogue.exe. # 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: # For Ubuntu Linux:
# Run "sudo apt-get install libsdl-dev" to install SDL in /usr/local. # Run "sudo apt-get install libsdl-dev" to install SDL in /usr/local.
@ -54,7 +62,7 @@ ifeq (${OS},linux)
endif endif
ifeq (${OS},mingw) 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 EXE_EXTENSION := .exe
LDFLAGS_GL := -lopengl32 LDFLAGS_GL := -lopengl32
LDFLAGS_GLEW := -lglew32 LDFLAGS_GLEW := -lglew32
@ -68,9 +76,10 @@ ifeq (${OS},mingw)
endif endif
ifeq (${OS},osx) 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 := EXE_EXTENSION :=
LDFLAGS_EARLY += -L/usr/local/lib LDFLAGS_EARLY += -L$(HOMEBREW_PREFIX)/lib
LDFLAGS_GL := -framework AppKit -framework OpenGL LDFLAGS_GL := -framework AppKit -framework OpenGL
LDFLAGS_GLEW := -lGLEW LDFLAGS_GLEW := -lGLEW
LDFLAGS_PNG := -lpng LDFLAGS_PNG := -lpng
@ -80,7 +89,7 @@ ifeq (${OS},osx)
endif endif
ifeq (${TOOLCHAIN},clang) ifeq (${TOOLCHAIN},clang)
CXXFLAGS_STD = -std=c++11 CXXFLAGS_STD = -std=c++14
CXXFLAGS_EARLY += -fPIC CXXFLAGS_EARLY += -fPIC
CXXFLAGS_EARLY += -W -Wall -Wextra -Wsuggest-override -pedantic 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 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 endif
ifeq (${TOOLCHAIN},gcc) ifeq (${TOOLCHAIN},gcc)
CXXFLAGS_STD = -std=c++11 CXXFLAGS_STD = -std=c++14
CXXFLAGS_EARLY += -fPIC CXXFLAGS_EARLY += -fPIC
CXXFLAGS_EARLY += -W -Wall -Wextra -pedantic CXXFLAGS_EARLY += -W -Wall -Wextra -pedantic
CXXFLAGS_EARLY += -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized CXXFLAGS_EARLY += -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized
@ -96,7 +105,7 @@ ifeq (${TOOLCHAIN},gcc)
endif endif
ifeq (${TOOLCHAIN},mingw) ifeq (${TOOLCHAIN},mingw)
CXXFLAGS_STD = -std=c++11 CXXFLAGS_STD = -std=c++14
CXXFLAGS_EARLY += -W -Wall -Wextra CXXFLAGS_EARLY += -W -Wall -Wextra
CXXFLAGS_EARLY += -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized CXXFLAGS_EARLY += -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized
CXXFLAGS_EARLY += -Wno-invalid-offsetof CXXFLAGS_EARLY += -Wno-invalid-offsetof
@ -173,7 +182,7 @@ mymake$(EXE_EXTENSION): mymake.cpp
emscripten: hyper.html emscripten: hyper.html
%.html %.js %.wasm: %.emscripten-sources %.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 hyper.emscripten-sources: *.cpp autohdr.h

View File

@ -1,11 +1,4 @@
# HyperRogue # 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. 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). 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: On macOS with Homebrew:
```brew install sdl sdl_ttf sdl_gfx sdl_mixer glew``` ```brew install sdl sdl_ttf sdl_gfx sdl_mixer glew libpng```
macOS users might also have to edit /usr/local/include/SDL/SDL_gfxPrimitives.h at line 38 to use quote include.
### Building HyperRogue from source ### ### Building HyperRogue from source ###
``` ```
git clone https://github.com/zenorogue/hyperrogue.git hyperrogue git clone https://github.com/zenorogue/hyperrogue.git hyperrogue
cd 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. 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/). 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" #include "hyper.h"
namespace hr { namespace hr {
#if HDR
#define NUMLEADER 90 #define NUMLEADER 90
#endif
EX bool test_achievements = false; EX bool test_achievements = false;
@ -86,9 +88,27 @@ EX const char* leadernames[NUMLEADER] = {
"Crossbow (geometric)", // 89 "Crossbow (geometric)", // 89
}; };
#if HDR
#define LB_PRINCESS 36
#define LB_STATISTICS 62 #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 #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 bool haveLeaderboard(int id);
EX int get_currentscore(int id); EX int get_currentscore(int id);
@ -96,11 +116,11 @@ EX void set_priority_board(int id);
EX int get_sync_status(); EX int get_sync_status();
EX bool score_loaded(int id); EX bool score_loaded(int id);
EX int score_default(int id); EX int score_default(int id);
EX void improveItemScores();
EX void upload_score(int id, int v); EX void upload_score(int id, int v);
string achievementMessage[3]; EX string achievementMessage[3];
int achievementTimer; EX int achievementTimer;
/** achievements received this game */ /** achievements received this game */
EX vector<string> achievementsReceived; EX vector<string> achievementsReceived;
@ -119,6 +139,7 @@ EX bool wrongMode(char flags) {
if(disksize) return true; if(disksize) return true;
} }
if(ineligible_starting_land && !flags) 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(shmup::on != (flags == rg::shmup || flags == rg::racing)) return true;
if(racing::on != (flags == rg::racing)) return true; if(racing::on != (flags == rg::racing)) return true;
@ -144,6 +165,7 @@ EX bool wrongMode(char flags) {
dls = land_structure; dls = land_structure;
if(land_structure != dls) return true; 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::friendly_fire) return true;
if(numplayers() > 1 && multi::pvp_mode) return true; if(numplayers() > 1 && multi::pvp_mode) return true;
if(numplayers() > 1 && multi::split_screen) return true; if(numplayers() > 1 && multi::split_screen) return true;
@ -166,7 +188,7 @@ EX void achievement_gain_once(const string& s, char flags IS(0)) {
namespace rg { namespace rg {
char check(bool b, char val = special_geometry) { return b ? val : fail; } 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_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_lovasz() { return rg::check(geometry == gKleinQuartic && variation == eVariation::untruncated && gp::param == gp::loc(1,1) && !disksize && in_lovasz()); }
@ -217,29 +239,24 @@ EX void achievement_log(const char* s, char flags) {
#endif #endif
} }
EX void achievement_init(); #ifndef LEADER
EX string myname(); #define LEADER "Unknown"
EX void achievement_close(); #define LEADERFULL "Unknown"
#endif
/** gain the given achievement. #if !CAP_ACHIEVE
* @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
void achievement_init() {} void achievement_init() {}
string myname() { return "Rogue"; } string myname() { return "Rogue"; }
void achievement_close() {} void achievement_close() {}
// gain the achievement with the given name. // gain the achievement with the given name.
// flags: 'e' - for Euclidean, 's' - for Shmup, '7' - for heptagonal // flags: 'e' - for Euclidean, 's' - for Shmup, '7' - for heptagonal
// Only awarded if special modes are matched exactly. // 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); achievement_log(s, flags);
} }
void achievement_pump() {}
EX int get_sync_status() { return 0; }
EX void set_priority_board(int) { }
#endif #endif
// gain the achievement for collecting a number of 'it'. // gain the achievement for collecting a number of 'it'.
@ -644,7 +661,7 @@ int specific_what = 0;
EX void improve_score(int i, eItem what) { EX void improve_score(int i, eItem what) {
if(offlineMode) return; if(offlineMode) return;
LATE( improve_score(i, what); ) LATE( improve_score(i, what); )
#ifdef HAVE_ACHIEVEMENTS #if CAP_ACHIEVE
if(haveLeaderboard(i)) updateHi(what, get_currentscore(i)); if(haveLeaderboard(i)) updateHi(what, get_currentscore(i));
if(items[what] && haveLeaderboard(i)) { if(items[what] && haveLeaderboard(i)) {
if(items[what] > get_currentscore(i) && score_loaded(i)) { if(items[what] > get_currentscore(i) && score_loaded(i)) {
@ -658,7 +675,7 @@ EX void improve_score(int i, eItem what) {
// scores for special challenges // scores for special challenges
EX void achievement_score(int cat, int number) { EX void achievement_score(int cat, int number) {
if(offlineMode) return; if(offlineMode) return;
#ifdef HAVE_ACHIEVEMENTS #if CAP_ACHIEVE
if(cheater) return; if(cheater) return;
if(casual) return; if(casual) return;
LATE( achievement_score(cat, number); ) LATE( achievement_score(cat, number); )
@ -680,6 +697,7 @@ EX void achievement_score(int cat, int number) {
return; return;
if(racing::on && cat != LB_RACING) return; if(racing::on && cat != LB_RACING) return;
if(bow::weapon) return; if(bow::weapon) return;
if(use_custom_land_list) return;
upload_score(cat, number); upload_score(cat, number);
#endif #endif
} }
@ -763,7 +781,7 @@ EX void achievement_final(bool really_final) {
LATE( achievement_final(really_final); ) LATE( achievement_final(really_final); )
#ifdef HAVE_ACHIEVEMENTS #if CAP_ACHIEVE
if(ticks > next_stat_tick) { if(ticks > next_stat_tick) {
upload_score(LB_STATISTICS, time(NULL)); upload_score(LB_STATISTICS, time(NULL));
next_stat_tick = ticks + 600000; next_stat_tick = ticks + 600000;
@ -804,6 +822,7 @@ EX void achievement_final(bool really_final) {
if(bow::crossbow_mode() && bow::style == bow::cbBull) specialcode += 32; 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::cbGeodesic) specialcode += 64;
if(bow::crossbow_mode() && bow::style == bow::cbGeometric) specialcode += 96; if(bow::crossbow_mode() && bow::style == bow::cbGeometric) specialcode += 96;
if(shmup::on && vid.creature_scale != 1) return;
if(sphere && specialland == laHalloween) { if(sphere && specialland == laHalloween) {
if(specialcode) return; if(specialcode) return;
@ -814,6 +833,7 @@ EX void achievement_final(bool really_final) {
if(ineligible_starting_land) return; if(ineligible_starting_land) return;
if(geometry) return; if(geometry) return;
if(NONSTDVAR) return; if(NONSTDVAR) return;
if(use_custom_land_list) return;
if(numplayers() > 1 && !multi::friendly_fire) return; if(numplayers() > 1 && !multi::friendly_fire) return;
if(numplayers() > 1 && multi::pvp_mode) return; if(numplayers() > 1 && multi::pvp_mode) return;
@ -896,7 +916,7 @@ EX void check_total_victory() {
EX void achievement_victory(bool hyper) { EX void achievement_victory(bool hyper) {
DEBBI(DF_STEAM, ("achievement_victory")) DEBBI(DF_STEAM, ("achievement_victory"))
if(offlineMode) return; if(offlineMode) return;
#ifdef HAVE_ACHIEVEMENTS #if CAP_ACHIEVE
if(cheater) return; if(cheater) return;
if(casual) return; if(casual) return;
if(bow::weapon) return; if(bow::weapon) return;
@ -909,6 +929,7 @@ EX void achievement_victory(bool hyper) {
if(tactic::on) return; if(tactic::on) return;
if(!ls::nice_walls()) return; if(!ls::nice_walls()) return;
if(ineligible_starting_land) return; if(ineligible_starting_land) return;
if(use_custom_land_list) return;
LATE( achievement_victory(hyper); ) LATE( achievement_victory(hyper); )
DEBB(DF_STEAM, ("after checks")) DEBB(DF_STEAM, ("after checks"))
@ -1029,13 +1050,9 @@ EX string get_rich_presence_text() {
return res; return res;
} }
#ifndef HAVE_ACHIEVEMENTS
void achievement_pump() {}
#endif
/** display the last achievement gained. */ /** display the last achievement gained. */
EX void achievement_display() { EX void achievement_display() {
#ifdef HAVE_ACHIEVEMENTS #if CAP_ACHIEVE
if(achievementTimer) { if(achievementTimer) {
int col = (ticks - achievementTimer); int col = (ticks - achievementTimer);
if(col > 5000) { achievementTimer = 0; return; } if(col > 5000) { achievementTimer = 0; return; }
@ -1065,9 +1082,4 @@ EX int score_default(int i) {
else return 0; 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) { if(specialland != laCanvas) {
canvas_default_wall = waInvisibleFloor; canvas_default_wall = waInvisibleFloor;
patterns::whichCanvas = 'g'; ccolor::set_plain(0xFFFFFF);
patterns::canvasback = 0xFFFFFF;
enable_canvas(); enable_canvas();
} }
start_game(); start_game();
@ -1283,7 +1282,7 @@ void connection_debugger() {
curvepoint(sh[0]); curvepoint(sh[0]);
color_t col = colortables['A'][id]; color_t col = ccolor::shape.ctab[id];
col = darkena(col, 0, 0xFF); col = darkena(col, 0, 0xFF);
if(&p == &last) { if(&p == &last) {
@ -1868,17 +1867,34 @@ EX void convert_max() {
EX void convert_minimize(int N, vector<int>& old_shvids, map<int, int>& old_to_new) { EX void convert_minimize(int N, vector<int>& old_shvids, map<int, int>& old_to_new) {
vector<pair<int, int>> address; vector<pair<int, int>> address;
vector<int> next; vector<int> address_start;
for(int i=0; i<N; i++) { for(int i=0; i<N; i++) {
int q = identification[old_shvids[i]].modval; int q = identification[old_shvids[i]].modval;
int c = isize(address); int c = isize(address);
address_start.push_back(c);
for(int j=0; j<q; j++) { for(int j=0; j<q; j++) {
address.emplace_back(i, j); address.emplace_back(i, j);
next.emplace_back(j == q-1 ? c : c+j+1);
} }
} }
int K = isize(address); int K = isize(address);
vector<int> next(K), step(K);
for(int k=0; k<K; k++) {
auto i = address[k].first;
auto j = address[k].second;
auto& id = identification[old_shvids[i]];
next[k] = address_start[i] + (j+1) % id.modval;
cell *s = id.sample;
cellwalker cw(s, j);
cw += wstep;
auto idx = get_identification(cw.at);
step[k] = address_start[old_to_new.at(idx.target)] + gmod(cw.spin - idx.shift, idx.modval);
}
vector<array<ld, 3> > dists(K); vector<array<ld, 3> > dists(K);
for(int i=0; i<K; i++) { for(int i=0; i<K; i++) {
auto pi = address[i]; auto pi = address[i];
@ -1911,11 +1927,18 @@ EX void convert_minimize(int N, vector<int>& old_shvids, map<int, int>& old_to_n
int chg = 1; int chg = 1;
while(chg) { while(chg) {
for(auto& eq: equal) println(hlog, eq); if(debugflags & DF_GEOM) {
println(hlog, "current table of equals:");
int eqid = 0;
for(auto& eq: equal) {
println(hlog, eq, " for ", eqid, ": ", address[eqid], " next= ", next[eqid], " step= ", step[eqid]);
eqid++;
}
}
chg = 0; chg = 0;
for(int i=0; i<K; i++) for(int i=0; i<K; i++)
for(int j=0; j<K; j++) for(int j=0; j<K; j++)
if(equal[i][j] && !equal[next[i]][next[j]]) { if(equal[i][j] && (!equal[next[i]][next[j]] || !equal[step[i]][step[j]])) {
equal[i][j] = false; equal[i][j] = false;
chg++; chg++;
} }
@ -1984,6 +2007,10 @@ EX void convert() {
sh.vertices.clear(); sh.vertices.clear();
sh.connections.clear(); sh.connections.clear();
sh.cycle_length = id.modval; sh.cycle_length = id.modval;
if(arcm::in())
sh.orig_id = arcm::get_graphical_id(s);
else
sh.orig_id = shvid(s);
sh.repeat_value = t / id.modval; sh.repeat_value = t / id.modval;
sh.flags = hr::pseudohept(s) ? arcm::sfPH : 0; sh.flags = hr::pseudohept(s) ? arcm::sfPH : 0;
#if CAP_ARCM #if CAP_ARCM

View File

@ -1078,6 +1078,20 @@ void archimedean_tiling::parse() {
prepare(); prepare();
} }
EX bool load_symbol(const string& s, bool switch_geom) {
archimedean_tiling at; at.parse(s);
if(at.errors) {
DEBB(DF_ERROR | DF_GEOM, ("error: ", at.errormsg));
return false;
}
if(!switch_geom && geometry != gArchimedean) return true;
stop_game();
set_geometry(gArchimedean);
current = at;
if(!delayed_start) start_game();
return true;
}
#if CAP_COMMANDLINE #if CAP_COMMANDLINE
int readArgs() { int readArgs() {
using namespace arg; using namespace arg;
@ -1085,16 +1099,8 @@ int readArgs() {
if(0) ; if(0) ;
else if(argis("-symbol")) { else if(argis("-symbol")) {
PHASEFROM(2); PHASEFROM(2);
archimedean_tiling at; shift(); load_symbol(args(), true);
shift(); at.parse(args()); showstartmenu = false;
if(at.errors) {
DEBB(DF_ERROR | DF_GEOM, ("error: ", at.errormsg));
}
else {
set_geometry(gArchimedean);
current = at;
showstartmenu = false;
}
} }
else if(argis("-dual")) { PHASEFROM(2); set_variation(eVariation::dual); } else if(argis("-dual")) { PHASEFROM(2); set_variation(eVariation::dual); }
else if(argis("-d:arcm")) else if(argis("-d:arcm"))
@ -1340,17 +1346,25 @@ EX void enable(archimedean_tiling& arct) {
start_game(); start_game();
} }
function<void()> setcanvas(char c) { function<void()> setcanvas(ccolor::data& c) {
return [c] () { auto pc = &c;
return [pc] () {
stop_game(); stop_game();
enable_canvas(); enable_canvas();
patterns::whichCanvas = c; ccolor::which = pc;
start_game(); start_game();
}; };
} }
dialog::string_dialog se; dialog::string_dialog se;
EX void init_symbol_edit() {
symbol_editing = true;
edited = current;
se.start_editing(edited.symbol);
edited.parse();
}
EX void show() { EX void show() {
if(lastsample < isize(samples)) { if(lastsample < isize(samples)) {
string s = samples[lastsample].first; string s = samples[lastsample].first;
@ -1404,12 +1418,7 @@ EX void show() {
else { else {
string cs = in() ? current.symbol : XLAT("OFF"); string cs = in() ? current.symbol : XLAT("OFF");
dialog::addSelItem("edit", cs, '/'); dialog::addSelItem("edit", cs, '/');
dialog::add_action([] () { dialog::add_action(init_symbol_edit);
symbol_editing = true;
edited = current;
se.start_editing(edited.symbol);
edited.parse();
});
dialog::addBreak(100); dialog::addBreak(100);
int nextpos = spos; int nextpos = spos;
int shown = 0; int shown = 0;
@ -1463,13 +1472,15 @@ EX void show() {
}); });
if(in()) { if(in()) {
dialog::addSelItem(XLAT("size of the world"), current.world_size(), 0); dialog::addSelItem(XLAT("size of the world"), current.world_size(), 'S');
add_size_action();
dialog::addSelItem(XLAT("edge length"), current.get_class() == gcEuclid ? (fts(current.edgelength) + XLAT(" (arbitrary)")) : fts(current.edgelength), 0); 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::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::addItem(XLAT("color by symmetries (reversed tiles marked)"), 'r');
dialog::add_action(setcanvas('R')); dialog::add_action(setcanvas(ccolor::shape_mirror));
} }
else { else {
dialog::addBreak(100); dialog::addBreak(100);
@ -1479,20 +1490,20 @@ EX void show() {
if(true) { if(true) {
dialog::addItem(XLAT("color by sides"), 'u'); dialog::addItem(XLAT("color by sides"), 'u');
dialog::add_action(setcanvas('B')); dialog::add_action(setcanvas(ccolor::sides));
} }
if(geosupport_threecolor() == 2) { if(geosupport_threecolor() == 2) {
dialog::addItem(XLAT("three colors"), 'w'); dialog::addItem(XLAT("three colors"), 'w');
dialog::add_action(setcanvas('T')); dialog::add_action(setcanvas(ccolor::threecolor));
} }
else if(geosupport_football() == 2) { else if(geosupport_football() == 2) {
dialog::addItem(XLAT("football"), 'w'); dialog::addItem(XLAT("football"), 'w');
dialog::add_action(setcanvas('F')); dialog::add_action(setcanvas(ccolor::football));
} }
else if(geosupport_chessboard()) { else if(geosupport_chessboard()) {
dialog::addItem(XLAT("chessboard"), 'w'); dialog::addItem(XLAT("chessboard"), 'w');
dialog::add_action(setcanvas('c')); dialog::add_action(setcanvas(ccolor::chessboard));
} }
else dialog::addBreak(100); else dialog::addBreak(100);
@ -1569,6 +1580,14 @@ EX bool is_vertex(heptagon *h) {
return id_of(h) >= 2 * current.N; return id_of(h) >= 2 * current.N;
} }
EX int get_graphical_id(cell *c) {
int id = arcm::id_of(c->master);
int tid = arcm::current.tilegroup[id];
int tid2 = arcm::current.tilegroup[id^1];
if(tid2 >= 0) tid = min(tid, tid2);
return tid;
}
bool archimedean_tiling::get_step_values(int& steps, int& single_step) { bool archimedean_tiling::get_step_values(int& steps, int& single_step) {
int nom = -2; int nom = -2;

View File

@ -151,7 +151,7 @@ EX bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags)
if(!(flags & (AF_GUN | AF_SWORD | AF_SWORD_INTO | AF_MAGIC | AF_PLAGUE))) if(!(flags & (AF_GUN | AF_SWORD | AF_SWORD_INTO | AF_MAGIC | AF_PLAGUE)))
if(c1 != c2 && !logical_adjacent(c1, m1, c2)) return false; 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)) if(c1 && c2 && againstRose(c1, c2) && !ignoresSmell(m1))
return false; return false;
@ -340,6 +340,10 @@ EX eWall conditional_flip_slime(bool flip, eWall t) {
return t; return t;
} }
EX void chainspill(cell *c) {
if(c->wall == waMagma && c->monst == moSlimeNextTurn) killMonster(c, moNone, 0);
}
EX void spillfix(cell* c, eWall t, int rad) { EX void spillfix(cell* c, eWall t, int rad) {
if(c->wall == waTemporary) { if(c->wall == waTemporary) {
changes.ccell(c); changes.ccell(c);
@ -348,6 +352,7 @@ EX void spillfix(cell* c, eWall t, int rad) {
if(rad) for(auto p: adj_minefield_cells_full(c)) { if(rad) for(auto p: adj_minefield_cells_full(c)) {
spillfix(p.c, conditional_flip_slime(p.mirrored, t), rad-1); spillfix(p.c, conditional_flip_slime(p.mirrored, t), rad-1);
} }
chainspill(c);
} }
EX void spill(cell* c, eWall t, int rad) { EX void spill(cell* c, eWall t, int rad) {
@ -362,6 +367,7 @@ EX void spill(cell* c, eWall t, int rad) {
si.second.spill_b > si.second.spill_a ? waFloorB : si.second.spill_b > si.second.spill_a ? waFloorB :
isAlchAny(si.second.orig) ? si.second.orig : isAlchAny(si.second.orig) ? si.second.orig :
waNone; waNone;
chainspill(c);
} }
} }
@ -757,6 +763,11 @@ EX void killMonster(cell *c, eMonster who, flagtype deathflags IS(0)) {
// a reward for killing him before he shoots! // a reward for killing him before he shoots!
c->item = itOrbDragon; 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) if(m == moOutlaw && (c->item == itNone || c->item == itRevolver) && c->wall != waChasm)
c->item = itBounty; c->item = itBounty;
// note: an Orb appears underwater! // note: an Orb appears underwater!
@ -939,6 +950,14 @@ EX void fightmessage(eMonster victim, eMonster attacker, bool stun, flagtype fla
else else
addMessage(XLAT("You pierce %the1.", victim)); // normal 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) { else if(!peace::on) {
playSound(NULL, "hit-sword"+pick123()); playSound(NULL, "hit-sword"+pick123());
addMessage(XLAT("You kill %the1.", victim)); // normal addMessage(XLAT("You kill %the1.", victim)); // normal

View File

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

View File

@ -1516,12 +1516,14 @@ EX void initialize_all() {
DEBBI(DF_INIT | DF_GRAPH, ("initgraph")); DEBBI(DF_INIT | DF_GRAPH, ("initgraph"));
DEBB(DF_INIT, ("initconfig"));
initConfig(); initConfig();
#if CAP_SDLJOY #if CAP_SDLJOY
joyx = joyy = 0; joydir.d = -1; joyx = joyy = 0; joydir.d = -1;
#endif #endif
DEBB(DF_INIT, ("restartGraph"));
restartGraph(); restartGraph();
if(noGUI) { if(noGUI) {
@ -1531,11 +1533,14 @@ EX void initialize_all() {
return; return;
} }
DEBB(DF_INIT, ("preparesort"));
preparesort(); preparesort();
#if CAP_CONFIG #if CAP_CONFIG
DEBB(DF_INIT, ("loadConfig"));
loadConfig(); loadConfig();
#endif #endif
#if CAP_ARCM #if CAP_ARCM
DEBB(DF_INIT, ("parse symbol"));
arcm::current.parse(); arcm::current.parse();
#endif #endif
if(mhybrid) geometry = hybrid::underlying; if(mhybrid) geometry = hybrid::underlying;
@ -1544,19 +1549,26 @@ EX void initialize_all() {
arg::read(2); arg::read(2);
#endif #endif
DEBB(DF_INIT | DF_GRAPH, ("init graph"));
init_graph(); init_graph();
DEBB(DF_INIT | DF_POLY, ("check CGI"));
check_cgi(); check_cgi();
DEBB(DF_INIT | DF_POLY, ("require basic"));
cgi.require_basics(); cgi.require_basics();
DEBB(DF_INIT | DF_GRAPH, ("init font"));
init_font(); init_font();
#if CAP_SDLJOY #if CAP_SDLJOY
initJoysticks(); initJoysticks_async();
#endif #endif
#if CAP_SDLAUDIO #if CAP_SDLAUDIO
DEBB(DF_INIT, ("init audio"));
initAudio(); initAudio();
#endif #endif
DEBB(DF_INIT, ("initialize_all done"));
} }
EX void quit_all() { EX void quit_all() {

View File

@ -703,6 +703,9 @@ EX int coastval(cell *c, eLand base) {
if(!c->landparam) return UNKNOWN; if(!c->landparam) return UNKNOWN;
return c->landparam & 255; return c->landparam & 255;
} }
else if(base == laWestWall) {
if(c->land != base) return 0;
}
else { else {
if(c->land == laOceanWall || c->land == laCaribbean || c->land == laWhirlpool || 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) c->land == laLivefjord || c->land == laWarpSea || c->land == laKraken || c->land == laDocks || c->land == laBrownian)
@ -1005,7 +1008,7 @@ EX void buildEquidistant(cell *c) {
if(c->landparam > 30 && b == laOcean && !generatingEquidistant && !mhybrid && hrand(10) < 5 && chance) if(c->landparam > 30 && b == laOcean && !generatingEquidistant && !mhybrid && hrand(10) < 5 && chance)
buildAnotherEquidistant(c); 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); buildAnotherEquidistant(c);
} }
@ -1132,6 +1135,7 @@ EX void setLandSphere(cell *c) {
vector<eLand> euland; vector<eLand> euland;
map<int, eLand> euland3; map<int, eLand> euland3;
map<int, eLand> euland3_hash; map<int, eLand> euland3_hash;
EX map<array<int, 3>, eLand> landscape_lands;
EX eLand& get_euland(int c) { EX eLand& get_euland(int c) {
euland.resize(max_vec); euland.resize(max_vec);
@ -1144,6 +1148,8 @@ EX void clear_euland(eLand first) {
if(!nonisotropic) euland[0] = euland[1] = euland[max_vec-1] = first; if(!nonisotropic) euland[0] = euland[1] = euland[max_vec-1] = first;
euland3.clear(); euland3.clear();
euland3[0] = first; euland3[0] = first;
landscape_lands.clear();
landscape_lands[make_array(0,0,0)] = first;
} }
bool valid_wall_at(int c) { bool valid_wall_at(int c) {
@ -1323,7 +1329,7 @@ EX void setLandEuclid(cell *c) {
return; return;
} }
#endif #endif
setland(c, specialland); if(!c->land) setland(c, specialland);
if(ls::any_nowall()) { if(ls::any_nowall()) {
auto co = euc2_coordinates(c); auto co = euc2_coordinates(c);
int y = co.second; int y = co.second;
@ -1768,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 && else if(good_for_wall(c) && isWarpedType(c->land) && hrand(10000) < 3000 && c->land &&
buildBarrierNowall(c, eLand(c->land ^ laWarpSea ^ laWarpCoast))) { } 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; else if(ls::single()) return;
@ -1789,11 +1810,11 @@ EX void build_walls(cell *c, cell *from) {
return; 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))) ; buildBarrierNowall(c, getNewLand(laCrossroads4))) ;
else if(good_for_wall(c) && hrand(I10000) < 20 && !generatingEquidistant && !yendor::on && !tactic::on && !racing::on && !isCrossroads(c->land) && else if(good_for_wall(c) && ls::any_wall() && hrand(I10000) < 20 && !generatingEquidistant && !yendor::on && !tactic::on && !racing::on && !isCrossroads(c->land) &&
gold() >= R200 && !weirdhyperbolic && !c->master->alt && c->bardir != NOBARRIERS && landUnlockedIngame(laCrossroads4) && !weirdhyperbolic && !c->master->alt && c->bardir != NOBARRIERS &&
!inmirror(c) && !isSealand(c->land) && !isHaunted(c->land) && !isGravityLand(c->land) && !inmirror(c) && !isSealand(c->land) && !isHaunted(c->land) && !isGravityLand(c->land) &&
(c->land != laRlyeh || rlyehComplete()) && (c->land != laRlyeh || rlyehComplete()) &&
c->land != laTortoise && c->land != laPrairie && c->land && c->land != laTortoise && c->land != laPrairie && c->land &&
@ -1873,13 +1894,13 @@ EX void build_horocycles(cell *c, cell *from) {
items[itEmerald] >= U5))) items[itEmerald] >= U5)))
start_camelot(c); 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); 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); 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); heptagon *h = create_altmap(c, horo_gen_distance(), hsA);
if(h) clearing::bpdata[h].root = NULL; if(h) clearing::bpdata[h].root = NULL;
} }
@ -1891,11 +1912,12 @@ EX void build_horocycles(cell *c, cell *from) {
if(c->land == laOcean && deepOcean && !generatingEquidistant && !peace::on && can_start_horo(c) && if(c->land == laOcean && deepOcean && !generatingEquidistant && !peace::on && can_start_horo(c) &&
(quickfind(laWhirlpool) || ( (quickfind(laWhirlpool) || (
hrand(2000) < (PURE ? 500 : 1000)))) hrand(2000) < (PURE ? 500 : 1000) && landUnlockedIngame(laWhirlpool))))
create_altmap(c, horo_gen_distance(), hsA); create_altmap(c, horo_gen_distance(), hsA);
#if CAP_COMPLEX2 #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); brownian::init_further(c);
#endif #endif
@ -1916,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 && if(c->land == laPalace && can_start_horo(c) && !princess::generating && !shmup::on && multi::players == 1 && !weirdhyperbolic &&
(princess::forceMouse ? canReachPlayer(from, moMouse) : (princess::forceMouse ? canReachPlayer(from, moMouse) :
(hrand(2000) < (peace::on ? 100 : 20))) && (hrand(2000) < (peace::on ? 100 : 20))) &&
(princess::challenge || kills[moVizier] || peace::on)) { landUnlockedIngame(laPrincessQuest)) {
create_altmap(c, PRADIUS0, hsOrigin, waPalace); create_altmap(c, PRADIUS0, hsOrigin, waPalace);
celllister cl(c, 5, 1000000, NULL); celllister cl(c, 5, 1000000, NULL);
for(cell *c: cl.lst) if(c->master->alt) currentmap->extend_altmap(c->master); for(cell *c: cl.lst) if(c->master->alt) currentmap->extend_altmap(c->master);
@ -2315,7 +2337,7 @@ EX void pregen() {
currentlands.clear(); currentlands.clear();
if(ls::any_chaos() && !ls::std_chaos()) if(ls::any_chaos() && !ls::std_chaos())
for(eLand l: land_over) for(eLand l: land_over)
if(landUnlocked(l) && isLandIngame(l)) if(landUnlockedIngame(l))
currentlands.push_back(l); currentlands.push_back(l);
} }

View File

@ -136,7 +136,7 @@ EX namespace bt {
h->emeraldval = gmod((parent->emeraldval - d1) * 7508, 15015); h->emeraldval = gmod((parent->emeraldval - d1) * 7508, 15015);
break; break;
case gTernary: case gTernary:
if(d < 2) if(d <= 2)
h->emeraldval = gmod(parent->emeraldval * 3 + d, 10010); h->emeraldval = gmod(parent->emeraldval * 3 + d, 10010);
else else
h->emeraldval = gmod((parent->emeraldval - d1) * 3337, 10010); 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 #endif
EX bool pseudohept(cell *c) { EX bool pseudohept(cell *c) {
if(WDIM == 2) switch(geometry) {
return c->type & c->master->distance & 1; case gBinary4:
else if(geometry == gHoroRec) c->cmove(3);
return c->c.spin(S7-1) == 0 && (c->master->distance & 1) && c->cmove(S7-1)->c.spin(S7-1) == 0; return (c->master->distance & 1) && (c->c.spin(3) == 0);
else if(geometry == gHoroTris)
return c->c.spin(S7-1) == 0 && (c->master->distance & 1); case gBinaryTiling:
else return c->master->distance & c->type & 1;
return (c->master->zebraval == 1) && (c->master->distance & 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) { EX pair<gp::loc, gp::loc> gpvalue(heptagon *h) {

View File

@ -94,6 +94,14 @@ void eclectic_red(color_t& col) {
constexpr ld spinspeed = .75 / M_PI; 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() { void celldrawer::setcolors() {
wcol = fcol = winf[c->wall].color; wcol = fcol = winf[c->wall].color;
@ -541,10 +549,7 @@ void celldrawer::setcolors() {
case waMineUnknown: case waMineMine: case waMineUnknown: case waMineMine:
#if CAP_COMPLEX2 #if CAP_COMPLEX2
if(mine::marked_safe(c)) if(!mine_markers) fcol = wcol = apply_mine_knowledge(wcol, 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);
goto fallthrough; goto fallthrough;
#endif #endif
@ -847,13 +852,6 @@ void celldrawer::draw_grid() {
int prec = grid_prec(); 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(inmirrorcount) return;
if(vid.grid || (c->land == laAsteroids && !(WDIM == 2 && GDIM == 3))) ; else return; if(vid.grid || (c->land == laAsteroids && !(WDIM == 2 && GDIM == 3))) ; else return;
@ -1386,6 +1384,39 @@ bool celldrawer::set_randompattern_floor() {
} }
EX bool numerical_minefield; EX 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() { void celldrawer::draw_features() {
char xch = winf[c->wall].glyph; char xch = winf[c->wall].glyph;
@ -1631,18 +1662,12 @@ void celldrawer::draw_features() {
case waMineOpen: { case waMineOpen: {
int mines = countMinesAround(c); int mines = countMinesAround(c);
if(numerical_minefield) { draw_mine_numbers(mines, V, ct6);
if(mines) { break;
string label = its(mines); }
queuestr(V, mines >= 10 ? .5 : 1, label, darkened(minecolors[mines]), 8);
} case waMineUnknown: case waMineMine: {
} draw_mine_markers(c, V);
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));
}
break; break;
} }
@ -1772,6 +1797,9 @@ void celldrawer::draw_features_and_walls_3d() {
if(anyshiftclick) return; if(anyshiftclick) return;
} }
if(among(c->wall, waMineUnknown, waMineMine))
draw_mine_markers(c, face_the_player(V));
if(isWall3(c, wcol)) { if(isWall3(c, wcol)) {
if(!no_wall_rendering) { if(!no_wall_rendering) {
if(c->wall == waChasm && c->land == laMemory && !in_perspective()) { 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)); 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 { else {
if(!no_wall_rendering) for(int a=0; a<c->type; a++) if(c->move(a)) { 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 { else {
int mines = countMinesAround(c); int mines = countMinesAround(c);
if(mines >= isize(minecolors)) draw_mine_numbers(mines, face_the_player(V), 0);
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));
} }
} }
@ -2079,7 +2111,7 @@ void celldrawer::draw_cellstat() {
if(c->land == laMirrored || c->land == laMirrorWall2 || c->land == laMirrored2) { if(c->land == laMirrored || c->land == laMirrorWall2 || c->land == laMirrored2) {
string label = its(c->landparam); string label = its(c->landparam);
queuestr(V, 1 * .2, label, 0xFFFFFFFF, 1); queuestr(V, mapfontscale / 500, label, 0xFFFFFFFF, 1);
} }
if(debug_tiles && mod_allowed()) { if(debug_tiles && mod_allowed()) {
@ -2105,22 +2137,22 @@ void celldrawer::draw_cellstat() {
#endif #endif
else else
label = its(shvid(c)); 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++) { 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(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))), .2, 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); 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) { if(cmode & sm::TORUSCONFIG) {
auto p = euc::coord_display(V, c); auto p = euc::coord_display(V, c);
if(p.second != "") 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 #if CAP_EDIT
@ -2135,13 +2167,13 @@ void celldrawer::draw_cellstat() {
string label = its(si.id & 255); string label = its(si.id & 255);
color_t col = forecolor ^ colorhash(si.id >> 8); color_t col = forecolor ^ colorhash(si.id >> 8);
queuestr(V, .5, label, 0xFF000000 + col); queuestr(V, mapfontscale / 200, label, 0xFF000000 + col);
} }
#endif #endif
if(debug_cellnames && pointer_indices.count(c)) { if(debug_cellnames && pointer_indices.count(c)) {
shstream ss; print(ss, 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)); queuepoly(V * ddspin(c, 0), cgi.shAsymmetric, darkena(0x000000, 0, 0xC0));
} }
} }
@ -2497,20 +2529,13 @@ void celldrawer::draw_item_full() {
if(doHighlight()) asciiborder = kind_outline(it) >> 8; if(doHighlight()) asciiborder = kind_outline(it) >> 8;
if(it == itCompass && isPlayerOn(c)) { if(it == itCompass && isPlayerOn(c)) {
cell *c1 = c ? findcompass(c) : NULL; shiftpoint dummy;
if(c1) { mark_compass(c, dummy);
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);
}
} }
} }
if(it) { if(it) {
if((c->land == laWhirlwind || c->item == itBabyTortoise || c->land == laWestWall) && c->wall != waBoat) { if(c->wall != waBoat) {
double footphase = 0; double footphase = 0;
applyAnimation(c, Vboat, footphase, LAYER_BOAT); applyAnimation(c, Vboat, footphase, LAYER_BOAT);
} }
@ -2581,7 +2606,7 @@ void celldrawer::draw_monster_full() {
bool dm = drawMonster(V, c->type, c, moncol, asciicol); bool dm = drawMonster(V, c->type, c, moncol, asciicol);
if(dm) onradar = false; if(dm) onradar = false;
#if CAP_SHAPES #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) if(WDIM == 2 && GDIM == 3 && abs(cgi.SLEV[sl] - cgi.FLOOR) > 1e-6)
pushdown(c, q, V, cgi.SLEV[sl] - cgi.FLOOR, false, false); 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) 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(callhandlers(false, hooks_drawcell, c, V)) return;
if(history::on || inHighQual || WDIM == 3 || shmup::on || sightrange_bonus > gamerange_bonus || !playermoved) checkTide(c); checkTide(c);
if(1) { if(1) {
@ -2962,7 +2987,7 @@ void celldrawer::draw() {
string s = s0+asciichar; string s = s0+asciichar;
dynamicval<color_t> p(poly_outline, asciiborder << 8); dynamicval<color_t> p(poly_outline, asciiborder << 8);
if(!wmascii3) 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)) { else if(highwall(c) && conegraph(c)) {
const int layers = 1 << detaillevel; const int layers = 1 << detaillevel;
string s1 = s0+asciichar1; string s1 = s0+asciichar1;
@ -2970,7 +2995,7 @@ void celldrawer::draw() {
for(int z=0; z<layers; z++) 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); 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; 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)) { else if(highwall(c)) {
const int layers = 1 << detaillevel; const int layers = 1 << detaillevel;
@ -2979,15 +3004,15 @@ void celldrawer::draw() {
for(int z=0; z<layers; z++) 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); 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; 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))) { else if((sl = snakelevel(c))) {
string s1 = s0+asciichar1; string s1 = s0+asciichar1;
poly_outline = bordcolor << 8; poly_outline = bordcolor << 8;
for(int z=0; z<sl*4; z++) if(z%4 == 0) 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; 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) { // else if(c->wall == waChasm) {
// const int layers = 1 << detaillevel; // const int layers = 1 << detaillevel;
@ -2996,12 +3021,12 @@ void celldrawer::draw() {
else if(chasmgraph(c)) { else if(chasmgraph(c)) {
string s1 = s0+asciichar1; string s1 = s0+asciichar1;
poly_outline = bordcolor << 8; 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; poly_outline = asciiborder << 8;
queuestrn(V, 1, s, darkenedby(asciicol, darken), 2); queuestrn(V, mapfontscale / 100, s, darkenedby(asciicol, darken), 2);
} }
else else
queuestrn(V, 1, s, darkenedby(asciicol, darken), 2); queuestrn(V, mapfontscale / 100, s, darkenedby(asciicol, darken), 2);
} }
draw_grid(); draw_grid();

View File

@ -5133,3 +5133,149 @@ Gameplay fixes:
Other: 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 - 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 - 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)
2024-05-28 19:35 Update 13.0j
- display charge count for all orbs, and activation costs for frog-like orbs
- "(v) menu" can now be replaced to show turn count or another parameter/formula
- Orb of Luck now removes the blue bug bias
- fixed the shape pattern for converted tilings
- fixed a bug in the tessellation converter
- the game spent 5s on startup initializing SDL joysticks -- this now can be avoided
- chainspilling lava slimes
- more explanation is now available for ON/OFF parameters
- fixed product rendering
- fixed model orientation for spiral
- fixed a crash when changing the 'race angle' setting
- fixed a possible crash when trying to build CR2 or CR5 next to CR4
Changes to the parameter/formula system:
- more values and functions are now available in formulas (including the new color formulas, including the 'formula' canvas pattern)
2024-05-28 20:21 Update 13.0k
- fixed orb change display
- fixed backward incompatible color reading from config
- fixed symbol changed enable archimedean unexpectedly
2024-05-29 13:54 Update 13.0l
- fixed some more errors with the config file
- show charges for Orb of Air, also fixed the line for Orb Energy
- fixed some characters not being enterable in SDL2

View File

@ -181,9 +181,7 @@ EX bool monstersnear(cell *c, eMonster who) {
} }
// consider normal monsters // consider normal monsters
if(c2 && if(c2 && isArmedEnemy(c2, who)) {
isArmedEnemy(c2, who) &&
(c2->monst != moLancer || isUnarmed(who) || !logical_adjacent(c, who, c2))) {
eMonster m = c2->monst; eMonster m = c2->monst;
if(elec::affected(c2)) continue; if(elec::affected(c2)) continue;
if(fast && c2->monst != moWitchSpeed) continue; if(fast && c2->monst != moWitchSpeed) continue;
@ -302,22 +300,29 @@ EX bool swordConflict(const player_move_info& sm1, const player_move_info& sm2)
EX string yasc_message; 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() { EX void create_yasc_message() {
set<pair<cell*, eMonster>> captures; set<pair<cell*, string>> captures;
auto all = move_issues; auto all = move_issues;
all.push_back(stay_issue); all.push_back(stay_issue);
for(auto c: all) if(c.type == miTHREAT) captures.emplace(c.where, c.monster); for(auto c: all) if(c.type == miTHREAT) captures.emplace(c.where, blocking_monster_name(c));
vector<string> context; vector<string> context;
if(!captures.empty()) { if(!captures.empty()) {
string msg = "captured by "; string msg = "captured by ";
map<eMonster, int> qties; map<string, int> qties;
for(auto ca: captures) qties[ca.second]++; for(auto ca: captures) qties[ca.second]++;
int iqties = 0; int iqties = 0;
for(auto q: qties) { for(auto q: qties) {
if(iqties && iqties == isize(qties) - 1) msg += " and "; if(iqties && iqties == isize(qties) - 1) msg += " and ";
else if(iqties) msg += ", "; else if(iqties) msg += ", ";
msg += dnameof(q.first); msg += q.first;
if(q.second > 1) msg += " (x" + its(q.second) + ")"; if(q.second > 1) msg += " (x" + its(q.second) + ")";
iqties++; iqties++;
} }
@ -336,13 +341,16 @@ EX void create_yasc_message() {
set<string> blocks; set<string> blocks;
int index = 0; int index = 0;
for(auto c: all) { for(auto c: all) {
if(c.type == miENTITY && !captures.count({c.where, c.monster})) blocks.insert(dnameof(c.monster)); if(c.type == miENTITY && !captures.count({c.where, blocking_monster_name(c)})) blocks.insert(blocking_monster_name(c));
if(c.subtype == siITEM) blocks.insert("item"); else if(c.type == miWALL && c.subtype == siMONSTER && !captures.count({c.where, blocking_monster_name(c)})) blocks.insert(blocking_monster_name(c));
if(c.subtype == siWALL) { else if(c.subtype == siITEM) blocks.insert("item");
else if(c.subtype == siWALL) {
if(c.where == cwt.at) { if(c.where == cwt.at) {
if(in_ctx) { if(in_ctx) {
if(c.where->wall == waNone && c.where->land == laBrownian) if(c.where->wall == waNone && c.where->land == laBrownian)
context.push_back("on level 3"); context.push_back("on level 3");
else if(c.where->wall == waRoundTable)
context.push_back("being polite");
else else
context.push_back(winf[c.where->wall].flags & WF_ON ? XLAT("on %the1", c.where->wall) : XLAT("in %the1", c.where->wall)); context.push_back(winf[c.where->wall].flags & WF_ON ? XLAT("on %the1", c.where->wall) : XLAT("in %the1", c.where->wall));
} }
@ -350,7 +358,7 @@ EX void create_yasc_message() {
} }
else if(c.where && c.where->wall != cwt.at->wall) blocks.insert(dnameof(c.where->wall)); else if(c.where && c.where->wall != cwt.at->wall) blocks.insert(dnameof(c.where->wall));
} }
if(c.type == siWARP) blocks.insert("warp"); else if(c.type == siWARP) blocks.insert("warp");
index++; index++;
} }
@ -377,9 +385,23 @@ EX void create_yasc_message() {
iqties++; 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); 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() { EX void checkmove() {
if(dual::state == 2) return; if(dual::state == 2) return;
@ -424,7 +446,7 @@ EX void checkmove() {
yasc_code = 0; yasc_code = 0;
for(int i=0; i<cwt.at->type; i++) for(int i=0; i<cwt.at->type; i++)
yasc_code += move_issues[i].type; yasc_code += yasc_recode(move_issues[i].type);
if(!canmove && bow::crossbow_mode() && !items[itCrossbow]) canmove = bow::have_bow_target(); if(!canmove && bow::crossbow_mode() && !items[itCrossbow]) canmove = bow::have_bow_target();

View File

@ -105,11 +105,7 @@ EX namespace arg {
EX bool argis(const string& s) { if(args()[0] == '-' && args()[1] == '-') return args().substr(1) == s; return args() == s; } EX bool argis(const string& s) { if(args()[0] == '-' && args()[1] == '-') return args().substr(1) == s; return args() == s; }
EX color_t argcolor(int bits) { EX color_t argcolor(int bits) {
string s = args(); return parsecolor(args(), bits == 32);
auto p = find_color_by_name(s);
if(p && bits == 24) return p->second;
if(p && bits == 32) return (p->second << 8) | 0xFF;
return strtoll(argcs(), NULL, 16);
} }
int parameter_id; int parameter_id;
@ -335,6 +331,19 @@ int arg::readCommon() {
clearMessages(); 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 // informational
else if(argis("-version") || argis("-v")) { else if(argis("-version") || argis("-v")) {
printf("HyperRogue version " VER "\n"); printf("HyperRogue version " VER "\n");
@ -432,6 +441,8 @@ EX hookset<int()> hooks_args;
EX map<string, pair<int, reaction_t>> *added_commands; EX map<string, pair<int, reaction_t>> *added_commands;
EX bool delayed_start;
EX namespace arg { EX namespace arg {
int read_added_commands() { int read_added_commands() {
@ -464,6 +475,7 @@ EX namespace arg {
void read(int phase) { void read(int phase) {
curphase = phase; curphase = phase;
callhooks(hooks_config); callhooks(hooks_config);
dynamicval<bool> ds(delayed_start, true);
while(pos < isize(argument)) { while(pos < isize(argument)) {
int r = callhandlers(1, hooks_args); int r = callhandlers(1, hooks_args);
switch (r) { switch (r) {

View File

@ -215,10 +215,14 @@ EX namespace elec {
if(c->wall == waSea || c->wall == waGrounded) return ecGrounded; if(c->wall == waSea || c->wall == waGrounded) return ecGrounded;
if(c->wall == waSandstone || c->wall == waDeadTroll || if(c->wall == waSandstone || c->wall == waDeadTroll ||
c->wall == waDeadTroll2 || c->wall == waDeadTroll2 ||
among(c->wall, waBigTree, waSmallTree, waExplosiveBarrel, waRed1, waRed2, waRed3) || c->wall == waExplosiveBarrel ||
c->wall == waVinePlant || c->wall == waVinePlant ||
c->wall == waMetal || isAlchAny(c)) c->wall == waMetal || isAlchAny(c))
return isElectricLand(c) ? ecConductor : ecGrounded; 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) if(c->wall == waBarrier)
return ecIsolator; return ecIsolator;
if(c->wall == waChasm) if(c->wall == waChasm)
@ -644,7 +648,7 @@ struct info {
if(newdist == OUT_OF_PRISON && princess::challenge) { if(newdist == OUT_OF_PRISON && princess::challenge) {
addMessage(XLAT("Congratulations! Your score is %1.", its(i->value))); addMessage(XLAT("Congratulations! Your score is %1.", its(i->value)));
achievement_gain_once("PRINCESS2", rg::princess); achievement_gain_once("PRINCESS2", rg::princess);
if(!cheater) achievement_score(36, i->value); if(!cheater) achievement_score(LB_PRINCESS, i->value);
LATE( showMissionScreen(); ) LATE( showMissionScreen(); )
} }
} }
@ -1684,6 +1688,7 @@ EX namespace hive {
EX eMonster randomHyperbug() { EX eMonster randomHyperbug() {
int h = hivehard(); int h = hivehard();
if(h && markOrb(itOrbLuck)) h /= 4;
if(hrand(200) < h) if(hrand(200) < h)
return moBug2; return moBug2;
return eMonster(moBug0 + hrand(BUGCOLORS)); return eMonster(moBug0 + hrand(BUGCOLORS));
@ -2126,6 +2131,8 @@ EX namespace heat {
if(c->monst == moDesertman) hmod += 4 * xrate; if(c->monst == moDesertman) hmod += 4 * xrate;
if(c->monst == moAngryDie) hmod += 4 * xrate; if(c->monst == moAngryDie) hmod += 4 * xrate;
if(c->monst == moMonkey) hmod += 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 == waDeadTroll) hmod -= 2 * xrate;
if(c->wall == waDeadTroll2) hmod -= 1.5 * xrate; if(c->wall == waDeadTroll2) hmod -= 1.5 * xrate;
if(c->wall == waBigStatue) hmod -= .5 * xrate; if(c->wall == waBigStatue) hmod -= .5 * xrate;
@ -2478,7 +2485,9 @@ EX void livecaves() {
if(hv > 0 && c->wall == waNone) { if(hv > 0 && c->wall == waNone) {
if(c->item && c->cpdist == 1 && markOrb(itOrbWater)) { if(c->item && c->cpdist == 1 && markOrb(itOrbWater)) {
bool saf = c->item == itOrbSafety; bool saf = c->item == itOrbSafety;
eItem it = c->item;
collectItem(c, c); collectItem(c, c);
if(it && !c->item) animate_item_throw(c, cwt.at, it);
if(saf) return; if(saf) return;
} }
c->wall = waSea; c->wall = waSea;
@ -3498,6 +3507,7 @@ EX namespace ca {
} }
for(int i=0; i<dcs; i++) { for(int i=0; i<dcs; i++) {
cell *c = allcells[i]; cell *c = allcells[i];
if(c->land != laCA) continue;
auto last = c->wall; auto last = c->wall;
c->wall = willlive[i] ? wlive : waNone; c->wall = willlive[i] ? wlive : waNone;
if(c->wall != last) { if(c->wall != last) {

View File

@ -166,11 +166,11 @@ EX namespace brownian {
ONEMPTY { 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) 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; c->item = itBrownian;
if(hrand_monster(8000) < 15 + items[itBrownian]) if(hrand_monster_in(laBrownian, 8000) < 15 + items[itBrownian])
c->monst = moAcidBird; c->monst = moAcidBird;
else if(hrand_monster(8000) < 15) else if(hrand_monster_in(laBrownian, 8000) < 15)
c->monst = moAlbatross; 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->monst = moBrownBug;
c->hitpoints = 3; c->hitpoints = 3;
} }
@ -291,7 +291,7 @@ extern array<feature, 21> features;
#define VF [] (cell *c) #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 {{ array<feature, 21> features {{
feature{(color_t)(-0x202020), 5, moNecromancer, VF { 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", "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", "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", "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; map<cell*, int> knight_id;

1525
config.cpp

File diff suppressed because it is too large Load Diff

View File

@ -973,7 +973,7 @@ WALL( '+', 0xFF0000, "giant rug", waGiantRug, ZERO | WF_ON, RESERVED, 0, sgNone,
"This is the biggest Hypersian Rug you have ever seen! " "This is the biggest Hypersian Rug you have ever seen! "
"Unfortunately, it is too large to take it as a trophy." ) "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( '#', 0xfffff0, "platform", waPlatform, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, "You can stand here.")
WALL( '#', 0x909090, "stone gargoyle", waGargoyle, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, gargdesc) WALL( '#', 0x909090, "stone gargoyle", waGargoyle, WF_WALL | WF_HIGHWALL | WF_NONBLOCK, RESERVED, 0, sgNone, gargdesc)
WALL( '.', 0xB0B0B0, "stone gargoyle floor", waGargoyleFloor, ZERO | WF_ON, RESERVED, 1, sgNone, gargdesc) WALL( '.', 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( '.', 0x909090, "rubble", waRubble, ZERO | WF_ON, RESERVED, 1, sgNone, "Some rubble.")
WALL( '+', 0x804000, "ladder", waLadder, ZERO | WF_ON, RESERVED, 0, sgNone, WALL( '+', 0x804000, "ladder", waLadder, ZERO | WF_ON, RESERVED, 0, sgNone,
@ -1018,7 +1018,7 @@ WALL( '+', 0x60C060, "canopy", waCanopy, ZERO, RESERVED, 0, sgNone,
) )
WALL( '#', 0xD0C060, "barrow wall", waBarrowWall, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, "This wall is quite strong. You will need another way in.") WALL( '#', 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( '#', 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( '.', 0xE8E8E8, "tower of Camelot", waTower, ZERO, RESERVED, 3, sgNone, camelothelp)
WALL( '-', 0x402000, "big bush", waBigBush, ZERO | WF_NOFLIGHT | WF_ON, 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. " "You can hold this bush to climb the Lost Mountain. "
@ -1298,11 +1298,11 @@ LAND( 0xE08020, "Canvas", laCanvas, ZERO | LF_TECHNICAL, itNone, RESERVED, "A fa
LAND( 0x00C000, "Palace Quest", laPrincessQuest, ZERO, itSavedPrincess, RESERVED, princessdesc) // fake LAND( 0x00C000, "Palace Quest", laPrincessQuest, ZERO, itSavedPrincess, RESERVED, princessdesc) // fake
NATIVE(isNative(laPalace, m)) 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) LAND( 0xD0D060, "Wild West", laWildWest, ZERO, itBounty, RESERVED, wildwestdesc)
NATIVE((m == moOutlaw) ? 2 : 0) NATIVE((m == moOutlaw) ? 2 : 0)
REQ( NEVER ) REQ( ALWAYS )
LAND( 0x80A080, "Land of Storms", laStorms, ZERO | LF_TROLL | LF_ELECTRIC, itFulgurite, RESERVED, elecdesc) LAND( 0x80A080, "Land of Storms", laStorms, ZERO | LF_TROLL | LF_ELECTRIC, itFulgurite, RESERVED, elecdesc)
NATIVE((m == moMetalBeast || m == moMetalBeast2 || m == moStormTroll) ? 1 : 0) NATIVE((m == moMetalBeast || m == moMetalBeast2 || m == moStormTroll) ? 1 : 0)
@ -1412,7 +1412,7 @@ LAND( 0xFF7518, "Halloween", laHalloween, ZERO, itTreat, RESERVED, halloweendesc
m == moLancer || m == moFireFairy || m == moLancer || m == moFireFairy ||
m == moBomberbird || m == moRatlingAvenger || m == moBomberbird || m == moRatlingAvenger ||
m == moVineBeast || m == moDragonHead || m == moDragonTail) ? 1 : 0) m == moVineBeast || m == moDragonHead || m == moDragonTail) ? 1 : 0)
REQ( NEVER ) REQ( ALWAYS )
LAND( 0x605040, "Dungeon", laDungeon, ZERO | LF_GRAVITY | LF_EQUI, itSlime, RESERVED, 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." "The result of a collaboration of the Great Vizier and the Wizard of the Ivory Tower."
@ -1454,7 +1454,7 @@ LAND( 0xC000C0, "Crossroads V", laCrossroads5, ZERO, itHyperstone, RESERVED, "Ex
LAND( 0xC0C0C0, "Cellular Automaton", laCA, ZERO | LF_TECHNICAL, itNone, RESERVED, cadesc) LAND( 0xC0C0C0, "Cellular Automaton", laCA, ZERO | LF_TECHNICAL, itNone, RESERVED, cadesc)
NATIVE(0) NATIVE(0)
REQ(NEVER) REQ(ALWAYS)
LAND( 0xC0C0FF, "Mirror Wall", laMirrorWall, ZERO | LF_TECHNICAL | LF_INMIRRORORWALL, itShard, RESERVED, mirroreddesc) LAND( 0xC0C0FF, "Mirror Wall", laMirrorWall, ZERO | LF_TECHNICAL | LF_INMIRRORORWALL, itShard, RESERVED, mirroreddesc)
NATIVE(isNative(laMirror, m)) NATIVE(isNative(laMirror, m))
@ -1569,9 +1569,9 @@ LAND( 0x30FF30, "Irradiated Field", laVariant, ZERO, itVarTreasure, RESERVED,
LAND( 0x202020, "Space Rocks", laAsteroids, ZERO, itAsteroid, RESERVED, rock_description) LAND( 0x202020, "Space Rocks", laAsteroids, ZERO, itAsteroid, RESERVED, rock_description)
ITEM( '!', 0xFFD0D0, "Fuel", itAsteroid, IC_TREASURE, ZERO, RESERVED, osNone, 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) NATIVE(m == moAsteroid ? 2 : 0)
REQ( NEVER ) REQ( ALWAYS )
LAND( 0x00C0C0, "Wetland", laWet, ZERO, itWet, RESERVED, LAND( 0x00C0C0, "Wetland", laWet, ZERO, itWet, RESERVED,
"Some people have definitely drowned in this treacherous area. Better be careful!" "Some people have definitely drowned in this treacherous area. Better be careful!"
@ -1797,4 +1797,5 @@ MONSTER( '*', 0, "vertex", moRogueviz, ZERO | CF_TECHNICAL, RESERVED, moN
#undef ACCONLY2 #undef ACCONLY2
#undef ACCONLY3 #undef ACCONLY3
#undef ACCONLYF #undef ACCONLYF
#undef IFINGAME #undef IFINGAME
#undef INMODE

View File

@ -212,16 +212,30 @@ EX void mousemovement() {
EX SDL_Joystick* sticks[8]; EX SDL_Joystick* sticks[8];
EX int numsticks; EX int numsticks;
EX void initJoysticks() { EX bool joysticks_initialized;
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) #if HDR
{ enum eJoystickInit { jiNoJoystick, jiFast, jiWait };
printf("Failed to initialize joysticks.\n"); #endif
numsticks = 0; EX eJoystickInit joy_init = jiFast;
return;
#if CAP_THREAD
EX std::thread *joythread;
std::atomic<bool> joystick_done(false);
#endif
EX void initJoysticks_async() {
if(joy_init == jiNoJoystick) return;
#if CAP_THREAD
if(joy_init == jiWait) { initJoysticks(); return; }
joythread = new std::thread([] { initJoysticks(); joystick_done = true; });
#else
initJoysticks();
#endif
} }
DEBB(DF_INIT, ("init joysticks")); EX void countJoysticks() {
DEBB(DF_INIT, ("opening joysticks"));
numsticks = SDL_NumJoysticks(); numsticks = SDL_NumJoysticks();
if(numsticks > 8) numsticks = 8; if(numsticks > 8) numsticks = 8;
for(int i=0; i<numsticks; i++) { for(int i=0; i<numsticks; i++) {
@ -235,6 +249,22 @@ EX void initJoysticks() {
} }
} }
EX void initJoysticks() {
DEBBI(DF_INIT, ("init joystick"));
DEBB(DF_INIT, ("init joystick subsystem"));
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
{
printf("Failed to initialize joysticks.\n");
numsticks = 0;
return;
}
countJoysticks();
joysticks_initialized = true;
}
EX void closeJoysticks() { EX void closeJoysticks() {
DEBB(DF_INIT, ("close joysticks")); DEBB(DF_INIT, ("close joysticks"));
for(int i=0; i<numsticks; i++) { for(int i=0; i<numsticks; i++) {
@ -376,6 +406,7 @@ EX void full_ystrafe_camera(ld t) {
EX ld third_person_rotation = 0; EX ld third_person_rotation = 0;
EX void full_rotate_camera(int dir, ld val) { EX void full_rotate_camera(int dir, ld val) {
if(!val) return;
if(rug::rug_control() && lshiftclick) { if(rug::rug_control() && lshiftclick) {
val *= camera_rot_speed; val *= camera_rot_speed;
hyperpoint h; hyperpoint h;
@ -524,7 +555,7 @@ EX void handleKeyNormal(int sym, int uni) {
if(!(uni >= 'A' && uni <= 'Z') && DEFAULTCONTROL && !game_keys_scroll) { if(!(uni >= 'A' && uni <= 'Z') && DEFAULTCONTROL && !game_keys_scroll) {
for(int i=0; i<8; i++) 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); movepckeydir(i);
} }
@ -872,7 +903,7 @@ EX void mainloopiter() {
targetclick = pandora_leftclick | pandora_rightclick; targetclick = pandora_leftclick | pandora_rightclick;
pandora_leftclick = pandora_rightclick = 0; pandora_leftclick = pandora_rightclick = 0;
#else #else
targetclick = keystate[SDLK_RSHIFT] | keystate[SDLK_LSHIFT]; targetclick = keystate[SDL12(SDLK_RSHIFT, SDL_SCANCODE_RSHIFT)] | keystate[SDL12(SDLK_LSHIFT, SDL_SCANCODE_LSHIFT)];
#endif #endif
} }
else { else {
@ -957,7 +988,7 @@ EX void mainloopiter() {
} }
else sc_ticks = ticks; 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; rug::using_rugview urv;
auto& lastticks = sc_ticks2; auto& lastticks = sc_ticks2;
ld t = (ticks - lastticks) * shiftmul / 1000.; ld t = (ticks - lastticks) * shiftmul / 1000.;
@ -999,6 +1030,7 @@ EX void mainloopiter() {
fix_mouseh(); fix_mouseh();
#if CAP_SDLJOY #if CAP_SDLJOY
if(joydir.d != -1) checkjoy(); if(joydir.d != -1) checkjoy();
if(joystick_done && joythread) { joythread->join(); delete joythread; joystick_done = false; }
#endif #endif
} }
@ -1014,8 +1046,7 @@ EX void handle_event(SDL_Event& ev) {
/* if(ev.type == SDL_JOYDEVICEADDED || ev.type == SDL_JOYDEVICEREMOVED) { /* if(ev.type == SDL_JOYDEVICEADDED || ev.type == SDL_JOYDEVICEREMOVED) {
joyx = joyy = 0; joyx = joyy = 0;
panjoyx = panjoyy = 0; panjoyx = panjoyy = 0;
closeJoysticks(); countJoysticks();
initJoysticks();
} */ } */
#if CAP_SDL2 #if CAP_SDL2
@ -1100,6 +1131,17 @@ EX void handle_event(SDL_Event& ev) {
sym = ev.key.keysym.sym; sym = ev.key.keysym.sym;
#if CAP_SDL2 #if CAP_SDL2
uni = ev.key.keysym.sym; uni = ev.key.keysym.sym;
if(uni == '=' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '+';
if(uni == '1' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '!';
if(uni == '2' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '@';
if(uni == '3' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '#';
if(uni == '4' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '$';
if(uni == '5' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '%';
if(uni == '6' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '^';
if(uni == '7' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '&';
if(uni == '8' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '*';
if(uni == '9' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '(';
if(uni == '0' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = ')';
if(uni >= 'a' && uni <= 'z') { if(uni >= 'a' && uni <= 'z') {
if(ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) uni -= 32; if(ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) uni -= 32;
else if(ev.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) uni -= 96; else if(ev.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) uni -= 96;

View File

@ -28,6 +28,7 @@ EX namespace bow {
#if HDR #if HDR
enum eWeapon { wBlade, wCrossbow }; enum eWeapon { wBlade, wCrossbow };
enum eCrossbowStyle { cbBull, cbGeodesic, cbGeometric }; enum eCrossbowStyle { cbBull, cbGeodesic, cbGeometric };
const string bowName[] = { "bull", "geod", "geom" };
#endif #endif
EX eWeapon weapon; EX eWeapon weapon;
@ -384,7 +385,7 @@ EX void shoot() {
vector<pair<cell*, int>> healthy_dragons; vector<pair<cell*, int>> healthy_dragons;
map<cell*, pair<int, int>> kraken_hits; map<cell*, pair<int, int>> kraken_hits;
int dragon_hits = 0; int dragon_hits = 0;
rusalka_curses++; rusalka_curses = 0;
// for achievements // for achievements
for(auto& mov: bowpath) { for(auto& mov: bowpath) {

View File

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

View File

@ -70,12 +70,20 @@ EX namespace dialog {
scaler sc; scaler sc;
int *intval; ld intbuf; int *intval; ld intbuf;
bool animatable; bool animatable;
bool *boolval;
void draw() override; void draw() override;
void apply_edit(); void apply_edit();
void apply_slider(); void apply_slider();
string disp(ld x); string disp(ld x);
void reset_str() { s = disp(*editwhat); } void reset_str() { s = disp(*editwhat); }
}; };
/** bool dialog */
struct bool_dialog : extdialog {
bool *editwhat, dft;
reaction_t switcher;
void draw() override;
};
#endif #endif
EX number_dialog& get_ne() { EX number_dialog& get_ne() {
@ -215,12 +223,16 @@ EX namespace dialog {
EX string keyname(int k) { EX string keyname(int k) {
if(k == 0) return ""; if(k == 0) return "";
if(k == SDLK_ESCAPE) return "Esc"; if(k == SDLK_ESCAPE) return "Esc";
if(k == SDLK_F5) return "F5";
if(k == SDLK_F10) return "F10";
if(k == SDLK_F9) return "F9";
if(k == SDLK_F1) return "F1"; if(k == SDLK_F1) return "F1";
if(k == SDLK_F4) return "F4"; if(k == SDLK_F2) return "F2";
if(k == SDLK_F3) return "F3"; if(k == SDLK_F3) return "F3";
if(k == SDLK_F4) return "F4";
if(k == SDLK_F5) return "F5";
if(k == SDLK_F6) return "F6";
if(k == SDLK_F7) return "F7";
if(k == SDLK_F8) return "F8";
if(k == SDLK_F9) return "F9";
if(k == SDLK_F10) return "F10";
if(k >= 10000 && k < 10500) return ""; if(k >= 10000 && k < 10500) return "";
if(k == SDLK_HOME) return "Home"; if(k == SDLK_HOME) return "Home";
if(k == SDLK_BACKSPACE) return "Backspace"; if(k == SDLK_BACKSPACE) return "Backspace";
@ -1227,6 +1239,7 @@ EX namespace dialog {
if(p) p->load_as_animation(formula); if(p) p->load_as_animation(formula);
} }
catch(hr_parse_exception&) { } catch(hr_parse_exception&) { }
catch(param_exception&) { }
}; };
dialog::get_di().dialogflags |= dialogflags; dialog::get_di().dialogflags |= dialogflags;
}); });
@ -1298,6 +1311,7 @@ EX namespace dialog {
} }
catch(const hr_parse_exception&) { catch(const hr_parse_exception&) {
} }
catch(param_exception&) { }
} }
EX void bound_low(ld val) { EX void bound_low(ld val) {
@ -1368,12 +1382,12 @@ EX namespace dialog {
dialog::addBreak(50); dialog::addBreak(50);
auto f = find_edit(!ptr ? nullptr : ne.intval ? (void*) ne.intval : (void*) ne.editwhat); auto f = find_edit(!ptr ? nullptr : ne.intval ? (void*) ne.intval : (void*) ne.editwhat);
if(f) if(f)
dialog::addHelp(XLAT("Parameter names, e.g. '%1'", f->parameter_name)); dialog::addHelp(XLAT("Parameter names, e.g. '%1'", f->name));
else else
dialog::addHelp(XLAT("Parameter names")); dialog::addHelp(XLAT("Parameter names"));
dialog::addBreak(50); dialog::addBreak(50);
for(auto& ap: anims::aps) { for(auto& ap: anims::aps) {
dialog::addInfo(ap.par->parameter_name + " = " + ap.formula); dialog::addInfo(ap.par->name + " = " + ap.formula);
} }
#endif #endif
dialog::addBreak(50); dialog::addBreak(50);
@ -1484,7 +1498,43 @@ EX namespace dialog {
} }
else if(doexiton(sym, uni)) ne.popfinal(); else if(doexiton(sym, uni)) ne.popfinal();
}; };
} }
void bool_dialog::draw() {
cmode = dialogflags;
gamescreen();
init(title);
dialog::addBreak(100);
auto switch_to = [this] (bool b) {
bool do_switch = (*editwhat != b);
auto sw = switcher;
auto re = reaction;
popScreen();
if(do_switch) { sw(); if(re) re(); }
};
dialog::addBoolItem(XLAT("disable"), false, '0');
dialog::add_action([switch_to] { switch_to(false); });
dialog::addBoolItem(XLAT("enable"), true, '1');
dialog::add_action([switch_to] { switch_to(true); });
dialog::addBoolItem(XLAT("switch"), !*editwhat, 's');
dialog::add_action([switch_to, this] { switch_to(!*editwhat); });
dialog::addBoolItem(XLAT("set default"), dft, 'd');
dialog::add_action([switch_to, this] { switch_to(dft); });
dialog::addBreak(100);
if(help != "") addHelp(help);
if(extra_options) extra_options();
display();
}
int nlpage = 1; int nlpage = 1;
int wheelshift = 0; int wheelshift = 0;
@ -1565,6 +1615,17 @@ EX namespace dialog {
return get_ne(); return get_ne();
} }
EX extdialog& editBool(bool& b, bool dft, string title, string help, const reaction_t& switcher) {
bool_dialog be;
be.editwhat = &b;
be.dft = dft;
be.title = title;
be.help = help;
be.switcher = switcher;
pushScreen(be);
return get_di();
}
EX number_dialog& editNumber(int& x, int vmin, int vmax, ld step, int dft, string title, string help) { EX number_dialog& editNumber(int& x, int vmin, int vmax, ld step, int dft, string title, string help) {
ld tmp; ld tmp;
auto& ne = editNumber(tmp, vmin, vmax, step, dft, title, help); auto& ne = editNumber(tmp, vmin, vmax, step, dft, title, help);

View File

@ -402,7 +402,7 @@ struct emb_none : embedding_method {
return embedding_method::flatten(a); return embedding_method::flatten(a);
} }
hyperpoint normalize_flat(hyperpoint a) override { return normalize(a); } hyperpoint normalize_flat(hyperpoint a) override { return gproduct ? flatten(a) : normalize(a); }
transmatrix base_to_actual(const transmatrix& T) override { return T; } transmatrix base_to_actual(const transmatrix& T) override { return T; }
hyperpoint base_to_actual(hyperpoint h) override { return h; } hyperpoint base_to_actual(hyperpoint h) override { return h; }

View File

@ -368,7 +368,7 @@ EX void bfs() {
c2->wall = waSea; c2->wall = waSea;
if(c2 && signed(c2->cpdist) > d+1) { 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; if(!first7) first7 = qb;
continue; continue;
} }

View File

@ -655,7 +655,7 @@ void celldrawer::do_viewdist() {
if(!dist_label_colored) dc = dist_label_color; if(!dist_label_colored) dc = dist_label_color;
if(label != "") 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() { EX void viewdist_configure_dialog() {

View File

@ -1,5 +1,7 @@
// Hyperbolic Rogue -- fake mobile target // Hyperbolic Rogue -- fake mobile target
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
//
// Compile with: g++ fake-mobile.cpp -o fake-mobile -I/usr/include/SDL -lSDL -lSDL_gfx -lGL -lSDL_ttf -lz -Wno-invalid-offsetof
#define ISFAKEMOBILE 1 #define ISFAKEMOBILE 1
#define MOBPAR_FORMAL int #define MOBPAR_FORMAL int
@ -9,7 +11,7 @@
#include <string> #include <string>
namespace hr { namespace hr {
string scorefile = "fakemobile_score.txt"; std::string scorefile = "fakemobile_score.txt";
} }
#include <SDL/SDL.h> #include <SDL/SDL.h>
@ -55,6 +57,17 @@ int gdpop() { return graphdata[gdpos++]; }
TTF_Font *font[256]; TTF_Font *font[256];
const char* fontname = "DejaVuSans-Bold.ttf";
void load_font() {
if(!font[size])
font[size] = TTF_OpenFont(fontname, size);
if(!font[size]) {
fprintf(stderr, "failed to open font: %s", fontname);
exit(1);
}
}
bool rawdisplaystr(int x, int y, int shift, int size, const char *str, int color, int align) { bool rawdisplaystr(int x, int y, int shift, int size, const char *str, int color, int align) {
if(strlen(str) == 0) return false; if(strlen(str) == 0) return false;
@ -69,8 +82,7 @@ bool rawdisplaystr(int x, int y, int shift, int size, const char *str, int color
col.r >>= darken; col.g >>= darken; col.b >>= darken; col.r >>= darken; col.g >>= darken; col.b >>= darken;
if(!font[size]) load_font();
font[size] = TTF_OpenFont("VeraBd.ttf", size);
SDL_Surface *txt = TTF_RenderText_Solid(font[size], str, col); SDL_Surface *txt = TTF_RenderText_Solid(font[size], str, col);
@ -95,7 +107,7 @@ bool rawdisplaystr(int x, int y, int shift, int size, const char *str, int color
int textwidth(int siz, const string &str) { int textwidth(int siz, const string &str) {
if(isize(str) == 0) return 0; if(isize(str) == 0) return 0;
if(!font[siz]) font[siz] = TTF_OpenFont("VeraBd.ttf", siz); load_font();
int w, h; int w, h;
TTF_SizeUTF8(font[siz], str.c_str(), &w, &h); TTF_SizeUTF8(font[siz], str.c_str(), &w, &h);

View File

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

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; vector<hyperpoint> actual;
for(int j=0; j<cor; j++) for(int j=0; j<cor; j++)
actual.push_back(get_corner_position(c, j)); actual.push_back(get_corner_position(c, j));

View File

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

View File

@ -152,11 +152,8 @@ void validity_info() {
EX bool showquotients; EX bool showquotients;
string validclasses[4] = {" (X)", " (½)", "", " (!)"}; 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; if(cheater) for(int i=0; i<landtypes; i++) landvisited[i] = true;
for(int i=0; i<landtypes; i++) for(int i=0; i<landtypes; i++)
@ -177,6 +174,13 @@ EX void ge_land_selection() {
landvisited[laCamelot] |= hiitemsMax(treasureType(laCamelot)) >= 1; landvisited[laCamelot] |= hiitemsMax(treasureType(laCamelot)) >= 1;
landvisited[laCA] = true; landvisited[laCA] = true;
landvisited[laAsteroids] = true; landvisited[laAsteroids] = true;
}
EX void ge_land_selection() {
cmode = sm::SIDE | sm::MAYDARK;
gamescreen();
gen_landvisited();
dialog::init(XLAT("select the starting land")); dialog::init(XLAT("select the starting land"));
if(dialog::infix != "") mouseovers = dialog::infix; if(dialog::infix != "") mouseovers = dialog::infix;
@ -940,6 +944,13 @@ EX geometry_data compute_geometry_data() {
return gd; return gd;
} }
EX void add_size_action() {
if(WDIM == 2 || reg3::exact_rules()) dialog::add_action([] {
if(!viewdists) { enable_viewdists(); pushScreen(viewdist_configure_dialog); }
else if(viewdists) viewdists = false;
});
}
EX void showEuclideanMenu() { EX void showEuclideanMenu() {
// for(int i=2; i<lt; i++) landvisited[i] = true; // for(int i=2; i<lt; i++) landvisited[i] = true;
@ -1109,7 +1120,7 @@ EX void showEuclideanMenu() {
} }
dialog::addBoolItem(XLAT("pattern"), specialland == laCanvas, 'p'); 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); dialog::add_action_push(patterns::showPrePattern);
validity_info(); validity_info();
if(WDIM == 3) { if(WDIM == 3) {
@ -1147,11 +1158,7 @@ EX void showEuclideanMenu() {
} }
dialog::addSelItem(XLAT("size of the world"), gd.size_str, '3'); dialog::addSelItem(XLAT("size of the world"), gd.size_str, '3');
add_size_action();
if(WDIM == 2 || reg3::exact_rules()) dialog::add_action([] {
if(!viewdists) { enable_viewdists(); pushScreen(viewdist_configure_dialog); }
else if(viewdists) viewdists = false;
});
if(closed_manifold) { if(closed_manifold) {
dialog::addSelItem(XLAT("Euler characteristics"), its(gd.euler), 0); dialog::addSelItem(XLAT("Euler characteristics"), its(gd.euler), 0);

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; static constexpr ld hcrossf7 = 0.620672, hexf7 = 0.378077, tessf7 = 1.090550, hexhexdist7 = 0.566256;
#endif #endif
EX bool scale_used() { return (shmup::on && geometry == gNormal && BITRUNCATED) ? (cheater || autocheat) : true; }
EX bool is_subcube_based(eVariation var) { EX bool is_subcube_based(eVariation var) {
return among(var, eVariation::subcubes, eVariation::dual_subcubes, eVariation::bch, eVariation::bch_oct); 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 && geuclid) scalefactor *= (1 + vid.depth);
if(msphere && ghyperbolic) scalefactor *= sinh(1 + vid.depth); if(msphere && ghyperbolic) scalefactor *= sinh(1 + vid.depth);
if(scale_used()) { if(true) {
scalefactor *= vid.creature_scale; scalefactor *= vid.creature_scale;
orbsize *= vid.creature_scale; orbsize *= vid.creature_scale;
} }
zhexf = BITRUNCATED ? hexf : crossf* .55; 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(WDIM == 2 && GDIM == 3) zhexf *= 1.5, orbsize *= 1.2;
if(cgi.emb->is_euc_in_hyp()) { if(cgi.emb->is_euc_in_hyp()) {
@ -1179,7 +1177,7 @@ EX namespace geom3 {
} }
EX void apply_settings_full() { EX void apply_settings_full() {
if(vid.always3) { if(cgip && vid.always3) {
changing_embedded_settings = true; changing_embedded_settings = true;
geom3::switch_fpp(); geom3::switch_fpp();
#if MAXMDIM >= 4 #if MAXMDIM >= 4
@ -1194,7 +1192,7 @@ EX namespace geom3 {
EX void apply_settings_light() { EX void apply_settings_light() {
#if MAXMDIM >= 4 #if MAXMDIM >= 4
if(vid.always3) { if(cgip && vid.always3) {
changing_embedded_settings = true; changing_embedded_settings = true;
geom3::switch_always3(); geom3::switch_always3();
geom3::switch_always3(); geom3::switch_always3();
@ -1314,7 +1312,7 @@ EX string cgi_string() {
V("RS:", fts(geom3::euclid_embed_rotate)); 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)); if(WDIM == 3) V("HTW", fts(vid.height_width));

View File

@ -1269,6 +1269,7 @@ EX namespace gp {
} }
hrmap_inverse() { hrmap_inverse() {
underlying_map = nullptr;
if(0) { if(0) {
println(hlog, "making ucgi"); println(hlog, "making ucgi");
dynamicval<eVariation> gva(variation, variation_for(param)); dynamicval<eVariation> gva(variation, variation_for(param));
@ -1441,11 +1442,17 @@ EX namespace gp {
return C0; return C0;
} }
}; };
EX hrmap* new_inverse() { return new hrmap_inverse; } EX hrmap* new_inverse() { return new hrmap_inverse; }
hrmap_inverse* inv_map() { return (hrmap_inverse*)currentmap; } 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 hrmap* get_underlying_map() { return inv_map()->underlying_map; }
EX cell* get_mapped(cell *c) { return inv_map()->get_mapped(c, 0); } EX cell* get_mapped(cell *c) { return inv_map()->get_mapped(c, 0); }
EX int untruncated_shift(cell *c) { return inv_map()->shift[c]; } EX int untruncated_shift(cell *c) { return inv_map()->shift[c]; }

114
graph.cpp
View File

@ -209,6 +209,7 @@ void drawSpeed(const shiftmatrix& V, ld scale=1) {
} }
void drawSafety(const shiftmatrix& V, int ct) { void drawSafety(const shiftmatrix& V, int ct) {
if(inHighQual) return;
#if CAP_QUEUE #if CAP_QUEUE
ld ds = ptick(50); ld ds = ptick(50);
color_t col = darkena(iinf[itOrbSafety].color, 0, 0xFF); color_t col = darkena(iinf[itOrbSafety].color, 0, 0xFF);
@ -769,11 +770,12 @@ EX shiftmatrix face_the_player(const shiftmatrix V) {
if(nonisotropic) return shiftless(spin_towards(unshift(V), dummy, C0, 2, 0)); if(nonisotropic) return shiftless(spin_towards(unshift(V), dummy, C0, 2, 0));
#if CAP_VR #if CAP_VR
if(vrhr::enabled) { if(vrhr::enabled) {
shiftpoint h = tC0(V); shiftpoint h = tC0(V);
hyperpoint uh = unshift(h); 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 #endif
return rgpushxto0(tC0(V)); return rgpushxto0(tC0(V));
} }
@ -846,12 +848,42 @@ EX void draw_ascii(const shiftmatrix& V, char glyph, color_t col, ld size) {
string s = s0 + glyph; string s = s0 + glyph;
int id = isize(ptds); int id = isize(ptds);
if(WDIM == 2 && GDIM == 3) 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 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; 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) { EX bool drawItemType(eItem it, cell *c, const shiftmatrix& V, color_t icol, int pticks, bool hidden) {
if(!it) return false; if(!it) return false;
char xch = iinf[it].glyph; char xch = iinf[it].glyph;
@ -953,18 +985,8 @@ EX bool drawItemType(eItem it, cell *c, const shiftmatrix& V, color_t icol, int
else else
#endif #endif
if(1) { if(1) {
cell *c1 = c ? findcompass(c) : NULL; shiftpoint P1;
if(c1) { if(mark_compass(c, P1)) {
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);
}
V2 = V * lrspintox(inverse_shift(V, P1)); V2 = V * lrspintox(inverse_shift(V, P1));
} }
else V2 = V; else V2 = V;
@ -3103,15 +3125,15 @@ EX bool drawMonster(const shiftmatrix& Vparam, int ct, cell *c, color_t col, col
col = mirrorcolor(geometry == gElliptic ? det(Vs.T) < 0 : mirr); col = mirrorcolor(geometry == gElliptic ? det(Vs.T) < 0 : mirr);
if(!mouseout() && !nospins && GDIM == 2) { if(!mouseout() && !nospins && GDIM == 2) {
shiftpoint P2 = Vs * inverse_shift(inmirrorcount ? ocwtV : cwtV, mouseh); 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(); if(!nospins && flipplayer) Vs = Vs * lpispin();
res = res && drawMonsterType(moMimic, c, Vs, col, footphase, asciicol); res = res && drawMonsterType(moMimic, c, Vs, col, footphase, asciicol);
drawPlayerEffects(Vs, Vparam, c, c->monst); drawPlayerEffects(Vs, Vparam, c, c->monst);
} }
} }
// illusions face randomly // illusions face randomly
else if(c->monst == moIllusion) { else if(c->monst == moIllusion) {
@ -3235,7 +3257,7 @@ EX bool drawMonster(const shiftmatrix& Vparam, int ct, cell *c, color_t col, col
hyperpoint h = inverse_shift(ocwtV, mouseh); hyperpoint h = inverse_shift(ocwtV, mouseh);
if(flipplayer) h = lpispin() * h; if(flipplayer) h = lpispin() * h;
shiftpoint P2 = Vs * h; shiftpoint P2 = Vs * h;
queuestr(P2, 10, "x", 0xFF00); queuestr(P2, mapfontscale / 10, "x", 0xFF00);
} }
if(hide_player()) { if(hide_player()) {
@ -3573,7 +3595,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); 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) 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 else
queuepoly(shiftless(T), cgi.shArrow, col); queuepoly(shiftless(T), cgi.shArrow, col);
@ -3581,7 +3603,7 @@ void draw_movement_arrows(cell *c, const transmatrix& V, int df) {
else if(!confusingGeometry()) break; 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); } EX int celldistAltPlus(cell *c) { return 1000000 + celldistAlt(c); }
@ -4008,12 +4030,16 @@ EX int colorhash(color_t i) {
return (i * 0x471211 + i*i*0x124159 + i*i*i*0x982165) & 0xFFFFFF; return (i * 0x471211 + i*i*0x124159 + i*i*i*0x982165) & 0xFFFFFF;
} }
EX int mine_opacity = 255;
EX bool isWall3(cell *c, color_t& wcol) { 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(isWall(c)) return true;
if(c->wall == waChasm && c->land == laMemory && (anyshiftclick || !(cgflags & qFRACTAL))) { wcol = 0x606000; return true; } if(c->wall == waChasm && c->land == laMemory && (anyshiftclick || !(cgflags & qFRACTAL))) { wcol = 0x606000; return true; }
if(c->wall == waInvisibleFloor) return false; if(c->wall == waInvisibleFloor) return false;
// if(chasmgraph(c)) return true; // 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; return false;
} }
@ -4056,6 +4082,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(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(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; return 0;
} }
@ -4761,7 +4789,7 @@ EX void drawMarkers() {
#if CAP_QUEUE #if CAP_QUEUE
if(haveMount()) if(haveMount())
for (const shiftmatrix& V : hr::span_at(current_display->all_drawn_copies, dragon::target)) { 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)); gradient(0, iinf[itOrbDomination].color, -1, sintick(dragon::whichturn == turncount ? 75 : 150), 1));
} }
#endif #endif
@ -4773,31 +4801,31 @@ EX void drawMarkers() {
using namespace yendor; using namespace yendor;
if(yii < isize(yi) && !yi[yii].found) { if(yii < isize(yi) && !yi[yii].found) {
cell *keycell = NULL; cell *keycell = NULL;
int i; int last_i = 0;
for(i=0; i<YDIST; i++) for(int i=0; i<YDIST; i++)
if(yi[yii].path[i]->cpdist <= get_sightrange_ambush()) { if(yi[yii].path[i]->cpdist <= get_sightrange_ambush()) {
keycell = yi[yii].path[i]; keycell = yi[yii].path[i]; last_i = i;
} }
if(keycell) { if(keycell) {
for(; i<YDIST; i++) { for(int i = last_i+1; i<YDIST; i++) {
cell *c = yi[yii].path[i]; cell *c = yi[yii].path[i];
if(inscreenrange(c)) if(inscreenrange(c))
keycell = c; keycell = c;
} }
shiftpoint H = tC0(ggmatrix(keycell)); shiftpoint H = tC0(ggmatrix(keycell));
#if CAP_QUEUE #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); int cd = celldistance(yi[yii].key(), cwt.at);
if(cd == DISTANCE_UNKNOWN) for(int i2 = 0; i2<YDIST; i2++) { if(cd == DISTANCE_UNKNOWN) for(int i2 = 0; i2<YDIST; i2++) {
int cd2 = celldistance(cwt.at, yi[yii].path[i2]); int cd2 = celldistance(cwt.at, yi[yii].path[i2]);
if(cd2 != DISTANCE_UNKNOWN) { if(cd2 != DISTANCE_UNKNOWN) {
cd = cd2 + (YDIST-1-i2); 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 #endif
addauraspecial(H, iinf[itOrbYendor].color, 0); addauraspecial(H, iinf[itOrbYendor].color, 0);
addradar(ggmatrix(keycell), 'X', iinf[itKey].color, kind_outline(itKey), true);
} }
} }
} }
@ -4930,9 +4958,10 @@ EX void drawMarkers() {
} }
if(items[itOrbAir] && mouseover->cpdist > 1) { if(items[itOrbAir] && mouseover->cpdist > 1) {
cell *c1 = mouseover; cell *c1 = mouseover;
int dir = c1->monst == moVoidBeast ? -1 : 1;
for(int it=0; it<10; it++) { for(int it=0; it<10; it++) {
int di; int di;
auto mib = blowoff_destination(c1, di); auto mib = blowoff_destination_dir(c1, di, dir);
if(!mib.proper()) break; if(!mib.proper()) break;
auto& c2 = mib.t; auto& c2 = mib.t;
shiftmatrix T1 = ggmatrix(c1); shiftmatrix T1 = ggmatrix(c1);
@ -4993,12 +5022,12 @@ EX void draw_flash(struct flashdata& f, const shiftmatrix& V, bool& kill) {
int r = 2; int r = 2;
apply_neon(col, r); apply_neon(col, r);
if(GDIM == 3 || sphere) 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) { else if(!kill) {
shiftpoint h = tC0(V); shiftpoint h = tC0(V);
if(hdist0(h) > .1) { if(hdist0(h) > .1) {
transmatrix V2 = rspintox(h.h) * xpush(hdist0(h.h) * (1 / (1 - tim * 1. / f.size))); 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) { if(static_bubbles) {
@ -5645,6 +5674,8 @@ EX bool just_refreshing;
EX int menu_darkening = 2; EX int menu_darkening = 2;
EX bool centered_menus = false; EX bool centered_menus = false;
EX string menu_format = "";
EX void gamescreen() { EX void gamescreen() {
if(cmode & sm::NOSCR) { if(cmode & sm::NOSCR) {
@ -5770,13 +5801,15 @@ EX void normalscreen() {
cmode = sm::NORMAL | sm::DOTOUR | sm::CENTER; cmode = sm::NORMAL | sm::DOTOUR | sm::CENTER;
if(viewdists && show_distance_lists) cmode |= sm::SIDE | sm::MAYDARK; if(viewdists && show_distance_lists) cmode |= sm::SIDE | sm::MAYDARK;
gamescreen(); drawStats(); gamescreen(); drawStats();
if(nomenukey || ISMOBILE) if(menu_format != "")
displayButton(vid.xres-8, vid.yres-vid.fsize, eval_programmable_string(menu_format), 'v', 16);
else if(nomenukey || ISMOBILE)
; ;
#if CAP_TOUR #if CAP_TOUR
else if(tour::on) else if(tour::on)
displayButton(vid.xres-8, vid.yres-vid.fsize, XLAT("(ESC) tour menu"), SDLK_ESCAPE, 16); displayButton(vid.xres-8, vid.yres-vid.fsize, XLAT("(ESC) tour menu"), SDLK_ESCAPE, 16);
else
#endif #endif
else
displayButton(vid.xres-8, vid.yres-vid.fsize, XLAT("(v) menu"), 'v', 16); displayButton(vid.xres-8, vid.yres-vid.fsize, XLAT("(v) menu"), 'v', 16);
keyhandler = handleKeyNormal; keyhandler = handleKeyNormal;
@ -5901,8 +5934,11 @@ EX void drawscreen() {
color_t col = linf[cwt.at->land].color; color_t col = linf[cwt.at->land].color;
if(cwt.at->land == laRedRock) col = 0xC00000; if(cwt.at->land == laRedRock) col = 0xC00000;
if(titlecolor) col = titlecolor; if(titlecolor) col = titlecolor;
if(nohelp != 1) if(nohelp != 1) {
displayfr(vid.xres/2, vid.fsize, 2, vid.fsize, mouseovers, col, 8); int size = vid.fsize;
while(size > 3 && textwidth(size, mouseovers) > vid.xres) size--;
displayfr(vid.xres/2, vid.fsize, 2, size, mouseovers, col, 8);
}
#endif #endif
drawmessages(); drawmessages();

View File

@ -236,12 +236,12 @@ EX void buildCredits() {
help += XLAT( help += XLAT(
"special thanks to the following people for their bug reports, feature requests, porting, and other help:\n\n%1\n\n", "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, " "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, " "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, " "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, " "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" "masonlgreen, A human, Pasu4"
); );
#ifdef EXTRALICENSE #ifdef EXTRALICENSE
help += EXTRALICENSE; help += EXTRALICENSE;
@ -527,6 +527,33 @@ EX string generateHelpForItem(eItem it) {
} }
} }
} }
int oc = orbcharges(it); if(oc) {
if(items[itOrbIntensity]) {
int oc2 = intensify(oc);
help += XLAT("\n\nOrb charges gained on pickup: %1 (increased to %2 by %the3)", its(oc), its(oc2), itOrbIntensity);
}
else
help += XLAT("\n\nOrb charges gained on pickup: %1", its(oc));
}
int ac = 0;
if(among(it, itOrbFrog, itOrbPhasing, itOrbDash)) ac = 5;
if(among(it, itOrbSummon)) ac = 20;
if(among(it, itOrbPsi)) ac = 30;
if(among(it, itOrbStunning)) ac = 10;
if(among(it, itOrbMorph)) ac = 3;
if(among(it, itOrbIllusion)) ac = 5;
if(among(it, itOrbDragon)) ac = 5;
if(among(it, itOrbAir)) ac = 1;
if(ac) {
if(items[itOrbEnergy])
help += XLAT("\n\nActivation cost: %1 charges (reduced to %2 by %the3)\n", its(ac), its((1+ac)/2), itOrbEnergy);
else
help += XLAT("\n\nActivation cost: %1 charges\n", its(ac));
}
if(it == itOrb37 && (S7 != 7 || !BITRUNCATED)) if(it == itOrb37 && (S7 != 7 || !BITRUNCATED))
help += "\n\n" + other_geometry() + forbidden_unmarked(); help += "\n\n" + other_geometry() + forbidden_unmarked();
@ -553,6 +580,20 @@ EX string generateHelpForItem(eItem it) {
return help; 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) { void addMinefieldExplanation(string& s) {
s += XLAT( s += XLAT(
@ -568,7 +609,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."); s += XLAT("Known mines may be marked by touching while in drag mode. Your allies won't step on marked mines.");
#endif #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) { EX string generateHelpForWall(eWall w) {
@ -700,6 +741,7 @@ void add_reqs(eLand l, string& s) {
#define COND(x,y) s += (y); #define COND(x,y) s += (y);
#define ITEMS_TOTAL(list, z) \ #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); } { 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 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 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 ACCONLY3(z,y,x) s += XLAT("Accessible only from %the1, %2, or %3.\n", z, y, x);
@ -882,10 +924,9 @@ EX void describeMouseover() {
if(shmup::on) if(shmup::on)
out += " (" + its(c->landparam)+")"; out += " (" + its(c->landparam)+")";
else { else {
calcTidalPhase(); bool b = c->landparam >= tide[turncount % tidalsize];
bool b = c->landparam >= tide[(turncount-1) % tidalsize];
int t = 1; 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) if(b)
out += " (" + turnstring(t) + XLAT(" to surface") + ")"; out += " (" + turnstring(t) + XLAT(" to surface") + ")";
else else
@ -894,7 +935,7 @@ EX void describeMouseover() {
} }
#if CAP_FIELD #if CAP_FIELD
else if(c->land == laVolcano) { else if(c->land == laVolcano) {
int id = lavatide(c, -1)/4; int id = lavatide(c, 0)/4;
if(id < 96/4) if(id < 96/4)
out += " (" + turnstring(96/4-id) + XLAT(" to go cold") + ")"; out += " (" + turnstring(96/4-id) + XLAT(" to go cold") + ")";
else else
@ -1089,16 +1130,7 @@ EX void describeMouseover() {
#endif #endif
} }
EX void showHelp() { EX void addHelpWithTitle() {
cmode = sm::HELP | sm::DOTOUR | sm::DARKEN;
getcstat = SDLK_ESCAPE;
if(help == "HELPFUN") {
help_delegate();
return;
}
gamescreen();
string help2;
if(help[0] == '@') { if(help[0] == '@') {
int iv = help.find("\t"); int iv = help.find("\t");
int id = help.find("\n"); int id = help.find("\n");
@ -1109,6 +1141,19 @@ EX void showHelp() {
dialog::init("help", forecolor, 120, 100); dialog::init("help", forecolor, 120, 100);
dialog::addHelp(help); 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; bool in_list = false;

View File

@ -756,19 +756,19 @@ EX namespace history {
history::includeHistory = false; history::includeHistory = false;
}) + addHook(hooks_configfile, 0, [] { }) + addHook(hooks_configfile, 0, [] {
addsaver(autobandhistory, "include history"); // check! param_b(autobandhistory, "include history"); // check!
param_f(lvspeed, "lvspeed", "lineview speed"); param_f(lvspeed, parameter_names("lvspeed", "lineview speed"));
addsaver(extra_line_steps, "lineview extension"); param_f(extra_line_steps, "lineview extension");
addsaver(bandhalf, "band width"); param_i(bandhalf, "band width");
addsaver(bandsegment, "band segment"); param_i(bandsegment, "band segment");
addsaver(autoband, "automatic band"); param_b(autoband, "automatic band");
addsaver(autobandhistory, "automatic band history"); param_b(autobandhistory, "automatic band history");
addsaver(dospiral, "do spiral"); param_b(dospiral, "do spiral");
#if CAP_SHOT && CAP_SDL #if CAP_SHOT && CAP_SDL
addsaver(band_format_auto, "band_format_auto"); param_str(band_format_auto, "band_format_auto");
addsaver(band_format_now, "band_format_now"); param_str(band_format_now, "band_format_now");
#endif #endif
}); });

View File

@ -36,6 +36,7 @@ EX string s0;
EX string its(int i) { return hr::format("%d", i); } EX string its(int i) { return hr::format("%d", i); }
EX string itsh8(int i) { return hr::format("%08X", i); } EX string itsh8(int i) { return hr::format("%08X", i); }
EX string itsh6(int i) { return hr::format("%06X", i); }
EX string fts(ld x, int prec IS(6)) { EX string fts(ld x, int prec IS(6)) {
std::stringstream ss; std::stringstream ss;
@ -144,7 +145,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 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...); } 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 { struct fhstream : hstream {
FILE *f; FILE *f;
@ -563,4 +567,12 @@ EX void debug_view(string context, string s) {
if(s != old) { old = s; println(hlog, s); } if(s != old) { old = s; println(hlog, s); }
} }
EX vector<string> split_string(const string& s, char sep) {
vector<string> res;
string next = "";
for(char c: s) if(c == sep) { res.push_back(next); next = ""; } else next += c;
res.push_back(next);
return res;
}
} }

View File

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

View File

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

16
hyper.h
View File

@ -13,8 +13,8 @@
#define _HYPER_H_ #define _HYPER_H_
// version numbers // version numbers
#define VER "13.0b" #define VER "13.0m"
#define VERNUM_HEX 0xAA02 #define VERNUM_HEX 0xAA0D
#include "sysconfig.h" #include "sysconfig.h"
@ -221,15 +221,6 @@ void addMessage(string s, char spamtype = 0);
#define NUMWITCH 7 #define NUMWITCH 7
// achievements
#define LB_YENDOR_CHALLENGE 40
#define LB_PURE_TACTICS 41
#define NUMLEADER 90
#define LB_PURE_TACTICS_SHMUP 49
#define LB_PURE_TACTICS_COOP 50
#define LB_RACING 81
#if ISMOBILE || ISWEB || ISPANDORA || 1 #if ISMOBILE || ISWEB || ISPANDORA || 1
typedef double ld; typedef double ld;
#define LDF "%lf" #define LDF "%lf"
@ -566,7 +557,7 @@ typedef function<int(struct cell*)> cellfunction;
// passable flags // passable flags
#define SAGEMELT .1 #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 ROCKSNAKELENGTH 50
#define WORMLENGTH 15 #define WORMLENGTH 15
#define PRIZEMUL 7 #define PRIZEMUL 7
@ -780,6 +771,7 @@ enum orbAction { roMouse, roKeyboard, roCheck, roMouseForce, roMultiCheck, roMul
#define pmodel (pconf.model) #define pmodel (pconf.model)
static constexpr int DISTANCE_UNKNOWN = 127; 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) { template<class T, class U> int addHook(hookset<T>& m, int prio, U&& hook) {
return m.add(prio, static_cast<U&&>(hook)); return m.add(prio, static_cast<U&&>(hook));

View File

@ -559,7 +559,7 @@ ld ellFaux(ld cos_phi, ld sin_phi, ld k) {
ld sqrt_clamp(ld x) { if(x<0) return 0; return sqrt(x); } ld sqrt_clamp(ld x) { if(x<0) return 0; return sqrt(x); }
hyperpoint to_square(hyperpoint H) { EX hyperpoint to_square(hyperpoint H) {
ld d = hypot_d(2, H); ld d = hypot_d(2, H);
ld x = d / (H[2] + 1); ld x = d / (H[2] + 1);
@ -1467,7 +1467,10 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
case mdSpiral: { case mdSpiral: {
cld z; 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; else ret = H;
z = cld(ret[0], ret[1]) * models::spiral_multiplier; z = cld(ret[0], ret[1]) * models::spiral_multiplier;
@ -1492,6 +1495,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
if(pconf.skiprope) if(pconf.skiprope)
ret = mobius(ret, pconf.skiprope, 1); ret = mobius(ret, pconf.skiprope, 1);
} }
models::ori_to_scr(ret);
break; break;
} }
@ -2522,13 +2526,14 @@ void circle_around_center(ld radius, color_t linecol, color_t fillcol, PPR prio)
#if CAP_QUEUE #if CAP_QUEUE
ld rad = 10; ld rad = 10;
if(euclid) rad = 1000; if(euclid) rad = 1000;
for(int i=0; i<=360; i++) curvepoint(xspinpush0(i * degree, rad)); for(int i=0; i<=36000; i+=10) curvepoint(xspinpush0(i * degree / 100., rad));
auto& c = queuecurve(shiftless(Id), linecol, fillcol, prio); auto& c = queuecurve(shiftless(Id), linecol, fillcol, prio);
if(pmodel == mdDisk && hyperbolic && pconf.alpha <= -1) if(pmodel == mdDisk && hyperbolic && pconf.alpha <= -1)
c.flags |= POLY_FORCE_INVERTED; c.flags |= POLY_FORCE_INVERTED;
if(pmodel == mdJoukowsky) if(pmodel == mdJoukowsky)
c.flags |= POLY_FORCE_INVERTED; c.flags |= POLY_FORCE_INVERTED;
c.flags |= POLY_ALWAYS_IN; c.flags |= POLY_ALWAYS_IN;
c.flags |= POLY_FORCEWIDE;
#endif #endif
} }
@ -3019,6 +3024,7 @@ EX void draw_boundary(int w) {
hyperpoint ret = point2(real(z), imag(z)); hyperpoint ret = point2(real(z), imag(z));
ret = mobius(ret, pconf.skiprope, 1); ret = mobius(ret, pconf.skiprope, 1);
ret *= current_display->radius; ret *= current_display->radius;
models::ori_to_scr(ret);
curvepoint(ret); curvepoint(ret);
} }
queuecurve(shiftless(Id), ringcolor, 0, p).flags |= POLY_ALWAYS_IN; queuecurve(shiftless(Id), ringcolor, 0, p).flags |= POLY_ALWAYS_IN;
@ -3212,7 +3218,7 @@ EX bool do_draw(cell *c) {
EX ld extra_generation_distance = 99; EX ld extra_generation_distance = 99;
// returns false if limited // returns false if limited
bool limited_generation(cell *c) { EX bool limited_generation(cell *c) {
if(c->mpdist <= 7) return true; if(c->mpdist <= 7) return true;
if(cells_generated > vid.cells_generated_limit) return false; if(cells_generated > vid.cells_generated_limit) return false;
setdist(c, 7, c); setdist(c, 7, c);
@ -3222,7 +3228,11 @@ bool limited_generation(cell *c) {
EX int min_cells_drawn = 50; EX int min_cells_drawn = 50;
EX hookset<int(cell*,const shiftmatrix&)> hooks_do_draw;
EX bool do_draw(cell *c, const shiftmatrix& T) { 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) { if(WDIM == 3) {
// do not care about cells outside of the track // 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; if(b) maxv = t; else minv = t;
shift_view(H * -t * scale); shift_view(H * -t * scale);
} }
println(hlog, "maxv = ", maxv); // println(hlog, "maxv = ", maxv);
shift_view(H * maxv * scale); shift_view(H * maxv * scale);
check_portal_movement(); check_portal_movement();
shift_view_portal(H * (1 - maxv) * scale); shift_view_portal(H * (1 - maxv) * scale);
@ -1181,7 +1181,7 @@ EX void add_options() {
} }
auto a = addHook(hooks_configfile, 100, [] { auto a = addHook(hooks_configfile, 100, [] {
param_b(auto_eyelevel, "auto_eyelevel") param_b(auto_eyelevel, "intra_eyelevel")
-> editable("keep eye level when walking enabled", 'L'); -> editable("keep eye level when walking enabled", 'L');
param_f(eye_level, "walk_eye_level") param_f(eye_level, "walk_eye_level")
-> editable(0, 5, .1, "walking eye level", -> editable(0, 5, .1, "walking eye level",

View File

@ -402,10 +402,7 @@ bool step(int delta) {
if(notfound) { status[4] = XLAT("cells badly paired: %1", its(notfound)); runlevel = 0; break; } if(notfound) { status[4] = XLAT("cells badly paired: %1", its(notfound)); runlevel = 0; break; }
int heptas = 0; int heptas = 0;
for(auto p: cells_of_heptagon) { for(auto p: cells_of_heptagon) heptas++;
printf("%p: %d\n", hr::voidp(p.first), isize(p.second));
heptas++;
}
if(heptas != isize(all)) { if(heptas != isize(all)) {
status[4] = XLAT("cells not covered: %1", its(isize(all) - heptas)); 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]; return hi.celldists[alts][cells[cellindex[c]].localindex];
} }
eGeometry orig_geometry; eGeometry orig_geometry, base_geometry;
void start_game_on_created_map() { void start_game_on_created_map() {
popScreen(); popScreen();
@ -807,6 +804,47 @@ bool save_map(const string& fname) {
return true; 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) { bool load_map(const string &fname) {
fhstream f(fname, "rt"); fhstream f(fname, "rt");
if(!f.f) return false; if(!f.f) return false;
@ -839,6 +877,52 @@ bool load_map(const string &fname) {
return true; 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() { void cancel_map_creation() {
base = NULL; base = NULL;
runlevel = 0; runlevel = 0;
@ -950,7 +1034,7 @@ void show_gridmaker() {
}; };
} }
EX void visual_creator() { EX void init() {
stop_game(); stop_game();
orig_geometry = geometry; orig_geometry = geometry;
switch(geometry) { switch(geometry) {
@ -966,13 +1050,19 @@ EX void visual_creator() {
break; break;
} }
base_geometry = geometry;
variation = eVariation::pure; variation = eVariation::pure;
start_game(); start_game();
if(base) delete base; if(base) delete base;
base = currentmap; base = currentmap;
base_config = euc::eu; base_config = euc::eu;
drawthemap();
cellcount = int(isize(base->allcells()) * density + .5); cellcount = int(isize(base->allcells()) * density + .5);
gridmaking = true;
drawthemap();
}
EX void visual_creator() {
init();
pushScreen(show_gridmaker); pushScreen(show_gridmaker);
runlevel = 0; runlevel = 0;
gridmaking = true; gridmaking = true;
@ -1015,7 +1105,7 @@ int readArgs() {
else if(argis("-irrload")) { else if(argis("-irrload")) {
PHASE(3); PHASE(3);
restart_game(); restart_game();
visual_creator(); init();
showstartmenu = false; showstartmenu = false;
shift(); shift();
load_map(args()); load_map(args());

View File

@ -16,8 +16,13 @@ EX array<int, ittypes> items;
EX map<modecode_t, array<int, ittypes> > hiitems; 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) { 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) { EX bool canPickupItemWithMagnetism(cell *c, cell *from) {
@ -40,6 +45,7 @@ EX bool doPickupItemsWithMagnetism(cell *c) {
changes.ccell(c3); changes.ccell(c3);
changes.ccell(c4); changes.ccell(c4);
moveItem(c3, c4, false); moveItem(c3, c4, false);
animateMovement(match(c3, c4), LAYER_BOAT);
moveEffect(movei(c4, c4, NODIR), moDeadBird); moveEffect(movei(c4, c4, NODIR), moDeadBird);
markOrb(itCurseRepulsion); markOrb(itCurseRepulsion);
} }
@ -56,8 +62,12 @@ EX bool doPickupItemsWithMagnetism(cell *c) {
} }
else if(c3->item == itOrbSafety || c3->item == itBuggy || c3->item == itBuggy2) else if(c3->item == itOrbSafety || c3->item == itBuggy || c3->item == itBuggy2)
csaf = c3; csaf = c3;
else if(markOrb(itOrbMagnetism)) else if(markOrb(itOrbMagnetism)) {
eItem it = c3->item;
collectItem(c3, c3, false); collectItem(c3, c3, false);
if(!c3->item)
animate_item_throw(c3, c, it);
}
} }
if(csaf) if(csaf)
return collectItem(csaf, csaf, false); return collectItem(csaf, csaf, false);
@ -732,7 +742,7 @@ EX void collectMessage(cell *c2, eItem which) {
EX bool itemHiddenFromSight(cell *c) { EX bool itemHiddenFromSight(cell *c) {
return isWatery(c) && !items[itOrbInvis] && !(items[itOrbFish] && playerInWater()) 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; else if(c->land == laEEarth) c->wall = waStone;
} }
// automatically adjust monster generation for 3D geometries // automatically adjust monster generation for 3D geometries and custom difficulty
EX int hrand_monster(int x) { EX int hrand_monster_in(eLand l, int x) {
// dual geometry mode is much harder, so generate less monsters to balance it // dual geometry mode is much harder, so generate less monsters to balance it
if(dual::state) x *= 3; if(dual::state) x *= 3;
// in 3D monster generation depends on the sight range // in 3D monster generation depends on the sight range
@ -180,9 +180,15 @@ EX int hrand_monster(int x) {
int t = isize(gmatrix); int t = isize(gmatrix);
if(t > 500) x = int(((long long)(x)) * t / 500); 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); return hrand(x);
} }
#define hrand_monster(x) hrand_monster_in(c->land, x)
EX bool is_zebra_trapdoor(cell *c) { EX bool is_zebra_trapdoor(cell *c) {
if(euclid && closed_or_bounded) return false; if(euclid && closed_or_bounded) return false;
#if CAP_ARCM #if CAP_ARCM
@ -195,7 +201,6 @@ EX bool is_zebra_trapdoor(cell *c) {
else if(PURE && reg3::exact_rules()) switch(geometry) { else if(PURE && reg3::exact_rules()) switch(geometry) {
case gSpace534: { case gSpace534: {
if(c->master->fieldval == 0) return true; if(c->master->fieldval == 0) return true;
forCellCM(c1, c) if(c1->master->fieldval == 0) return true;
return false; return false;
} }
case gSpace435: { case gSpace435: {
@ -280,6 +285,23 @@ EX void gen_baby_tortoise(cell *c) {
tortoise::babymap[c] = tortoise::getb(c) ^ tortoise::getRandomBits(); 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) { EX void giantLandSwitch(cell *c, int d, cell *from) {
bool fargen = d == 9; bool fargen = d == 9;
switch(c->land) { switch(c->land) {
@ -536,7 +558,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
// no Plates or Trapdoors in the Princess cell // no Plates or Trapdoors in the Princess cell
if(d < 3 && (c->wall == waClosePlate || c->wall == waOpenPlate || c->wall == waTrapdoor)) if(d < 3 && (c->wall == waClosePlate || c->wall == waOpenPlate || c->wall == waTrapdoor))
c->wall = waNone; c->wall = waNone;
if(d > 1) c->item = itNone; if(d > 1) clear_item(c);
// the Princess herself // the Princess herself
if(d == 0) { if(d == 0) {
c->monst = moPrincess; c->monst = moPrincess;
@ -634,9 +656,9 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
c->wall = waCavewall; c->wall = waCavewall;
else c->wall = waCavefloor; 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; c->wall = hrand(100) < 50 ? waCavefloor : waCavewall;
else if(!BITRUNCATED) { else if(!BITRUNCATED && geometry != gOctagon) {
if(polarb50(c)) if(polarb50(c))
c->wall = waCavewall; c->wall = waCavewall;
else c->wall = waCavefloor; else c->wall = waCavefloor;
@ -743,7 +765,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
} }
} }
// seal entrances to the Land of Power. // seal entrances to the Land of Power.
if(d == 7 && ctof(c)) { if(d == 7 && ctof(c) && land_structure != lsLandscape) {
bool onwall = false; bool onwall = false;
for(int i=0; i<c->type; i++) if(c->move(i) && c->move(i)->land == laBarrier) for(int i=0; i<c->type; i++) if(c->move(i) && c->move(i)->land == laBarrier)
onwall = true; onwall = true;
@ -753,13 +775,16 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
cell *c3 = c2->modmove(c->c.spin(i) + 3); cell *c3 = c2->modmove(c->c.spin(i) + 3);
if(!c3) continue; if(!c3) continue;
if(c3->land != laPower && c3->land != laBarrier) 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; if(isFire(c)) c->monst = moWitchWinter;
else if(c->wall == waGlass) c->monst = moWitchGhost; else if(c->wall == waGlass) c->monst = moWitchGhost;
else c->monst = moEvilGolem; else c->monst = moEvilGolem;
} }
} }
} }
if(d == 7 && land_structure == lsLandscape) {
forCellEx(c2, c) if(c2->land != laPower) c->wall = waEternalFire;
}
ONEMPTY { ONEMPTY {
if(hrand(5000+50*items[itPower]) < 1200) { if(hrand(5000+50*items[itPower]) < 1200) {
eItem powerorbs[6] = { eItem powerorbs[6] = {
@ -811,7 +836,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
} }
else if(WDIM == 3 && hyperbolic && !bt::in()) else if(WDIM == 3 && hyperbolic && !bt::in())
c->wall = (c->master->zebraval & 2) ? waVinePlant : waNone; 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; c->wall = hrand(100) < 50 ? waNone : waVinePlant;
else { else {
int v = emeraldval(c); 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)) forCellCM(c2, c) if(emeraldval(c2) == (v^1))
c->wall = waVinePlant; 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: case laTrollheim:
if(fargen) { 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; bool okay = true;
forCellCM(c2, c) forCellCM(c3, c2) forCellCM(c4, c3) forCellCM(c5, c4) { forCellCM(c2, c) forCellCM(c3, c2) forCellCM(c4, c3) forCellCM(c5, c4) {
cell *cx = ls::any_chaos() ? c3 : c5; 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; okay = false;
if(cx->bardir != NODIR) okay = false; if(cx->bardir != NODIR) okay = false;
} }
@ -1226,7 +1258,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
if(fargen) { if(fargen) {
if(hrand(500) < 15) if(hrand(500) < 15)
createArrowTrapAt(c, laTerracotta); 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->wall = waTerraWarrior;
c->wparam = terracotta::randterra ? 0 : 3 + hrand(3); c->wparam = terracotta::randterra ? 0 : 3 + hrand(3);
if(hrand(100) < items[itTerra]-10) if(hrand(100) < items[itTerra]-10)
@ -1268,7 +1300,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
if(d == 8) { if(d == 8) {
bool ok = c->landparam == 0; bool ok = c->landparam == 0;
forCellEx(c2, c) if(c2->landparam) ok = false; 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; if(!peace::on) c->item = itMutant;
c->landparam = items[itMutant] + 5 + hrand(11); c->landparam = items[itMutant] + 5 + hrand(11);
c->wall = waNone; c->wall = waNone;
@ -1296,6 +1328,12 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
break; break;
case laHalloween: case laHalloween:
if(!closed_or_bounded) {
ONEMPTY {
if(hrand(1000) < PT(20, 20)) c->item = itTreat;
if(hrand(1000) < 20) c->wall = waChasm;
}
}
break; break;
case laWildWest: case laWildWest:
@ -1503,7 +1541,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
if(fargen) { if(fargen) {
if(randomPatternsMode) if(randomPatternsMode)
c->wall = RANDPAT ? ((RANDPATV(laCrossroads) || RANDPATV(laCrossroads2)) ? waAncientGrave : waFreshGrave) : waNone; 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; c->wall = hrand(5) ? waAncientGrave : waFreshGrave;
} }
ONEMPTY { ONEMPTY {
@ -1536,7 +1574,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
c->move(i)->wall = waNone; c->move(i)->wall = waNone;
} }
} }
if(pseudohept(c) && hrand(2)) c->wall = waColumn; if(pseudohept_r(c) && hrand(2)) c->wall = waColumn;
} }
} }
ONEMPTY { ONEMPTY {
@ -2047,7 +2085,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
case laHunting: case laHunting:
if(d == 7 && c->land == laHunting && !racing::on && !safety && !reptilecheat) { 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(openplains(c)) {
if(hrand(2) == 0) { if(hrand(2) == 0) {
if(!items[itHunting]) { if(!items[itHunting]) {
@ -2255,11 +2293,11 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
c->monst = moMonkey; c->monst = moMonkey;
else if(hrand_monster(80000) < 5 + items[itRuby] + yendor::hardness()) else if(hrand_monster(80000) < 5 + items[itRuby] + yendor::hardness())
c->monst = moEagle; 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(); int hardchance = items[itRuby] + yendor::hardness();
if(hardchance > 25) hardchance = 25; if(hardchance > 25) hardchance = 25;
bool hardivy = hrand(100) < hardchance; 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; c->item = itRuby;
} }
} }
@ -2299,7 +2337,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
int d = -celldistAlt(c); int d = -celldistAlt(c);
if(hrand_monster(2500) < items[itMutant2] + yendor::hardness() - 10 && !reptilecheat) if(hrand_monster(2500) < items[itMutant2] + yendor::hardness() - 10 && !reptilecheat)
c->monst = moRedFox; c->monst = moRedFox;
else if(hrand(100 + d) < d && !reptilecheat) else if(d > 0 && hrand(100 + d) < d && !reptilecheat)
c->item = itMutant2; c->item = itMutant2;
} }
} }
@ -2378,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)) { if(hrand(1500) < PT(30 + kills[moHexDemon] + kills[moAltDemon] + kills[moMonk] + kills[moPair] + kills[moCrusher], 100) && notDippingFor(itRuins)) {
c->item = itRuins; c->item = itRuins;
forCellEx(c2, c) if(c2->monst == moMonk) forCellEx(c2, c) if(c2->monst == moMonk)
c->item = itNone; clear_item(c);
} }
if(hrand_monster(7000) < kf && !c->monst) { if(hrand_monster(7000) < kf && !c->monst) {
c->monst = genRuinMonster(c); c->monst = genRuinMonster(c);
@ -2516,7 +2554,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
if(d == 7) { if(d == 7) {
c->wall = waNone; c->wall = waNone;
c->item = itNone; c->monst = moNone; clear_item(c); c->monst = moNone;
if(hrand(100) < 25) if(hrand(100) < 25)
c->wall = hrand(2) ? waBigTree : waSmallTree; c->wall = hrand(2) ? waBigTree : waSmallTree;
@ -2557,7 +2595,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
treasure_rate += variant::features[i].rate_change; treasure_rate += variant::features[i].rate_change;
variant::features[i].build(c); 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; c->item = itVarTreasure;
} }
if(d == 7 && c->wall == waTrapdoor) { if(d == 7 && c->wall == waTrapdoor) {
@ -2628,7 +2666,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
} }
case laCursed: { case laCursed: {
if(fargen) { if(fargen && c->wall != waRubble) {
c->wall = waStone; c->wall = waStone;
for(int i=0; i<3; i++) { for(int i=0; i<3; i++) {
auto ew = [i] (cell *c1) { auto ew = [i] (cell *c1) {
@ -2664,7 +2702,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
c->wall = waStone; c->wall = waStone;
else { else {
c->monst = moHexer; c->monst = moHexer;
c->item = pick(itCurseWeakness, itCurseDraining, itCurseWater, itCurseFatigue, itCurseRepulsion, itCurseGluttony); c->item = random_curse();
} }
break; break;
} }
@ -2882,13 +2920,37 @@ EX void share_land(cell *c, cell *c2) {
c->land = c2->land; 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(!c->land && isize(currentlands)) {
if(land_structure == lsTotalChaos) { if(land_structure == lsTotalChaos) {
setland(c, random_land()); setland(c, random_land());
return; 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 */ /* note: Nil patched chaos done in setLandNil */
if(ls::patched_chaos() && (cgflags & qFRACTAL)) { if(ls::patched_chaos() && (cgflags & qFRACTAL)) {
share_land(c, fractal_rep(c)); share_land(c, fractal_rep(c));
@ -2990,7 +3052,7 @@ EX void setdist(cell *c, int d, cell *from) {
} }
#endif #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(!hasbardir(c)) setland(c, from->land);
} }
if(c->land == laTemple && ls::any_order()) setland(c, laRlyeh); if(c->land == laTemple && ls::any_order()) setland(c, laRlyeh);
@ -3013,10 +3075,10 @@ EX void setdist(cell *c, int d, cell *from) {
} }
if(d == BARLEV && c->land == laCanvas) { if(d == BARLEV && c->land == laCanvas) {
color_t col = patterns::generateCanvas(c); color_t col = ccolor::generateCanvas(c);
c->landparam = col; c->landparam = col;
c->wall = canvas_default_wall; c->wall = canvas_default_wall;
if((GDIM == 3 || geom3::flipped) && (col & 0x1000000)) c->wall = waWaxWall; if(col & 0x1000000) c->wall = waWaxWall;
} }
#if CAP_FIELD #if CAP_FIELD
@ -3139,4 +3201,6 @@ EX void setdist(cell *c, int d, cell *from) {
#endif #endif
} }
#undef hrand_monster
} }

View File

@ -81,7 +81,7 @@ EX eLand firstland = laIce;
EX eLand specialland = laIce; EX eLand specialland = laIce;
#if HDR #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 #endif
EX eLandStructure land_structure; EX eLandStructure land_structure;
@ -90,9 +90,9 @@ EX namespace ls {
EX bool single() { return land_structure == lsSingle; } 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 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 patched_chaos() { return land_structure == lsPatchedChaos; }
EX bool any_order() { return among(land_structure, lsNiceWalls, lsNoWalls, lsHorodisks, lsVoronoi); } 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 == lsChaosRW) return 80;
if(land_structure == lsPatchedChaos) return 60; if(land_structure == lsPatchedChaos) return 60;
if(land_structure == lsChaos) return 40; if(land_structure == lsChaos) return 40;
if(land_structure == lsLandscape) return 35;
if(land_structure == lsWallChaos) return 30; 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 == lsVoronoi) return 20;
if(land_structure == lsSingle) return 0; if(land_structure == lsSingle) return 0;
return 10; 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 bool tame_chaos() { return any_chaos() && chaoticity() < 35; }
EX } EX }
@ -139,8 +160,16 @@ EX string land_structure_name(bool which) {
return XLAT("horodisks"); return XLAT("horodisks");
case lsVoronoi: case lsVoronoi:
return XLAT("ideal Voronoi"); return XLAT("ideal Voronoi");
case lsLandscape:
return XLAT("landscape");
case lsNoWalls: case lsNoWalls:
return XLAT("wall-less"); return XLAT("wall-less");
case lsCrossWalls:
return XLAT("excessive crossing walls");
case lsVineWalls:
return XLAT("regular walls");
case lsCursedWalls:
return XLAT("cursed walls");
default: default:
return "error structure"; return "error structure";
} }
@ -151,6 +180,8 @@ EX void fix_land_structure_choice() {
if(land_structure != lsTotalChaos && land_structure != lsChaosRW) if(land_structure != lsTotalChaos && land_structure != lsChaosRW)
land_structure = lsSingle; land_structure = lsSingle;
} }
if(land_structure == lsLandscape && !geometry_supports_cdata())
land_structure = lsChaosRW;
if(tactic::on || princess::challenge) if(tactic::on || princess::challenge)
land_structure = lsSingle; land_structure = lsSingle;
if(yendor::on) if(yendor::on)
@ -159,6 +190,12 @@ EX void fix_land_structure_choice() {
land_structure = lsNoWalls; land_structure = lsNoWalls;
if(!nice_walls_available() && land_structure == lsWallChaos) if(!nice_walls_available() && land_structure == lsWallChaos)
land_structure = lsChaos; 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)) if(ls::hv_structure() && (!hyperbolic || bt::in() || quotient))
land_structure = lsSingle; land_structure = lsSingle;
if(walls_not_implemented() && among(land_structure, lsChaos, lsNoWalls)) if(walls_not_implemented() && among(land_structure, lsChaos, lsNoWalls))
@ -225,6 +262,7 @@ EX bool landUnlocked(eLand l) {
#define ACCONLY3(x,y,z) #define ACCONLY3(x,y,z)
#define ACCONLYF(x) #define ACCONLYF(x)
#define IFINGAME(land, ok, fallback) if(isLandIngame(land)) { ok } else { fallback } #define IFINGAME(land, ok, fallback) if(isLandIngame(land)) { ok } else { fallback }
#define INMODE(x) if(x) return true;
#include "content.cpp" #include "content.cpp"
case landtypes: return false; case landtypes: return false;
@ -246,6 +284,10 @@ EX void countHyperstoneQuest(int& i1, int& i2) {
i1 = 0; i2 = 0; i1 = 0; i2 = 0;
generateLandList(isLandIngame); generateLandList(isLandIngame);
for(eLand l: landlist) { 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); eItem ttype = treasureType(l);
if(!required_for_hyperstones(ttype)) continue; if(!required_for_hyperstones(ttype)) continue;
i2++; if(items[ttype] >= R10) i1++; i2++; if(items[ttype] >= R10) i1++;
@ -377,7 +419,7 @@ EX eLand pickluck(eLand l1, eLand l2) {
} */ } */
EX eLand getNewSealand(eLand old) { EX eLand getNewSealand(eLand old) {
while(true) { for(int it=0; it<100; it++) {
eLand p = pick(laOcean, pick(laCaribbean, laLivefjord, laWarpSea, laKraken, laDocks)); eLand p = pick(laOcean, pick(laCaribbean, laLivefjord, laWarpSea, laKraken, laDocks));
if(p == laKraken && !landUnlocked(p)) continue; if(p == laKraken && !landUnlocked(p)) continue;
if(p == laKraken && peace::on) continue; if(p == laKraken && peace::on) continue;
@ -386,6 +428,7 @@ EX eLand getNewSealand(eLand old) {
if(!isLandIngame(p)) continue; if(!isLandIngame(p)) continue;
return p; return p;
} }
return old;
} }
EX bool createOnSea(eLand old) { EX bool createOnSea(eLand old) {
@ -552,7 +595,8 @@ EX eLand getNewLand(eLand old) {
// the intermediate lands // the intermediate lands
if(all_unlocked || gold() >= R30) { if(all_unlocked || gold() >= R30) {
tab[cnt++] = laCrossroads; tab[cnt++] = laCrossroads;
tab[cnt++] = (geometry || ls::hv_structure()) ? laMirrorOld : laMirror; tab[cnt++] = laMirrorOld;
tab[cnt++] = laMirror;
tab[cnt++] = laOcean; tab[cnt++] = laOcean;
tab[cnt++] = laLivefjord; tab[cnt++] = laLivefjord;
if(all_unlocked || kills[moVizier]) tab[cnt++] = laEmerald; if(all_unlocked || kills[moVizier]) tab[cnt++] = laEmerald;
@ -561,6 +605,11 @@ EX eLand getNewLand(eLand old) {
tab[cnt++] = laDocks; tab[cnt++] = laDocks;
} }
tab[cnt++] = laHalloween;
tab[cnt++] = laWildWest;
tab[cnt++] = laAsteroids;
tab[cnt++] = laCA;
// the advanced lands // the advanced lands
if(all_unlocked || gold() >= R60) { if(all_unlocked || gold() >= R60) {
tab[cnt++] = laCrossroads; tab[cnt++] = laCrossroads;
@ -626,13 +675,24 @@ EX eLand getNewLand(eLand old) {
if(ls::horodisk_structure() && tortoise::seek()) LIKELY tab[cnt++] = laTortoise; if(ls::horodisk_structure() && tortoise::seek()) LIKELY tab[cnt++] = laTortoise;
eLand n = old; int idx = 0;
while(incompatible(n, old) || !isLandIngame(n)) { while (idx < cnt) {
n = tab[hrand(cnt)]; eLand n = tab[idx];
if(weirdhyperbolic && specialland == laCrossroads4 && isCrossroads(n)) if (incompatible(n, old) || !isLandIngame(n))
n = laCrossroads4; 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; return n;
} }
@ -712,14 +772,26 @@ EX eLand getLandForList(cell *c) {
return l; 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) { EX bool isLandIngame(eLand l) {
if(isElemental(l)) l = laElementalWall; 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(dual::state == 2 && !dual::check_side(l)) return false;
if((eubinary || sol) && isCyclic(l) && l != specialland) return false; if((eubinary || sol) && isCyclic(l) && l != specialland) return false;
if(l == laCamelot && hyperbolic && WDIM == 3) return false; if(l == laCamelot && hyperbolic && WDIM == 3) return false;
return land_validity(l).flags & lv::appears_in_full; 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 { namespace lv {
flagtype q0 = lv::display_error_message | lv::display_in_help | lv::appears_in_geom_exp; flagtype q0 = lv::display_error_message | lv::display_in_help | lv::appears_in_geom_exp;
@ -745,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 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 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_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_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 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." }; land_validity_t special_chaos = { 2, qm2, "Special construction in the Chaos mode." };
@ -802,6 +875,132 @@ EX const int cursed_when = 386;
EX const int walls_when = 388; 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 // check if the given land should appear in lists
EX land_validity_t& land_validity(eLand l) { EX land_validity_t& land_validity(eLand l) {
@ -995,7 +1194,7 @@ EX land_validity_t& land_validity(eLand l) {
if(l == laWhirlwind && hyperbolic_not37) if(l == laWhirlwind && hyperbolic_not37)
return pattern_incompatibility; 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 // available only in non-standard geometries
if(l == laMirrorOld && better_mirror) if(l == laMirrorOld && better_mirror)
@ -1016,6 +1215,9 @@ EX land_validity_t& land_validity(eLand l) {
if(l == laHaunted && ls::std_chaos()) if(l == laHaunted && ls::std_chaos())
return not_in_chaos; return not_in_chaos;
if(among(l, laHaunted, laElementalWall) && land_structure == lsLandscape)
return not_in_landscape;
// standard, non-PTM specific // standard, non-PTM specific
if(l == laCrossroads5 && old_daily_id < 999 && tactic::on) if(l == laCrossroads5 && old_daily_id < 999 && tactic::on)
return not_in_ptm; return not_in_ptm;

View File

@ -9037,19 +9037,20 @@ S("display only chessboard white", "zobrazit pouze bílá políčka šachovnice"
S("display only chessboard black", "zobrazit pouze černá políčka šachovnice") S("display only chessboard black", "zobrazit pouze černá políčka šachovnice")
S( S(
"This lets you specify the color pattern as a function of the cell. " "This lets you specify the color pattern as a function of the cell.\n",
"Zde můžeš specifikovat barevný vzor jako funkci políčka.\n")
S(
"Available parameters:\n\n" "Available parameters:\n\n"
"x, y, z (hyperboloid/sphere/plane coordinates in non-crystal geometries)\n" "x, y, z (hyperboloid/sphere/plane coordinates in non-crystal geometries)\n"
"ex, ey, ez (in Euclidean geometries)\n" "ex, ey, ez (in Euclidean geometries)\n"
"x0, x1, x2... (crystal geometry only)\n" "x0, x1, x2... (crystal geometry only)\n",
"0 is black, 1 is white, rgb(1,0,0) is red, ifp(p-2,1,0) is blue (p=1 for red, 2 for green, 3 for blue).",
"Zde můžeš specifikovat barevný vzor jako funkci políčka. "
"Dostupné parametry:\n\n" "Dostupné parametry:\n\n"
"x, y, z (souřadnice hyperboloidu/koule/roviny v nekrystalových geometriích)\n" "x, y, z (souřadnice hyperboloidu/koule/roviny v nekrystalových geometriích)\n"
"ex, ey, ez (v eukleidovských geometriích)\n" "ex, ey, ez (v eukleidovských geometriích)\n"
"x0, x1, x2... (pouze v krystalové geometrii)\n" "x0, x1, x2... (pouze v krystalové geometrii)\n"
"0 je černá, 1 bílá, rbg(1,0,0) červená, ifp(p-2,1,0) modrá (p=1 pro červenou, 2 pro zelenou, 3 pro modrou)."
) )
S( S(

View File

@ -8652,19 +8652,20 @@ S("display only chessboard white", "afficher seulement le plateau d'échec blanc
S("display only chessboard black", "afficher seulement le plateau d'échec noir") S("display only chessboard black", "afficher seulement le plateau d'échec noir")
S( S(
"This lets you specify the color pattern as a function of the cell. " "This lets you specify the color pattern as a function of the cell.\n",
"Vous laisse choisir le motif de couleur comme fonction de la case.\n")
S(
"Available parameters:\n\n" "Available parameters:\n\n"
"x, y, z (hyperboloid/sphere/plane coordinates in non-crystal geometries)\n" "x, y, z (hyperboloid/sphere/plane coordinates in non-crystal geometries)\n"
"ex, ey, ez (in Euclidean geometries)\n" "ex, ey, ez (in Euclidean geometries)\n"
"x0, x1, x2... (crystal geometry only)\n" "x0, x1, x2... (crystal geometry only)\n",
"0 is black, 1 is white, rgb(1,0,0) is red, ifp(p-2,1,0) is blue (p=1 for red, 2 for green, 3 for blue).",
"Vous laisse choisir le motif de couleur comme fonction de la case. "
"Paramètres disponibles : \n\n" "Paramètres disponibles : \n\n"
"x, y, z (coordonnées hyperboloïde/sphère/plan dans des géométries non-cristallines)\n" "x, y, z (coordonnées hyperboloïde/sphère/plan dans des géométries non-cristallines)\n"
"ex, ey, ez (dans une géométrie euclidienne)\n" "ex, ey, ez (dans une géométrie euclidienne)\n"
"x0, x1, x2... (dans les géométries cristallines seulement)\n" "x0, x1, x2... (dans les géométries cristallines seulement)\n"
"0 est noir, 1 est blanc, rgb(1,0,0) est rouge, ifp(p-2,1,0) est bleu (p=1 pour rouge, 2 pour vert, 3 pour bleu)."
) )
S( S(

View File

@ -8756,20 +8756,21 @@ S("display only chessboard white", "tylko białe pola szachownicy")
S("display only chessboard black", "tylko czarne pola szachownicy") S("display only chessboard black", "tylko czarne pola szachownicy")
S( S(
"This lets you specify the color pattern as a function of the cell. " "This lets you specify the color pattern as a function of the cell.\n",
"Tu możesz określić wzór jako funkcję komórki.\n")
S(
"Available parameters:\n\n" "Available parameters:\n\n"
"x, y, z (hyperboloid/sphere/plane coordinates in non-crystal geometries)\n" "x, y, z (hyperboloid/sphere/plane coordinates in non-crystal geometries)\n"
"ex, ey, ez (in Euclidean geometries)\n" "ex, ey, ez (in Euclidean geometries)\n"
"x0, x1, x2... (crystal geometry only)\n" "x0, x1, x2... (crystal geometry only)\n",
"0 is black, 1 is white, rgb(1,0,0) is red, ifp(p-2,1,0) is blue (p=1 for red, 2 for green, 3 for blue).",
"Tu możesz określić wzór jako funkcję komórki. Dostępne parametry:\n\n" "Dostępne parametry:\n\n"
"x, y, z (współrzędne hiperboloidy/sfery/powierczni, poza kryształami)\n" "x, y, z (współrzędne hiperboloidy/sfery/powierczni, poza kryształami)\n"
"ex, ey, ez (w geometriach euklidesowych)\n" "ex, ey, ez (w geometriach euklidesowych)\n"
"x0, x1, x2... (w kryształach)\n" "x0, x1, x2... (w kryształach)\n"
"0 to czarny, 1 to biały, rgb(1,0,0) to czerwony, ifp(p-2,1,0) to niebieski (p=1 to czerwony, 2 to zielony, 3 to niebieski)."
) )
S( S(
"w (fourth coordinate)\n" "w (fourth coordinate)\n"
"wallif(condition, color)\n", "wallif(condition, color)\n",

View File

@ -206,6 +206,7 @@ EX modecode_t legacy_modecode() {
if(int(geometry) > 3 || int(variation) > 1) return UNKNOWN; if(int(geometry) > 3 || int(variation) > 1) return UNKNOWN;
if(casual) return UNKNOWN; if(casual) return UNKNOWN;
if(bow::weapon) return UNKNOWN; if(bow::weapon) return UNKNOWN;
if(use_custom_land_list) return UNKNOWN;
bool is_default_land_structure = bool is_default_land_structure =
(princess::challenge || tactic::on) ? ls::single() : (princess::challenge || tactic::on) ? ls::single() :
@ -426,6 +427,14 @@ int read_legacy_args_anim() {
shift_arg_formula(normal_angle); shift_arg_formula(normal_angle);
} }
} }
else if(argis("-innerwall")) {
PHASEFROM(2);
patterns::innerwalls = true;
}
else if(argis("-noinnerwall")) {
PHASEFROM(2);
patterns::innerwalls = false;
}
else if(argis("-animrotd")) { else if(argis("-animrotd")) {
start_game(); start_game();
ma = maRotation; ma = maRotation;

View File

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

View File

@ -491,6 +491,9 @@ EX namespace mapstream {
f.write(gp::param.second); f.write(gp::param.second);
} }
#endif #endif
#if CAP_IRR
if(IRREGULAR) irr::save_map_bin(f);
#endif
#if MAXMDIM >= 4 #if MAXMDIM >= 4
if(variation == eVariation::coxeter) { if(variation == eVariation::coxeter) {
f.write(reg3::coxeter_param); f.write(reg3::coxeter_param);
@ -587,6 +590,9 @@ EX namespace mapstream {
f.read(gp::param.second); f.read(gp::param.second);
} }
#endif #endif
#if CAP_IRR
if(IRREGULAR) { irr::load_map_full(f); stop_game(); }
#endif
#if MAXMDIM >= 4 #if MAXMDIM >= 4
if(variation == eVariation::coxeter && vernum >= 0xA908) { if(variation == eVariation::coxeter && vernum >= 0xA908) {
f.read(reg3::coxeter_param); f.read(reg3::coxeter_param);
@ -740,14 +746,16 @@ EX namespace mapstream {
f.write(gen_wandering); f.write(gen_wandering);
f.write(reptilecheat); f.write(reptilecheat);
f.write(timerghost); f.write(timerghost);
f.write(patterns::canvasback); f.write(ccolor::plain.ctab[0]);
f.write(patterns::whichShape); f.write(patterns::whichShape);
f.write(patterns::subpattern_flags); 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(patterns::displaycodes);
f.write(canvas_default_wall); f.write(canvas_default_wall);
f.write(mapeditor::drawplayer); 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(canvasfloor);
f.write(canvasdark); f.write(canvasdark);
@ -940,15 +948,21 @@ EX namespace mapstream {
f.read(gen_wandering); f.read(gen_wandering);
f.read(reptilecheat); f.read(reptilecheat);
f.read(timerghost); f.read(timerghost);
f.read(patterns::canvasback); f.read(ccolor::plain.ctab[0]);
f.read(patterns::whichShape); f.read(patterns::whichShape);
f.read(patterns::subpattern_flags); 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); f.read(patterns::displaycodes);
if(f.vernum >= 0xA816) if(f.vernum >= 0xA816)
f.read(canvas_default_wall); f.read(canvas_default_wall);
f.read(mapeditor::drawplayer); 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) { if(f.vernum >= 0xA90D) {
f.read(canvasfloor); f.read(canvasfloor);
f.read(canvasdark); f.read(canvasdark);
@ -2588,16 +2602,16 @@ EX namespace mapeditor {
bool onelayeronly; bool onelayeronly;
bool loadPicFile(const string& s) { bool loadPicFile(const string& s) {
fhstream f(picfile, "rt"); fhstream f(s, "rt");
if(!f.f) { if(!f.f) {
addMessage(XLAT("Failed to load pictures from %1", picfile)); addMessage(XLAT("Failed to load pictures from %1", s));
return false; return false;
} }
scanline(f); scanline(f);
scan(f, f.vernum); scan(f, f.vernum);
printf("vernum = %x\n", f.vernum); printf("vernum = %x\n", f.vernum);
if(f.vernum == 0) { if(f.vernum == 0) {
addMessage(XLAT("Failed to load pictures from %1", picfile)); addMessage(XLAT("Failed to load pictures from %1", s));
return false; return false;
} }
@ -2625,6 +2639,7 @@ EX namespace mapeditor {
} }
initShape(i, j); initShape(i, j);
println(hlog, "shape ", tie(i, j), " layer ", l);
usershapelayer& ds(usershapes[i][j]->d[l]); usershapelayer& ds(usershapes[i][j]->d[l]);
if(f.vernum >= 0xA608) scan(f, ds.zlevel); if(f.vernum >= 0xA608) scan(f, ds.zlevel);
ds.shift = readHyperpoint(f); ds.shift = readHyperpoint(f);
@ -2738,8 +2753,7 @@ EX namespace mapeditor {
stop_game(); stop_game();
enable_canvas(); enable_canvas();
canvas_default_wall = waInvisibleFloor; canvas_default_wall = waInvisibleFloor;
patterns::whichCanvas = 'g'; ccolor::set_plain(0xFFFFFF);
patterns::canvasback = 0xFFFFFF;
dtcolor = (forecolor << 8) | 255; dtcolor = (forecolor << 8) | 255;
drawplayer = false; drawplayer = false;
vid.use_smart_range = 2; 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 coastvalEdge(cell *c) { return coastval(c, laIvoryTower); }
EX int coastvalWest(cell *c) { return coastval(c, laWestWall); }
EX int gravityLevel(cell *c) { EX int gravityLevel(cell *c) {
if(c->land == laIvoryTower && ls::hv_structure()) if(c->land == laIvoryTower && ls::hv_structure())
@ -601,10 +602,10 @@ EX int gravityLevelDiff(cell *c, cell *d) {
if(shmup::on) return 0; if(shmup::on) return 0;
int nid = neighborId(c, d); 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 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); int di2 = angledist(c->type, id2, nid);
if(di1 < di2) return 1; if(di1 < di2) return 1;
@ -708,8 +709,8 @@ EX void checkTide(cell *c) {
if(!c2) continue; if(!c2) continue;
if(c2->land == laBarrier || c2->land == laOceanWall) ; if(c2->land == laBarrier || c2->land == laOceanWall) ;
else if(c2->land == laOcean) else if(c2->land == laOcean)
seadist = min(seadist, c2->SEADIST ? c2->SEADIST+1 : 7), seadist = min(seadist, c2->SEADIST >= 1 ? c2->SEADIST+1 : 7),
landdist = min(landdist, c2->LANDDIST ? c2->LANDDIST+1 : 7); landdist = min(landdist, c2->LANDDIST >= 1 ? c2->LANDDIST+1 : 7);
else if(isSealand(c2->land)) seadist = 1; else if(isSealand(c2->land)) seadist = 1;
else landdist = 1; else landdist = 1;
} }
@ -743,20 +744,35 @@ EX void checkTide(cell *c) {
else if(c->wall == waMagma) c->wall = waNone; else if(c->wall == waMagma) c->wall = waNone;
} }
#endif #endif
if(c->land == laCanvas && ccolor::live_canvas) {
color_t col = ccolor::generateCanvas(c);
c->landparam = col;
c->wall = canvas_default_wall;
if(col & 0x1000000) c->wall = waWaxWall;
}
}
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) { EX bool makeEmpty(cell *c) {
if(c->monst != moPrincess) { if(c->monst != moPrincess) {
if(isAnyIvy(c->monst)) killMonster(c, moPlayer, 0); if(!makeNoMonster(c)) return false;
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(c->land == laCanvas) ; if(c->land == laCanvas) ;
@ -814,10 +830,12 @@ EX bool makeEmpty(cell *c) {
} }
if(c->land == laWildWest) { if(c->land == laWildWest) {
forCellEx(c2, c) celllister cl(cwt.at, 100, 1000000, NULL);
forCellEx(c3, c2) for(cell *c: cl.lst) {
if(c3->wall != waBarrier) if(c == cwt.at) continue;
c3->wall = waNone; if(c->wall != waSaloon) break;
c->wall = waNone;
}
} }
return true; return true;

View File

@ -276,13 +276,17 @@ EX void enable_cheat() {
// -- game modes -- // -- game modes --
EX void switchHardcore() { EX void switchHardcore_quiet() {
if(hardcore && !canmove) { if(hardcore && !canmove) {
restart_game(); if(delayed_start) stop_game(); else restart_game();
hardcore = false; hardcore = false;
} }
else if(hardcore && canmove) { hardcore = false; } else if(hardcore && canmove) { hardcore = false; }
else { hardcore = true; canmove = true; hardcoreAt = turncount; } else { hardcore = true; canmove = true; hardcoreAt = turncount; }
}
EX void switchHardcore() {
switchHardcore_quiet();
if(hardcore) if(hardcore)
addMessage(XLAT("One wrong move and it is game over!")); addMessage(XLAT("One wrong move and it is game over!"));
else else
@ -374,6 +378,9 @@ EX void showCreative() {
} }
#endif #endif
dialog::addItem(XLAT("line patterns"), 'l');
dialog::add_action_push(linepatterns::showMenu);
// dialog::addBoolItem(XLAT("expansion"), viewdists, 'x'); // dialog::addBoolItem(XLAT("expansion"), viewdists, 'x');
dialog::addBreak(50); dialog::addBreak(50);
@ -464,12 +471,69 @@ EX void show_chaos() {
add_edit(horodisk_from); add_edit(horodisk_from);
else if(land_structure == lsChaosRW) else if(land_structure == lsChaosRW)
add_edit(randomwalk_size); add_edit(randomwalk_size);
else if(land_structure == lsLandscape)
add_edit(landscape_div);
else if(land_structure == lsCursedWalls)
add_edit(curse_percentage);
else else
dialog::addBreak(100); dialog::addBreak(100);
dialog::addBack(); dialog::addBack();
dialog::display(); 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() { EX void mode_higlights() {
cmode = sm::NOSCR; cmode = sm::NOSCR;
gamescreen(); gamescreen();
@ -685,6 +749,9 @@ EX void showChangeMode() {
multi::cpid = 0; multi::cpid = 0;
menuitem_land_structure('l'); 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::addBoolItem(XLAT("weapon selection"), bow::weapon, 'b');
dialog::add_action_push(bow::showMenu); dialog::add_action_push(bow::showMenu);
@ -722,7 +789,7 @@ EX void showChangeMode() {
#endif #endif
dialog::addBoolItem(XLAT("%1 Challenge", moPrincess), (princess::challenge), 'P'); dialog::addBoolItem(XLAT("%1 Challenge", moPrincess), (princess::challenge), 'P');
dialog::add_action_confirmed([] { dialog::add_action_confirmed([] {
if(!princess::everSaved) if(!princess::everSaved && !autocheat)
addMessage(XLAT("Save %the1 first to unlock this challenge!", moPrincess)); addMessage(XLAT("Save %the1 first to unlock this challenge!", moPrincess));
else restart_game(rg::princess); else restart_game(rg::princess);
}); });
@ -746,6 +813,8 @@ EX void showChangeMode() {
dialog::addBreak(50); dialog::addBreak(50);
dialog::addItem(XLAT("highlights & achievements"), 'h'); dialog::addItem(XLAT("highlights & achievements"), 'h');
dialog::add_action_push(mode_higlights); dialog::add_action_push(mode_higlights);
dialog::addItem(XLAT("custom mode manager"), 'm');
dialog::add_action_push(show_custom);
dialog::addBack(); dialog::addBack();
dialog::display(); dialog::display();
@ -947,7 +1016,7 @@ EX void showStartMenu() {
stop_game(); stop_game();
enable_canvas(); enable_canvas();
cheater = true; cheater = true;
patterns::canvasback = 0xFFFFFF; ccolor::set_plain(0xFFFFFF);
mapeditor::drawplayer = false; mapeditor::drawplayer = false;
start_game(); start_game();
clearMessages(); clearMessages();

View File

@ -919,14 +919,14 @@ EX namespace models {
#endif #endif
void add_model_config() { void add_model_config() {
addsaver(polygonal::SI, "polygon sides"); param_i(polygonal::SI, "polygon sides");
param_f(polygonal::STAR, "star", "polygon star factor"); param_f(polygonal::STAR, parameter_names("star", "polygon star factor"));
addsaver(polygonal::deg, "polygonal degree"); param_i(polygonal::deg, "polygonal degree");
addsaver(polygonal::maxcoef, "polynomial degree"); param_i(polygonal::maxcoef, "polynomial degree");
for(int i=0; i<polygonal::MSI; i++) { for(int i=0; i<polygonal::MSI; i++) {
addsaver(polygonal::coefr[i], "polynomial "+its(i)+".real"); param_f(polygonal::coefr[i], "polynomial "+its(i)+".real");
addsaver(polygonal::coefi[i], "polynomial "+its(i)+".imag"); param_f(polygonal::coefi[i], "polynomial "+its(i)+".imag");
} }
auto setrot = [] { auto setrot = [] {
@ -941,7 +941,7 @@ EX namespace models {
param_matrix(models::rotation.v3, "rotation3", 3)->editable("auto rotation in 3D", "", 'r')->set_extra(setrot); param_matrix(models::rotation.v3, "rotation3", 3)->editable("auto rotation in 3D", "", 'r')->set_extra(setrot);
param_i(models::do_rotate, "auto_rotation_mode", 1); param_i(models::do_rotate, "auto_rotation_mode", 1);
param_f(pconf.halfplane_scale, "hp", "halfplane scale", 1); param_f(pconf.halfplane_scale, parameter_names("hp", "halfplane scale"), 1);
auto add_all = [&] (projection_configuration& p, string pp, string sp) { auto add_all = [&] (projection_configuration& p, string pp, string sp) {
@ -949,8 +949,11 @@ EX namespace models {
dynamicval<function<bool()>> ds(auto_restrict); dynamicval<function<bool()>> ds(auto_restrict);
auto_restrict = [&p] { return &vpconf == &p; }; auto_restrict = [&p] { return &vpconf == &p; };
addsaverenum(p.model, pp+"used model", mdDisk); if(&p.model == &pmodel) {
if(&p.model == &pmodel) param_custom(pmodel, "projection|Poincare|Klein|half-plane|perspective", menuitem_projection, '1'); auto par = param_custom_int(pmodel, parameter_names(pp+"used_model", "used model"), menuitem_projection, '1');
par->help_text = "projection|Poincare|Klein|half-plane|perspective";
}
else param_enum(p.model, parameter_names(pp+"used_model", sp+"used model"), mdDisk);
param_matrix(p.mori().v2, pp+"mori", 2) param_matrix(p.mori().v2, pp+"mori", 2)
-> editable("model orientation", "", 'o'); -> editable("model orientation", "", 'o');
@ -960,32 +963,32 @@ EX namespace models {
param_f(p.top_z, sp+"topz", 5) param_f(p.top_z, sp+"topz", 5)
-> editable(1, 20, .25, "maximum z coordinate to show", "maximum z coordinate to show", 'l'); -> editable(1, 20, .25, "maximum z coordinate to show", "maximum z coordinate to show", 'l');
param_f(p.model_transition, pp+"mtrans", sp+"model transition", 1) param_f(p.model_transition, parameter_names(pp+"mtrans", sp+"model transition"), 1)
-> editable(0, 1, .1, "model transition", -> editable(0, 1, .1, "model transition",
"You can change this parameter for a transition from another model to this one.", 't'); "You can change this parameter for a transition from another model to this one.", 't');
param_f(p.rotational_nil, sp+"rotnil", 1); param_f(p.rotational_nil, sp+"rotnil", 1);
param_f(p.clip_min, pp+"clipmin", sp+"clip-min", rug ? -100 : -1); param_f(p.clip_min, parameter_names(pp+"clipmin", sp+"clip-min"), rug ? -100 : -1);
param_f(p.clip_max, pp+"clipmax", sp+"clip-max", rug ? +10 : +1); param_f(p.clip_max, parameter_names(pp+"clipmax", sp+"clip-max"), rug ? +10 : +1);
param_f(p.euclid_to_sphere, pp+"ets", sp+"euclid to sphere projection", 1.5) param_f(p.euclid_to_sphere, parameter_names(pp+"ets", sp+"euclid to sphere projection"), 1.5)
-> editable(1e-1, 10, .1, "ETS parameter", "Stereographic projection to a sphere. Choose the radius of the sphere.", 'l') -> editable(1e-1, 10, .1, "ETS parameter", "Stereographic projection to a sphere. Choose the radius of the sphere.", 'l')
-> set_sets(dialog::scaleLog); -> set_sets(dialog::scaleLog);
param_f(p.twopoint_param, pp+"twopoint", sp+"twopoint parameter", 1) param_f(p.twopoint_param, parameter_names(pp+"twopoint", sp+"twopoint parameter"), 1)
-> editable(1e-3, 10, .1, "two-point parameter", "In two-point-based models, this parameter gives the distance from each of the two points to the center.", 'b') -> editable(1e-3, 10, .1, "two-point parameter", "In two-point-based models, this parameter gives the distance from each of the two points to the center.", 'b')
-> set_sets(dialog::scaleLog); -> set_sets(dialog::scaleLog);
param_f(p.axial_angle, pp+"axial", sp+"axial angle", 90) param_f(p.axial_angle, parameter_names(pp+"axial", sp+"axial angle"), 90)
-> editable(1e-3, 10, .1, "angle between the axes", "In two-axe-based models, this parameter gives the angle between the two axes.", 'x') -> editable(1e-3, 10, .1, "angle between the axes", "In two-axe-based models, this parameter gives the angle between the two axes.", 'x')
-> set_sets(dialog::scaleLog); -> set_sets(dialog::scaleLog);
param_f(p.fisheye_param, pp+"fisheye", sp+"fisheye parameter", 1) param_f(p.fisheye_param, parameter_names(pp+"fisheye", sp+"fisheye parameter"), 1)
-> editable(1e-3, 10, .1, "fisheye parameter", "Size of the fish eye.", 'b') -> editable(1e-3, 10, .1, "fisheye parameter", "Size of the fish eye.", 'b')
-> set_sets(dialog::scaleLog); -> set_sets(dialog::scaleLog);
param_f(p.fisheye_alpha, pp+"fishalpha", sp+"off-center parameter", 0) param_f(p.fisheye_alpha, parameter_names(pp+"fishalpha", sp+"off-center parameter"), 0)
-> editable(1e-1, 10, .1, "off-center parameter", -> editable(1e-1, 10, .1, "off-center parameter",
"This projection is obtained by composing gnomonic projection and inverse stereographic projection. " "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 " "This parameter changes the center of the first projection (0 = gnomonic, 1 = stereographic). Use a value closer to 1 "
@ -999,9 +1002,9 @@ EX namespace models {
param_f(p.product_z_scale, pp+"zstretch") param_f(p.product_z_scale, pp+"zstretch")
-> editable(0.1, 10, 0.1, "product Z stretch", "", 'Z'); -> editable(0.1, 10, 0.1, "product Z stretch", "", 'Z');
param_f(p.collignon_parameter, pp+"collignon", sp+"collignon-parameter", 1) param_f(p.collignon_parameter, parameter_names(pp+"collignon", sp+"collignon-parameter"), 1)
-> editable(-1, 1, .1, "Collignon parameter", "", 'b') -> editable(-1, 1, .1, "Collignon parameter", "", 'b')
-> modif([] (float_setting* f) { -> modif([] (float_parameter* f) {
f->unit = vpconf.collignon_reflected ? " (r)" : ""; f->unit = vpconf.collignon_reflected ? " (r)" : "";
}) })
-> set_extra([&p] { -> set_extra([&p] {
@ -1044,9 +1047,9 @@ EX namespace models {
param_b(p.dualfocus_autoscale, sp+"dualfocus_autoscale", 0) param_b(p.dualfocus_autoscale, sp+"dualfocus_autoscale", 0)
-> editable("autoscale dual focus", 'A'); -> editable("autoscale dual focus", 'A');
addsaver(p.formula, sp+"formula"); param_str(p.formula, sp+"formula");
addsaverenum(p.basic_model, sp+"basic model"); param_enum(p.basic_model, sp+"basic model");
addsaver(p.use_atan, sp+"use_atan"); param_b(p.use_atan, sp+"use_atan");
param_f(p.spiral_angle, sp+"sang") param_f(p.spiral_angle, sp+"sang")
-> editable(0, 360, 15, "spiral angle", "set to 90° for the ring projection", 'x') -> editable(0, 360, 15, "spiral angle", "set to 90° for the ring projection", 'x')
@ -1062,11 +1065,13 @@ EX namespace models {
param_i(p.back_and_front, sp+"backandfront", 0); param_i(p.back_and_front, sp+"backandfront", 0);
auto projsaver = addsaver(p.alpha, sp+"projection", 1);
if(&p.model == &pmodel) { if(&p.model == &pmodel) {
auto proj = param_custom(p.alpha, sp+"projection", menuitem_projection_distance, 'p'); p.alpha = 1;
auto proj = param_custom_ld(p.alpha, sp+"projection", menuitem_projection_distance, 'p');
proj->help_text = "projection distance|Gans Klein Poincare orthographic stereographic"; proj->help_text = "projection distance|Gans Klein Poincare orthographic stereographic";
proj->saver = projsaver; }
else {
param_f(p.alpha, sp+"projection", 1);
} }
param_matrix(p.cam(), pp+"cameraangle", 3) param_matrix(p.cam(), pp+"cameraangle", 3)
@ -1093,16 +1098,16 @@ EX namespace models {
"(2) in hyperbolic geometry, with spiral angle being +90° or -90°\n" "(2) in hyperbolic geometry, with spiral angle being +90° or -90°\n"
"(3) in hyperbolic geometry, with other spiral angles (1 makes the bands fit exactly)"; "(3) in hyperbolic geometry, with other spiral angles (1 makes the bands fit exactly)";
param_f(p.sphere_spiral_multiplier, "sphere_spiral_multiplier") param_f(p.sphere_spiral_multiplier, pp+"sphere_spiral_multiplier")
-> editable(0, 10, .1, "sphere spiral multiplier", help, 'M')->unit = "°"; -> editable(0, 10, .1, "sphere spiral multiplier", help, 'M')->unit = "°";
param_f(p.right_spiral_multiplier, "right_spiral_multiplier") param_f(p.right_spiral_multiplier, pp+"right_spiral_multiplier")
-> editable(0, 10, .1, "right spiral multiplier", help, 'M')->unit = "°"; -> editable(0, 10, .1, "right spiral multiplier", help, 'M')->unit = "°";
param_f(p.any_spiral_multiplier, "any_spiral_multiplier") param_f(p.any_spiral_multiplier, pp+"any_spiral_multiplier")
-> editable(0, 10, .1, "any spiral multiplier", help, 'M')->unit = "°"; -> editable(0, 10, .1, "any spiral multiplier", help, 'M')->unit = "°";
param_f(p.spiral_cone, "spiral_cone") param_f(p.spiral_cone, pp+"spiral_cone")
-> editable(0, 360, -45, "spiral cone", "", 'C')->unit = "°"; -> editable(0, 360, -45, "spiral cone", "", 'C')->unit = "°";
}; };

View File

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

View File

@ -11,17 +11,18 @@ namespace hr {
EX namespace multi { EX namespace multi {
#if HDR #if HDR
static constexpr int SCANCODES = 512;
static constexpr int MAXJOY = 8; static constexpr int MAXJOY = 8;
static constexpr int MAXBUTTON = 64; static constexpr int MAXBUTTON = 64;
static constexpr int MAXAXE = 16; static constexpr int MAXAXE = 16;
static constexpr int MAXHAT = 4; static constexpr int MAXHAT = 4;
struct config { struct config {
char keyaction[512]; int keyaction[SCANCODES];
char joyaction[MAXJOY][MAXBUTTON]; int joyaction[MAXJOY][MAXBUTTON];
char axeaction[MAXJOY][MAXAXE]; int axeaction[MAXJOY][MAXAXE];
char hataction[MAXJOY][MAXHAT][4]; int hataction[MAXJOY][MAXHAT][4];
int deadzoneval[MAXJOY][MAXAXE]; int deadzoneval[MAXJOY][MAXAXE];
}; };
#endif #endif
@ -165,13 +166,13 @@ EX const char* axemodes3[4] = {
EX int centerplayer = -1; EX int centerplayer = -1;
char* axeconfigs[24]; int numaxeconfigs; int* axeconfigs[24]; int numaxeconfigs;
int* dzconfigs[24]; int* dzconfigs[24];
string listkeys(config& scfg, int id) { string listkeys(config& scfg, int id) {
#if CAP_SDL #if CAP_SDL
string lk = ""; string lk = "";
for(int i=0; i<512; i++) for(int i=0; i<SCANCODES; i++)
if(scfg.keyaction[i] == id) if(scfg.keyaction[i] == id)
#if CAP_SDL2 #if CAP_SDL2
lk = lk + " " + SDL_GetScancodeName(SDL_Scancode(i)); lk = lk + " " + SDL_GetScancodeName(SDL_Scancode(i));
@ -265,7 +266,8 @@ struct key_configurer {
if(!setwhat) dialog::handleNavigation(sym, uni); if(!setwhat) dialog::handleNavigation(sym, uni);
if(sym) { if(sym) {
if(setwhat) { 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; setwhat = 0;
} }
else if(uni >= 'a' && uni < 'a' + isize(shmupcmdtable) && shmupcmdtable[uni-'a'][0]) else if(uni >= 'a' && uni < 'a' + isize(shmupcmdtable) && shmupcmdtable[uni-'a'][0])
@ -584,9 +586,19 @@ void pressaction(int id) {
actionspressed[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) { EX bool notremapped(int sym) {
auto& scfg = scfg_default; 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; if(k == 0) return true;
k /= 16; k /= 16;
if(k > 3) k--; else if(k==3) k = 0; if(k > 3) k--; else if(k==3) k = 0;
@ -595,31 +607,31 @@ EX bool notremapped(int sym) {
EX void sconfig_savers(config& scfg, string prefix) { EX void sconfig_savers(config& scfg, string prefix) {
// unfortunately we cannot use key names here because SDL is not yet initialized // 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)); param_i(scfg.keyaction[i], prefix + string("key:")+its(i));
for(int i=0; i<MAXJOY; i++) { for(int i=0; i<MAXJOY; i++) {
string pre = prefix + "joystick "+cts('A'+i); string pre = prefix + "joystick "+cts('A'+i);
for(int j=0; j<MAXBUTTON; j++) for(int j=0; j<MAXBUTTON; j++)
addsaver(scfg.joyaction[i][j], pre+"-B"+its(j)); param_i(scfg.joyaction[i][j], pre+"-B"+its(j));
for(int j=0; j<MAXAXE; j++) { for(int j=0; j<MAXAXE; j++) {
addsaver(scfg.axeaction[i][j], pre+" axis "+its(j)); param_i(scfg.axeaction[i][j], pre+" axis "+its(j));
addsaver(scfg.deadzoneval[i][j], pre+" deadzone "+its(j)); param_i(scfg.deadzoneval[i][j], pre+" deadzone "+its(j));
} }
for(int j=0; j<MAXHAT; j++) for(int k=0; k<4; k++) { for(int j=0; j<MAXHAT; j++) for(int k=0; k<4; k++) {
addsaver(scfg.hataction[i][j][k], pre+" hat "+its(j)+" "+"URDL"[k]); param_i(scfg.hataction[i][j][k], pre+" hat "+its(j)+" "+"URDL"[k]);
} }
} }
} }
EX void clear_config(config& scfg) { 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() { EX void initConfig() {
auto& scfg = scfg_default; auto& scfg = scfg_default;
char* t = scfg.keyaction; int* t = scfg.keyaction;
#if CAP_SDL2 #if CAP_SDL2
@ -754,7 +766,7 @@ EX void initConfig() {
multi::scs[6].uicolor = 0xC0C0C0FF; multi::scs[6].uicolor = 0xC0C0C0FF;
#if CAP_CONFIG #if CAP_CONFIG
addsaver(multi::players, "mode-number of players"); param_i(multi::players, "mode-number of players")->be_non_editable();
param_b(multi::split_screen, "splitscreen", false) param_b(multi::split_screen, "splitscreen", false)
->editable("split screen mode", 's'); ->editable("split screen mode", 's');
param_b(multi::pvp_mode, "pvp_mode", false) param_b(multi::pvp_mode, "pvp_mode", false)
@ -765,9 +777,9 @@ EX void initConfig() {
->editable("self hits", 'h'); ->editable("self hits", 'h');
param_b(multi::two_focus, "two_focus", false) param_b(multi::two_focus, "two_focus", false)
->editable("auto-adjust dual-focus projections", 'f'); ->editable("auto-adjust dual-focus projections", 'f');
addsaver(alwaysuse, "use configured keys"); param_b(alwaysuse, "use configured keys");
for(int i=0; i<7; i++) addsaver(multi::scs[i], "player"+its(i)); for(int i=0; i<7; i++) paramset(multi::scs[i], "player"+its(i));
sconfig_savers(scfg, ""); sconfig_savers(scfg, "");
#endif #endif
@ -821,7 +833,8 @@ EX void handleInput(int delta, config &scfg) {
get_actions(scfg); get_actions(scfg);
const Uint8 *keystate = SDL12_GetKeyState(NULL); 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 = double panx =
actionspressed[49] - actionspressed[51] + axespressed[2] / 32000.0; actionspressed[49] - actionspressed[51] + axespressed[2] / 32000.0;

View File

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

View File

@ -1360,6 +1360,7 @@ EX namespace hybrid {
cell* gamestart() override { return getCell(underlying_map->gamestart(), 0); } cell* gamestart() override { return getCell(underlying_map->gamestart(), 0); }
hrmap_hybrid() { hrmap_hybrid() {
underlying_map = nullptr;
twisted = false; twisted = false;
disc_quotient = 0; disc_quotient = 0;
in_underlying([this] { initcells(); underlying_map = currentmap; }); in_underlying([this] { initcells(); underlying_map = currentmap; });
@ -2358,7 +2359,7 @@ EX namespace rots {
ptds.clear(); ptds.clear();
drawthemap(); drawthemap();
drawqueue(); drawqueue();
displaychr(current_display->xcenter, current_display->ycenter, 0, 24, '+', 0xFFFFFFFF); displaychr(current_display->xcenter, current_display->ycenter, 0, 24 * mapfontscale / 100, '+', 0xFFFFFFFF);
glflush(); glflush();
}); });
gmatrix = std::move(g); gmatrix = std::move(g);

View File

@ -664,7 +664,7 @@ EX void teleportTo(cell *dest) {
} }
/* calls changes.rollback or changes.commit */ /* 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"); if(byWhat != itStrongWind) playSound(dest, "orb-frog");
cell *from = cwt.at; cell *from = cwt.at;
changes.value_keep(cwt); changes.value_keep(cwt);
@ -683,7 +683,10 @@ EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMons
if(byWhat == itOrbPhasing) { if(byWhat == itOrbPhasing) {
useupOrb(itOrbPhasing, 5); 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); movecost(from, dest, 1);
@ -822,7 +825,14 @@ void telekinesis(cell *dest) {
} }
moveItem(dest, cwt.at, true); moveItem(dest, cwt.at, true);
eItem it = cwt.at->item;
bool saf = it == itOrbSafety;
collectItem(cwt.at, cwt.at, true); 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); useupOrb(itOrbSpace, cost.first);
if(cost.second) if(cost.second)
markOrb(itOrbMagnetism); markOrb(itOrbMagnetism);
@ -874,6 +884,10 @@ EX eMonster summonedAt(cell *dest) {
dest->land == laWarpCoast ? moRatling : dest->land == laWarpCoast ? moRatling :
dest->land == laDocks ? moWaterElemental : dest->land == laDocks ? moWaterElemental :
moPirate; moPirate;
if(among(dest->wall, waDeepWater, waShallow))
return moRusalka;
if(dest->wall == waCamelotMoat)
return moWaterElemental;
if(isReptile(dest->wall)) if(isReptile(dest->wall))
return moReptile; return moReptile;
if(dest->wall == waChasm) if(dest->wall == waChasm)
@ -1136,8 +1150,10 @@ void blowoff(const movei& mi) {
auto& ct = mi.t; auto& ct = mi.t;
bool die = cf->wall == waRichDie; bool die = cf->wall == waRichDie;
playSound(ct, "orb-ranged"); playSound(ct, "orb-ranged");
if(cf->monst) if(cf->monst == moVoidBeast)
addMessage(XLAT("You blow %the1 away!", cf->monst)); 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(cf->wall == waThumperOff) activateActiv(cf, false);
if(isPushable(cf->wall) || cf->wall == waBigStatue) if(isPushable(cf->wall) || cf->wall == waBigStatue)
pushThumper(mi); pushThumper(mi);
@ -1205,9 +1221,9 @@ EX bool monstersnearO(orbAction a, cell *c) {
EX bool isCheck(orbAction a) { return a == roCheck || a == roMultiCheck; } EX bool isCheck(orbAction a) { return a == roCheck || a == roMultiCheck; }
EX bool isWeakCheck(orbAction a) { return a == roCheck || a == roMultiCheck || a == roMouse; } 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; 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++) { if(d<c->type) for(int e=d; e<d+c->type; e++) {
int di = e % c->type; int di = e % c->type;
cell *c2 = c->move(di); cell *c2 = c->move(di);
@ -1215,11 +1231,16 @@ EX movei blowoff_destination(cell *c, int& di) {
if(dice::on(c) && !dice::can_roll(movei(c, di))) if(dice::on(c) && !dice::can_roll(movei(c, di)))
continue; continue;
#endif #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); 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) { EX int check_jump(cell *cf, cell *ct, flagtype flags, cell*& jumpthru) {
int partial = 1; int partial = 1;
forCellCM(c2, cf) { forCellCM(c2, cf) {
@ -1510,7 +1531,7 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
} }
if(phasestate == 3) { 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 wouldkill_there = true;
} }
else changes.rollback(); 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(airdist(w) < 3) return false;
if(againstWind(w,from)) return false; if(againstWind(w,from)) return false;
if(isGravityLand(w)) return false; if(isGravityLand(w)) return false;
if(w->wall == waChasm && w->land == laDual) return false;
} }
if(from && strictlyAgainstGravity(w, from, vrevdir, flags) if(from && strictlyAgainstGravity(w, from, vrevdir, flags)
@ -258,7 +259,8 @@ EX bool passable(cell *w, cell *from, flagtype flags) {
} }
if(isWatery(w)) { 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) && else if(from && from->wall == waBoat && F(P_USEBOAT) &&
(!againstCurrent(w, from) || F(P_MARKWATER)) && !(from->item == itOrbYendor)) ; (!againstCurrent(w, from) || F(P_MARKWATER)) && !(from->item == itOrbYendor)) ;
else if(from && isWatery(from) && F(P_CHAIN) && F(P_USEBOAT) && !againstCurrent(w, from)) ; 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) { 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; eWall x = mi.t->wall; mi.t->wall = mi.s->wall; mi.s->wall = x;
mi.t->mondir = mi.rev_dir_or(NODIR); mi.t->mondir = mi.rev_dir_or(NODIR);
moveItem(mi.s, mi.t, false); moveItem(mi.s, mi.t, false);

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,8 @@
namespace hr { namespace hr {
EX int illegal_moves;
EX bool keepLightning = false; EX bool keepLightning = false;
EX bool seenSevenMines = false; EX bool seenSevenMines = false;
@ -198,6 +200,7 @@ bool pcmove::checkNeedMove(bool checkonly, bool attacking) {
yasc_message = XLAT("did not leave %the1", cwt.at->wall); yasc_message = XLAT("did not leave %the1", cwt.at->wall);
killHardcorePlayer(multi::cpid, flags); killHardcorePlayer(multi::cpid, flags);
} }
if(!checkonly) illegal_moves++;
return true; return true;
} }
@ -214,6 +217,7 @@ struct pcmove {
bool fmsMove, fmsAttack, fmsActivate; bool fmsMove, fmsAttack, fmsActivate;
int d; int d;
int subdir; 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 boatmove;
bool good_tortoise; bool good_tortoise;
flagtype attackflags; flagtype attackflags;
@ -443,6 +447,8 @@ bool pcmove::movepcto() {
} }
} }
} }
if(checked_move_issue.type == miTHREAT && !checkonly) illegal_moves++;
} }
return b; return b;
@ -489,7 +495,7 @@ bool pcmove::swing() {
mirror::act(origd, mirror::SPINMULTI | mirror::ATTACK); mirror::act(origd, mirror::SPINMULTI | mirror::ATTACK);
if(monstersnear_add_pmi(movei(cwt.at, STAY))) { if(monstersnear_add_pmi(movei(cwt.at, STAY))) {
if(vmsg_threat()) if(nextmovetype == lmAttack ? vmsg(miWALL, siWALL, mi.t, who_kills_me) : vmsg_threat())
wouldkill("You would be killed by %the1!"); wouldkill("You would be killed by %the1!");
return false; return false;
} }
@ -802,6 +808,16 @@ bool pcmove::actual_move() {
c2->monst = moNone; c2->monst = moNone;
c2->wall = waRichDie; 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 #endif
@ -834,13 +850,10 @@ bool pcmove::actual_move() {
return boat_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->monst && cwt.at->wall == waBoat && cwt.at->item != itOrbYendor && boatGoesThrough(c2) && markOrb(itOrbWater) && !nonAdjacentPlayer(c2, cwt.at) && fmsMove) {
if(c2->item && collectItem(c2, cwt.at)) return true;
if(c2->item && !cwt.at->item) moveItem(c2, cwt.at, false), boatmove = true;
placeWater(c2, cwt.at);
moveBoat(mi);
changes.ccell(c2); changes.ccell(c2);
c2->mondir = revhint(cwt.at, d); placeWater(c2, cwt.at);
if(c2->item) boatmove = !boatmove; moveBoat(mi); boatmove = true;
return perform_actual_move(); return perform_actual_move();
} }
@ -921,8 +934,6 @@ void pcmove::tell_why_cannot_attack() {
addMessage(XLAT("You cannot attack Raiders directly!")); addMessage(XLAT("You cannot attack Raiders directly!"));
else if(isSwitch(c2->monst)) else if(isSwitch(c2->monst))
addMessage(XLAT("You cannot attack Jellies in their wall form!")); 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) else if(c2->monst == moAngryDie)
addMessage(XLAT("This die is really angry at you!")); addMessage(XLAT("This die is really angry at you!"));
else if((attackflags & AF_WEAK) && isIvy(c2)) else if((attackflags & AF_WEAK) && isIvy(c2))
@ -1285,21 +1296,15 @@ bool pcmove::perform_actual_move() {
handle_friendly_ivy(); handle_friendly_ivy();
if(items[itOrbDigging]) { if(items[itOrbDigging]) {
invismove = false; if(earthMove(mi)) {
if(earthMove(mi)) markOrb(itOrbDigging); invismove = false;
markOrb(itOrbDigging);
}
} }
movecost(cwt.at, c2, 1); movecost(cwt.at, c2, 1);
if(!boatmove && collectItem(c2, cwt.at)) return true; 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(doPickupItemsWithMagnetism(c2)) return true;
if(isIcyLand(cwt.at) && cwt.at->wall == waNone && markOrb(itOrbWinter)) { if(isIcyLand(cwt.at) && cwt.at->wall == waNone && markOrb(itOrbWinter)) {
@ -1311,7 +1316,11 @@ bool pcmove::perform_actual_move() {
forCellEx(c3, c2) if(c3->wall == waIcewall && c3->item) { forCellEx(c3, c2) if(c3->wall == waIcewall && c3->item) {
changes.ccell(c3); changes.ccell(c3);
markOrb(itOrbWinter); 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); movecost(cwt.at, c2, 2);

View File

@ -26,12 +26,27 @@ EX int getgametime() {
return (int) (savetime + (timerstopped ? 0 : (time(NULL) - timerstart))); return (int) (savetime + (timerstopped ? 0 : (time(NULL) - timerstart)));
} }
EX ld getgametime_precise() {
return savetime + (timerstopped ? 0 : (ticks - tickstart) / 1000.);
}
EX string getgametime_s(int timespent IS(getgametime())) { EX string getgametime_s(int timespent IS(getgametime())) {
return hr::format("%d:%02d", timespent/60, timespent % 60); return hr::format("%d:%02d", timespent/60, timespent % 60);
} }
EX bool display_yasc_codes; 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 timeline() {
string s; string s;
if(shmup::on) if(shmup::on)
@ -39,7 +54,7 @@ string timeline() {
else { else {
s = XLAT("%1 turns (%2)", its(turncount), getgametime_s()); s = XLAT("%1 turns (%2)", its(turncount), getgametime_s());
if(display_yasc_codes) if(display_yasc_codes)
s+= XLAT(" YASC code: ") + its(yasc_code); s += XLAT(" YASC code: ") + formatted_yasc_code();
} }
return s; return s;
} }
@ -321,7 +336,7 @@ EX void showGameMenu() {
#if CAP_TOUR #if CAP_TOUR
tour::on ? (canmove ? XLAT("guided tour") : XLAT("GAME OVER")) : tour::on ? (canmove ? XLAT("guided tour") : XLAT("GAME OVER")) :
#endif #endif
(cheater && !autocheat)? XLAT("It is a shame to cheat!") : (cheater && !autocheat) ? XLAT("It is a shame to cheat!") :
racing::on ? "racing mode" : racing::on ? "racing mode" :
(canmove && princess::challenge) ? XLAT("%1 Challenge", moPrincess) : (canmove && princess::challenge) ? XLAT("%1 Challenge", moPrincess) :
canmove ? XLAT("Quest status") : canmove ? XLAT("Quest status") :
@ -434,7 +449,7 @@ EX void showGameMenu() {
if(cheater && !autocheat) { if(cheater && !autocheat) {
dialog::addInfo(XLAT("you have cheated %1 times", its(cheater)), 0xFF2020); dialog::addInfo(XLAT("you have cheated %1 times", its(cheater)), 0xFF2020);
} }
else if(!racing::on) { if(!racing::on) {
dialog::addInfo(timeline(), dialog::dialogcolor); dialog::addInfo(timeline(), dialog::dialogcolor);
} }
@ -639,7 +654,8 @@ EX void handleKeyQuit(int sym, int uni) {
popScreen(); popScreen();
msgs.clear(); msgs.clear();
if(!canmove) { if(!canmove) {
addMessage(XLAT("GAME OVER")); if(yasc_message != "") addMessage(XLAT("GAME OVER") + ": " + yasc_message);
else addMessage(XLAT("GAME OVER"));
addMessage(timeline()); addMessage(timeline());
} }
} }

View File

@ -1039,10 +1039,15 @@ void race_projection() {
if(GDIM == 2) { if(GDIM == 2) {
dialog::addMatrixItem(XLAT("race angle"), race_angle.get(), 'a'); dialog::addMatrixItem(XLAT("race angle"), race_angle.get(), 'a');
dialog::add_action([] () { 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 q = rot_inverse(race_angle) * pconf.mori();
auto last = dialog::get_ne().reaction; auto last = d.reaction;
dialog::get_ne().reaction = [q, last] () { last(); pconf.mori() = race_angle * q; }; 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 { namespace hr {
#if MAXMDIM >= 4 #if MAXMDIM >= 4
pair<bool, hyperpoint> makeradar(shiftpoint h) { pair<bool, hyperpoint> makeradar(shiftpoint h, bool distant) {
hyperpoint h1; hyperpoint h1;
@ -23,8 +23,13 @@ pair<bool, hyperpoint> makeradar(shiftpoint h) {
if(WDIM == 3) { if(WDIM == 3) {
ld d = hdist0(h); ld d = hdist0(h);
if(d >= vid.radarrange) return {false, h1}; if(distant) {
if(d) h1 = h1 * (d / vid.radarrange / hypot_d(3, h1)); 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 { else {
h1 = cgi.emb->actual_to_base(h1); h1 = cgi.emb->actual_to_base(h1);
@ -45,16 +50,16 @@ pair<bool, hyperpoint> makeradar(shiftpoint h) {
return {true, h1}; 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(); shiftpoint h = V * tile_center();
auto hp = makeradar(h); auto hp = makeradar(h, distant);
if(hp.first) if(hp.first)
current_display->radarpoints.emplace_back(radarpoint{hp.second, ch, col, outline}); current_display->radarpoints.emplace_back(radarpoint{hp.second, ch, col, outline});
} }
EX void addradar(const shiftpoint h1, const shiftpoint h2, color_t col) { EX void addradar(const shiftpoint h1, const shiftpoint h2, color_t col) {
auto hp1 = makeradar(h1); auto hp1 = makeradar(h1, false);
auto hp2 = makeradar(h2); auto hp2 = makeradar(h2, false);
if(hp1.first && hp2.first) if(hp1.first && hp2.first)
current_display->radarlines.emplace_back(radarline{hp1.second, hp2.second, col}); 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) { auto compassdir = [&] (char dirname, hyperpoint h) {
h = NLP * h * .8; 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); 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('E', point3(+1, 0, 0));
compassdir('N', point3(0, +1, 0)); compassdir('N', point3(0, +1, 0));
@ -180,10 +185,10 @@ EX void draw_radar(bool cornermode) {
glflush(); glflush();
for(auto& r: cd->radarpoints) { 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 { else {
hyperpoint h = locate(r.h); 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 #endif

View File

@ -3164,10 +3164,10 @@ void addconfig() {
param_f(hard_limit, "ray_hard_limit"); param_f(hard_limit, "ray_hard_limit");
param_i(want_use, "ray_want_use"); param_i(want_use, "ray_want_use");
param_f(exp_decay_poly, "ray_exp_decay_poly"); param_f(exp_decay_poly, "ray_exp_decay_poly");
addsaver(max_iter_iso, "ray_max_iter_iso"); param_i(max_iter_iso, "ray_max_iter_iso");
addsaver(max_iter_sol, "ray_max_iter_sol"); param_i(max_iter_sol, "ray_max_iter_sol");
param_i(max_cells, "ray_max_cells"); param_i(max_cells, "ray_max_cells");
addsaver(rays_generate, "ray_generate"); param_b(rays_generate, "ray_generate");
param_b(fixed_map, "ray_fixed_map"); param_b(fixed_map, "ray_fixed_map");
param_i(max_wall_offset, "max_wall_offset"); param_i(max_wall_offset, "max_wall_offset");
param_i(max_celltype, "max_celltype"); param_i(max_celltype, "max_celltype");

View File

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

View File

@ -45,7 +45,7 @@ namespace hr {
namespace ads_game { namespace ads_game {
void change_default_key(int key, int val) { void change_default_key(int key, int val) {
char* t = scfg_ads.keyaction; int* t = scfg_ads.keyaction;
t[key] = val; t[key] = val;
} }
@ -154,8 +154,8 @@ void default_settings() {
lps_add(lps_relhell, vid.drawmousecircle, false); lps_add(lps_relhell, vid.drawmousecircle, false);
lps_add(lps_relhell, draw_centerover, false); lps_add(lps_relhell, draw_centerover, false);
lps_add(lps_relhell, vid.axes3, false); lps_add(lps_relhell, vid.axes3, false);
lps_add(lps_relhell, patterns::whichCanvas, 'r'); lps_add(lps_relhell, ccolor::which, &ccolor::random);
lps_add(lps_relhell, patterns::rwalls, 0); lps_add(lps_relhell, ccolor::rwalls, 0);
lps_add(lps_relhell, vid.fov, 150.); lps_add(lps_relhell, vid.fov, 150.);
lps_add(lps_relhell_ds_spacetime_klein, pmodel, mdDisk); lps_add(lps_relhell_ds_spacetime_klein, pmodel, mdDisk);
@ -213,7 +213,7 @@ auto shot_hooks =
+ addHook(hooks_configfile, 100, [] { + addHook(hooks_configfile, 100, [] {
param_f(ads_how_much_invincibility, "ads_invinc") param_f(ads_how_much_invincibility, "ads_invinc")
-> editable(0, TAU, TAU/4, "AdS invincibility time", "How long does the period of invincibility after crashing last, in absolute units.", 'i'); -> editable(0, TAU, TAU/4, "AdS invincibility time", "How long does the period of invincibility after crashing last, in absolute units.", 'i');
param_f(ds_how_much_invincibility, "ads_invinc") param_f(ds_how_much_invincibility, "ds_invinc")
-> editable(0, TAU, TAU/4, "dS invincibility time", "How long does the period of invincibility after crashing last, in absolute units.", 'i'); -> editable(0, TAU, TAU/4, "dS invincibility time", "How long does the period of invincibility after crashing last, in absolute units.", 'i');
param_b(auto_angle, "ads_auto_angle") param_b(auto_angle, "ads_auto_angle")
-> editable("automatically rotate the projection", 'a'); -> editable("automatically rotate the projection", 'a');
@ -287,7 +287,7 @@ auto shot_hooks =
param_i(spacetime_qty, "ads_spacetime_qty") param_i(spacetime_qty, "ads_spacetime_qty")
-> editable(0, 100, 5, "step quantity in the spacetime display", "", 'q'); -> editable(0, 100, 5, "step quantity in the spacetime display", "", 'q');
addsaver(ghost_color, "color:ghost"); param_color(ghost_color, "color:ghost", true);
rsrc_config(); rsrc_config();
}); });

View File

@ -82,7 +82,7 @@ void fire() {
bool handleKey(int sym, int uni) { bool handleKey(int sym, int uni) {
if(cmode & sm::NORMAL) { if(cmode & sm::NORMAL) {
char* t = scfg_ads.keyaction; int* t = scfg_ads.keyaction;
if(t[sym] >= 16 && t[sym] < 32) return true; if(t[sym] >= 16 && t[sym] < 32) return true;
if(sym == 'v') pushScreen(game_menu); if(sym == 'v') pushScreen(game_menu);
if(sym == SDLK_ESCAPE) pushScreen(game_menu); if(sym == SDLK_ESCAPE) pushScreen(game_menu);
@ -159,7 +159,7 @@ bool ads_turn(int idelta) {
if(a[16+7] && !la[16+7]) auto_rotate = !auto_rotate; if(a[16+7] && !la[16+7]) auto_rotate = !auto_rotate;
if(a[16+8] && !la[16+8]) pushScreen(game_menu); if(a[16+8] && !la[16+8]) pushScreen(game_menu);
if(auto_angle) pconf.model_orientation += ang; if(auto_angle) pconf.mori().get() = spin(ang) * pconf.mori().get();
if(true) { if(true) {
@ -219,7 +219,7 @@ bool ads_turn(int idelta) {
else view_pt += tc; else view_pt += tc;
} }
if(auto_angle) pconf.model_orientation -= ang; if(auto_angle) pconf.mori().get() = spin(-ang) * pconf.mori().get();
fixmatrix_ads(current.T); fixmatrix_ads(current.T);
fixmatrix_ads(new_vctrV.T); fixmatrix_ads(new_vctrV.T);

View File

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

View File

@ -1296,14 +1296,14 @@ void visual_menu() {
dialog::addSelItem(XLAT("iterations in raycasting"), its(ray::max_iter_current()), 's'); dialog::addSelItem(XLAT("iterations in raycasting"), its(ray::max_iter_current()), 's');
dialog::add_action([&] { dialog::add_action([&] {
dialog::editNumber(ray::max_iter_current(), 0, 600, 1, 60, XLAT("iterations in raycasting"), ""); auto& di = dialog::editNumber(ray::max_iter_current(), 0, 600, 1, 60, XLAT("iterations in raycasting"), "");
dialog::reaction = ray::reset_raycaster; di.reaction = ray::reset_raycaster;
}); });
dialog::addSelItem(XLAT("reflective walls in raycasting"), fts(ray::reflect_val), 'R'); dialog::addSelItem(XLAT("reflective walls in raycasting"), fts(ray::reflect_val), 'R');
dialog::add_action([&] { dialog::add_action([&] {
dialog::editNumber(ray::reflect_val, 0, 1, 0.1, 0, XLAT("reflective walls"), ""); auto& di = dialog::editNumber(ray::reflect_val, 0, 1, 0.1, 0, XLAT("reflective walls"), "");
dialog::reaction = ray::reset_raycaster; di.reaction = ray::reset_raycaster;
}); });
dialog::addSelItem(XLAT("cells to draw per level"), its(draw_per_level), 'R'); dialog::addSelItem(XLAT("cells to draw per level"), its(draw_per_level), 'R');
@ -2032,7 +2032,7 @@ int args() {
} }
void change_default_key(int key, int val) { void change_default_key(int key, int val) {
char* t = scfg_bringris.keyaction; int* t = scfg_bringris.keyaction;
t[key] = val; t[key] = val;
} }

View File

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

View File

@ -342,7 +342,7 @@ void compute_betweenness(bool verify) {
auto b = betweenness3(c1); auto b = betweenness3(c1);
// add_to_set(c1, 1, 0); // add_to_set(c1, 1, 0);
auto b4 = betweenness4(c1); 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) { if(verify) {
/* /*
betweenness_type a = b.first; betweenness_type a = b.first;

View File

@ -86,7 +86,8 @@ int movearound() {
int move_restart() { int move_restart() {
indenter_finish im("move_restart"); indenter_finish im("move_restart");
ld llo = loglik_chosen(); 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 moves = 0;
// int im = 0; // int im = 0;
@ -319,7 +320,7 @@ void load_embedded(const string s) {
while(true) { while(true) {
char who[500], where[500]; char who[500], where[500];
who[0] = 0; 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(who[0] == 0) break;
if(!ids.count(who)) printf("unknown vertex: %s\n", who); if(!ids.count(who)) printf("unknown vertex: %s\n", who);
string wh = where; string wh = where;

View File

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

View File

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

View File

@ -35,6 +35,9 @@ struct embset {
string name; string name;
geom3::eSpatialEmbedding se; geom3::eSpatialEmbedding se;
ld walls, scale, depth, eye, sun, sky, star; 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() { 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, "}"); 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 edefault = embset("default", geom3::seDefault, 1.2, 0, 0, 1.5, 0.333333, 10, 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 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", .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 eincyl = embset("in cylinder E", geom3::seCylinderE, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 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 eoutcyl = embset("out cylinder E", geom3::seCylinderE, -1.2, M_PI/10, 0, 1.5, 0.3, 10, 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 eouthoro = embset("out horosphere", geom3::seLowerCurvature, 1.2, 0.1, 0, 1.5, 0.25, 8, 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 = embset("in horosphere", geom3::seLowerCurvature, -1.2, 0.1, 0, 1.5, 0.25, 12, 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 einhoro_small = embset("in horosphere (small sky)", geom3::seLowerCurvature, -1.2, 0.1, 0, 1.5, 0.25, 18, 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 esolv = embset("solv", geom3::seSol, 1.2, 0.1, 0, 1.5, 0.25, 12, 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 einnih = embset("in NIH", geom3::seNIH, -1.2, 0.1, 0, 1.5, 0.25, 12, 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 eoutnih = embset("out NIH", geom3::seNIH, 1.2, 0.1, 0, 1.5, 0.25, 8, 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 eclifford = embset("Clifford", geom3::seCliffordTorus, 1.2, M_PI/10, -0.0561826, 1.5, 0.25, 2.55, 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 enil = embset("Nil flat", geom3::seNil, 1.2, 0.1, 0, 1.5, 0.25, 12, 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 esl2 = embset("SL(2,R) flat", geom3::seSL2, 1.2, 0.1, 0, 1.5, 0.25, 12, 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 eincylh = embset("in cylinderH", geom3::seCylinderH, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 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 eincylhe = embset("in cylinderHE", geom3::seCylinderHE, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 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 eincylnil = embset("in cylinder Nil", geom3::seCylinderNil, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 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 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{.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 einhorocyl = embset("in horocylinder", geom3::seCylinderHoro, -1.2, M_PI/10, 0, 1.5, 0.10472, 8, 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 eouthorocyl = embset("out horocylinder", geom3::seCylinderHoro, 1.2, M_PI/10, 0, 1.5, 0.10472, 4, 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_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{.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 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{.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_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{.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 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; } embset& edok() { return vid.wall_height > 0 ? edefault : edefaulti; }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -248,7 +248,7 @@ void run() {
dialog::add_key_action(PSEUDOKEY_SIM, toggle_replay); dialog::add_key_action(PSEUDOKEY_SIM, toggle_replay);
dialog::display(); dialog::display();
char* t = scfg_nilrider.keyaction; int* t = scfg_nilrider.keyaction;
for(int i=1; i<512; i++) { for(int i=1; i<512; i++) {
auto& ka = dialog::key_actions; auto& ka = dialog::key_actions;
if(t[i] == 16+5) ka[i] = ka[PSEUDOKEY_PAUSE]; if(t[i] == 16+5) ka[i] = ka[PSEUDOKEY_PAUSE];
@ -544,7 +544,7 @@ void main_menu() {
bool on; bool on;
void change_default_key(int key, int val) { void change_default_key(int key, int val) {
char* t = scfg_nilrider.keyaction; int* t = scfg_nilrider.keyaction;
t[key] = val; t[key] = val;
} }
@ -585,12 +585,13 @@ local_parameter_set lps_nilrider("nilrider:");
void default_settings() { void default_settings() {
lps_add(lps_nilrider, vid.cells_drawn_limit, 1); lps_add(lps_nilrider, vid.cells_drawn_limit, 1);
lps_add(lps_nilrider, (color_t&) patterns::canvasback, 0); lps_add(lps_nilrider, ccolor::plain.ctab, colortable{0});
lps_add(lps_nilrider, smooth_scrolling, true); lps_add(lps_nilrider, smooth_scrolling, true);
lps_add(lps_nilrider, mapeditor::drawplayer, false); lps_add(lps_nilrider, mapeditor::drawplayer, false);
lps_add(lps_nilrider, backcolor, 0xC0C0FFFF); lps_add(lps_nilrider, backcolor, 0xC0C0FFFF);
lps_add(lps_nilrider, logfog, 1); lps_add(lps_nilrider, logfog, 1);
lps_add(lps_nilrider, patterns::whichCanvas, 0); lps_add(lps_nilrider, ccolor::which, &ccolor::plain);
lps_add(lps_nilrider, ccolor::rwalls, 0);
#if CAP_VR #if CAP_VR
lps_add(lps_nilrider, vrhr::hsm, vrhr::eHeadset::reference); lps_add(lps_nilrider, vrhr::hsm, vrhr::eHeadset::reference);
@ -611,10 +612,10 @@ void initialize() {
curlev->init(); curlev->init();
param_enum(planning_mode, "nil_planning", "nil_planning", false) param_enum(planning_mode, "nil_planning", false)
-> editable({{"manual", "control the unicycle manually"}, {"planning", "try to plan the optimal route!"}}, "game mode", 'p'); -> editable({{"manual", "control the unicycle manually"}, {"planning", "try to plan the optimal route!"}}, "game mode", 'p');
param_enum(stepped_display, "stepped_display", "stepped_display", false) param_enum(stepped_display, "stepped_display", false)
-> editable({{"smooth", "ride on a smooth surface"}, {"blocky", "makes slopes more visible -- actual physics are not affected"}}, "game mode", 's'); -> editable({{"smooth", "ride on a smooth surface"}, {"blocky", "makes slopes more visible -- actual physics are not affected"}}, "game mode", 's');
param_i(nilrider_tempo, "nilrider_tempo"); param_i(nilrider_tempo, "nilrider_tempo");

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -85,6 +85,9 @@ static constexpr flagtype w_less_smart_advance = Flag(23); /*< stop early when e
static constexpr flagtype w_no_queued_extensions = Flag(24); /*< consider extensions one by one */ static constexpr flagtype w_no_queued_extensions = Flag(24); /*< consider extensions one by one */
static constexpr flagtype w_no_branch_skipping = Flag(24); /*< do not skip branches */ static constexpr flagtype w_no_branch_skipping = Flag(24); /*< do not skip branches */
/* extra */
static constexpr flagtype w_optimize2 = Flag(25); /*< optimize in 2D */
/* for 3D honeycombs */ /* for 3D honeycombs */
static constexpr flagtype w_skip_transducers = Flag(32); /*< skip the transducer test */ static constexpr flagtype w_skip_transducers = Flag(32); /*< skip the transducer test */
static constexpr flagtype w_skip_transducer_loops = Flag(33); /*< skip loops during the transducer test */ static constexpr flagtype w_skip_transducer_loops = Flag(33); /*< skip loops during the transducer test */
@ -1563,6 +1566,7 @@ void minimize_rules() {
int new_ids = 0; int new_ids = 0;
for(int id=0; id<next_id; id++) { for(int id=0; id<next_id; id++) {
if(treestates[id].giver.at == nullptr) { new_id[id] = new_ids++; println(hlog, "no giver in minimize_rules for state ", id); continue; }
auto aid = get_aid(treestates[id].giver); auto aid = get_aid(treestates[id].giver);
if(!new_id_of.count(aid)) new_id_of[aid] = new_ids++; if(!new_id_of.count(aid)) new_id_of[aid] = new_ids++;
@ -2001,6 +2005,8 @@ EX void rules_iteration() {
if(examine_branch(id, fb, sb)) checks_to_skip.insert(b); if(examine_branch(id, fb, sb)) checks_to_skip.insert(b);
}; };
if(WDIM == 2 && (flags & w_optimize2)) optimize();
if(WDIM == 2) for(int id=0; id<isize(treestates); id++) if(treestates[id].is_live) { if(WDIM == 2) for(int id=0; id<isize(treestates); id++) if(treestates[id].is_live) {
auto r = treestates[id].rules; /* no & because treestates might have moved */ auto r = treestates[id].rules; /* no & because treestates might have moved */
if(r.empty()) continue; if(r.empty()) continue;
@ -2590,11 +2596,18 @@ EX void show() {
dialog::addBoolItem(XLAT("in tes internal format"), arb::in(), 't'); dialog::addBoolItem(XLAT("in tes internal format"), arb::in(), 't');
dialog::add_action([] { dialog::add_action([] {
if(!arb::in()) { if(!arb::in()) {
arb::convert::convert(); try {
arb::convert::activate(); arb::convert::convert();
start_game(); arb::convert::activate();
rule_status = XLAT("converted successfully -- %1 cell types", its(isize(arb::current.shapes))); start_game();
rules_known_for = "unknown"; rule_status = XLAT("converted successfully -- %1 cell types", its(isize(arb::current.shapes)));
rules_known_for = "unknown";
}
catch(hr_parse_exception& ex) {
println(hlog, "failed: ", ex.s);
rule_status = XLAT("failed to convert: ") + ex.s;
rules_known_for = "unknown";
}
} }
else if(arb::convert::in()) { else if(arb::convert::in()) {
stop_game(); stop_game();

View File

@ -1430,7 +1430,7 @@ EX void optimize() {
int N = isize(treestates); int N = isize(treestates);
println(hlog, "optimize: changes = ", changes, " errors = ", errors, " unreachable = ", N - isize(seen)); if(rdebug_flags & 64) println(hlog, "optimize: changes = ", changes, " errors = ", errors, " unreachable = ", N - isize(seen));
if(errors) throw rulegen_retry("error found in optimize"); if(errors) throw rulegen_retry("error found in optimize");
@ -1471,7 +1471,7 @@ EX void optimize() {
} }
} }
if(steps) { println(hlog, "steps = ", steps); throw rulegen_retry("unreachable found in optimize"); } if(steps) { if(rdebug_flags & 64) println(hlog, "steps = ", steps); throw rulegen_retry("unreachable found in optimize"); }
important.clear(); important.clear();
for(auto s: seen) important.push_back(treestates[s].giver); for(auto s: seen) important.push_back(treestates[s].giver);

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