2019-08-10 11:43:24 +00:00
// Hyperbolic Rogue - Complex features part II
2019-01-02 21:01:00 +00:00
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
2018-10-25 00:43:14 +00:00
2019-08-10 11:43:24 +00:00
/** \file complex2.cpp
* \ brief Continuation of complex . cpp
*
* Includes : Brownian , Irradiated , Free Fall
*/
2019-09-05 07:15:40 +00:00
# include "hyper.h"
2018-10-25 00:43:14 +00:00
# ifdef CAP_COMPLEX2
namespace hr {
2019-08-09 20:37:11 +00:00
EX namespace brownian {
# if HDR
const int level = 5 ;
# endif
2018-10-25 00:43:14 +00:00
2019-01-20 11:46:05 +00:00
map < cell * , vector < pair < cell * , int > > > futures ;
2018-10-25 00:43:14 +00:00
int centersteps = 0 ;
int totalsteps = 0 ;
void rise ( cell * c , int val ) {
if ( c - > wall = = waSea ) c - > wall = waNone ;
if ( c - > land = = laOcean | | c - > land = = laNone ) {
c - > land = laBrownian ;
c - > landparam = 0 ;
}
c - > bardir = NOBARRIERS ;
forCellCM ( c1 , c ) {
c1 - > bardir = NOBARRIERS ;
if ( c1 - > mpdist > BARLEV ) {
setdist ( c1 , BARLEV , c ) ;
}
if ( c1 - > land = = laOcean ) {
c1 - > land = laBrownian ;
c1 - > landparam = 0 ;
2019-01-03 16:19:23 +00:00
c1 - > wall = waSea ;
2018-10-25 00:43:14 +00:00
}
}
c - > landparam + = val ;
}
2019-01-20 11:46:05 +00:00
static const int FAT = ( - 100 ) ; // less than 0
2018-10-25 00:43:14 +00:00
2019-01-20 11:46:05 +00:00
void recurse ( cell * c , int fatten_from ) {
2019-01-03 01:00:15 +00:00
int dl = getDistLimit ( ) ;
2018-10-25 00:43:14 +00:00
while ( true ) {
2019-01-20 11:46:05 +00:00
int cd = celldist ( c ) ;
bool fat = cd > fatten_from ;
2018-10-25 00:43:14 +00:00
totalsteps + + ;
2019-01-20 11:46:05 +00:00
if ( cd > = dl * ( fat ? 4 : ISMOBILE ? 2 : 3 ) + celldist ( cwt . at ) ) {
2018-10-25 00:43:14 +00:00
cell * c1 = c ;
while ( true ) {
cell * c2 = ts : : left_parent ( c1 , celldist ) ;
if ( ! c2 | | c2 - > mpdist < BARLEV ) break ;
setdist ( c2 , BARLEV , c1 ) ;
c1 = c2 ;
}
2019-01-20 11:46:05 +00:00
futures [ c1 ] . emplace_back ( c , fatten_from ) ;
2018-10-25 00:43:14 +00:00
return ;
}
2019-01-03 16:19:23 +00:00
if ( c - > mpdist < = 7 | | ! among ( c - > land , laNone , laOcean , laBrownian ) | | ( c - > land ! = laBrownian & & c - > bardir ! = NODIR ) ) {
centersteps + + ; return ;
}
cell * c2 = c - > cmove ( hrand ( c - > type ) ) ;
2019-01-20 11:46:05 +00:00
int cd2 = celldist ( c2 ) ;
2018-10-25 00:43:14 +00:00
// while(hrand(1000) < 1000 * chance) recurse(c);
2019-01-20 11:46:05 +00:00
if ( ! fat & & ( cd2 > fatten_from | | hrand ( 100000 ) = = 0 ) ) {
recurse ( c , FAT ) ;
fatten_from = FAT ;
2019-01-02 21:01:00 +00:00
}
2019-01-20 11:46:05 +00:00
else if ( fat ) recurse ( c , cd + dl * 6 ) ;
2018-10-25 00:43:14 +00:00
rise ( c , fat ? 256 : 1 ) ;
2019-01-03 16:19:23 +00:00
c = c2 ;
2018-10-25 00:43:14 +00:00
}
}
2019-09-05 10:00:55 +00:00
EX void dissolve_brownian ( cell * c , int x ) {
2018-10-25 00:43:14 +00:00
if ( c - > land = = laBrownian ) {
if ( among ( c - > wall , waNone , waStrandedBoat , waMineOpen , waFire ) ) {
if ( c - > landparam > = 4 * level ) c - > landparam = 4 * level - 1 ;
c - > landparam - = level * x ;
c - > wall = waNone ;
if ( c - > landparam < 0 ) c - > wall = waSea , c - > landparam = 0 ;
if ( c - > landparam = = 0 ) c - > landparam = 1 ;
}
}
}
2019-09-05 10:00:55 +00:00
EX void dissolve ( cell * c , int x ) {
2018-10-25 00:43:14 +00:00
destroyTrapsAround ( c ) ;
if ( c - > land = = laBrownian )
dissolve_brownian ( c , x ) ;
else if ( c - > wall = = waRed2 ) c - > wall = waRed1 ;
else if ( c - > wall = = waRed3 ) c - > wall = waRed2 ;
else if ( among ( c - > wall , waRed1 , waDeadfloor2 , waRubble , waBoat , waFire , waCIsland , waCIsland2 , waBigBush , waSmallBush ) ) c - > wall = waNone ;
else if ( c - > wall = = waStrandedBoat ) c - > wall = waNone ;
else if ( c - > wall = = waFrozenLake ) c - > wall = waLake ;
else if ( among ( c - > wall , waReptile , waGargoyleFloor ) | | cellUnstable ( c ) ) c - > wall = waChasm ;
else if ( among ( c - > wall , waNone , waDock , waBurningDock , waFloorA , waFloorB , waCavefloor , waDeadfloor , waMineMine , waMineUnknown , waMineOpen , waOpenGate , waClosePlate , waOpenPlate , waGargoyleBridge , waReptileBridge ) )
c - > wall = waSea ;
else if ( cellHalfvine ( c ) ) destroyHalfvine ( c , waNone , 4 ) ;
}
2019-08-09 20:37:11 +00:00
EX void init ( cell * c ) {
2019-01-24 13:49:50 +00:00
if ( ! hyperbolic ) return ;
2019-01-20 11:46:05 +00:00
recurse ( c , FAT ) ;
recurse ( c , FAT ) ;
2019-01-02 21:01:00 +00:00
}
2019-09-06 06:17:02 +00:00
EX void init_further ( cell * c ) {
2019-01-24 13:49:50 +00:00
if ( ! hyperbolic ) return ;
2019-01-20 11:46:05 +00:00
int dl = getDistLimit ( ) ;
2019-01-02 21:01:00 +00:00
dynamicval < bool > be ( generatingEquidistant , true ) ;
int gdir = - 1 ;
for ( int i = 0 ; i < c - > type ; i + + ) {
if ( c - > move ( i ) & & c - > move ( i ) - > mpdist < c - > mpdist ) gdir = i ;
}
if ( gdir < 0 ) return ;
cellwalker cw ( c , gdir ) ;
for ( int i = 0 ; i < 4 ; i + + ) {
cw + = revstep ;
setdist ( cw . at , BARLEV , cw . peek ( ) ) ;
buildEquidistant ( cw . at ) ;
println ( hlog , " from " , cw . peek ( ) , " to " , cw . at , " , land = " , dnameof ( cw . at - > land ) , " lp = " , cw . at - > landparam ) ;
}
if ( c - > land ! = laOcean | | ! no_barriers_in_radius ( cw . at , 2 ) ) return ;
println ( hlog , " brownian::init " , cw . at , " in distance " , celldistance ( cw . at , cwt . at ) ) ;
2019-01-20 11:46:05 +00:00
recurse ( cw . at , celldist ( c ) + dl * 3 ) ;
recurse ( cw . at , celldist ( c ) + dl * 3 ) ;
2019-01-02 21:01:00 +00:00
cell * c2 = c ;
while ( c2 - > mpdist > 7 ) {
forCellEx ( c3 , c2 ) if ( c3 - > mpdist < c2 - > mpdist ) { c2 = c3 ; goto next ; }
break ;
next : ;
}
if ( ! c2 - > monst & & c2 - > wall ! = waBoat ) c2 - > monst = moAcidBird ;
2018-10-25 00:43:14 +00:00
}
2019-01-03 16:19:23 +00:00
2019-09-05 10:00:55 +00:00
EX void apply_futures ( cell * c ) {
2018-10-25 00:43:14 +00:00
if ( futures . count ( c ) ) {
2019-01-03 16:19:23 +00:00
auto m = move ( futures [ c ] ) ;
futures . erase ( c ) ;
2019-01-20 11:46:05 +00:00
for ( auto p : m )
2018-10-25 00:43:14 +00:00
recurse ( p . first , p . second ) ;
futures . erase ( c ) ;
printf ( " centersteps = %d futures = %d totalsteps = %d \n " , centersteps , isize ( futures ) , totalsteps ) ;
}
2019-01-03 16:19:23 +00:00
}
2019-08-09 20:37:11 +00:00
EX void build ( cell * c , int d ) {
2019-01-24 13:49:50 +00:00
if ( ! hyperbolic ) c - > wall = waNone , c - > landparam = 256 ;
2018-10-25 00:43:14 +00:00
ONEMPTY {
2019-01-02 21:01:00 +00:00
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 )
2018-10-25 00:43:14 +00:00
c - > item = itBrownian ;
2019-03-10 11:06:58 +00:00
if ( hrand_monster ( 8000 ) < 15 + items [ itBrownian ] )
2018-10-25 00:43:14 +00:00
c - > monst = moAcidBird ;
2019-03-10 11:06:58 +00:00
else if ( hrand_monster ( 8000 ) < 15 )
2018-10-25 00:43:14 +00:00
c - > monst = moAlbatross ;
2019-03-10 11:06:58 +00:00
else if ( hrand_monster ( 8000 ) < 15 + items [ itBrownian ] ) {
2018-10-25 00:43:14 +00:00
c - > monst = moBrownBug ;
c - > hitpoints = 3 ;
}
}
}
2018-12-25 11:49:54 +00:00
2019-09-05 10:00:55 +00:00
EX colortable colors = { 0x603000 , 0x804000 , 0xA05000 , 0xC09050 , 0xE0D0A0 } ;
2019-01-03 16:21:11 +00:00
2019-09-06 06:17:02 +00:00
EX color_t get_color ( int y ) {
2018-12-25 11:49:54 +00:00
return
2019-01-03 16:21:11 +00:00
y < level ? gradient ( colors [ 0 ] , colors [ 1 ] , 1 , y , level - 1 ) :
y < 2 * level ? colors [ 2 ] :
y < 3 * level ? colors [ 3 ] :
colors [ 4 ] ;
}
2019-09-05 10:00:55 +00:00
EX color_t & get_color_edit ( int y ) {
2019-01-03 16:21:11 +00:00
return
y < level / 2 ? colors [ 0 ] :
y < level ? colors [ 1 ] :
y < 2 * level ? colors [ 2 ] :
y < 3 * level ? colors [ 3 ] :
colors [ 4 ] ;
2018-12-25 11:49:54 +00:00
}
2018-10-25 00:43:14 +00:00
2019-01-11 01:23:00 +00:00
int hrc = addHook ( hooks_removecells , 0 , [ ] ( ) {
vector < cell * > to_remove ;
for ( auto p : futures ) if ( is_cell_removed ( p . first ) ) to_remove . push_back ( p . first ) ;
for ( auto r : to_remove ) futures . erase ( r ) ;
2020-04-11 18:40:12 +00:00
} ) + addHook ( hooks_clearmemory , 0 , [ ] ( ) { futures . clear ( ) ; } )
2019-05-30 14:12:38 +00:00
+ addHook ( hooks_gamedata , 0 , [ ] ( gamedata * gd ) { gd - > store ( futures ) ; } ) ;
2019-01-11 01:23:00 +00:00
2019-09-05 10:00:55 +00:00
EX }
2018-10-25 00:43:14 +00:00
2019-09-05 10:00:55 +00:00
EX namespace westwall {
2018-12-21 13:41:23 +00:00
2019-09-05 10:00:55 +00:00
EX void switchTreasure ( cell * c ) {
2018-12-21 13:41:23 +00:00
c - > item = itNone ;
if ( safety ) return ;
2019-01-24 13:49:25 +00:00
if ( hrand ( 5000 ) < PT ( 100 + 2 * ( kills [ moAirElemental ] + kills [ moWindCrow ] ) , 200 ) & & c - > landparam > = 5 + items [ itWest ] )
2018-12-21 13:41:23 +00:00
c - > item = itWest ;
else if ( hrand ( 5000 ) < 20 * PRIZEMUL )
placeLocalOrbs ( c ) ;
}
2019-09-06 06:17:02 +00:00
EX int coastvalEdge1 ( cell * c ) {
2018-12-22 21:39:16 +00:00
if ( c - > land = = laWestWall & & ! c - > landparam ) buildEquidistant ( c ) ;
return coastvalEdge ( c ) ;
}
2018-12-21 13:41:23 +00:00
void build ( vector < cell * > & whirlline , int d ) {
again :
cell * at = whirlline [ isize ( whirlline ) - 1 ] ;
cell * prev = whirlline [ isize ( whirlline ) - 2 ] ;
for ( int i = 0 ; i < at - > type ; i + + )
2018-12-22 21:39:16 +00:00
if ( at - > move ( i ) & & coastvalEdge1 ( at - > move ( i ) ) = = d & & at - > move ( i ) ! = prev ) {
2018-12-21 13:41:23 +00:00
whirlline . push_back ( at - > move ( i ) ) ;
goto again ;
}
}
void moveAt ( cell * c , manual_celllister & cl ) {
if ( cl . listed ( c ) ) return ;
if ( c - > land ! = laWestWall ) return ;
vector < cell * > whirlline ;
int d = coastvalEdge ( c ) ;
whirlline . push_back ( c ) ;
2018-12-23 02:14:48 +00:00
whirlline . push_back ( gravity_state = = gsAnti ? ts : : right_of ( c , coastvalEdge1 ) : ts : : left_of ( c , coastvalEdge1 ) ) ;
2018-12-21 13:41:23 +00:00
build ( whirlline , d ) ;
reverse ( whirlline . begin ( ) , whirlline . end ( ) ) ;
build ( whirlline , d ) ;
int z = isize ( whirlline ) ;
for ( int i = 0 ; i < z ; i + + ) {
cl . add ( whirlline [ i ] ) ;
if ( whirlline [ i ] - > mpdist = = BARLEV )
switchTreasure ( whirlline [ i ] ) ;
}
for ( int i = 0 ; i < z - 1 ; i + + ) {
moveItem ( whirlline [ i ] , whirlline [ i + 1 ] , true ) ;
if ( whirlline [ i ] - > item )
2019-11-22 17:48:51 +00:00
animateMovement ( match ( whirlline [ i + 1 ] , whirlline [ i ] ) , LAYER_BOAT ) ;
2018-12-21 13:41:23 +00:00
}
for ( int i = 0 ; i < z ; i + + )
pickupMovedItems ( whirlline [ i ] ) ;
}
2019-09-05 10:00:55 +00:00
EX void move ( ) {
2018-12-21 13:41:23 +00:00
manual_celllister cl ;
2018-12-23 02:14:48 +00:00
if ( gravity_state = = gsLevitation ) return ;
2018-12-21 13:41:23 +00:00
for ( cell * c : dcal ) moveAt ( c , cl ) ;
// Keys and Orbs of Yendor always move
using namespace yendor ;
for ( int i = 0 ; i < isize ( yi ) ; i + + ) {
moveAt ( yi [ i ] . path [ 0 ] , cl ) ;
2018-12-22 21:39:16 +00:00
// println(hlog, "coastval of actual key is ", coastvalEdge1(yi[i].actual_key()), " and item is ", dnameof(yi[i].actual_key()->item), "and mpdist is ", yi[i].actual_key()->mpdist);
moveAt ( yi [ i ] . actual_key ( ) , cl ) ;
if ( yi [ i ] . actualKey ) {
2018-12-23 02:14:48 +00:00
if ( gravity_state = = gsAnti ) yi [ i ] . age - - ;
else yi [ i ] . age + + ;
2018-12-22 21:39:16 +00:00
setdist ( yi [ i ] . actual_key ( ) , 8 , NULL ) ;
}
2018-12-21 13:41:23 +00:00
}
}
2019-09-05 10:00:55 +00:00
EX }
2018-12-21 13:41:23 +00:00
2019-12-08 18:17:28 +00:00
EX namespace variant {
2019-09-05 10:00:55 +00:00
# if HDR
2019-12-08 18:17:28 +00:00
struct feature {
2018-12-25 11:51:25 +00:00
color_t color_change ;
int rate_change ;
eMonster wanderer ;
void ( * build ) ( cell * ) ;
} ;
2019-12-08 18:17:28 +00:00
extern array < feature , 21 > features ;
2019-09-05 10:00:55 +00:00
# endif
2018-12-25 11:51:25 +00:00
# define VF [] (cell *c)
2020-02-26 00:23:42 +00:00
bool hrand_var ( int i ) { return hrand_monster ( i ) < 25 + items [ itVarTreasure ] + yendor : : hardness ( ) ; }
2019-12-08 18:17:28 +00:00
array < feature , 21 > features { {
feature { ( color_t ) ( - 0x202020 ) , 5 , moNecromancer , VF {
2018-12-25 22:52:54 +00:00
if ( c - > wall = = waNone & & hrand ( 1500 ) < 20 ) c - > wall = waFreshGrave ;
2018-12-25 11:51:25 +00:00
if ( hrand ( 20000 ) < 10 + items [ itVarTreasure ] )
c - > monst = moNecromancer ;
} } ,
2020-02-26 00:23:42 +00:00
{ 0x000010 , 5 , moLancer , VF { if ( c - > wall = = waNone & & ! c - > monst & & hrand_var ( 80000 ) ) c - > monst = moLancer ; } } ,
{ 0x100008 , 15 , moMonk , VF { if ( c - > wall = = waNone & & ! c - > monst & & hrand_var ( 80000 ) ) c - > monst = moMonk ; } } ,
{ 0x080010 , 5 , moCrusher , VF { if ( c - > wall = = waNone & & ! c - > monst & & hrand_var ( 80000 ) ) c - > monst = moCrusher ; } } ,
{ 0x181418 , 5 , moSkeleton , VF { if ( c - > wall = = waNone & & ! c - > monst & & hrand_var ( 80000 ) ) c - > monst = moSkeleton , c - > hitpoints = 3 ; } } ,
{ 0x180000 , 5 , moPyroCultist , VF { if ( c - > wall = = waNone & & ! c - > monst & & hrand_var ( 80000 ) ) c - > monst = moPyroCultist ; } } ,
{ 0x00000C , 2 , moFlailer , VF { if ( c - > wall = = waNone & & ! c - > monst & & hrand_var ( 80000 ) ) c - > monst = moFlailer ; } } ,
{ 0x1C0700 , 1 , moHedge , VF { if ( c - > wall = = waNone & & ! c - > monst & & hrand_var ( 80000 ) & & valence ( ) = = 3 ) c - > monst = moHedge ; } } ,
2019-01-02 15:19:22 +00:00
{ 0x000c00 , - 1 , moNone , VF { if ( hrand ( 1500 ) < 30 ) createArrowTrapAt ( c , laVariant ) ; } } ,
{ 0x001200 , - 1 , moNone , VF { if ( hrand ( 1500 ) < 50 & & c - > wall = = waNone ) c - > wall = waTrapdoor ; } } ,
{ 0x000c18 , - 1 , moNone , VF { if ( hrand ( 1500 ) < 30 ) build_pool ( c , true ) ; } } ,
{ 0x040A00 , - 1 , moNone , VF { if ( c - > wall = = waNone & & ! c - > monst & & ! c - > monst & & hrand ( 1500 ) < 10 ) c - > wall = waThumperOff ; } } ,
{ 0x080A00 , - 1 , moNone , VF { if ( hrand ( 1500 ) < 20 & & ! c - > monst & & ! c - > wall ) c - > wall = waFireTrap ; } } ,
2019-01-16 23:45:36 +00:00
{ 0x0C0A00 , 0 , moNone , VF {
bool inyendor = yendor : : on & & specialland = = laVariant & & celldist ( c ) < 7 ;
int chance = inyendor ? 800 : 100 ;
if ( c - > wall = = waNone & & ! c - > monst & & hrand ( 5000 ) < chance ) c - > wall = waExplosiveBarrel ;
} } ,
2019-01-02 15:19:22 +00:00
{ 0x060D04 , 0 , moNone , VF {
2018-12-25 11:51:25 +00:00
if ( c - > wall = = waNone & & ! c - > monst & & pseudohept ( c ) & & hrand ( 30000 ) < 25 + items [ itVarTreasure ] )
if ( buildIvy ( c , 0 , c - > type ) & & ! peace : : on ) c - > item = itVarTreasure ;
} } ,
2019-01-02 15:19:22 +00:00
{ 0x000A08 , 0 , moNone , VF { if ( c - > wall = = waNone & & ! c - > monst & & hrand ( 5000 ) < 100 ) c - > wall = waSmallTree ; } } ,
{ 0x100A10 , 1 , moRagingBull , VF { if ( c - > wall = = waNone & & hrand ( 10000 ) < 10 + items [ itVarTreasure ] ) c - > monst = moSleepBull , c - > hitpoints = 3 ; } } ,
{ 0x00110C , 0 , moNone , VF { if ( c - > wall = = waNone & & ! c - > monst & & hrand ( 5000 ) < 100 ) c - > wall = waBigTree ; } } ,
{ 0x000A28 , 1 , moNone , VF { if ( hrand ( 500 ) < 10 ) build_pool ( c , false ) ; } } ,
2020-02-26 00:23:42 +00:00
{ 0x100A00 , 2 , moVariantWarrior , VF { if ( c - > wall = = waNone & & ! c - > monst & & hrand_var ( 40000 ) ) c - > monst = moVariantWarrior ; } } ,
{ 0x100708 , 1 , moRatling , VF { if ( c - > wall = = waNone & & ! c - > monst & & hrand_var ( 50000 ) ) c - > monst = moRatling ; } }
2018-12-25 11:51:25 +00:00
} } ;
# undef VF
2019-12-08 18:17:28 +00:00
EX }
EX namespace camelot {
/** number of Grails collected, to show you as a knight */
EX int knighted = 0 ;
/** this value is used when using Orb of Safety in the Camelot in Pure Tactics Mode */
EX int anthraxBonus = 0 ;
2020-03-06 14:17:25 +00:00
vector < string > knight_names = {
" DivisionByZero " , " tricosahedron " , " BillSYZ0317 " , " rjdimo " , " Person " , " Strange Yeah " , " godamnsteemsux " , " Allalinor " , " Spuddnik " , " QETC Crimson " ,
" cannobeens " , " Dylgear " , " Patashu " , " hotdogPi " , " vincent " , " Chimera245 " , " BreedPineapple " , " TaeK " , " Aliased " , " Vipul " , " english5040 " , " marvincast " ,
" Lord Ignus " , " Darth Calculus " , " *****-mail " , " Wheat Wizard " , " xiqnyl " , " zelda0x181e " , " ad-jones " , " mtomato " , " Fififionek " , " jkvw3 " , " J Pystynen " ,
" krstefan11 " , " green orange " , " ZombieGirl1616 " , " z.chlebicki " , " Lokki " , " zeno " , " Fulgur14 " , " uqblf " , " santagonewrong " , " CtrlAltDestroy " , " Vee Nought " ,
" archmageomega " , " Wroclaw " , " lunaduskjr " , " loper " , " Sharklilly " , " Dasypus Daimon " , " Mateusz " , " guysige " , " MrSprucetree " , " Atia " , " nerdyjoe " , " florrat " ,
" psychopanda121 " , " Sprite Guard " , " Fluffiest Princess " , " no stop " , " Kieroshark " , " juhdanad " , " lllllllllwith10ls " , " NattieGilgamesh " , " chocokels " , " oren " ,
" sir289 " , " pringle " , " Spicy " , " Cheetahs " , " xy2 " , " Heavpoot " , " 2jjy " , " Hirgon " , " martradams " , " TravelDemon " , " The Big Extent " , " fones4jenke13 " , " ekisacik " ,
" j0eymcgrath " , " EatChangmyeong " , " craus " , " akei_arkay " , " __________ " , " Ichigo Jam " , " supernewton " , " Westville " , " Huja (chat off) " , " Just A Witch " , " Particles " ,
" The Horrendous Space Kablooie " , " ddtizm " , " amagikuser " , " vkozulya " , " gassa " , " Factitious " , " wonderfullizardofoz " , " woofmao " , " CandorVelexion " , " Toricon " ,
" Vectis99 " , " RobotNerd277 " , " jerrypoons " , " MagmaMcFry " , " unczane " , " glass " , " Wegener " , " JeLomun " , " kip " , " Fooruman " , " Prezombie " , " ashley89 " , " bjobae " ,
" MFErtre " , " Roaringdragon2 " , " howilovepi " , " Yulgash " , " coper " , " Tirear " , " qoala _ " , " Tiegon " , " Metroid26 " , " Sklorg " , " Fumblestealth " , " Toph " , " jruderman " ,
" ray " , " Deathroll " , " Sinquetica " , " mootmoot " , " Noobinator " , " Gunblob " , " Snakebird Priestess " , " brisingre " , " Khashishi " , " Berenthas " , " Misery " , " Altripp " , " Aldrenean " ,
} ;
map < cell * , int > knight_id ;
EX string knight_name ( cell * c ) {
if ( ! knight_id . count ( c ) ) knight_id [ c ] = rand ( ) % isize ( knight_names ) ;
return knight_names [ knight_id [ c ] ] ;
}
EX void move_knight ( cell * c1 , cell * c2 ) {
LATE ( move_knight ( c1 , c2 ) ; )
if ( knight_id . count ( c1 ) ) {
knight_id [ c2 ] = knight_id [ c1 ] ;
knight_id . erase ( c1 ) ;
}
}
2019-12-08 18:17:28 +00:00
EX void roundTableMessage ( cell * c2 ) {
if ( ! euclid & & ! cwt . at - > master - > alt ) return ;
if ( ! euclid & & ! c2 - > master - > alt ) return ;
int dd = celldistAltRelative ( c2 ) - celldistAltRelative ( cwt . at ) ;
bool tooeasy = ( roundTableRadius ( c2 ) < newRoundTableRadius ( ) ) ;
if ( dd > 0 ) {
if ( grailWasFound ( cwt . at ) ) {
addMessage ( XLAT ( " The Knights congratulate you on your success! " ) ) ;
knighted = roundTableRadius ( cwt . at ) ;
}
else if ( ! tooeasy )
addMessage ( XLAT ( " The Knights laugh at your failure! " ) ) ;
}
else {
if ( grailWasFound ( cwt . at ) )
addMessage ( XLAT ( " The Knights stare at you! " ) ) ;
else if ( tooeasy ) {
if ( ! tactic : : on )
addMessage ( XLAT ( " Come on, this is too easy... find a bigger castle! " ) ) ;
}
else
addMessage ( XLAT ( " The Knights wish you luck! " ) ) ;
}
}
EX void knightFlavorMessage ( cell * c2 ) {
if ( ! eubinary & & ! c2 - > master - > alt ) {
addMessage ( XLAT ( " \" I am lost... \" " ) ) ;
return ;
}
if ( tactic : : on ) {
addMessage ( XLAT ( " \" The Knights of the Horocyclic Table salute you! \" " ) ) ;
return ;
}
bool grailfound = grailWasFound ( c2 ) ;
int rad = roundTableRadius ( c2 ) ;
bool tooeasy = ( rad < newRoundTableRadius ( ) ) ;
static int msgid = 0 ;
2020-02-29 16:58:59 +00:00
changes . value_keep ( msgid ) ;
2019-12-08 18:17:28 +00:00
retry :
if ( msgid > = 32 ) msgid = 0 ;
if ( msgid = = 0 & & grailfound ) {
addMessage ( XLAT ( " \" I would like to congratulate you again! \" " ) ) ;
}
else if ( msgid = = 1 & & ! tooeasy ) {
addMessage ( XLAT ( " \" Find the Holy Grail to become one of us! \" " ) ) ;
}
else if ( msgid = = 2 & & ! tooeasy ) {
addMessage ( XLAT ( " \" The Holy Grail is in the center of the Round Table. \" " ) ) ;
}
# if CAP_CRYSTAL
else if ( msgid = = 3 & & cryst ) {
if ( crystal : : pure ( ) )
addMessage ( XLAT ( " \" Each piece of the Round Table is exactly %1 steps away from the Holy Grail. \" " , its ( roundTableRadius ( c2 ) ) ) ) ;
else
addMessage ( XLAT ( " \" According to Merlin, the Round Table is a perfect Euclidean sphere in %1 dimensions. \" " , its ( ginf [ gCrystal ] . sides / 2 ) ) ) ;
}
# endif
else if ( msgid = = 3 & & ! peace : : on & & in_full_game ( ) ) {
addMessage ( XLAT ( " \" I enjoy watching the hyperbug battles. \" " ) ) ;
}
else if ( msgid = = 4 & & in_full_game ( ) ) {
addMessage ( XLAT ( " \" Have you visited a temple in R'Lyeh? \" " ) ) ;
}
else if ( msgid = = 5 & & in_full_game ( ) ) {
addMessage ( XLAT ( " \" Nice castle, eh? \" " ) ) ;
}
else if ( msgid = = 6 & & items [ itSpice ] < 10 & & ! peace : : on & & in_full_game ( ) ) {
addMessage ( XLAT ( " \" The Red Rock Valley is dangerous, but beautiful. \" " ) ) ;
}
else if ( msgid = = 7 & & items [ itSpice ] < 10 & & ! peace : : on & & in_full_game ( ) ) {
addMessage ( XLAT ( " \" Train in the Desert first! \" " ) ) ;
}
else if ( msgid = = 8 & & sizes_known ( ) & & ! tactic : : on ) {
string s = " " ;
if ( 0 ) ;
# if CAP_CRYSTAL
else if ( cryst )
s = crystal : : get_table_boundary ( ) ;
# endif
else if ( ! quotient )
s = expansion . get_descendants ( rad ) . get_str ( 100 ) ;
if ( s = = " " ) { msgid + + ; goto retry ; }
addMessage ( XLAT ( " \" Our Table seats %1 Knights! \" " , s ) ) ;
}
else if ( msgid = = 9 & & sizes_known ( ) & & ! tactic : : on ) {
string s = " " ;
if ( 0 ) ;
# if CAP_CRYSTAL
else if ( cryst )
s = crystal : : get_table_volume ( ) ;
# endif
else if ( ! quotient )
s = expansion . get_descendants ( rad - 1 , expansion . diskid ) . get_str ( 100 ) ;
if ( s = = " " ) { msgid + + ; goto retry ; }
addMessage ( XLAT ( " \" There are %1 floor tiles inside our Table! \" " , s ) ) ;
}
else if ( msgid = = 10 & & ! items [ itPirate ] & & ! items [ itWhirlpool ] & & ! peace : : on & & in_full_game ( ) ) {
addMessage ( XLAT ( " \" Have you tried to take a boat and go into the Ocean? Try it! \" " ) ) ;
}
else if ( msgid = = 11 & & ! princess : : saved & & in_full_game ( ) ) {
addMessage ( XLAT ( " \" When I visited the Palace, a mouse wanted me to go somewhere. \" " ) ) ;
}
else if ( msgid = = 12 & & ! princess : : saved & & in_full_game ( ) ) {
addMessage ( XLAT ( " \" I wonder what was there... \" " ) ) ;
}
else if ( msgid = = 13 & & ! peace : : on & & in_full_game ( ) ) {
addMessage ( XLAT ( " \" Be careful in the Rose Garden! It is beautiful, but very dangerous! \" " ) ) ;
}
else if ( msgid = = 14 ) {
addMessage ( XLAT ( " \" There is no royal road to geometry. \" " ) ) ;
}
else if ( msgid = = 15 ) {
addMessage ( XLAT ( " \" There is no branch of mathematics, however abstract, " ) ) ;
addMessage ( XLAT ( " which may not some day be applied to phenomena of the real world. \" " ) ) ;
}
else if ( msgid = = 16 ) {
addMessage ( XLAT ( " \" It is not possession but the act of getting there, " ) ) ;
addMessage ( XLAT ( " which grants the greatest enjoyment. \" " ) ) ;
}
else if ( msgid = = 17 ) {
addMessage ( XLAT ( " \" We live in a beautiful and orderly world, " ) ) ;
addMessage ( XLAT ( " and not in a chaos without norms. \" " ) ) ;
}
else if ( msgid = = 25 ) {
addMessage ( XLAT ( " \" Thank you very much for talking, and have a great rest of your day! \" " ) ) ;
}
else {
msgid + + ; goto retry ;
}
msgid + + ;
}
EX }
EX namespace mine {
EX bool uncoverMines ( cell * c , int lev , int dist , bool just_checking ) {
bool b = false ;
if ( c - > wall = = waMineMine & & just_checking ) return true ;
if ( c - > wall = = waMineUnknown ) {
if ( just_checking )
return true ;
else {
2020-03-01 13:09:24 +00:00
changes . ccell ( c ) ;
2019-12-08 18:17:28 +00:00
c - > wall = waMineOpen ;
b = true ;
}
}
bool minesNearby = false ;
bool nominesNearby = false ;
bool mineopens = false ;
auto adj = adj_minefield_cells ( c ) ;
for ( cell * c2 : adj ) {
if ( c2 - > wall = = waMineMine ) minesNearby = true ;
if ( c2 - > wall = = waMineOpen ) mineopens = true ;
if ( c2 - > wall = = waMineUnknown & & ! c2 - > item ) nominesNearby = true ;
}
if ( lev & & ( nominesNearby | | mineopens ) & & ! minesNearby ) for ( cell * c2 : adj )
if ( c2 - > wall = = waMineUnknown | | c2 - > wall = = waMineOpen ) {
b | = uncoverMines ( c2 , lev - 1 , dist + 1 , just_checking ) ;
if ( b & & just_checking ) return true ;
}
if ( minesNearby & & ! nominesNearby & & dist = = 0 ) {
for ( cell * c2 : adj )
if ( c2 - > wall = = waMineMine & & c2 - > land = = laMinefield )
2020-03-01 13:09:24 +00:00
changes . ccell ( c2 ) ,
2019-12-08 18:17:28 +00:00
c2 - > landparam | = 1 ;
}
return b ;
}
EX bool mightBeMine ( cell * c ) {
return c - > wall = = waMineUnknown | | c - > wall = = waMineMine ;
}
2020-04-11 18:47:14 +00:00
EX hookset < bool ( cell * ) > hooks_mark ;
2019-12-08 18:17:28 +00:00
EX void performMarkCommand ( cell * c ) {
if ( ! c ) return ;
if ( callhandlers ( false , hooks_mark , c ) ) return ;
if ( c - > land = = laCA & & c - > wall = = waNone )
c - > wall = waFloorA ;
else if ( c - > land = = laCA & & c - > wall = = waFloorA )
c - > wall = waNone ;
if ( c - > land ! = laMinefield ) return ;
if ( c - > item ) return ;
if ( ! mightBeMine ( c ) ) return ;
bool adj = false ;
forCellEx ( c2 , c ) if ( c2 - > wall = = waMineOpen ) adj = true ;
if ( adj ) c - > landparam ^ = 1 ;
}
EX bool marked_mine ( cell * c ) {
if ( ! mightBeMine ( c ) ) return false ;
if ( c - > item ) return false ;
if ( c - > land ! = laMinefield ) return true ;
return c - > landparam & 1 ;
}
EX bool marked_safe ( cell * c ) {
if ( ! mightBeMine ( c ) ) return false ;
if ( c - > item ) return true ;
if ( c - > land ! = laMinefield ) return false ;
return c - > landparam & 2 ;
}
EX bool safe ( ) {
return items [ itOrbAether ] ;
}
EX void uncover_full ( cell * c2 ) {
int mineradius =
bounded ? 3 :
( items [ itBombEgg ] < 1 & & ! tactic : : on ) ? 0 :
items [ itBombEgg ] < 20 ? 1 :
items [ itBombEgg ] < 30 ? 2 :
3 ;
bool nomine = ! normal_gravity_at ( c2 ) ;
if ( ! nomine & & uncoverMines ( c2 , mineradius , 0 , true ) & & markOrb ( itOrbAether ) )
nomine = true ;
if ( ! nomine ) {
uncoverMines ( c2 , mineradius , 0 , false ) ;
mayExplodeMine ( c2 , moPlayer ) ;
}
}
EX void auto_teleport_charges ( ) {
if ( specialland = = laMinefield & & firstland = = laMinefield & & bounded )
items [ itOrbTeleport ] = isFire ( cwt . at - > wall ) ? 0 : 1 ;
}
EX }
EX namespace terracotta {
# if HDR
// predictable or not
static constexpr bool randterra = false ;
# endif
EX void check ( cell * c ) {
if ( c - > wall = = waTerraWarrior & & ! c - > monst & & ! racing : : on ) {
bool live = false ;
if ( randterra ) {
c - > landparam + + ;
if ( ( c - > landparam = = 3 & & hrand ( 3 ) = = 0 ) | |
( c - > landparam = = 4 & & hrand ( 2 ) = = 0 ) | |
c - > landparam = = 5 )
live = true ;
}
else {
c - > landparam - - ;
live = ! c - > landparam ;
}
if ( live )
c - > monst = moTerraWarrior ,
c - > hitpoints = 7 ,
c - > wall = waNone ;
}
}
EX void check_around ( cell * c ) {
forCellEx ( c2 , c )
check ( c2 ) ;
}
EX void check ( ) {
for ( int i = 0 ; i < numplayers ( ) ; i + + )
forCellEx ( c , playerpos ( i ) ) {
if ( shmup : : on ) {
forCellEx ( c2 , c )
check ( c2 ) ;
}
else
check ( c ) ;
}
}
EX }
EX namespace ambush {
EX void mark ( cell * c , manual_celllister & cl ) {
if ( ! cl . add ( c ) ) return ;
forCellEx ( c2 , c )
if ( c2 - > cpdist < c - > cpdist )
mark ( c2 , cl ) ;
}
EX int distance ;
EX bool ambushed ;
EX void check_state ( ) {
if ( havewhat & HF_HUNTER ) {
manual_celllister cl ;
for ( cell * c : dcal ) {
if ( c - > monst = = moHunterDog ) {
if ( c - > cpdist > distance )
distance = c - > cpdist ;
mark ( c , cl ) ;
}
if ( c - > monst = = moHunterGuard & & c - > cpdist < = 4 )
mark ( c , cl ) ;
}
if ( items [ itHunting ] > 5 & & items [ itHunting ] < = 22 ) {
int q = 0 ;
for ( int i = 0 ; i < numplayers ( ) ; i + + )
forCellEx ( c2 , playerpos ( i ) )
if ( cl . listed ( c2 ) )
q + + ;
if ( q = = 1 ) havewhat | = HF_FAILED_AMBUSH ;
if ( q = = 2 ) {
for ( int i = 0 ; i < numplayers ( ) ; i + + )
forCellEx ( c2 , playerpos ( i ) )
if ( cl . listed ( c2 ) )
forCellEx ( c3 , playerpos ( i ) )
if ( c3 ! = c2 & & isNeighbor ( c2 , c3 ) )
if ( cl . listed ( c3 ) )
havewhat | = HF_FAILED_AMBUSH ;
}
if ( havewhat & HF_FAILED_AMBUSH & & ambushed ) {
addMessage ( XLAT ( " The Hunting Dogs give up. " ) ) ;
ambushed = false ;
}
}
}
}
EX int fixed_size ;
EX int size ( cell * c , eItem what ) {
bool restricted = false ;
for ( cell * c2 : dcal ) {
if ( c2 - > cpdist > 3 ) break ;
if ( c2 - > monst & & ! isFriendly ( c2 ) & & ! slowMover ( c2 ) & & ! isMultitile ( c2 ) ) restricted = true ;
}
int qty = items [ itHunting ] ;
if ( fixed_size )
return fixed_size ;
switch ( what ) {
case itCompass :
return 0 ;
case itHunting :
return min ( min ( qty , max ( 33 - qty , 6 ) ) , 15 ) ;
case itOrbSide3 :
return restricted ? 10 : 20 ;
case itOrbFreedom :
return restricted ? 10 : 60 ;
2020-03-05 17:48:11 +00:00
case itOrbImpact :
case itOrbPlague :
return 10 ;
2019-12-08 18:17:28 +00:00
case itOrbThorns :
case itOrb37 :
2020-03-05 17:48:11 +00:00
case itOrbChaos :
2019-12-08 18:17:28 +00:00
return 20 ;
case itOrbLava :
return 20 ;
case itOrbBeauty :
return 35 ;
case itOrbShell :
return 35 ;
case itOrbPsi :
// return 40; -> no benefits
return 20 ;
case itOrbDash :
case itOrbFrog :
return 40 ;
case itOrbAir :
case itOrbDragon :
return 50 ;
case itOrbStunning :
// return restricted ? 50 : 60; -> no benefits
return 30 ;
case itOrbBull :
case itOrbSpeed :
case itOrbShield :
return 60 ;
case itOrbInvis :
return 80 ;
case itOrbTeleport :
return 300 ;
case itGreenStone :
case itOrbSafety :
case itOrbYendor :
return 0 ;
case itKey :
return 16 ;
case itWarning :
return qty ;
default :
return restricted ? 6 : 10 ;
break ;
// Flash can survive about 70, but this gives no benefits
}
}
2020-03-07 03:37:24 +00:00
EX void ambush ( cell * c , int dogs ) {
LATE ( ambush ( c , dogs ) ; )
2019-12-08 18:17:28 +00:00
int maxdist = gamerange ( ) ;
celllister cl ( c , maxdist , 1000000 , NULL ) ;
cell * c0 = c ;
int d = 0 ;
int dogs0 = 0 ;
for ( cell * cx : cl . lst ) {
int dh = cl . getdist ( cx ) ;
if ( dh < = 2 & & cx - > monst = = moHunterGuard )
cx - > monst = moHunterDog , dogs0 + + ;
if ( dh > d ) c0 = cx , d = dh ;
}
if ( sphere ) {
for ( int i = cl . lst . size ( ) - 1 ; i > 0 & & dogs ; i - - )
if ( ! isPlayerOn ( cl . lst [ i ] ) & & ! cl . lst [ i ] - > monst )
cl . lst [ i ] - > monst = moHunterDog , dogs - - ;
}
vector < cell * > around ;
cell * clast = NULL ;
cell * ccur = c0 ;
2019-12-14 11:31:20 +00:00
int v = valence ( ) ;
2019-12-08 18:17:28 +00:00
if ( v > 4 ) {
for ( cell * c : cl . lst ) if ( cl . getdist ( c ) = = d ) around . push_back ( c ) ;
hrandom_shuffle ( & around [ 0 ] , isize ( around ) ) ;
}
else {
for ( int tries = 0 ; tries < 10000 ; tries + + ) {
cell * c2 = NULL ;
if ( v = = 3 ) {
forCellEx ( c1 , ccur )
if ( c1 ! = clast & & cl . listed ( c1 ) & & cl . getdist ( c1 ) = = d )
c2 = c1 ;
}
if ( v = = 4 ) {
for ( int i = 0 ; i < ccur - > type ; i + + ) {
cell * c1 = ( cellwalker ( ccur , i ) + wstep + 1 ) . peek ( ) ;
if ( ! c1 ) continue ;
if ( c1 ! = clast & & cl . listed ( c1 ) & & cl . getdist ( c1 ) = = d )
c2 = c1 ;
}
}
if ( ! c2 ) break ;
if ( c2 - > land = = laHunting & & c2 - > wall = = waNone & & c2 - > monst = = moNone )
around . push_back ( c2 ) ;
clast = ccur ; ccur = c2 ;
if ( c2 = = c0 ) break ;
}
}
int N = isize ( around ) ;
int gaps = dogs ;
2020-03-05 17:48:59 +00:00
int result = dogs0 ;
if ( N ) {
ambushed = true ;
int shift = hrand ( N ) ;
dogs = min ( dogs , N ) ;
gaps = min ( gaps , N ) ;
for ( int i = 0 ; i < dogs ; i + + ) {
int pos = ( shift + ( N * i ) / gaps ) % N ;
cell * nextdog = around [ pos ] ;
nextdog - > monst = moHunterDog ;
nextdog - > stuntime = 1 ;
drawFlash ( nextdog ) ;
}
result + = dogs ;
}
if ( result )
addMessage ( XLAT ( " You are ambushed! " ) ) ;
2019-12-08 18:17:28 +00:00
}
EX }
2018-12-25 11:51:25 +00:00
2018-10-25 00:43:14 +00:00
}
# endif