2018-02-08 23:40:26 +00:00
// Hyperbolic Rogue -- main graphics file
2019-08-10 11:43:24 +00:00
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
2015-08-08 13:57:52 +00:00
2019-08-10 11:43:24 +00:00
/** \file graph.cpp
* \ brief Drawing cells , monsters , items , etc .
*/
2016-08-26 09:58:03 +00:00
2019-09-05 07:15:40 +00:00
# include "hyper.h"
2018-06-10 23:58:31 +00:00
namespace hr {
2019-10-25 10:44:41 +00:00
EX int last_firelimit ;
EX int firelimit ;
2019-03-13 13:04:06 +00:00
2019-08-09 19:00:52 +00:00
EX int inmirrorcount = 0 ;
2017-07-16 21:00:55 +00:00
2019-10-12 09:21:00 +00:00
/** wall optimization: do not draw things beyond walls */
EX bool wallopt ;
2019-12-06 10:45:19 +00:00
EX bool in_wallopt ( ) { return wallopt | | racing : : on ; }
2019-08-09 21:24:33 +00:00
EX bool spatial_graphics ;
2020-01-30 16:45:05 +00:00
EX bool wmspatial , wmescher , wmplain , wmblack , wmascii , wmascii3 ;
2019-08-09 21:24:33 +00:00
EX bool mmspatial , mmhigh , mmmon , mmitem ;
2017-03-23 10:53:57 +00:00
2019-08-09 19:00:52 +00:00
EX int detaillevel = 0 ;
2017-03-23 10:53:57 +00:00
2019-08-09 19:00:52 +00:00
EX bool first_cell_to_draw = true ;
2019-04-15 21:29:07 +00:00
2019-08-09 19:00:52 +00:00
EX bool in_perspective ( ) {
2022-05-17 07:40:33 +00:00
return models : : is_perspective ( pconf . model ) ;
2020-11-08 11:09:42 +00:00
}
EX bool in_perspective_v ( ) {
2022-05-17 07:40:33 +00:00
return models : : is_perspective ( vpconf . model ) ;
2019-07-28 09:07:21 +00:00
}
2019-08-09 19:00:52 +00:00
EX bool hide_player ( ) {
2019-08-15 13:05:43 +00:00
return GDIM = = 3 & & playermoved & & vid . yshift = = 0 & & vid . sspeed > - 5 & & in_perspective ( ) & & ( first_cell_to_draw | | elliptic ) & & ( WDIM = = 3 | | vid . camera = = 0 ) & & ! inmirrorcount
2019-06-01 14:59:04 +00:00
# if CAP_RACING
2019-09-27 16:04:04 +00:00
& & ! ( racing : : on & & ! racing : : use_standard_centering ( ) & & ! racing : : player_relative )
2019-06-01 14:59:04 +00:00
# endif
;
2019-03-09 14:31:02 +00:00
}
2022-11-12 21:38:45 +00:00
EX transmatrix ddspin180 ( cell * c , int dir ) { return ddspin ( c , dir , M_PI ) ; }
EX transmatrix iddspin180 ( cell * c , int dir ) { return iddspin ( c , dir , M_PI ) ; }
2022-03-27 10:42:44 +00:00
# if HDR
2021-07-18 21:30:07 +00:00
template < class T >
class span {
T * begin_ = nullptr ;
T * end_ = nullptr ;
public :
explicit span ( ) = default ;
explicit span ( T * p , int n ) : begin_ ( p ) , end_ ( p + n ) { }
T * begin ( ) const { return begin_ ; }
T * end ( ) const { return end_ ; }
} ;
template < class Map , class Key >
hr : : span < const shiftmatrix > span_at ( const Map & map , const Key & key ) {
auto it = map . find ( key ) ;
return ( it = = map . end ( ) ) ? hr : : span < const shiftmatrix > ( ) : hr : : span < const shiftmatrix > ( it - > second . data ( ) , it - > second . size ( ) ) ;
}
2022-03-27 10:42:44 +00:00
# endif
2019-12-06 13:03:02 +00:00
2020-04-11 18:47:14 +00:00
EX hookset < bool ( int sym , int uni ) > hooks_handleKey ;
2020-07-27 16:49:04 +00:00
EX hookset < bool ( cell * c , const shiftmatrix & V ) > hooks_drawcell ;
2019-08-09 19:00:52 +00:00
EX purehookset hooks_frame , hooks_markers ;
2017-07-10 18:47:38 +00:00
2019-08-09 19:00:52 +00:00
EX ld animation_factor = 1 ;
EX int animation_lcm = 0 ;
2018-09-10 15:49:51 +00:00
2019-08-09 19:00:52 +00:00
EX ld ptick ( int period , ld phase IS ( 0 ) ) {
2018-09-10 15:49:51 +00:00
if ( animation_lcm ) animation_lcm = animation_lcm * ( period / gcd ( animation_lcm , period ) ) ;
2022-11-12 21:38:45 +00:00
return ( ticks * animation_factor * vid . ispeed ) / period + phase * TAU ;
2018-09-10 15:49:51 +00:00
}
2019-08-09 19:00:52 +00:00
EX ld fractick ( int period , ld phase IS ( 0 ) ) {
2022-11-12 21:38:45 +00:00
ld t = ptick ( period , phase ) / TAU ;
2018-09-10 15:49:51 +00:00
t - = floor ( t ) ;
if ( t < 0 ) t + + ;
return t ;
}
2019-08-09 19:00:52 +00:00
EX ld sintick ( int period , ld phase IS ( 0 ) ) {
2018-09-10 15:49:51 +00:00
return sin ( ptick ( period , phase ) ) ;
}
2019-08-09 19:00:52 +00:00
EX transmatrix spintick ( int period , ld phase IS ( 0 ) ) {
2018-09-10 15:49:51 +00:00
return spin ( ptick ( period , phase ) ) ;
}
2016-08-26 09:58:03 +00:00
# define WOLNIEJ 1
2016-01-02 10:09:13 +00:00
# define BTOFF 0x404040
# define BTON 0xC0C000
2017-03-23 10:53:57 +00:00
// #define PANDORA
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
int colorbar ;
2016-08-26 09:58:03 +00:00
2019-08-09 19:00:52 +00:00
EX bool inHighQual ; // taking high quality screenshot
2019-08-09 20:07:03 +00:00
EX bool auraNOGL ; // aura without GL
2015-08-08 13:57:52 +00:00
//
int axestate ;
2019-08-09 19:00:52 +00:00
EX int ticks ;
2019-09-06 06:17:02 +00:00
EX int frameid ;
2015-08-08 13:57:52 +00:00
2019-09-06 06:17:02 +00:00
EX bool camelotcheat ;
2019-08-09 19:00:52 +00:00
EX bool nomap ;
2017-04-08 15:18:29 +00:00
2019-08-09 20:07:03 +00:00
EX eItem orbToTarget ;
EX eMonster monsterToSummon ;
2017-03-23 10:53:57 +00:00
2019-08-09 20:07:03 +00:00
EX int sightrange_bonus = 0 ;
2017-03-23 10:53:57 +00:00
2019-08-09 19:00:52 +00:00
EX string mouseovers ;
2015-08-08 13:57:52 +00:00
2019-08-09 19:00:52 +00:00
EX int darken = 0 ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
struct fallanim {
2017-08-06 12:50:16 +00:00
int t_mon , t_floor , pid ;
2017-03-23 10:53:57 +00:00
eWall walltype ;
eMonster m ;
2017-08-06 12:50:16 +00:00
fallanim ( ) { t_floor = 0 ; t_mon = 0 ; pid = 0 ; walltype = waNone ; }
2017-03-23 10:53:57 +00:00
} ;
map < cell * , fallanim > fallanims ;
2019-08-09 19:00:52 +00:00
EX bool doHighlight ( ) {
2020-09-15 18:39:15 +00:00
return mmhigh ;
2016-01-02 10:09:13 +00:00
}
2017-07-10 18:47:38 +00:00
int dlit ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
ld spina ( cell * c , int dir ) {
2022-11-12 21:38:45 +00:00
return TAU * dir / c - > type ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
2024-07-09 19:38:45 +00:00
/** @brief used to alternate colors depending on distance to something. In chessboard-patterned geometries, automatically a third step.
* In some cases , we want to avoid a number of colors in the table - - set @ param subtract to the number of such colors .
*/
EX color_t get_color_auto3 ( int f , const colortable & ctab , int subtract IS ( 0 ) ) {
int size = ctab . size ( ) - subtract ;
if ( size < 1 ) return 0 ;
if ( geosupport_chessboard ( ) & & size = = 2 ) {
2020-05-29 00:42:54 +00:00
f = gmod ( f , 3 ) ;
2024-07-09 19:38:45 +00:00
if ( f = = 1 )
return gradient ( ctab [ 0 ] , ctab [ 1 ] , 0 , 1 , 2 ) ;
return ctab [ f / 2 ] ;
2020-05-29 00:42:54 +00:00
}
else
2024-07-09 19:38:45 +00:00
return ctab [ gmod ( f , size ) ] ;
2020-05-29 00:42:54 +00:00
}
2018-09-04 17:53:42 +00:00
color_t fc ( int ph , color_t col , int z ) {
2017-07-10 18:47:38 +00:00
if ( items [ itOrbFire ] ) col = darkena ( firecolor ( ph ) , 0 , 0xFF ) ;
if ( items [ itOrbAether ] ) col = ( col & ~ 0XFF ) | ( col & 0xFF ) / 2 ;
2021-03-06 10:46:13 +00:00
for ( cell * pc : player_positions ( ) )
if ( items [ itOrbFish ] & & isWatery ( pc ) & & z ! = 3 ) return watercolor ( ph ) ;
2017-07-10 18:47:38 +00:00
if ( invismove )
col =
shmup : : on ?
( col & ~ 0XFF ) | ( int ( ( col & 0xFF ) * .25 ) )
2018-09-10 15:56:37 +00:00
: ( col & ~ 0XFF ) | ( int ( ( col & 0xFF ) * ( 100 + 100 * sintick ( 500 ) ) ) / 200 ) ;
2017-07-10 18:47:38 +00:00
return col ;
}
2015-08-08 13:57:52 +00:00
2019-08-09 20:07:03 +00:00
EX int lightat , safetyat ;
2019-08-09 19:00:52 +00:00
EX void drawLightning ( ) { lightat = ticks ; }
EX void drawSafety ( ) { safetyat = ticks ; }
2015-08-08 13:57:52 +00:00
2022-03-27 11:23:59 +00:00
EX void drawShield ( const shiftmatrix & V , eItem it ) {
2017-12-01 23:23:15 +00:00
# if CAP_CURVE
2018-09-10 15:49:51 +00:00
float ds = ptick ( 300 ) ;
2018-09-04 17:53:42 +00:00
color_t col = iinf [ it ] . color ;
2017-07-10 18:47:38 +00:00
if ( it = = itOrbShield & & items [ itOrbTime ] & & ! orbused [ it ] )
col = ( col & 0xFEFEFE ) / 2 ;
2018-08-17 22:46:45 +00:00
if ( sphere & & cwt . at - > land = = laHalloween & & ! wmblack & & ! wmascii )
2017-07-10 18:47:38 +00:00
col = 0 ;
2019-05-26 16:04:02 +00:00
double d = it = = itOrbShield ? cgi . hexf : cgi . hexf - .1 ;
2017-07-10 18:47:38 +00:00
int mt = sphere ? 7 : 5 ;
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 )
2023-02-04 00:58:13 +00:00
queueball ( V * lzpush ( cgi . GROIN1 ) , cgi . human_height / 2 , darkena ( col , 0 , 0xFF ) , itOrbShield ) ;
2019-06-01 14:59:04 +00:00
# else
if ( 1 ) ;
# endif
2019-05-11 13:04:54 +00:00
else {
2019-05-26 16:04:02 +00:00
for ( ld a = 0 ; a < = cgi . S84 * mt + 1e-6 ; a + = pow ( .5 , vid . linequality ) )
2022-11-12 21:38:45 +00:00
curvepoint ( xspinpush0 ( a * cgi . S_step , d + sin ( ds + 90. _deg * a / mt ) * .1 ) ) ;
2020-07-27 16:49:04 +00:00
queuecurve ( V , darkena ( col , 0 , 0xFF ) , 0x8080808 , PPR : : LINE ) ;
2019-05-11 13:04:54 +00:00
}
2017-12-01 23:23:15 +00:00
# endif
2017-07-10 18:47:38 +00:00
}
2017-03-23 10:53:57 +00:00
2022-08-27 23:37:49 +00:00
void drawSpeed ( const shiftmatrix & V , ld scale = 1 ) {
2017-12-01 23:23:15 +00:00
# if CAP_CURVE
2018-09-10 15:49:51 +00:00
ld ds = ptick ( 10 ) ;
2018-09-04 17:53:42 +00:00
color_t col = darkena ( iinf [ itOrbSpeed ] . color , 0 , 0xFF ) ;
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2023-02-04 00:58:13 +00:00
if ( GDIM = = 3 ) queueball ( V * lzpush ( cgi . GROIN1 ) , cgi . human_height * 0.55 , col , itOrbSpeed ) ;
2019-06-01 14:59:04 +00:00
else
# endif
for ( int b = 0 ; b < cgi . S84 ; b + = cgi . S14 ) {
2018-08-01 09:07:22 +00:00
PRING ( a )
2022-11-12 21:38:45 +00:00
curvepoint ( xspinpush0 ( ( ds + b + a ) * cgi . S_step , cgi . hexf * a / cgi . S84 * scale ) ) ;
2020-07-27 16:49:04 +00:00
queuecurve ( V , col , 0x8080808 , PPR : : LINE ) ;
2017-03-23 10:53:57 +00:00
}
2017-12-01 23:23:15 +00:00
# endif
2015-08-08 13:57:52 +00:00
}
2020-07-27 16:49:04 +00:00
void drawSafety ( const shiftmatrix & V , int ct ) {
2024-05-25 09:46:11 +00:00
if ( inHighQual ) return ;
2017-12-01 23:23:15 +00:00
# if CAP_QUEUE
2018-09-10 15:49:51 +00:00
ld ds = ptick ( 50 ) ;
2018-09-04 17:53:42 +00:00
color_t col = darkena ( iinf [ itOrbSafety ] . color , 0 , 0xFF ) ;
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 ) {
2023-02-04 00:58:13 +00:00
queueball ( V * lzpush ( cgi . GROIN1 ) , 2 * cgi . hexf , col , itOrbSafety ) ;
2019-06-01 14:59:04 +00:00
return ;
}
# endif
for ( int a = 0 ; a < ct ; a + + )
2022-11-12 21:38:45 +00:00
queueline ( V * xspinpush0 ( ( ds + a * cgi . S84 / ct ) * cgi . S_step , 2 * cgi . hexf ) , V * xspinpush0 ( ( ds + ( a + ( ct - 1 ) / 2 ) * cgi . S84 / ct ) * cgi . S_step , 2 * cgi . hexf ) , col , vid . linequality ) ;
2017-12-01 23:23:15 +00:00
# endif
2017-07-10 18:47:38 +00:00
}
2017-03-23 10:53:57 +00:00
2020-07-27 16:49:04 +00:00
void drawFlash ( const shiftmatrix & V ) {
2017-12-01 23:23:15 +00:00
# if CAP_CURVE
2018-09-10 15:49:51 +00:00
float ds = ptick ( 300 ) ;
2018-09-04 17:53:42 +00:00
color_t col = darkena ( iinf [ itOrbFlash ] . color , 0 , 0xFF ) ;
2017-07-10 18:47:38 +00:00
col & = ~ 1 ;
for ( int u = 0 ; u < 5 ; u + + ) {
2019-05-26 16:04:02 +00:00
ld rad = cgi . hexf * ( 2.5 + .5 * sin ( ds + u * .3 ) ) ;
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 ) {
2023-02-04 00:58:13 +00:00
queueball ( V * lzpush ( cgi . GROIN1 ) , rad , col , itOrbFlash ) ;
2019-05-11 13:04:54 +00:00
}
2019-06-01 14:59:04 +00:00
# else
if ( 1 ) ;
# endif
2019-05-11 13:04:54 +00:00
else {
2022-11-12 21:38:45 +00:00
PRING ( a ) curvepoint ( xspinpush0 ( a * cgi . S_step , rad ) ) ;
2020-07-27 16:49:04 +00:00
queuecurve ( V , col , 0x8080808 , PPR : : LINE ) ;
2019-05-11 13:04:54 +00:00
}
2017-03-23 10:53:57 +00:00
}
2017-12-01 23:23:15 +00:00
# endif
2017-07-10 18:47:38 +00:00
}
2015-08-08 13:57:52 +00:00
2019-10-25 10:44:41 +00:00
EX ld cheilevel ( ld v ) {
2019-05-26 16:04:02 +00:00
return cgi . FLOOR + ( cgi . HEAD - cgi . FLOOR ) * v ;
2019-05-15 08:51:46 +00:00
}
2019-10-25 10:44:41 +00:00
EX transmatrix chei ( const transmatrix V , int a , int b ) {
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2019-08-15 13:05:43 +00:00
if ( GDIM = = 2 ) return V ;
2023-02-04 00:58:13 +00:00
return V * lzpush ( cheilevel ( ( a + .5 ) / b ) ) ;
2019-06-01 14:59:04 +00:00
# else
return V ;
# endif
2019-05-11 13:04:54 +00:00
}
2020-07-27 16:49:04 +00:00
EX shiftmatrix chei ( const shiftmatrix V , int a , int b ) {
# if MAXMDIM >= 4
if ( GDIM = = 2 ) return V ;
2023-02-04 00:58:13 +00:00
return V * lzpush ( cheilevel ( ( a + .5 ) / b ) ) ;
2020-07-27 16:49:04 +00:00
# else
return V ;
# endif
}
void drawLove ( const shiftmatrix & V , int hdir ) {
2017-12-01 23:23:15 +00:00
# if CAP_CURVE
2018-09-10 15:49:51 +00:00
float ds = ptick ( 300 ) ;
2018-09-04 17:53:42 +00:00
color_t col = darkena ( iinf [ itOrbLove ] . color , 0 , 0xFF ) ;
2017-07-10 18:47:38 +00:00
col & = ~ 1 ;
for ( int u = 0 ; u < 5 ; u + + ) {
2020-07-27 16:49:04 +00:00
shiftmatrix V1 = chei ( V , u , 5 ) ;
2018-08-01 09:07:22 +00:00
PRING ( a ) {
2022-11-12 21:38:45 +00:00
double d = ( 1 + cos ( a * cgi . S_step ) ) / 2 ;
2019-05-26 16:04:02 +00:00
double z = a ; if ( z > cgi . S42 ) z = cgi . S84 - z ;
2017-07-10 18:47:38 +00:00
if ( z < = 10 ) d + = ( 10 - z ) * ( 10 - z ) * ( 10 - z ) / 3000. ;
2015-08-08 13:57:52 +00:00
2019-05-26 16:04:02 +00:00
ld rad = cgi . hexf * ( 2.5 + .5 * sin ( ds + u * .3 ) ) * d ;
2022-11-12 21:38:45 +00:00
curvepoint ( xspinpush0 ( ( cgi . S42 + hdir + a - 1 ) * cgi . S_step , rad ) ) ;
2017-07-10 18:47:38 +00:00
}
2020-07-27 16:49:04 +00:00
queuecurve ( V1 , col , 0x8080808 , PPR : : LINE ) ;
2017-03-23 10:53:57 +00:00
}
2017-12-01 23:23:15 +00:00
# endif
2015-08-08 13:57:52 +00:00
}
2021-05-21 23:26:59 +00:00
void drawWinter ( const shiftmatrix & V , ld hdir , color_t col ) {
2017-12-01 23:23:15 +00:00
# if CAP_QUEUE
2018-09-10 15:49:51 +00:00
float ds = ptick ( 300 ) ;
2021-05-21 23:26:59 +00:00
col = darkena ( col , 0 , 0xFF ) ;
2017-07-10 18:47:38 +00:00
for ( int u = 0 ; u < 20 ; u + + ) {
2022-11-12 21:38:45 +00:00
ld rad = sin ( ds + u * TAU / 20 ) * M_PI / S7 ;
2020-07-27 16:49:04 +00:00
shiftmatrix V1 = chei ( V , u , 20 ) ;
2019-05-26 16:04:02 +00:00
queueline ( V1 * xspinpush0 ( M_PI + hdir + rad , cgi . hexf * .5 ) , V1 * xspinpush0 ( M_PI + hdir + rad , cgi . hexf * 3 ) , col , 2 + vid . linequality ) ;
2015-08-08 13:57:52 +00:00
}
2017-12-01 23:23:15 +00:00
# endif
2015-08-08 13:57:52 +00:00
}
2020-07-27 16:49:04 +00:00
void drawLightning ( const shiftmatrix & V ) {
2017-12-01 23:23:15 +00:00
# if CAP_QUEUE
2022-03-08 00:37:35 +00:00
float ds = ptick ( 600 ) ;
2018-09-04 17:53:42 +00:00
color_t col = darkena ( iinf [ itOrbLightning ] . color , 0 , 0xFF ) ;
2017-07-10 18:47:38 +00:00
for ( int u = 0 ; u < 20 ; u + + ) {
2022-03-08 00:37:35 +00:00
ld leng , rad ;
if ( vid . flasheffects ) {
leng = 0.5 / ( 0.1 + ( rand ( ) % 100 ) / 100.0 ) ;
rad = rand ( ) % 1000 ;
}
else {
if ( u % 5 ) leng = 1.25 + sintick ( 200 , ld ( u ) * 1.25 ) * 0.25 ;
else leng = 2 + sintick ( 200 , ld ( u ) * 1.25 ) ;
2022-11-12 21:38:45 +00:00
rad = ( u + ds ) * TAU / 20 ;
2022-03-08 00:37:35 +00:00
}
2020-07-27 16:49:04 +00:00
shiftmatrix V1 = chei ( V , u , 20 ) ;
2019-05-26 16:04:02 +00:00
queueline ( V1 * xspinpush0 ( rad , cgi . hexf * 0.3 ) , V1 * xspinpush0 ( rad , cgi . hexf * leng ) , col , 2 + vid . linequality ) ;
2017-07-04 13:38:33 +00:00
}
2017-12-01 23:23:15 +00:00
# endif
2017-07-10 18:47:38 +00:00
}
2017-07-04 13:38:33 +00:00
2022-03-08 00:37:35 +00:00
void drawCurse ( const shiftmatrix & V , eItem it ) {
2021-05-21 23:26:59 +00:00
# if CAP_QUEUE
2022-03-08 00:37:35 +00:00
float ds = ptick ( 450 ) + ( it * 5.5 ) ; // Extra offset so both Gluttony and Repulsion are easily visible
color_t col = darkena ( iinf [ it ] . color , 0 , 0xFF ) ;
2021-05-21 23:26:59 +00:00
for ( int u = 0 ; u < 20 ; u + + ) {
2022-03-08 00:37:35 +00:00
ld leng , rad ;
if ( vid . flasheffects ) {
leng = 0.6 + 0.3 * randd ( ) ;
rad = rand ( ) % 1000 ;
}
else {
leng = 0.85 + sintick ( 150 , ld ( u ) * 1.25 ) * 0.15 ;
2022-11-12 21:38:45 +00:00
rad = ( u + ds ) * TAU / 20 ;
2022-03-08 00:37:35 +00:00
}
2021-05-21 23:26:59 +00:00
shiftmatrix V1 = chei ( V , u , 20 ) ;
queueline ( V1 * xspinpush0 ( rad , cgi . hexf * 0.3 ) , V1 * xspinpush0 ( rad , cgi . hexf * leng ) , col , 2 + vid . linequality ) ;
}
# endif
}
2019-08-15 13:05:43 +00:00
# define UNTRANS (GDIM == 3 ? 0x000000FF : 0)
2019-04-20 23:06:37 +00:00
2022-12-13 18:04:43 +00:00
EX transmatrix lpispin ( ) {
2022-12-15 10:43:26 +00:00
return spin180 ( ) ;
2022-12-13 18:04:43 +00:00
}
2022-06-17 07:43:37 +00:00
EX void drawPlayerEffects ( const shiftmatrix & V , const shiftmatrix & Vparam , cell * c , eMonster m ) {
2022-01-08 17:53:57 +00:00
bool onplayer = m = = moPlayer ;
2017-07-10 18:47:38 +00:00
if ( ! onplayer & & ! items [ itOrbEmpathy ] ) return ;
if ( items [ itOrbShield ] > ( shmup : : on ? 0 : ORBBASE ) ) drawShield ( V , itOrbShield ) ;
if ( items [ itOrbShell ] > ( shmup : : on ? 0 : ORBBASE ) ) drawShield ( V , itOrbShell ) ;
2017-07-04 13:38:33 +00:00
2017-07-10 18:47:38 +00:00
if ( items [ itOrbSpeed ] ) drawSpeed ( V ) ;
2022-03-08 00:37:35 +00:00
if ( items [ itCurseGluttony ] ) drawCurse ( V , itCurseGluttony ) ;
if ( items [ itCurseRepulsion ] ) drawCurse ( V , itCurseRepulsion ) ;
2017-07-04 13:38:33 +00:00
2017-07-10 18:47:38 +00:00
if ( onplayer & & ( items [ itOrbSword ] | | items [ itOrbSword2 ] ) ) {
using namespace sword ;
2015-08-08 13:57:52 +00:00
2019-08-19 08:55:02 +00:00
if ( shmup : : on & & SWORDDIM = = 2 ) {
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2017-07-10 18:47:38 +00:00
if ( items [ itOrbSword ] )
2019-05-26 16:04:02 +00:00
queuepoly ( V * spin ( shmup : : pc [ multi : : cpid ] - > swordangle ) , ( peace : : on ? cgi . shMagicShovel : cgi . shMagicSword ) , darkena ( iinf [ itOrbSword ] . color , 0 , 0xC0 + 0x30 * sintick ( 200 ) ) ) ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
if ( items [ itOrbSword2 ] )
2019-05-26 16:04:02 +00:00
queuepoly ( V * spin ( shmup : : pc [ multi : : cpid ] - > swordangle + M_PI ) , ( peace : : on ? cgi . shMagicShovel : cgi . shMagicSword ) , darkena ( iinf [ itOrbSword2 ] . color , 0 , 0xC0 + 0x30 * sintick ( 200 ) ) ) ;
2017-12-01 23:23:15 +00:00
# endif
2017-07-10 18:47:38 +00:00
}
2019-03-09 16:38:23 +00:00
2019-08-19 08:55:02 +00:00
else if ( SWORDDIM = = 3 ) {
2019-03-09 16:38:23 +00:00
# if CAP_SHAPES
2020-07-27 16:49:04 +00:00
shiftmatrix Vsword =
2022-11-12 21:38:45 +00:00
shmup : : on ? V * shmup : : swordmatrix [ multi : : cpid ] * cspin90 ( 2 , 0 )
2022-06-17 07:43:37 +00:00
: Vparam * rgpushxto0 ( inverse_shift ( gmatrix [ c ] , tC0 ( V ) ) ) * sword : : dir [ multi : : cpid ] . T ;
2019-06-24 20:28:20 +00:00
2019-03-09 16:38:23 +00:00
if ( items [ itOrbSword ] )
2019-06-24 20:28:20 +00:00
queuepoly ( Vsword * cspin ( 1 , 2 , ticks / 150. ) , ( peace : : on ? cgi . shMagicShovel : cgi . shMagicSword ) , darkena ( iinf [ itOrbSword ] . color , 0 , 0xC0 + 0x30 * sintick ( 200 ) ) ) ;
2019-03-09 16:38:23 +00:00
if ( items [ itOrbSword2 ] )
2022-12-13 18:04:43 +00:00
queuepoly ( Vsword * lpispin ( ) * cspin ( 1 , 2 , ticks / 150. ) , ( peace : : on ? cgi . shMagicShovel : cgi . shMagicSword ) , darkena ( iinf [ itOrbSword2 ] . color , 0 , 0xC0 + 0x30 * sintick ( 200 ) ) ) ;
2019-03-09 16:38:23 +00:00
# endif
}
2017-07-10 18:47:38 +00:00
2015-08-08 13:57:52 +00:00
else {
2019-06-24 20:28:20 +00:00
int & ang = sword : : dir [ multi : : cpid ] . angle ;
2019-05-28 23:01:13 +00:00
ang % = sword : : sword_angles ;
2019-02-17 17:41:40 +00:00
2019-02-17 18:39:44 +00:00
# if CAP_QUEUE || CAP_SHAPES
2022-11-12 21:38:45 +00:00
shiftmatrix Vnow = Vparam * rgpushxto0 ( inverse_shift ( Vparam , tC0 ( V ) ) ) * ddspin180 ( c , 0 ) ;
2019-02-17 17:41:40 +00:00
# endif
2019-05-28 23:01:13 +00:00
int adj = 1 - ( ( sword_angles / cwt . at - > type ) & 1 ) ;
2017-07-10 18:47:38 +00:00
2017-12-01 23:23:15 +00:00
# if CAP_QUEUE
2022-12-08 18:38:06 +00:00
if ( ! euclid & & ! mhybrid ) for ( int a = 0 ; a < sword_angles ; a + + ) {
2017-07-10 18:47:38 +00:00
if ( a = = ang & & items [ itOrbSword ] ) continue ;
2019-02-26 13:10:23 +00:00
if ( ( a + sword_angles / 2 ) % sword_angles = = ang & & items [ itOrbSword2 ] ) continue ;
2019-06-24 20:28:20 +00:00
bool longer = sword : : pos2 ( cwt . at , a - 1 ) ! = sword : : pos2 ( cwt . at , a + 1 ) ;
2019-05-28 23:01:13 +00:00
if ( sword_angles > 48 & & ! longer ) continue ;
2018-09-04 17:53:42 +00:00
color_t col = darkena ( 0xC0C0C0 , 0 , 0xFF ) ;
2019-05-26 16:04:02 +00:00
ld l0 = PURE ? 0.6 * cgi . scalefactor : longer ? 0.36 : 0.4 ;
ld l1 = PURE ? 0.7 * cgi . scalefactor : longer ? 0.44 : 0.42 ;
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2023-02-04 00:58:13 +00:00
hyperpoint h0 = GDIM = = 3 ? xpush ( l0 ) * lzpush ( cgi . FLOOR - cgi . human_height / 50 ) * C0 : xpush0 ( l0 ) ;
hyperpoint h1 = GDIM = = 3 ? xpush ( l1 ) * lzpush ( cgi . FLOOR - cgi . human_height / 50 ) * C0 : xpush0 ( l1 ) ;
2019-06-01 14:59:04 +00:00
# else
hyperpoint h0 = xpush0 ( l0 ) ;
hyperpoint h1 = xpush0 ( l1 ) ;
# endif
2020-07-27 16:49:04 +00:00
shiftmatrix T = Vnow * spin ( ( sword_angles + ( - adj - 2 * a ) ) * M_PI / sword_angles ) ;
2019-05-11 13:19:32 +00:00
queueline ( T * h0 , T * h1 , col , 1 , PPR : : SUPERLINE ) ;
2017-07-10 18:47:38 +00:00
}
2017-12-01 23:23:15 +00:00
# endif
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2017-07-10 18:47:38 +00:00
if ( items [ itOrbSword ] )
2019-05-28 23:01:13 +00:00
queuepoly ( Vnow * spin ( M_PI + ( - adj - 2 * ang ) * M_PI / sword_angles ) , ( peace : : on ? cgi . shMagicShovel : cgi . shMagicSword ) , darkena ( iinf [ itOrbSword ] . color , 0 , 0x80 + 0x70 * sintick ( 200 ) ) ) ;
2017-07-10 18:47:38 +00:00
if ( items [ itOrbSword2 ] )
2019-05-28 23:01:13 +00:00
queuepoly ( Vnow * spin ( ( - adj - 2 * ang ) * M_PI / sword_angles ) , ( peace : : on ? cgi . shMagicShovel : cgi . shMagicSword ) , darkena ( iinf [ itOrbSword2 ] . color , 0 , 0x80 + 0x70 * sintick ( 200 ) ) ) ;
2017-12-01 23:23:15 +00:00
# endif
2015-08-08 13:57:52 +00:00
}
}
2017-10-28 08:04:28 +00:00
if ( onplayer & & items [ itOrbSafety ] ) drawSafety ( V , c - > type ) ;
2017-07-04 13:38:33 +00:00
2017-07-10 18:47:38 +00:00
if ( onplayer & & items [ itOrbFlash ] ) drawFlash ( V ) ;
if ( onplayer & & items [ itOrbLove ] ) drawLove ( V , 0 ) ; // displaydir(c, cwt.spin));
2017-07-04 13:38:33 +00:00
2017-07-10 18:47:38 +00:00
if ( items [ itOrbWinter ] )
2021-05-21 23:26:59 +00:00
drawWinter ( V , 0 , iinf [ itOrbWinter ] . color ) ; // displaydir(c, cwt.spin));
if ( items [ itOrbFire ] )
drawWinter ( V , 0 , iinf [ itOrbFire ] . color ) ; // displaydir(c, cwt.spin));
if ( items [ itCurseWater ] )
drawWinter ( V , 0 , iinf [ itCurseWater ] . color ) ; // displaydir(c, cwt.spin));
2017-07-10 18:47:38 +00:00
if ( onplayer & & items [ itOrbLightning ] ) drawLightning ( V ) ;
if ( safetyat > 0 ) {
int tim = ticks - safetyat ;
if ( tim > 2500 ) safetyat = 0 ;
for ( int u = tim ; u < = 2500 ; u + + ) {
if ( ( u - tim ) % 250 ) continue ;
2019-05-26 16:04:02 +00:00
ld rad = cgi . hexf * u / 250 ;
2018-09-04 17:53:42 +00:00
color_t col = darkena ( iinf [ itOrbSafety ] . color , 0 , 0xFF ) ;
2018-08-01 09:07:22 +00:00
PRING ( a )
2022-11-12 21:38:45 +00:00
curvepoint ( xspinpush0 ( a * cgi . S_step , rad ) ) ;
2020-07-27 16:49:04 +00:00
queuecurve ( V , col , 0 , PPR : : LINE ) ;
2015-08-08 13:57:52 +00:00
}
2017-07-10 18:47:38 +00:00
}
2015-08-08 13:57:52 +00:00
}
2020-07-27 16:49:04 +00:00
void drawStunStars ( const shiftmatrix & V , int t ) {
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2017-07-10 18:47:38 +00:00
for ( int i = 0 ; i < 3 * t ; i + + ) {
2022-11-12 21:38:45 +00:00
shiftmatrix V2 = V * spin ( TAU * i / ( 3 * t ) + ptick ( 200 ) ) ;
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2023-02-04 00:58:13 +00:00
if ( GDIM = = 3 ) V2 = V2 * lzpush ( cgi . HEAD ) ;
2019-06-01 14:59:04 +00:00
# endif
2019-05-26 16:04:02 +00:00
queuepolyat ( V2 , cgi . shFlailBall , 0xFFFFFFFF , PPR : : STUNSTARS ) ;
2017-07-10 18:47:38 +00:00
}
2017-12-01 23:23:15 +00:00
# endif
2017-07-10 18:47:38 +00:00
}
2017-03-23 10:53:57 +00:00
2019-10-25 10:44:41 +00:00
EX namespace tortoise {
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
// small is 0 or 2
2020-07-27 16:49:04 +00:00
void draw ( const shiftmatrix & V , int bits , int small , int stuntime ) {
2017-03-23 10:53:57 +00:00
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2018-09-04 17:53:42 +00:00
color_t eyecolor = getBit ( bits , tfEyeHue ) ? 0xFF0000 : 0xC0C0C0 ;
color_t shellcolor = getBit ( bits , tfShellHue ) ? 0x00C040 : 0xA06000 ;
color_t scutecolor = getBit ( bits , tfScuteHue ) ? 0x00C040 : 0xA06000 ;
color_t skincolor = getBit ( bits , tfSkinHue ) ? 0x00C040 : 0xA06000 ;
2017-07-10 18:47:38 +00:00
if ( getBit ( bits , tfShellSat ) ) shellcolor = gradient ( shellcolor , 0xB0B0B0 , 0 , .5 , 1 ) ;
if ( getBit ( bits , tfScuteSat ) ) scutecolor = gradient ( scutecolor , 0xB0B0B0 , 0 , .5 , 1 ) ;
if ( getBit ( bits , tfSkinSat ) ) skincolor = gradient ( skincolor , 0xB0B0B0 , 0 , .5 , 1 ) ;
if ( getBit ( bits , tfShellDark ) ) shellcolor = gradient ( shellcolor , 0 , 0 , .5 , 1 ) ;
if ( getBit ( bits , tfSkinDark ) ) skincolor = gradient ( skincolor , 0 , 0 , .5 , 1 ) ;
2020-03-02 02:06:15 +00:00
if ( bits < 0 ) {
skincolor = 0xC00060 ;
shellcolor = 0xFF00FF ;
scutecolor = 0x6000C0 ;
eyecolor = 0xFFFFFF ;
}
2017-12-01 23:23:15 +00:00
for ( int i = 0 ; i < 12 ; i + + ) {
2018-09-04 17:53:42 +00:00
color_t col =
2017-07-10 18:47:38 +00:00
i = = 0 ? shellcolor :
i < 8 ? scutecolor :
skincolor ;
int b = getBit ( bits , i ) ;
int d = darkena ( col , 0 , 0xFF ) ;
if ( i > = 1 & & i < = 7 ) if ( b ) { d = darkena ( col , 1 , 0xFF ) ; b = 0 ; }
if ( i > = 8 & & i < = 11 & & stuntime > = 3 ) continue ;
2017-12-01 23:23:15 +00:00
2019-05-26 16:04:02 +00:00
queuepoly ( V , cgi . shTortoise [ i ] [ b + small ] , d ) ;
2017-07-10 18:47:38 +00:00
if ( ( i > = 5 & & i < = 7 ) | | ( i > = 9 & & i < = 10 ) )
2022-12-13 18:04:43 +00:00
queuepoly ( V * lmirror ( ) , cgi . shTortoise [ i ] [ b + small ] , d ) ;
2017-07-10 18:47:38 +00:00
if ( i = = 8 ) {
for ( int k = 0 ; k < stuntime ; k + + ) {
eyecolor & = 0xFEFEFE ;
eyecolor > > = 1 ;
}
2019-05-26 16:04:02 +00:00
queuepoly ( V , cgi . shTortoise [ 12 ] [ b + small ] , darkena ( eyecolor , 0 , 0xFF ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( V * lmirror ( ) , cgi . shTortoise [ 12 ] [ b + small ] , darkena ( eyecolor , 0 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
}
}
2017-12-01 23:23:15 +00:00
# endif
2017-07-10 18:47:38 +00:00
}
2017-03-23 10:53:57 +00:00
2019-10-25 10:44:41 +00:00
EX int getMatchColor ( int bits ) {
2017-07-10 18:47:38 +00:00
int mcol = 1 ;
double d = tortoise : : getScent ( bits ) ;
if ( d > 0 ) mcol = 0xFFFFFF ;
else if ( d < 0 ) mcol = 0 ;
2022-11-12 21:38:45 +00:00
int dd = 0xFF * ( atan ( fabs ( d ) / 2 ) / 90. _deg ) ;
2017-07-10 18:47:38 +00:00
return gradient ( 0x487830 , mcol , 0 , dd , 0xFF ) ;
2017-03-23 10:53:57 +00:00
}
2020-02-23 01:51:27 +00:00
EX }
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
double footfun ( double d ) {
d - = floor ( d ) ;
return
d < .25 ? d :
d < .75 ? .5 - d :
d - 1 ;
}
2015-08-08 13:57:52 +00:00
2019-08-09 21:08:42 +00:00
EX bool ivoryz ;
2022-12-06 00:04:26 +00:00
/** Change the level of V. Takes ivoryz and all geometries into account */
EX transmatrix at_smart_lof ( const transmatrix & V , ld lev ) {
if ( ! mmspatial ) return V ;
if ( ivoryz ) return mzscale ( V , lev ) ;
return orthogonal_move_fol ( V , lev ) ;
}
EX shiftmatrix at_smart_lof ( const shiftmatrix & V , ld lev ) { return shiftless ( at_smart_lof ( V . T , lev ) , V . shift ) ; }
2020-07-27 16:49:04 +00:00
void animallegs ( const shiftmatrix & V , eMonster mo , color_t col , double footphase ) {
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2017-07-10 18:47:38 +00:00
footphase / = SCALE ;
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
bool dog = mo = = moRunDog ;
bool bug = mo = = moBug0 | | mo = = moMetalBeast ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
if ( bug ) footphase * = 2.5 ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
double rightfoot = footfun ( footphase / .4 / 2 ) / 4 * 2 ;
double leftfoot = footfun ( footphase / .4 / 2 - ( bug ? .5 : dog ? .1 : .25 ) ) / 4 * 2 ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
if ( bug ) rightfoot / = 2.5 , leftfoot / = 2.5 ;
2015-08-08 13:57:52 +00:00
2019-02-28 02:38:22 +00:00
rightfoot * = SCALE ;
leftfoot * = SCALE ;
2017-07-10 18:47:38 +00:00
if ( ! footphase ) rightfoot = leftfoot = 0 ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
hpcshape * sh [ 6 ] [ 4 ] = {
2019-05-26 16:04:02 +00:00
{ & cgi . shDogFrontPaw , & cgi . shDogRearPaw , & cgi . shDogFrontLeg , & cgi . shDogRearLeg } ,
{ & cgi . shWolfFrontPaw , & cgi . shWolfRearPaw , & cgi . shWolfFrontLeg , & cgi . shWolfRearLeg } ,
{ & cgi . shReptileFrontFoot , & cgi . shReptileRearFoot , & cgi . shReptileFrontLeg , & cgi . shReptileRearLeg } ,
{ & cgi . shBugLeg , NULL , NULL , NULL } ,
{ & cgi . shTrylobiteFrontClaw , & cgi . shTrylobiteRearClaw , & cgi . shTrylobiteFrontLeg , & cgi . shTrylobiteRearLeg } ,
{ & cgi . shBullFrontHoof , & cgi . shBullRearHoof , & cgi . shBullFrontHoof , & cgi . shBullRearHoof } ,
2017-07-10 18:47:38 +00:00
} ;
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
hpcshape * * x = sh [ mo = = moRagingBull ? 5 : mo = = moBug0 ? 3 : mo = = moMetalBeast ? 4 : mo = = moRunDog ? 0 : mo = = moReptile ? 2 : 1 ] ;
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2023-02-04 10:50:48 +00:00
if ( GDIM = = 3 & & ! ( embedded_plane & & gproduct ) ) {
2019-05-24 21:50:06 +00:00
if ( x [ 0 ] ) queuepolyat ( V * front_leg_move * cspin ( 0 , 2 , rightfoot / leg_length ) * front_leg_move_inverse , * x [ 0 ] , col , PPR : : MONSTER_FOOT ) ;
2022-12-13 18:04:43 +00:00
if ( x [ 0 ] ) queuepolyat ( V * lmirror ( ) * front_leg_move * cspin ( 0 , 2 , leftfoot / leg_length ) * front_leg_move_inverse , * x [ 0 ] , col , PPR : : MONSTER_FOOT ) ;
2019-05-24 21:50:06 +00:00
if ( x [ 1 ] ) queuepolyat ( V * rear_leg_move * cspin ( 0 , 2 , - rightfoot / leg_length ) * rear_leg_move_inverse , * x [ 1 ] , col , PPR : : MONSTER_FOOT ) ;
2022-12-13 18:04:43 +00:00
if ( x [ 1 ] ) queuepolyat ( V * lmirror ( ) * rear_leg_move * cspin ( 0 , 2 , - leftfoot / leg_length ) * rear_leg_move_inverse , * x [ 1 ] , col , PPR : : MONSTER_FOOT ) ;
2019-05-16 15:22:04 +00:00
return ;
}
2019-06-01 14:59:04 +00:00
# endif
2015-08-08 13:57:52 +00:00
2022-12-06 00:04:26 +00:00
const shiftmatrix VL = at_smart_lof ( V , cgi . ALEG0 ) ;
const shiftmatrix VAML = at_smart_lof ( V , cgi . ALEG ) ;
2017-03-23 10:53:57 +00:00
2023-02-04 10:50:48 +00:00
if ( x [ 0 ] ) queuepolyat ( VL * lxpush ( rightfoot ) , * x [ 0 ] , col , PPR : : MONSTER_FOOT ) ;
if ( x [ 0 ] ) queuepolyat ( VL * lmirror ( ) * lxpush ( leftfoot ) , * x [ 0 ] , col , PPR : : MONSTER_FOOT ) ;
if ( x [ 1 ] ) queuepolyat ( VL * lxpush ( - rightfoot ) , * x [ 1 ] , col , PPR : : MONSTER_FOOT ) ;
if ( x [ 1 ] ) queuepolyat ( VL * lmirror ( ) * lxpush ( - leftfoot ) , * x [ 1 ] , col , PPR : : MONSTER_FOOT ) ;
2015-08-08 13:57:52 +00:00
2023-02-04 10:50:48 +00:00
if ( x [ 2 ] ) queuepolyat ( VAML * lxpush ( rightfoot / 2 ) , * x [ 2 ] , col , PPR : : MONSTER_FOOT ) ;
if ( x [ 2 ] ) queuepolyat ( VAML * lmirror ( ) * lxpush ( leftfoot / 2 ) , * x [ 2 ] , col , PPR : : MONSTER_FOOT ) ;
if ( x [ 3 ] ) queuepolyat ( VAML * lxpush ( - rightfoot / 2 ) , * x [ 3 ] , col , PPR : : MONSTER_FOOT ) ;
if ( x [ 3 ] ) queuepolyat ( VAML * lmirror ( ) * lxpush ( - leftfoot / 2 ) , * x [ 3 ] , col , PPR : : MONSTER_FOOT ) ;
2017-12-01 23:23:15 +00:00
# endif
2015-08-08 13:57:52 +00:00
}
2019-08-09 19:00:52 +00:00
EX bool noshadow ;
2018-06-25 20:59:29 +00:00
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2020-07-27 16:49:04 +00:00
EX void ShadowV ( const shiftmatrix & V , const hpcshape & bp , PPR prio IS ( PPR : : MONSTER_SHADOW ) ) {
2019-05-13 07:34:22 +00:00
if ( WDIM = = 2 & & GDIM = = 3 & & bp . shs ! = bp . she ) {
2023-02-05 20:58:56 +00:00
if ( noshadow ) return ;
2019-05-13 11:18:55 +00:00
auto & p = queuepolyat ( V , bp , 0x18 , PPR : : TRANSPARENT_SHADOW ) ;
2019-05-13 07:34:22 +00:00
p . outline = 0 ;
p . subprio = - 100 ;
p . offset = bp . shs ;
p . cnt = bp . she - bp . shs ;
p . flags & = ~ POLY_TRIANGLES ;
p . tinf = NULL ;
return ;
}
2017-07-10 18:47:38 +00:00
if ( mmspatial ) {
2019-02-22 20:27:42 +00:00
if ( model_needs_depth ( ) | | noshadow )
2017-07-10 18:47:38 +00:00
return ; // shadows break the depth testing
2018-09-04 17:53:42 +00:00
dynamicval < color_t > p ( poly_outline , OUTLINE_TRANS ) ;
2017-07-10 18:47:38 +00:00
queuepolyat ( V , bp , SHADOW_MON , prio ) ;
2015-08-08 13:57:52 +00:00
}
}
2019-02-17 18:39:44 +00:00
# endif
2015-08-08 13:57:52 +00:00
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2020-07-27 16:49:04 +00:00
transmatrix otherbodyparts ( const shiftmatrix & V , color_t col , eMonster who , double footphase ) {
2017-07-10 18:47:38 +00:00
2022-12-08 18:38:06 +00:00
# define VFOOT ((GDIM == 2 || mhybrid) ? V : at_smart_lof(V, cgi.LEG0))
2022-12-06 00:04:26 +00:00
# define VLEG at_smart_lof(V, cgi.LEG)
# define VGROIN at_smart_lof(V, cgi.GROIN)
# define VBODY at_smart_lof(V, cgi.BODY)
# define VBODY1 at_smart_lof(V, cgi.BODY1)
# define VBODY2 at_smart_lof(V, cgi.BODY2)
# define VBODY3 at_smart_lof(V, cgi.BODY3)
# define VNECK at_smart_lof(V, cgi.NECK)
# define VHEAD at_smart_lof(V, cgi.HEAD)
# define VHEAD1 at_smart_lof(V, cgi.HEAD1)
# define VHEAD2 at_smart_lof(V, cgi.HEAD2)
# define VHEAD3 at_smart_lof(V, cgi.HEAD3)
2017-07-10 18:47:38 +00:00
# define VALEGS V
2022-12-06 00:04:26 +00:00
# define VABODY at_smart_lof(V, cgi.ABODY)
# define VAHEAD at_smart_lof(V, cgi.AHEAD)
2017-05-27 19:40:40 +00:00
2017-07-10 18:47:38 +00:00
# define VFISH V
2022-12-06 00:04:26 +00:00
# define VBIRD ((GDIM == 3 || (where && bird_disruption(where))) ? (WDIM == 2 ? at_smart_lof(V, cgi.BIRD) : V) : at_smart_lof(V, cgi.BIRD + .05 * sintick(1000, static_cast<int>(reinterpret_cast<size_t>(where)) / 1000.)))
# define VGHOST at_smart_lof(V, cgi.GHOST)
2015-08-08 13:57:52 +00:00
2022-12-06 00:04:26 +00:00
# define VSLIMEEYE orthogonal_move_fol(V, cgi.FLATEYE)
2017-05-27 19:40:40 +00:00
2017-07-10 18:47:38 +00:00
// if(!mmspatial && !footphase && who != moSkeleton) return;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
footphase / = SCALE ;
2019-02-28 02:38:22 +00:00
double rightfoot = footfun ( footphase / .4 / 2.5 ) / 4 * 2.5 * SCALE ;
2018-12-23 13:00:52 +00:00
const double wobble = - 1 ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
// todo
2015-08-08 13:57:52 +00:00
2019-08-15 13:05:43 +00:00
if ( detaillevel > = 2 & & GDIM = = 2 ) {
2022-12-06 00:04:26 +00:00
shiftmatrix VL = at_smart_lof ( V , cgi . LEG1 ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VL * xpush ( rightfoot * 3 / 4 ) , cgi . shHumanLeg , col ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VL * lmirror ( ) * xpush ( - rightfoot * 3 / 4 ) , cgi . shHumanLeg , col ) ;
2017-07-10 18:47:38 +00:00
}
2015-08-08 13:57:52 +00:00
2019-08-15 13:05:43 +00:00
if ( GDIM = = 2 ) {
2022-12-06 00:04:26 +00:00
shiftmatrix VL = at_smart_lof ( V , cgi . LEG ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VL * xpush ( rightfoot / 2 ) , cgi . shHumanLeg , col ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VL * lmirror ( ) * xpush ( - rightfoot / 2 ) , cgi . shHumanLeg , col ) ;
2017-07-10 18:47:38 +00:00
}
2015-08-08 13:57:52 +00:00
2019-08-15 13:05:43 +00:00
if ( detaillevel > = 2 & & GDIM = = 2 ) {
2022-12-06 00:04:26 +00:00
shiftmatrix VL = at_smart_lof ( V , cgi . LEG3 ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VL * xpush ( rightfoot / 4 ) , cgi . shHumanLeg , col ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VL * lmirror ( ) * xpush ( - rightfoot / 4 ) , cgi . shHumanLeg , col ) ;
2017-07-10 18:47:38 +00:00
}
2015-08-08 13:57:52 +00:00
2020-07-27 16:49:04 +00:00
shiftmatrix Tright , Tleft ;
2019-04-20 23:21:03 +00:00
2023-01-26 23:27:10 +00:00
if ( GDIM = = 2 | | mhybrid | | cgi . emb - > is_euc_in_product ( ) ) {
2019-04-20 23:21:03 +00:00
Tright = VFOOT * xpush ( rightfoot ) ;
2022-12-13 18:04:43 +00:00
Tleft = VFOOT * lmirror ( ) * xpush ( - rightfoot ) ;
2019-04-20 23:21:03 +00:00
}
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2019-04-20 23:21:03 +00:00
else {
2020-07-27 16:49:04 +00:00
shiftmatrix V1 = V ;
2022-12-13 18:04:43 +00:00
if ( WDIM = = 2 ) V1 = V1 * lzpush ( cgi . GROIN ) ;
2023-01-26 23:27:10 +00:00
int zdir = cgi . emb - > is_euc_in_nil ( ) ? 1 : 2 ;
2022-12-13 18:04:43 +00:00
Tright = V1 * cspin ( 0 , zdir , rightfoot / leg_length ) ;
Tleft = V1 * lmirror ( ) * cspin ( zdir , 0 , rightfoot / leg_length ) ;
Tright = V1 ; Tleft = V1 * lmirror ( ) ;
if ( WDIM = = 2 ) Tleft = Tleft * lzpush ( - cgi . GROIN ) , Tright = Tright * lzpush ( - cgi . GROIN ) ;
2019-04-20 23:21:03 +00:00
}
2019-06-01 14:59:04 +00:00
# endif
2019-04-20 23:21:03 +00:00
2019-08-15 13:05:43 +00:00
if ( who = = moWaterElemental & & GDIM = = 2 ) {
2017-07-10 18:47:38 +00:00
double fishtail = footfun ( footphase / .4 ) / 4 * 1.5 ;
2019-05-26 16:04:02 +00:00
queuepoly ( VFOOT * xpush ( fishtail ) , cgi . shFishTail , watercolor ( 100 ) ) ;
2017-07-10 18:47:38 +00:00
}
else if ( who = = moSkeleton ) {
2019-05-26 16:04:02 +00:00
queuepoly ( Tright , cgi . shSkeletalFoot , col ) ;
queuepoly ( Tleft , cgi . shSkeletalFoot , col ) ;
2018-12-23 13:00:52 +00:00
return spin ( rightfoot * wobble ) ;
2017-07-10 18:47:38 +00:00
}
else if ( isTroll ( who ) | | who = = moMonkey | | who = = moYeti | | who = = moRatling | | who = = moRatlingAvenger | | who = = moGoblin ) {
2019-05-26 16:04:02 +00:00
queuepoly ( Tright , cgi . shYetiFoot , col ) ;
queuepoly ( Tleft , cgi . shYetiFoot , col ) ;
2015-08-08 13:57:52 +00:00
}
else {
2019-05-26 16:04:02 +00:00
queuepoly ( Tright , cgi . shHumanFoot , col ) ;
queuepoly ( Tleft , cgi . shHumanFoot , col ) ;
2015-08-08 13:57:52 +00:00
}
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 | | ! mmspatial ) return spin ( rightfoot * wobble ) ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
if ( detaillevel > = 2 & & who ! = moZombie )
2022-12-06 00:04:26 +00:00
queuepoly ( at_smart_lof ( V , cgi . NECK1 ) , cgi . shHumanNeck , col ) ;
2017-07-10 18:47:38 +00:00
if ( detaillevel > = 1 ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VGROIN , cgi . shHumanGroin , col ) ;
if ( who ! = moZombie ) queuepoly ( VNECK , cgi . shHumanNeck , col ) ;
2015-08-08 13:57:52 +00:00
}
2017-07-10 18:47:38 +00:00
if ( detaillevel > = 2 ) {
2022-12-06 00:04:26 +00:00
queuepoly ( at_smart_lof ( V , cgi . GROIN1 ) , cgi . shHumanGroin , col ) ;
if ( who ! = moZombie ) queuepoly ( at_smart_lof ( V , cgi . NECK3 ) , cgi . shHumanNeck , col ) ;
2016-08-26 09:58:03 +00:00
}
2018-12-23 13:00:52 +00:00
return spin ( rightfoot * wobble ) ;
2016-08-26 09:58:03 +00:00
}
2019-02-17 18:39:44 +00:00
# endif
2016-08-26 09:58:03 +00:00
2019-10-25 10:44:41 +00:00
EX bool drawstar ( cell * c ) {
2017-07-10 18:47:38 +00:00
for ( int t = 0 ; t < c - > type ; t + + )
2018-08-17 22:46:45 +00:00
if ( c - > move ( t ) & & c - > move ( t ) - > wall ! = waSulphur & & c - > move ( t ) - > wall ! = waSulphurC & &
c - > move ( t ) - > wall ! = waBarrier )
2017-07-10 18:47:38 +00:00
return false ;
return true ;
2017-05-27 19:40:40 +00:00
}
2019-10-25 10:44:41 +00:00
EX bool drawing_usershape_on ( cell * c , mapeditor : : eShapegroup sg ) {
2018-08-31 18:59:58 +00:00
# if CAP_EDIT
2018-08-28 12:09:36 +00:00
return c & & c = = mapeditor : : drawcell & & mapeditor : : drawcellShapeGroup ( ) = = sg ;
2018-08-31 18:59:58 +00:00
# else
return false ;
# endif
2018-08-28 11:45:11 +00:00
}
2019-10-25 10:44:41 +00:00
EX color_t kind_outline ( eItem it ) {
2019-02-28 15:24:46 +00:00
int k = itemclass ( it ) ;
if ( k = = IC_TREASURE )
return OUTLINE_TREASURE ;
else if ( k = = IC_ORB )
return OUTLINE_ORB ;
else
return OUTLINE_OTHER ;
}
2024-07-23 13:50:59 +00:00
/** should objects fly slightly up and down in product/twisted product geometries */
EX bool bobbing = true ;
2020-07-27 16:49:04 +00:00
EX shiftmatrix face_the_player ( const shiftmatrix V ) {
2019-08-15 13:05:43 +00:00
if ( GDIM = = 2 ) return V ;
2024-07-23 13:50:59 +00:00
if ( mproduct ) return bobbing ? orthogonal_move ( V , cos ( ptick ( 750 ) ) * cgi . plevel / 16 ) : V ;
if ( mhybrid ) return bobbing ? V * zpush ( cos ( ptick ( 750 ) ) * cgi . plevel / 16 ) : V ;
2019-08-26 07:06:39 +00:00
transmatrix dummy ; /* used only in prod anyways */
2023-02-04 01:04:35 +00:00
if ( embedded_plane & & ! cgi . emb - > is_same_in_same ( ) ) return V ;
if ( nonisotropic ) return shiftless ( spin_towards ( unshift ( V ) , dummy , C0 , 2 , 0 ) ) ;
2021-02-04 20:29:11 +00:00
# if CAP_VR
if ( vrhr : : enabled ) {
2024-03-24 10:14:28 +00:00
shiftpoint h = tC0 ( V ) ;
2021-02-04 20:29:11 +00:00
hyperpoint uh = unshift ( h ) ;
2024-03-24 10:14:28 +00:00
return shiftless ( cspin90 ( 1 , 2 ) * rspintox ( cspin90 ( 2 , 1 ) * uh ) * xpush ( hdist0 ( uh ) ) * cspin90 ( 0 , 2 ) * spin270 ( ) ) ;
2021-02-04 20:29:11 +00:00
}
# endif
2024-03-24 10:14:28 +00:00
2019-03-23 15:26:53 +00:00
return rgpushxto0 ( tC0 ( V ) ) ;
}
2019-08-09 21:08:42 +00:00
EX hpcshape & orbshape ( eOrbshape s ) {
2022-10-06 11:10:57 +00:00
if ( vid . orbmode = = 0 ) return cgi . shRing ;
2019-03-23 15:26:53 +00:00
switch ( s ) {
2019-05-26 16:04:02 +00:00
case osLove : return cgi . shLoveRing ;
case osRanged : return cgi . shTargetRing ;
2022-10-06 11:10:57 +00:00
case osOffensive : return cgi . shSawRing ;
case osDirectional : return vid . orbmode = = 2 ? cgi . shSawRing : cgi . shSpearRing ;
2019-05-26 16:04:02 +00:00
case osFriend : return cgi . shPeaceRing ;
case osUtility : return cgi . shGearRing ;
2021-05-02 11:39:09 +00:00
case osPowerUtility : return cgi . shPowerGearRing ;
2019-05-26 16:04:02 +00:00
case osWarping : return cgi . shHeptaRing ;
2020-02-25 23:56:06 +00:00
case osFrog : return cgi . shFrogRing ;
2021-05-02 11:39:09 +00:00
case osProtective : return cgi . shProtectiveRing ;
case osTerraform : return cgi . shTerraRing ;
case osMovement : return cgi . shMoveRing ;
2019-05-26 16:04:02 +00:00
default : return cgi . shRing ;
2019-03-23 15:26:53 +00:00
}
}
2021-05-09 00:25:05 +00:00
void queue_ring ( const shiftmatrix & V , hpcshape & sh , color_t col , PPR p ) {
queuepolyat ( V , sh , col , p ) . outline = 0 ;
auto & p1 = queuepolyat ( V , sh , col , p ) ;
p1 . cnt = cgi . orb_inner_ring ;
p1 . color = 0 ;
auto & p2 = queuepolyat ( V , sh , col , p ) ;
p2 . color = 0 ;
p2 . offset + = cgi . orb_inner_ring ;
p2 . cnt - = cgi . orb_inner_ring + 1 ;
}
2020-02-29 19:30:15 +00:00
EX color_t orb_auxiliary_color ( eItem it ) {
if ( it = = itOrbFire ) return firecolor ( 200 ) ;
2022-08-29 02:06:01 +00:00
if ( it = = itOrbWater ) return 0x000060 ;
2020-02-29 19:30:15 +00:00
if ( it = = itOrbFriend | | it = = itOrbDiscord ) return 0xC0C0C0 ;
if ( it = = itOrbFrog ) return 0xFF0000 ;
if ( it = = itOrbImpact ) return 0xFF0000 ;
2022-10-04 16:14:16 +00:00
if ( it = = itOrbPhasing ) return 0xFF0000 ;
if ( it = = itOrbDash ) return 0xFF0000 ;
2020-02-29 19:30:15 +00:00
if ( it = = itOrbFreedom ) return 0xC0FF00 ;
if ( it = = itOrbPlague ) return 0x409040 ;
if ( it = = itOrbChaos ) return 0xFF00FF ;
if ( it = = itOrbAir ) return 0xFFFFFF ;
if ( it = = itOrbUndeath ) return minf [ moFriendlyGhost ] . color ;
if ( it = = itOrbRecall ) return 0x101010 ;
2022-08-27 01:48:21 +00:00
if ( it = = itOrbLife ) return 0x90B090 ;
2020-02-29 19:30:15 +00:00
if ( it = = itOrbSlaying ) return 0xFF0000 ;
2022-08-27 01:48:21 +00:00
if ( it = = itOrbSide1 ) return 0x307080 ;
2022-08-27 02:10:39 +00:00
if ( it = = itOrbDigging ) return 0x606060 ;
2022-08-27 19:43:22 +00:00
if ( it = = itOrbEnergy ) return 0xFFFF80 ;
2020-02-29 19:30:15 +00:00
return iinf [ it ] . color ;
}
2022-10-04 16:14:16 +00:00
EX color_t orb_inner_color ( eItem it ) {
if ( it = = itOrbWater ) return 0x0070C0 ;
if ( it = = itOrbEnergy ) return 0x8B4513 ;
// if(it == itOrbDash) return 0xFF0000;
if ( it = = itOrbSide1 ) return 0x00FF00 ;
// if(it == itOrbPhasing) return 0xFF0000;
if ( it = = itOrbDigging ) return 0x00FF00 ;
if ( it = = itOrbLife ) return 0x306000 ;
return iinf [ it ] . color ;
}
2021-04-15 13:26:32 +00:00
EX void draw_ascii ( const shiftmatrix & V , char glyph , color_t col , ld size ) {
string s = s0 + glyph ;
int id = isize ( ptds ) ;
if ( WDIM = = 2 & & GDIM = = 3 )
2024-03-21 17:44:19 +00:00
queuestrn ( V * lzpush ( cgi . FLOOR - cgi . scalefactor * size / 4 ) , size * mapfontscale / 100 , s , darkenedby ( col , darken ) , 0 ) ;
2021-04-15 13:26:32 +00:00
else
2024-03-21 17:44:19 +00:00
queuestrn ( V , mapfontscale / 100 , s , darkenedby ( col , darken ) , GDIM = = 3 ? 0 : 2 ) ;
2021-04-15 13:26:32 +00:00
while ( id < isize ( ptds ) ) ptds [ id + + ] - > prio = PPR : : MONSTER_BODY ;
}
2024-03-24 10:14:05 +00:00
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 ) ;
2024-05-09 19:10:53 +00:00
addradar ( P , ' X ' , iinf [ itCompass ] . color , 0xFF , true ) ;
2024-03-24 10:14:05 +00:00
}
return true ;
}
2020-07-27 16:49:04 +00:00
EX bool drawItemType ( eItem it , cell * c , const shiftmatrix & V , color_t icol , int pticks , bool hidden ) {
2021-04-15 13:26:32 +00:00
if ( ! it ) return false ;
2019-02-17 17:41:40 +00:00
char xch = iinf [ it ] . glyph ;
2021-04-15 13:26:32 +00:00
# if MAXMDIM >= 4
if ( c & & GDIM = = 3 )
addradar ( V , xch , icol , kind_outline ( it ) ) ;
# endif
if ( WDIM = = 3 & & c = = centerover & & in_perspective ( ) & & hdist0 ( tC0 ( V ) ) < cgi . orbsize * 0.25 ) return false ;
if ( ! mmitem | | ! CAP_SHAPES ) {
draw_ascii ( V , iinf [ it ] . glyph , icol , 1 ) ;
return true ;
}
# if CAP_SHAPES
2022-01-31 21:21:36 +00:00
auto sinptick = [ c , pticks ] ( int period ) { return c ? sintick ( period ) : sin ( animation_factor * vid . ispeed * pticks / period ) ; } ;
2022-11-12 21:38:45 +00:00
auto spinptick = [ c , pticks ] ( int period , ld phase ) { return c ? spintick ( period , phase ) : spin ( ( animation_factor * vid . ispeed * pticks ) / period + phase * TAU ) ; } ;
2017-10-28 08:04:28 +00:00
int ct6 = c ? ctof ( c ) : 1 ;
2017-07-10 18:47:38 +00:00
hpcshape * xsh =
2019-05-26 16:04:02 +00:00
( it = = itPirate | | it = = itKraken ) ? & cgi . shPirateX :
( it = = itBuggy | | it = = itBuggy2 ) ? & cgi . shPirateX :
it = = itHolyGrail ? & cgi . shGrail :
isElementalShard ( it ) ? & cgi . shElementalShard :
2021-05-29 13:47:02 +00:00
( it = = itBombEgg | | it = = itTrollEgg | | it = = itCursed ) ? & cgi . shEgg :
2022-08-25 08:38:22 +00:00
( it = = itFrog | | it = = itWhirlpool ) ? & cgi . shDisk :
2019-05-26 16:04:02 +00:00
it = = itHunting ? & cgi . shTriangle :
2021-05-27 11:00:20 +00:00
( it = = itDodeca | | it = = itDice ) ? & cgi . shDodeca :
2019-05-26 16:04:02 +00:00
xch = = ' * ' ? & cgi . shGem [ ct6 ] :
xch = = ' ( ' ? & cgi . shKnife :
it = = itShard ? & cgi . shMFloor . b [ 0 ] :
it = = itTreat ? & cgi . shTreat :
it = = itSlime ? & cgi . shEgg :
xch = = ' % ' ? & cgi . shDaisy : xch = = ' $ ' ? & cgi . shStar : xch = = ' ; ' ? & cgi . shTriangle :
xch = = ' ! ' ? & cgi . shTriangle : it = = itBone ? & cgi . shNecro : it = = itStatue ? & cgi . shStatue :
2020-03-02 18:52:22 +00:00
among ( it , itIvory , itEclectic ) ? & cgi . shFigurine :
2019-05-26 16:04:02 +00:00
xch = = ' ? ' ? & cgi . shBookCover :
it = = itKey ? & cgi . shKey :
it = = itRevolver ? & cgi . shGun :
2017-07-10 18:47:38 +00:00
NULL ;
2019-02-28 15:24:46 +00:00
if ( c & & doHighlight ( ) )
poly_outline = kind_outline ( it ) ;
2019-04-07 01:07:39 +00:00
2020-07-27 16:49:04 +00:00
shiftmatrix Vit = V ;
2023-02-04 09:18:01 +00:00
if ( embedded_plane & & c & & it ! = itBabyTortoise ) Vit = orthogonal_move_fol ( V , cgi . STUFF ) ;
2022-12-08 18:38:06 +00:00
if ( c & & mproduct )
2022-12-06 00:04:26 +00:00
Vit = orthogonal_move ( Vit , sin ( ptick ( 750 ) ) * cgi . plevel / 4 ) ;
2023-02-04 09:18:01 +00:00
else if ( c & & sl2 & & ! embedded_plane )
2019-08-24 12:49:49 +00:00
Vit = Vit * zpush ( sin ( ptick ( 750 ) ) * cgi . plevel / 4 ) ;
2019-08-18 19:30:39 +00:00
else
if ( GDIM = = 3 & & c & & it ! = itBabyTortoise ) Vit = face_the_player ( Vit ) ;
2019-02-26 13:35:04 +00:00
// V * cspin(0, 2, ptick(618, 0));
2019-02-22 20:29:01 +00:00
2021-06-17 07:39:08 +00:00
# if CAP_SHAPES
if ( mapeditor : : drawUserShape ( Vit , mapeditor : : sgItem , it , darkena ( icol , 0 , 0xFF ) , c ) ) return true ;
# endif
2019-08-09 22:58:50 +00:00
if ( c & & history : : includeHistory & & history : : infindhistory . count ( c ) ) poly_outline = OUTLINE_DEAD ;
2018-08-27 17:27:35 +00:00
2017-07-10 18:47:38 +00:00
else if ( it = = itSavedPrincess ) {
2019-06-24 10:57:00 +00:00
drawMonsterType ( moPrincess , c , V , icol , 0 , icol ) ;
2021-04-15 13:26:32 +00:00
return true ;
2017-03-23 10:53:57 +00:00
}
2017-07-10 18:47:38 +00:00
else if ( it = = itStrongWind ) {
2020-02-23 03:42:52 +00:00
queuepoly ( Vit * spinptick ( 750 , 0 ) , cgi . shFan , darkena ( icol , 0 , 255 ) ) ;
2017-07-10 18:47:38 +00:00
}
2017-03-23 10:53:57 +00:00
2021-05-02 13:16:29 +00:00
else if ( it = = itFatigue ) {
queuepoly ( Vit * spinptick ( 750 , 0 ) , cgi . shFan , darkena ( icol , 0 , 255 ) ) ;
}
2017-07-10 18:47:38 +00:00
else if ( it = = itWarning ) {
2020-02-23 03:42:52 +00:00
queuepoly ( Vit * spinptick ( 750 , 0 ) , cgi . shTriangle , darkena ( icol , 0 , 255 ) ) ;
2017-07-10 18:47:38 +00:00
}
2017-03-23 10:53:57 +00:00
2023-10-26 10:32:09 +00:00
else if ( it = = itCrossbow ) {
queuepoly ( Vit , cgi . shCrossbowIcon , getcs ( ) . bowcolor ) ;
queuepoly ( Vit , cgi . shCrossbowstringIcon , getcs ( ) . bowcolor2 ) ;
}
2017-07-10 18:47:38 +00:00
else if ( it = = itBabyTortoise ) {
int bits = c ? tortoise : : babymap [ c ] : tortoise : : last ;
int over = c & & c - > monst = = moTortoise ;
2020-02-23 03:42:52 +00:00
tortoise : : draw ( Vit * spinptick ( 5000 , 0 ) * ypush ( cgi . crossf * .15 ) , bits , over ? 4 : 2 , 0 ) ;
2019-05-26 16:04:02 +00:00
// queuepoly(Vit, cgi.shHeptaMarker, darkena(tortoise::getMatchColor(bits), 0, 0xC0));
2017-03-23 10:53:57 +00:00
}
2017-07-10 18:47:38 +00:00
else if ( it = = itCompass ) {
2020-07-27 16:49:04 +00:00
shiftmatrix V2 ;
2019-02-17 17:28:20 +00:00
# if CAP_CRYSTAL
2019-08-22 10:14:39 +00:00
if ( cryst ) {
2018-12-25 22:54:34 +00:00
if ( crystal : : compass_probability < = 0 ) return true ;
if ( cwt . at - > land = = laCamelot & & celldistAltRelative ( cwt . at ) < 0 ) crystal : : used_compass_inside = true ;
2018-12-03 22:03:35 +00:00
V2 = V * spin ( crystal : : compass_angle ( ) + M_PI ) ;
2018-12-25 22:54:34 +00:00
}
2019-02-17 17:28:20 +00:00
else
# endif
if ( 1 ) {
2024-03-24 10:14:05 +00:00
shiftpoint P1 ;
if ( mark_compass ( c , P1 ) ) {
2022-12-08 18:38:06 +00:00
V2 = V * lrspintox ( inverse_shift ( V , P1 ) ) ;
2017-08-06 12:50:16 +00:00
}
2018-12-03 22:03:35 +00:00
else V2 = V ;
2017-08-06 12:50:16 +00:00
}
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 ) {
2021-05-09 00:25:05 +00:00
queue_ring ( Vit , cgi . shRing , 0xFFFFFFFF , PPR : : ITEM ) ;
2022-12-06 00:04:26 +00:00
if ( WDIM = = 2 ) V2 = orthogonal_move_fol ( V2 , cgi . STUFF ) ;
2019-03-04 16:57:54 +00:00
V2 = V2 * cspin ( 1 , 2 , M_PI * sintick ( 100 ) / 39 ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( V2 , cgi . shCompass3 , 0xFF0000FF ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( V2 * lpispin ( ) , cgi . shCompass3 , 0x000000FF ) ;
2019-03-04 16:57:54 +00:00
}
else {
if ( c ) V2 = V2 * spin ( M_PI * sintick ( 100 ) / 30 ) ;
2020-07-24 14:21:11 +00:00
color_t hider = hidden ? 0xFFFFFF20 : 0xFFFFFFFF ;
queuepoly ( V2 , cgi . shCompass1 , 0xFF8080FF & hider ) ;
queuepoly ( V2 , cgi . shCompass2 , 0xFFFFFFFF & hider ) ;
queuepoly ( V2 , cgi . shCompass3 , 0xFF0000FF & hider ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( V2 * lpispin ( ) , cgi . shCompass3 , 0x000000FF & hider ) ;
2019-03-04 16:57:54 +00:00
}
2017-07-10 18:47:38 +00:00
xsh = NULL ;
}
2017-04-14 18:12:23 +00:00
2017-07-10 18:47:38 +00:00
else if ( it = = itPalace ) {
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2019-05-25 01:36:48 +00:00
if ( GDIM = = 3 & & WDIM = = 2 ) {
2021-03-30 09:27:48 +00:00
ld h = cgi . human_height ;
2019-05-25 01:36:48 +00:00
dynamicval < qfloorinfo > qfi2 ( qfi , qfi ) ;
2022-01-31 21:21:36 +00:00
shiftmatrix V2 = V * spin ( pticks * vid . ispeed / 1500. ) ;
2019-05-25 01:36:48 +00:00
/* divisors should be higher than in plate renderer */
2019-05-26 16:04:02 +00:00
qfi . fshape = & cgi . shMFloor2 ;
2023-02-04 00:58:13 +00:00
draw_shapevec ( c , V2 * lzpush ( - h / 30 ) , qfi . fshape - > levels [ 0 ] , 0xFFD500FF , PPR : : WALL ) ;
2019-05-25 01:36:48 +00:00
2019-05-26 16:04:02 +00:00
qfi . fshape = & cgi . shMFloor3 ;
2023-02-04 00:58:13 +00:00
draw_shapevec ( c , V2 * lzpush ( - h / 25 ) , qfi . fshape - > levels [ 0 ] , darkena ( icol , 0 , 0xFF ) , PPR : : WALL ) ;
2019-05-25 01:36:48 +00:00
2019-05-26 16:04:02 +00:00
qfi . fshape = & cgi . shMFloor4 ;
2023-02-04 00:58:13 +00:00
draw_shapevec ( c , V2 * lzpush ( - h / 20 ) , qfi . fshape - > levels [ 0 ] , 0xFFD500FF , PPR : : WALL ) ;
2019-05-25 01:36:48 +00:00
}
2019-07-30 11:00:30 +00:00
else if ( WDIM = = 3 & & c ) {
2021-03-30 09:33:35 +00:00
ld h = cgi . human_height ;
2022-01-31 21:21:36 +00:00
shiftmatrix V2 = Vit * spin ( pticks * vid . ispeed / 1500. ) ;
2023-02-04 00:58:13 +00:00
draw_floorshape ( c , V2 * lzpush ( h / 100 ) , cgi . shMFloor3 , 0xFFD500FF ) ;
draw_floorshape ( c , V2 * lzpush ( h / 50 ) , cgi . shMFloor4 , darkena ( icol , 0 , 0xFF ) ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( V2 , cgi . shGem [ ct6 ] , 0xFFD500FF ) ;
2019-05-25 01:36:48 +00:00
}
2019-07-30 11:00:30 +00:00
else if ( WDIM = = 3 & & ! c ) {
queuepoly ( Vit , cgi . shGem [ ct6 ] , 0xFFD500FF ) ;
}
2019-06-01 14:59:04 +00:00
else
# endif
{
2020-07-24 14:21:11 +00:00
color_t hider = hidden ? 0xFFFFFF20 : 0xFFFFFFFF ;
2022-01-31 21:21:36 +00:00
shiftmatrix V2 = Vit * spin ( pticks * vid . ispeed / 1500. ) ;
2020-07-24 14:21:11 +00:00
draw_floorshape ( c , V2 , cgi . shMFloor3 , 0xFFD500FF & hider ) ;
draw_floorshape ( c , V2 , cgi . shMFloor4 , darkena ( icol , 0 , 0xFF ) & hider ) ;
queuepoly ( V2 , cgi . shGem [ ct6 ] , 0xFFD500FF & hider ) ;
2019-05-25 01:36:48 +00:00
}
2017-07-10 18:47:38 +00:00
xsh = NULL ;
2017-03-23 10:53:57 +00:00
}
2017-07-10 18:47:38 +00:00
else if ( it = = itRose ) {
for ( int u = 0 ; u < 4 ; u + + )
2022-11-12 21:38:45 +00:00
queuepoly ( Vit * spinptick ( 1500 , 0 ) * spin ( 30. _deg * u ) , cgi . shRoseItem , darkena ( icol , 0 , hidden ? 0x30 : 0xA0 ) ) ;
2017-03-23 10:53:57 +00:00
}
2017-07-10 18:47:38 +00:00
else if ( it = = itBarrow & & c ) {
for ( int i = 0 ; i < c - > landparam ; i + + )
2022-11-12 21:38:45 +00:00
queuepolyat ( Vit * spin ( TAU * i / c - > landparam ) * xpush ( .15 ) * spinptick ( 1500 , 0 ) , * xsh , darkena ( icol , 0 , hidden ? 0x40 :
2017-07-10 18:47:38 +00:00
( highwall ( c ) & & wmspatial ) ? 0x60 : 0xFF ) ,
2018-08-28 12:27:23 +00:00
PPR : : HIDDEN ) ;
2016-08-26 09:58:03 +00:00
}
2017-07-10 18:47:38 +00:00
else if ( xsh ) {
if ( it = = itFireShard ) icol = firecolor ( 100 ) ;
if ( it = = itWaterShard ) icol = watercolor ( 100 ) > > 8 ;
if ( it = = itZebra ) icol = 0xFFFFFF ;
if ( it = = itLotus ) icol = 0x101010 ;
2018-01-04 14:46:06 +00:00
if ( it = = itSwitch ) icol = minf [ active_switch ( ) ] . color ;
2017-07-10 18:47:38 +00:00
2020-07-27 16:49:04 +00:00
shiftmatrix V2 = Vit * spinptick ( 1500 , 0 ) ;
2017-03-23 10:53:57 +00:00
2019-05-26 16:04:02 +00:00
if ( xsh = = & cgi . shBookCover & & mmitem ) {
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 )
2019-05-26 16:04:02 +00:00
queuepoly ( V2 * cpush ( 2 , 1e-3 ) , cgi . shBook , 0x805020FF ) ;
2019-02-22 20:29:01 +00:00
else
2019-05-26 16:04:02 +00:00
queuepoly ( V2 , cgi . shBook , 0x805020FF ) ;
2019-02-22 20:29:01 +00:00
}
2017-09-30 09:46:41 +00:00
2018-08-28 12:27:23 +00:00
PPR pr = PPR : : ITEM ;
2017-09-30 09:46:41 +00:00
int alpha = hidden ? ( it = = itKraken ? 0xC0 : 0x40 ) : 0xF0 ;
2018-08-28 12:27:23 +00:00
if ( c & & c - > wall = = waIcewall ) pr = PPR : : HIDDEN , alpha = 0x80 ;
2016-01-02 10:09:13 +00:00
2017-09-30 09:46:41 +00:00
queuepolyat ( V2 , * xsh , darkena ( icol , 0 , alpha ) , pr ) ;
2017-07-10 18:47:38 +00:00
2020-01-28 12:01:28 +00:00
if ( it = = itZebra ) {
2020-07-27 16:49:04 +00:00
shiftmatrix Vx = Vit * spinptick ( 1500 , .5 / ( ct6 + 6 ) ) ;
2020-01-28 12:01:28 +00:00
if ( GDIM = = 3 )
Vx = Vx * cpush ( 2 , - 1e-3 ) ;
queuepolyat ( Vx , * xsh , darkena ( 0x202020 , 0 , hidden ? 0x40 : 0xF0 ) , PPR : : ITEMb ) ;
}
2016-08-26 09:58:03 +00:00
}
2021-05-02 13:16:29 +00:00
else if ( xch = = ' o ' | | xch = = ' c ' | | it = = itInventory ) {
2017-07-10 18:47:38 +00:00
if ( it = = itOrbFire ) icol = firecolor ( 100 ) ;
2018-08-28 12:27:23 +00:00
PPR prio = PPR : : ITEM ;
2017-10-10 12:05:36 +00:00
bool inice = c & & c - > wall = = waIcewall ;
2018-08-28 12:27:23 +00:00
if ( inice ) prio = PPR : : HIDDEN ;
2020-02-26 00:20:22 +00:00
color_t icol1 = icol ;
2020-02-29 19:30:15 +00:00
icol = orb_auxiliary_color ( it ) ;
2018-09-10 15:49:51 +00:00
color_t col = darkena ( icol , 0 , int ( 0x80 + 0x70 * sinptick ( 300 ) ) ) ;
2022-10-04 16:14:16 +00:00
2022-10-06 11:10:57 +00:00
if ( it = = itOrbFish & & vid . orbmode = = 2 )
2020-02-23 03:42:52 +00:00
queuepolyat ( Vit * spinptick ( 1500 , 0 ) , cgi . shFishTail , col , PPR : : ITEM_BELOW ) ;
2021-05-02 13:16:29 +00:00
if ( xch = = ' c ' )
queuepolyat ( Vit * spinptick ( 500 , 0 ) , cgi . shMoonDisk , darkena ( 0x801080 , 0 , hidden ? 0x20 : 0xC0 ) , prio ) ;
2022-10-06 11:10:57 +00:00
else if ( vid . orbmode < 2 ) {
icol1 = orb_inner_color ( it ) ;
queuepolyat ( Vit , cgi . shDisk , darkena ( icol1 , 0 , inice ? 0x80 : hidden ? 0x20 : 0xC0 ) , prio ) ;
}
2022-08-26 15:46:32 +00:00
else {
2022-10-04 16:14:16 +00:00
icol1 = orb_inner_color ( it ) ;
2022-08-26 19:34:04 +00:00
auto dark = darkena ( icol1 , 0 , inice ? 0x80 : hidden ? 0x20 : ( it = = itOrbBeauty ) ? 0xA0 : 0xC0 ) ;
2022-10-04 16:14:16 +00:00
auto dark1 = darkena ( icol1 , 0 , inice ? 0x40 : hidden ? 0x10 : ( it = = itOrbBeauty ) ? 0x50 : 0x60 ) ;
if ( c & & GDIM = = 2 ) Vit = rgpushxto0 ( tC0 ( Vit ) ) ;
2022-11-12 21:38:45 +00:00
auto Vit1 = Vit * spin90 ( ) ;
2022-10-04 16:14:16 +00:00
if ( it = = itOrbBeauty ) {
queuepolyat ( Vit , cgi . shDisk , dark1 , prio ) ;
2022-08-26 19:34:04 +00:00
for ( int u = 0 ; u < 3 ; u + + )
2022-11-12 21:38:45 +00:00
queuepolyat ( Vit1 * spin ( 40. _deg * u ) , cgi . shSmallRose , dark , prio ) ;
2022-10-04 16:14:16 +00:00
}
2022-08-29 16:44:36 +00:00
else if ( it = = itOrbLife ) {
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit , cgi . shDisk , dark1 , prio ) ;
queuepolyat ( Vit1 , cgi . shSmallPBody , dark , prio ) ;
queuepolyat ( Vit1 , cgi . shDiskM , dark , prio ) ;
2022-08-28 01:21:53 +00:00
}
else if ( it = = itOrbBull ) {
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit , cgi . shDisk , dark1 , prio ) ;
queuepolyat ( Vit1 , cgi . shTinyBullBody , dark , prio ) ;
queuepolyat ( Vit1 , cgi . shTinyBullHead , dark , prio ) ;
queuepolyat ( Vit1 , cgi . shTinyBullHorn , dark , prio ) ;
2022-12-13 18:04:43 +00:00
queuepolyat ( Vit1 * lmirror ( ) , cgi . shTinyBullHorn , dark , prio ) ;
2022-10-04 16:14:16 +00:00
}
else if ( it = = itOrbFrog & & false ) {
queuepolyat ( Vit , cgi . shDisk , dark1 , prio ) ;
queuepolyat ( Vit1 , cgi . shSmallFrogBody , dark , prio ) ;
queuepolyat ( Vit1 , cgi . shSmallFrogRearFoot , dark , prio ) ;
queuepolyat ( Vit1 , cgi . shSmallFrogRearLeg , dark , prio ) ;
queuepolyat ( Vit1 , cgi . shSmallFrogRearLeg2 , dark , prio ) ;
queuepolyat ( Vit1 , cgi . shSmallFrogFrontFoot , dark , prio ) ;
queuepolyat ( Vit1 , cgi . shSmallFrogFrontLeg , dark , prio ) ;
2022-12-13 18:04:43 +00:00
queuepolyat ( Vit1 * lmirror ( ) , cgi . shSmallFrogRearFoot , dark , prio ) ;
queuepolyat ( Vit1 * lmirror ( ) , cgi . shSmallFrogRearLeg , dark , prio ) ;
queuepolyat ( Vit1 * lmirror ( ) , cgi . shSmallFrogRearLeg2 , dark , prio ) ;
queuepolyat ( Vit1 * lmirror ( ) , cgi . shSmallFrogFrontFoot , dark , prio ) ;
queuepolyat ( Vit1 * lmirror ( ) , cgi . shSmallFrogFrontLeg , dark , prio ) ;
2022-08-28 01:21:53 +00:00
}
2022-10-04 16:14:16 +00:00
else if ( it = = itOrbSpeed ) {
queuepolyat ( Vit , cgi . shDisk , dark1 , prio ) ;
drawSpeed ( Vit , 0.3 ) ;
2022-08-26 22:21:00 +00:00
}
2022-08-29 04:09:24 +00:00
else if ( it = = itOrbStunning ) {
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit , cgi . shDisk , dark1 , prio ) ;
2022-08-29 16:44:36 +00:00
queuepolyat ( Vit , cgi . shDiskM , dark , prio ) ;
2022-08-29 04:09:24 +00:00
for ( int i = 0 ; i < 5 ; i + + ) {
2022-11-12 21:38:45 +00:00
shiftmatrix V2 = Vit * spin ( TAU * i / 5 + ptick ( 300 ) ) ;
2022-08-29 04:09:24 +00:00
queuepolyat ( V2 , cgi . shSmallFlailBall , dark , prio ) ;
}
}
2022-08-29 03:05:03 +00:00
else if ( it = = itOrbDragon ) {
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit , cgi . shDisk , dark1 , prio ) ;
queuepolyat ( Vit1 , cgi . shSmallDragonHead , dark , prio ) ;
queuepolyat ( Vit1 , cgi . shSmallDragonNostril , 0xFF , prio ) ;
2022-12-13 18:04:43 +00:00
queuepolyat ( Vit1 * lmirror ( ) , cgi . shSmallDragonNostril , 0xFF , prio ) ;
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit1 , cgi . shSmallDragonEyes , 0x60 , prio ) ;
2022-12-13 18:04:43 +00:00
queuepolyat ( Vit1 * lmirror ( ) , cgi . shSmallDragonEyes , 0x60 , prio ) ;
2022-08-29 03:05:03 +00:00
}
else if ( it = = itOrbDomination ) {
2022-10-05 15:43:16 +00:00
queuepolyat ( Vit1 * MirrorX , cgi . shSmallWormHead , dark , prio ) ;
queuepolyat ( Vit1 * MirrorX , cgi . shSmallWormEyes , 0x60 , prio ) ;
2022-12-13 18:04:43 +00:00
queuepolyat ( Vit1 * MirrorX * lmirror ( ) , cgi . shSmallWormEyes , 0x60 , prio ) ;
2022-10-04 16:14:16 +00:00
}
else if ( it = = itOrbMorph | | it = = itOrbChaos | | it = = itOrbPlague ) {
queuepolyat ( Vit , cgi . shDisk , dark1 , prio ) ;
queuepolyat ( Vit1 , cgi . shSmallTreat , dark , prio ) ;
}
else if ( it = = itOrbWinter ) {
queuepolyat ( Vit , cgi . shDisk , dark1 , prio ) ;
queuepolyat ( Vit1 , cgi . shSnowflake , dark , prio ) ;
2022-08-29 03:05:03 +00:00
}
2022-08-29 16:44:36 +00:00
else if ( it = = itOrbLuck )
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit1 , cgi . shSmallerDodeca , dark , prio ) ;
2022-08-30 02:03:12 +00:00
else if ( it = = itOrbAether ) {
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit1 , cgi . shHalfDisk , dark , prio ) ;
2022-12-13 18:04:43 +00:00
queuepolyat ( Vit1 * lmirror ( ) , cgi . shHalfDisk , 0xFF , prio ) ;
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit1 * MirrorX , cgi . shHalfHumanoid , dark , prio ) ;
2022-12-13 18:04:43 +00:00
queuepolyat ( Vit1 * lmirror ( ) * MirrorX , cgi . shHalfHumanoid , 0xFF , prio ) ;
2022-08-30 02:03:12 +00:00
}
2022-08-29 16:44:36 +00:00
else if ( it = = itOrbFlash )
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit1 , cgi . shFlash , dark , prio ) ;
else if ( it = = itOrbMatter | | it = = itOrbStone ) {
queuepolyat ( Vit , cgi . shDisk , dark1 , prio ) ;
queuepolyat ( Vit1 , cgi . shDiskSq , dark , prio ) ;
}
2022-09-15 04:32:36 +00:00
else if ( it = = itOrbSummon ) {
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit1 , cgi . shHeptagon , dark , prio ) ;
queuepolyat ( Vit1 , cgi . shHeptagram , dark , prio ) ;
}
else if ( it = = itOrbSafety ) {
queuepolyat ( Vit , cgi . shDisk , dark , prio ) ;
dynamicval < color_t > p ( poly_outline , dark ) ;
queuepolyat ( Vit1 , cgi . shHeptagram , 0 , prio ) ;
2022-09-15 04:32:36 +00:00
}
2022-08-26 17:04:52 +00:00
else {
2022-10-04 16:14:16 +00:00
bool jump = ( it = = itOrbPhasing | | it = = itOrbDash | | it = = itOrbFrog ) ;
2022-08-29 16:44:36 +00:00
auto shape = ( it = = itOrbFriend ) ? & cgi . shTinyBird :
( it = = itOrbSide1 ) ? & cgi . shSmallPSword :
( it = = itOrbDigging ) ? & cgi . shSmallPickAxe :
( it = = itOrbSword | | it = = itOrbSword2 ) ? & cgi . shSmallSword :
( it = = itOrbThorns ) ? & cgi . shSmallHedgehogBlade :
2022-08-29 17:30:37 +00:00
( it = = itOrbSide2 | | it = = itOrb37 | | it = = itOrbLava ) ? & cgi . shDiskT :
2022-08-29 16:44:36 +00:00
( it = = itOrbGravity ) ? & cgi . shTinyArrow :
2022-10-04 16:14:16 +00:00
( it = = itOrbFreedom | | it = = itOrbRecall ) ? & cgi . shDiskSq :
2022-08-29 16:44:36 +00:00
( it = = itOrbEnergy ) ? & cgi . shHalfDisk :
2022-09-15 23:02:27 +00:00
( it = = itOrbSpace ) ? & cgi . shSmallPirateHook :
2022-09-17 02:24:01 +00:00
( it = = itOrbChoice | | it = = itOrbMirror | | it = = itOrbMagnetism | | it = = itOrbEmpathy | | it = = itOrbDiscord ) ? & cgi . shEccentricDisk :
2022-08-29 16:44:36 +00:00
( it = = itOrbPsi | | it = = itOrbSide3 ) ? & cgi . shDiskS :
2022-08-29 17:05:40 +00:00
( it = = itOrbPurity ) ? & cgi . shSmallEgg :
2022-08-29 23:14:59 +00:00
( it = = itOrbLightning ) ? & cgi . shLightningBolt :
2022-09-16 19:13:20 +00:00
( it = = itOrbShield ) ? & cgi . shShield :
2022-09-13 17:49:10 +00:00
( it = = itOrbTime ) ? & cgi . shHourglass :
2022-09-17 02:24:01 +00:00
( it = = itOrbAir ) ? & cgi . shSmallFan :
2022-09-17 04:59:23 +00:00
( it = = itOrbWoods ) ? & cgi . shTreeIcon :
2022-09-17 20:39:11 +00:00
( it = = itOrbNature ) ? & cgi . shLeafIcon :
2022-09-15 01:11:52 +00:00
( it = = itOrbIllusion | | it = = itOrbInvis | | it = = itOrbTeleport ) ? & cgi . shHumanoid :
2022-10-04 16:14:16 +00:00
jump ? & cgi . shDiskSegment :
2022-08-29 17:30:37 +00:00
NULL ;
2022-08-29 16:44:36 +00:00
queuepolyat ( Vit , cgi . shDisk , dark , prio ) ;
2022-10-06 06:49:26 +00:00
bool reversed = ( shape = = & cgi . shTreeIcon | | shape = = & cgi . shHumanoid | | it = = itOrbSword2 ) ;
2022-10-04 16:14:16 +00:00
bool left90 = ( shape = = & cgi . shLeafIcon | | shape = = & cgi . shLightningBolt ) ;
2022-08-29 17:30:37 +00:00
if ( shape )
2022-11-12 21:38:45 +00:00
queuepolyat ( reversed ? Vit1 * MirrorX : left90 ? Vit1 * spin270 ( ) : Vit1 , * shape , ( it = = itOrbInvis | | it = = itOrbTeleport ) ? 0x20 : 0x80 , prio ) ;
2022-09-15 01:23:43 +00:00
if ( it = = itOrbSide1 | | ( shape = = & cgi . shEccentricDisk & & it ! = itOrbDiscord ) )
2022-12-13 18:04:43 +00:00
queuepolyat ( Vit1 * lmirror ( ) , * shape , 0x80 , prio ) ;
2022-10-04 16:14:16 +00:00
if ( jump | | it = = itOrbEnergy )
2022-12-13 18:04:43 +00:00
queuepolyat ( Vit1 * lmirror ( ) , * shape , col , prio ) ;
2022-08-28 18:10:12 +00:00
if ( it = = itOrbIntensity | | it = = itOrbImpact )
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit1 , cgi . shDiskM , 0x80 , prio ) ;
2022-08-29 16:44:36 +00:00
if ( it = = itOrbHorns ) {
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit1 , cgi . shSmallBullHead , 0x80 , prio ) ;
queuepolyat ( Vit1 , cgi . shSmallBullHorn , 0x80 , prio ) ;
2022-12-13 18:04:43 +00:00
queuepolyat ( Vit1 * lmirror ( ) , cgi . shSmallBullHorn , 0x80 , prio ) ;
2022-08-29 16:44:36 +00:00
}
2022-08-29 16:55:51 +00:00
if ( it = = itOrbUndeath ) {
2022-10-04 16:14:16 +00:00
dark = darkena ( fghostcolor ( c ) /* minf[moFriendlyGhost].color */ , 0 , inice ? 0x80 : hidden ? 0x20 : 0xC0 ) ;
queuepolyat ( Vit1 , cgi . shMiniGhost , dark , prio ) ;
queuepolyat ( Vit1 , cgi . shMiniEyes , 0xFF , prio ) ;
2022-08-29 16:55:51 +00:00
}
if ( it = = itOrbSlaying ) {
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit1 , cgi . shSmallFlailTrunk , 0x80 , prio ) ;
queuepolyat ( Vit1 , cgi . shSmallHammerHead , 0x80 , prio ) ;
2022-08-29 16:55:51 +00:00
}
2022-08-29 16:44:36 +00:00
if ( it = = itOrbShell )
for ( int i = 1 ; i < 8 ; i + + ) {
2022-10-04 16:14:16 +00:00
queuepolyat ( Vit1 , cgi . shTortoise [ i ] [ 2 ] , 0x80 , prio ) ;
2022-08-29 16:44:36 +00:00
if ( i > = 5 & & i < = 7 )
2022-12-13 18:04:43 +00:00
queuepolyat ( Vit1 * lmirror ( ) , cgi . shTortoise [ i ] [ 2 ] , 0x80 , prio ) ;
2022-08-29 16:44:36 +00:00
}
2022-08-26 17:04:52 +00:00
}
}
2019-03-23 15:26:53 +00:00
2021-05-09 00:25:05 +00:00
queue_ring ( Vit * spinptick ( 1500 , 0 ) , orbshape ( iinf [ it ] . orbshape ) , col , prio ) ;
2016-08-26 09:58:03 +00:00
}
2021-04-15 13:26:32 +00:00
else {
draw_ascii ( V , xch , icol , 1 ) ;
}
2015-08-08 13:57:52 +00:00
2021-04-15 13:26:32 +00:00
return true ;
2017-12-01 23:23:15 +00:00
# endif
2016-08-26 09:58:03 +00:00
}
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2019-06-16 13:24:48 +00:00
color_t skincolor = 0xD0C080FF ;
2020-07-27 16:49:04 +00:00
void humanoid_eyes ( const shiftmatrix & V , color_t ecol , color_t hcol = skincolor ) {
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 ) {
2019-06-16 13:24:48 +00:00
queuepoly ( VHEAD , cgi . shPHeadOnly , hcol ) ;
queuepoly ( VHEAD , cgi . shSkullEyes , ecol ) ;
}
}
2020-07-27 16:49:04 +00:00
EX void drawTerraWarrior ( const shiftmatrix & V , int t , int hp , double footphase ) {
2021-04-15 15:17:01 +00:00
if ( ! mmmon ) {
draw_ascii ( V , ' T ' , gradient ( 0x202020 , 0xFFFFFF , 0 , t , 6 ) , 1.5 ) ;
return ;
}
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
2018-09-04 17:53:42 +00:00
color_t col = linf [ laTerracotta ] . color ;
2017-10-04 19:26:26 +00:00
int bcol = darkena ( false ? 0xC0B23E : col , 0 , 0xFF ) ;
2019-02-27 18:15:58 +00:00
const transmatrix VBS = otherbodyparts ( V , bcol , moDesertman , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , cgi . shPBody , bcol ) ;
2022-12-13 18:04:43 +00:00
if ( ! peace : : on ) queuepoly ( VBODY * VBS * lmirror ( ) , cgi . shPSword , darkena ( 0xC0C0C0 , 0 , 0xFF ) ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY1 * VBS , cgi . shTerraArmor1 , darkena ( t > 0 ? 0x4040FF : col , 0 , 0xFF ) ) ;
if ( hp > = 4 ) queuepoly ( VBODY2 * VBS , cgi . shTerraArmor2 , darkena ( t > 1 ? 0xC00000 : col , 0 , 0xFF ) ) ;
if ( hp > = 2 ) queuepoly ( VBODY3 * VBS , cgi . shTerraArmor3 , darkena ( t > 2 ? 0x612600 : col , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , cgi . shTerraHead , darkena ( t > 4 ? 0x202020 : t > 3 ? 0x504040 : col , 0 , 0xFF ) ) ;
queuepoly ( VHEAD1 , cgi . shPFace , bcol ) ;
2019-06-16 13:24:48 +00:00
humanoid_eyes ( V , 0x400000FF , darkena ( col , 0 , 0xFF ) ) ;
2017-09-30 09:46:41 +00:00
}
2019-02-17 18:39:44 +00:00
# endif
2017-09-30 09:46:41 +00:00
2020-07-27 16:49:04 +00:00
EX void drawPlayer ( eMonster m , cell * where , const shiftmatrix & V , color_t col , double footphase , bool stop IS ( false ) ) {
2019-03-30 12:16:19 +00:00
charstyle & cs = getcs ( ) ;
2020-10-15 14:33:52 +00:00
# if CAP_COMPLEX2
2019-12-08 18:17:28 +00:00
auto & knighted = camelot : : knighted ;
2020-10-15 14:33:52 +00:00
# else
const bool knighted = false ;
# endif
2015-08-08 13:57:52 +00:00
2021-04-15 13:26:32 +00:00
if ( GDIM = = 3 ) {
addradar ( V , ' @ ' , cs . uicolor > > 8 , 0xFF00FF00 ) ;
}
2019-03-30 12:16:19 +00:00
if ( mapeditor : : drawplayer & & ! mapeditor : : drawUserShape ( V , mapeditor : : sgPlayer , cs . charid , cs . skincolor , where ) ) {
2017-03-23 10:53:57 +00:00
2019-03-30 12:16:19 +00:00
if ( cs . charid > = 8 ) {
/* famililar */
2019-06-24 11:46:27 +00:00
if ( ! mmspatial & & ! footphase ) {
if ( stop ) return ;
2019-05-26 16:04:02 +00:00
queuepoly ( VALEGS , cgi . shWolfLegs , fc ( 150 , cs . dresscolor , 4 ) ) ;
2019-06-24 11:46:27 +00:00
}
2019-03-30 12:16:19 +00:00
else {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shWolfBody ) ;
2019-06-24 11:46:27 +00:00
if ( stop ) return ;
2019-03-30 12:16:19 +00:00
animallegs ( VALEGS , moWolf , fc ( 500 , cs . dresscolor , 4 ) , footphase ) ;
}
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shWolfBody , fc ( 0 , cs . skincolor , 0 ) ) ;
queuepoly ( VAHEAD , cgi . shFamiliarHead , fc ( 500 , cs . haircolor , 2 ) ) ;
2019-03-30 12:16:19 +00:00
if ( ! shmup : : on | | shmup : : curtime > = shmup : : getPlayer ( ) - > nextshot ) {
2019-05-12 19:09:27 +00:00
color_t col = items [ itOrbDiscord ] ? watercolor ( 0 ) : fc ( 314 , cs . eyecolor , 3 ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD , cgi . shFamiliarEye , col ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VAHEAD * lmirror ( ) , cgi . shFamiliarEye , col ) ;
2019-03-30 12:16:19 +00:00
}
2018-08-27 17:27:35 +00:00
2019-03-30 12:16:19 +00:00
if ( knighted )
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shKnightCloak , darkena ( cloakcolor ( knighted ) , 1 , 0xFF ) ) ;
2018-12-23 13:00:52 +00:00
2019-03-30 12:16:19 +00:00
if ( tortoise : : seek ( ) )
tortoise : : draw ( VABODY , tortoise : : seekbits , 4 , 0 ) ;
}
else if ( cs . charid > = 6 ) {
/* dog */
2019-06-24 11:46:27 +00:00
if ( ! mmspatial & & ! footphase ) {
if ( stop ) return ;
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shDogBody , fc ( 0 , cs . skincolor , 0 ) ) ;
2019-06-24 11:46:27 +00:00
}
2019-03-30 12:16:19 +00:00
else {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shDogTorso ) ;
2019-06-24 11:46:27 +00:00
if ( stop ) return ;
2019-03-30 12:16:19 +00:00
animallegs ( VALEGS , moRunDog , fc ( 500 , cs . dresscolor , 4 ) , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shDogTorso , fc ( 0 , cs . skincolor , 0 ) ) ;
2017-07-10 18:47:38 +00:00
}
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD , cgi . shDogHead , fc ( 150 , cs . haircolor , 2 ) ) ;
2015-08-08 13:57:52 +00:00
2019-03-30 12:16:19 +00:00
if ( ! shmup : : on | | shmup : : curtime > = shmup : : getPlayer ( ) - > nextshot ) {
2019-05-12 19:09:27 +00:00
color_t col = items [ itOrbDiscord ] ? watercolor ( 0 ) : fc ( 314 , cs . eyecolor , 3 ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD , cgi . shWolf1 , col ) ;
queuepoly ( VAHEAD , cgi . shWolf2 , col ) ;
2019-03-30 12:16:19 +00:00
}
2017-12-03 19:10:42 +00:00
2019-03-30 12:16:19 +00:00
color_t colnose = items [ itOrbDiscord ] ? watercolor ( 0 ) : fc ( 314 , 0xFF , 3 ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD , cgi . shWolf3 , colnose ) ;
2018-12-23 13:00:52 +00:00
2019-03-30 12:16:19 +00:00
if ( knighted )
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shKnightCloak , darkena ( cloakcolor ( knighted ) , 1 , 0xFF ) ) ;
2018-12-23 13:00:52 +00:00
2019-03-30 12:16:19 +00:00
if ( tortoise : : seek ( ) )
tortoise : : draw ( VABODY , tortoise : : seekbits , 4 , 0 ) ;
}
else if ( cs . charid > = 4 ) {
/* cat */
2019-06-24 11:46:27 +00:00
if ( ! mmspatial & & ! footphase ) {
if ( stop ) return ;
2019-05-26 16:04:02 +00:00
queuepoly ( VALEGS , cgi . shCatLegs , fc ( 500 , cs . dresscolor , 4 ) ) ;
2019-06-24 11:46:27 +00:00
}
2017-07-10 18:47:38 +00:00
else {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shCatBody ) ;
2019-06-24 11:46:27 +00:00
if ( stop ) return ;
2019-03-30 12:16:19 +00:00
animallegs ( VALEGS , moRunDog , fc ( 500 , cs . dresscolor , 4 ) , footphase ) ;
}
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shCatBody , fc ( 0 , cs . skincolor , 0 ) ) ;
queuepoly ( VAHEAD , cgi . shCatHead , fc ( 150 , cs . haircolor , 2 ) ) ;
2019-03-30 12:16:19 +00:00
if ( ! shmup : : on | | shmup : : curtime > = shmup : : getPlayer ( ) - > nextshot ) {
2019-05-12 19:09:27 +00:00
color_t col = items [ itOrbDiscord ] ? watercolor ( 0 ) : fc ( 314 , cs . eyecolor , 3 ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD * xpush ( .04 ) , cgi . shWolf1 , col ) ;
queuepoly ( VAHEAD * xpush ( .04 ) , cgi . shWolf2 , col ) ;
2019-03-30 12:16:19 +00:00
}
2015-08-08 13:57:52 +00:00
2019-03-30 12:16:19 +00:00
if ( knighted )
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shKnightCloak , darkena ( cloakcolor ( knighted ) , 1 , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
2019-03-30 12:16:19 +00:00
if ( tortoise : : seek ( ) )
tortoise : : draw ( VABODY , tortoise : : seekbits , 4 , 0 ) ;
}
else {
/* human */
2019-06-24 11:46:27 +00:00
ShadowV ( V , ( cs . charid & 1 ) ? cgi . shFemaleBody : cgi . shPBody ) ;
if ( stop ) return ;
2019-03-30 12:16:19 +00:00
const transmatrix VBS = otherbodyparts ( V , fc ( 0 , cs . skincolor , 0 ) , items [ itOrbFish ] ? moWaterElemental : moPlayer , footphase ) ;
2019-06-24 11:46:27 +00:00
queuepoly ( VBODY * VBS , ( cs . charid & 1 ) ? cgi . shFemaleBody : cgi . shPBody , fc ( 0 , cs . skincolor , 0 ) ) ;
2019-03-30 12:16:19 +00:00
2017-07-10 18:47:38 +00:00
if ( cs . charid & 1 )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY1 * VBS , cgi . shFemaleDress , fc ( 500 , cs . dresscolor , 4 ) ) ;
2019-03-30 12:16:19 +00:00
2017-07-10 18:47:38 +00:00
if ( cs . charid = = 2 )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY2 * VBS , cgi . shPrinceDress , fc ( 400 , cs . dresscolor , 5 ) ) ;
2017-07-10 18:47:38 +00:00
if ( cs . charid = = 3 )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY2 * VBS , cgi . shPrincessDress , fc ( 400 , cs . dresscolor2 , 5 ) ) ;
2017-10-12 10:05:12 +00:00
if ( items [ itOrbSide3 ] )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , ( cs . charid & 1 ) ? cgi . shFerocityF : cgi . shFerocityM , fc ( 0 , cs . skincolor , 0 ) ) ;
2019-03-30 12:16:19 +00:00
2017-07-10 18:47:38 +00:00
if ( items [ itOrbHorns ] ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , cgi . shBullHead , items [ itOrbDiscord ] ? watercolor ( 0 ) : 0xFF000030 ) ;
queuepoly ( VBODY * VBS , cgi . shBullHorn , items [ itOrbDiscord ] ? watercolor ( 0 ) : 0xFF000040 ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VBODY * VBS * lmirror ( ) , cgi . shBullHorn , items [ itOrbDiscord ] ? watercolor ( 0 ) : 0xFF000040 ) ;
2017-07-10 18:47:38 +00:00
}
2019-03-30 12:16:19 +00:00
2017-10-12 10:05:12 +00:00
if ( items [ itOrbSide1 ] & & ! shmup : : on )
2022-11-12 21:38:45 +00:00
queuepoly ( VBODY * VBS * spin ( - 15. _deg ) , cs . charid > = 2 ? cgi . shSabre : cgi . shPSword , fc ( 314 , cs . swordcolor , 3 ) ) ; // 3 not colored
2017-10-12 10:05:12 +00:00
2022-12-13 18:04:43 +00:00
shiftmatrix VWPN = cs . lefthanded ? VBODY * VBS * lmirror ( ) : VBODY * VBS ;
2018-11-10 17:32:55 +00:00
2019-01-07 03:55:21 +00:00
if ( peace : : on ) ;
else if ( racing : : on ) {
2019-03-30 12:16:19 +00:00
# if CAP_RACING
2019-01-07 03:55:21 +00:00
if ( racing : : trophy [ multi : : cpid ] )
2019-05-26 16:04:02 +00:00
queuepoly ( VWPN , cgi . shTrophy , racing : : trophy [ multi : : cpid ] ) ;
2019-03-30 12:16:19 +00:00
# endif
2019-01-07 03:55:21 +00:00
}
2023-10-26 10:33:02 +00:00
else if ( bow : : crossbow_mode ( ) & & cs . charid < 4 ) {
queuepoly ( VWPN , cgi . shCrossbow , fc ( 314 , cs . bowcolor , 3 ) ) ;
2023-10-27 21:22:51 +00:00
int ti = items [ itCrossbow ] ;
if ( shmup : : on ) {
ti = shmup : : getPlayer ( ) - > nextshot - shmup : : curtime ;
if ( ti < = 0 ) ti = 0 ;
else ti = 1 + ti / 500 ;
}
2023-10-29 08:57:19 +00:00
shiftmatrix VWPN1 = VWPN , VWPN2 = VWPN ;
if ( GDIM = = 3 ) { ld h = cgi . human_height ; VWPN1 = VWPN * lzpush ( - h / 60 ) ; VWPN2 = VWPN * lzpush ( - h / 30 ) ; }
if ( ti < = 1 ) queuepoly ( VWPN1 , cgi . shCrossbowstringLoaded , fc ( 314 , cs . bowcolor2 , 3 ) ) ;
else if ( ti < = 2 ) queuepoly ( VWPN1 , cgi . shCrossbowstringSemiloaded , fc ( 314 , cs . bowcolor2 , 3 ) ) ;
else queuepoly ( VWPN1 , cgi . shCrossbowstringUnloaded , fc ( 314 , cs . bowcolor2 , 3 ) ) ;
if ( ti = = 0 ) queuepoly ( VWPN2 , cgi . shCrossbowBolt , fc ( 314 , cs . swordcolor , 3 ) ) ;
2023-10-26 10:33:02 +00:00
}
2017-07-10 18:47:38 +00:00
else if ( items [ itOrbThorns ] )
2019-05-26 16:04:02 +00:00
queuepoly ( VWPN , cgi . shHedgehogBladePlayer , items [ itOrbDiscord ] ? watercolor ( 0 ) : 0x00FF00FF ) ;
2017-07-10 18:47:38 +00:00
else if ( ! shmup : : on & & items [ itOrbDiscord ] )
2019-05-26 16:04:02 +00:00
queuepoly ( VWPN , cs . charid > = 2 ? cgi . shSabre : cgi . shPSword , watercolor ( 0 ) ) ;
2017-07-10 18:47:38 +00:00
else if ( items [ itRevolver ] )
2019-05-26 16:04:02 +00:00
queuepoly ( VWPN , cgi . shGunInHand , fc ( 314 , cs . swordcolor , 3 ) ) ; // 3 not colored
2018-01-03 21:32:34 +00:00
else if ( items [ itOrbSlaying ] ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VWPN , cgi . shFlailTrunk , fc ( 314 , cs . swordcolor , 3 ) ) ;
queuepoly ( VWPN , cgi . shHammerHead , fc ( 314 , cs . swordcolor , 3 ) ) ;
2018-01-03 21:32:34 +00:00
}
2021-05-21 23:26:59 +00:00
else if ( items [ itCurseWeakness ] ) {
/* no weapon shown */
}
2017-07-10 18:47:38 +00:00
else if ( ! shmup : : on )
2019-05-26 16:04:02 +00:00
queuepoly ( VWPN , cs . charid > = 2 ? cgi . shSabre : cgi . shPSword , fc ( 314 , cs . swordcolor , 3 ) ) ; // 3 not colored
2017-07-10 18:47:38 +00:00
else if ( shmup : : curtime > = shmup : : getPlayer ( ) - > nextshot )
2019-05-26 16:04:02 +00:00
queuepoly ( VWPN , cgi . shPKnife , fc ( 314 , cs . swordcolor , 3 ) ) ; // 3 not colored
2017-07-10 18:47:38 +00:00
if ( items [ itOrbBeauty ] ) {
if ( cs . charid & 1 )
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD1 , cgi . shFlowerHair , darkena ( iinf [ itOrbBeauty ] . color , 0 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
else
2019-05-26 16:04:02 +00:00
queuepoly ( VWPN , cgi . shFlowerHand , darkena ( iinf [ itOrbBeauty ] . color , 0 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
}
if ( where & & where - > land = = laWildWest ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD1 , cgi . shWestHat1 , darkena ( cs . swordcolor , 1 , 0XFF ) ) ;
queuepoly ( VHEAD2 , cgi . shWestHat2 , darkena ( cs . swordcolor , 0 , 0XFF ) ) ;
2017-07-10 18:47:38 +00:00
}
2019-03-30 12:16:19 +00:00
2017-07-10 18:47:38 +00:00
if ( cheater & & ! autocheat ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD1 , ( cs . charid & 1 ) ? cgi . shGoatHead : cgi . shDemon , darkena ( 0xFFFF00 , 0 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
// queuepoly(V, shHood, darkena(0xFF00, 1, 0xFF));
}
else {
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD , cgi . shPFace , fc ( 500 , cs . skincolor , 1 ) ) ;
queuepoly ( VHEAD1 , ( cs . charid & 1 ) ? cgi . shFemaleHair : cgi . shPHead , fc ( 150 , cs . haircolor , 2 ) ) ;
2017-07-10 18:47:38 +00:00
}
2019-05-12 19:09:27 +00:00
humanoid_eyes ( V , cs . eyecolor , cs . skincolor ) ;
2019-03-30 12:16:19 +00:00
2017-07-10 18:47:38 +00:00
if ( knighted )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , cgi . shKnightCloak , darkena ( cloakcolor ( knighted ) , 1 , 0xFF ) ) ;
2019-03-30 12:16:19 +00:00
2017-07-10 18:47:38 +00:00
if ( tortoise : : seek ( ) )
2019-05-26 16:04:02 +00:00
tortoise : : draw ( VBODY * VBS * ypush ( - cgi . crossf * .25 ) , tortoise : : seekbits , 4 , 0 ) ;
2018-12-23 13:00:52 +00:00
}
2019-03-30 12:16:19 +00:00
}
}
2019-08-09 19:00:52 +00:00
EX int wingphase ( int period , int phase IS ( 0 ) ) {
2019-05-16 15:08:12 +00:00
ld t = fractick ( period , phase ) ;
2019-06-18 14:15:57 +00:00
const int WINGS2 = WINGS * 2 ;
int ti = int ( t * WINGS2 ) % WINGS2 ;
if ( ti > WINGS ) ti = WINGS2 - ti ;
2019-06-18 14:09:54 +00:00
return ti ;
2019-05-16 15:08:12 +00:00
}
transmatrix wingmatrix ( int period , int phase = 0 ) {
2022-11-12 21:38:45 +00:00
ld t = fractick ( period , phase ) * TAU ;
2019-05-16 15:08:12 +00:00
transmatrix Vwing = Id ;
Vwing [ 1 ] [ 1 ] = .85 + .15 * sin ( t ) ;
return Vwing ;
}
2020-07-27 16:49:04 +00:00
void drawMimic ( eMonster m , cell * where , const shiftmatrix & V , color_t col , double footphase ) {
2019-03-30 12:16:19 +00:00
charstyle & cs = getcs ( ) ;
2019-03-30 12:17:51 +00:00
if ( mapeditor : : drawUserShape ( V , mapeditor : : sgPlayer , cs . charid , darkena ( col , 0 , 0x80 ) , where ) ) return ;
2019-03-30 12:16:19 +00:00
if ( cs . charid > = 8 ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shWolfBody , darkena ( col , 0 , 0xC0 ) ) ;
ShadowV ( V , cgi . shWolfBody ) ;
2019-03-30 12:16:19 +00:00
if ( mmspatial | | footphase )
animallegs ( VALEGS , moWolf , darkena ( col , 0 , 0xC0 ) , footphase ) ;
else
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shWolfLegs , darkena ( col , 0 , 0xC0 ) ) ;
2019-03-30 12:16:19 +00:00
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shFamiliarHead , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VAHEAD , cgi . shFamiliarEye , darkena ( col , 0 , 0xC0 ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VAHEAD * lmirror ( ) , cgi . shFamiliarEye , darkena ( col , 0 , 0xC0 ) ) ;
2019-03-30 12:16:19 +00:00
}
else if ( cs . charid > = 6 ) {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shDogBody ) ;
queuepoly ( VAHEAD , cgi . shDogHead , darkena ( col , 0 , 0xC0 ) ) ;
2019-03-30 12:16:19 +00:00
if ( mmspatial | | footphase ) {
animallegs ( VALEGS , moRunDog , darkena ( col , 0 , 0xC0 ) , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shDogTorso , darkena ( col , 0 , 0xC0 ) ) ;
2019-03-30 12:16:19 +00:00
}
else
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shDogBody , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VABODY , cgi . shWolf1 , darkena ( col , 1 , 0xC0 ) ) ;
queuepoly ( VABODY , cgi . shWolf2 , darkena ( col , 1 , 0xC0 ) ) ;
queuepoly ( VABODY , cgi . shWolf3 , darkena ( col , 1 , 0xC0 ) ) ;
2019-03-30 12:16:19 +00:00
}
else if ( cs . charid > = 4 ) {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shCatBody ) ;
queuepoly ( VABODY , cgi . shCatBody , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VAHEAD , cgi . shCatHead , darkena ( col , 0 , 0xC0 ) ) ;
2019-03-30 12:16:19 +00:00
if ( mmspatial | | footphase )
animallegs ( VALEGS , moRunDog , darkena ( col , 0 , 0xC0 ) , footphase ) ;
else
2019-05-26 16:04:02 +00:00
queuepoly ( VALEGS , cgi . shCatLegs , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VAHEAD * xpush ( .04 ) , cgi . shWolf1 , darkena ( col , 1 , 0xC0 ) ) ;
queuepoly ( VAHEAD * xpush ( .04 ) , cgi . shWolf2 , darkena ( col , 1 , 0xC0 ) ) ;
2019-03-30 12:16:19 +00:00
}
else {
const transmatrix VBS = otherbodyparts ( V , darkena ( col , 0 , 0x40 ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , ( cs . charid & 1 ) ? cgi . shFemaleBody : cgi . shPBody , darkena ( col , 0 , 0X80 ) ) ;
2018-12-23 13:00:52 +00:00
2023-10-27 21:22:51 +00:00
if ( bow : : crossbow_mode ( ) & & cs . charid < 4 ) {
shiftmatrix VWPN = cs . lefthanded ? VBODY * VBS * lmirror ( ) : VBODY * VBS ;
color_t col1 = darkena ( col , 0 , 0x40 ) ;
queuepoly ( VWPN , cgi . shCrossbow , col1 ) ;
int ti = items [ itCrossbow ] ;
if ( shmup : : on ) {
ti = shmup : : getPlayer ( ) - > nextshot - shmup : : curtime ;
if ( ti < = 0 ) ti = 0 ;
else ti = 1 + ti / 500 ;
}
2023-10-29 08:57:19 +00:00
shiftmatrix VWPN1 = VWPN , VWPN2 = VWPN ;
if ( GDIM = = 3 ) { ld h = cgi . human_height ; VWPN1 = VWPN * lzpush ( - h / 60 ) ; VWPN2 = VWPN * lzpush ( - h / 30 ) ; }
if ( ti < = 1 ) queuepoly ( VWPN1 , cgi . shCrossbowstringLoaded , col1 ) ;
else if ( ti < = 2 ) queuepoly ( VWPN1 , cgi . shCrossbowstringSemiloaded , col1 ) ;
else queuepoly ( VWPN1 , cgi . shCrossbowstringUnloaded , col1 ) ;
if ( ti = = 0 ) queuepoly ( VWPN2 , cgi . shCrossbowBolt , col1 ) ;
2023-10-27 21:22:51 +00:00
}
else if ( ! shmup : : on ) {
2019-03-30 12:16:19 +00:00
bool emp = items [ itOrbEmpathy ] & & m ! = moShadow ;
if ( items [ itOrbThorns ] & & emp )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , cgi . shHedgehogBladePlayer , darkena ( col , 0 , 0x40 ) ) ;
2019-03-30 12:16:19 +00:00
if ( items [ itOrbSide1 ] & & ! shmup : : on )
2022-11-12 21:38:45 +00:00
queuepoly ( VBODY * VBS * spin ( - 15. _deg ) , cs . charid > = 2 ? cgi . shSabre : cgi . shPSword , darkena ( col , 0 , 0x40 ) ) ;
2019-03-30 12:16:19 +00:00
if ( items [ itOrbSide3 ] & & emp )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , ( cs . charid & 1 ) ? cgi . shFerocityF : cgi . shFerocityM , darkena ( col , 0 , 0x40 ) ) ;
2016-01-02 10:09:13 +00:00
2022-12-13 18:04:43 +00:00
shiftmatrix VWPN = cs . lefthanded ? VBODY * VBS * lmirror ( ) : VBODY * VBS ;
2022-10-16 17:02:32 +00:00
queuepoly ( VWPN , ( cs . charid > = 2 ? cgi . shSabre : cgi . shPSword ) , darkena ( col , 0 , 0XC0 ) ) ;
2016-01-02 10:09:13 +00:00
}
2019-03-30 12:16:19 +00:00
else if ( ! where | | shmup : : curtime > = shmup : : getPlayer ( ) - > nextshot )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , cgi . shPKnife , darkena ( col , 0 , 0XC0 ) ) ;
2019-03-30 12:16:19 +00:00
2020-10-15 14:33:52 +00:00
# if CAP_COMPLEX2
2019-12-08 18:17:28 +00:00
if ( camelot : : knighted )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY3 * VBS , cgi . shKnightCloak , darkena ( col , 1 , 0xC0 ) ) ;
2020-10-15 14:33:52 +00:00
# endif
2019-03-30 12:16:19 +00:00
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD1 , ( cs . charid & 1 ) ? cgi . shFemaleHair : cgi . shPHead , darkena ( col , 1 , 0XC0 ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( col , 0 , 0XC0 ) ) ;
2019-03-30 12:16:19 +00:00
if ( cs . charid & 1 )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY1 * VBS , cgi . shFemaleDress , darkena ( col , 1 , 0XC0 ) ) ;
2019-03-30 12:16:19 +00:00
if ( cs . charid = = 2 )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY2 * VBS , cgi . shPrinceDress , darkena ( col , 1 , 0XC0 ) ) ;
2019-03-30 12:16:19 +00:00
if ( cs . charid = = 3 )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY2 * VBS , cgi . shPrincessDress , darkena ( col , 1 , 0XC0 ) ) ;
2019-05-20 13:28:20 +00:00
humanoid_eyes ( V , 0xFF , darkena ( col , 0 , 0x40 ) ) ;
2015-08-08 13:57:52 +00:00
}
2019-03-30 12:16:19 +00:00
}
2020-07-27 16:49:04 +00:00
EX bool drawMonsterType ( eMonster m , cell * where , const shiftmatrix & V1 , color_t col , double footphase , color_t asciicol ) {
2019-03-30 12:16:19 +00:00
# if MAXMDIM >= 4
2020-08-01 14:48:08 +00:00
if ( GDIM = = 3 & & asciicol ! = NOCOLOR ) {
2019-06-24 10:57:00 +00:00
addradar ( V1 , minf [ m ] . glyph , asciicol , isFriendly ( m ) ? 0x00FF00FF : 0xFF0000FF ) ;
2020-08-01 14:48:08 +00:00
}
2019-03-30 12:16:19 +00:00
# endif
char xch = minf [ m ] . glyph ;
2019-04-20 23:08:27 +00:00
2020-07-27 16:49:04 +00:00
shiftmatrix V = V1 ;
2022-12-08 18:38:06 +00:00
if ( WDIM = = 3 & & ( classflag ( m ) & CF_FACE_UP ) & & where & & ! mhybrid ) V = V1 * cspin90 ( 0 , 2 ) ;
2021-04-15 13:26:32 +00:00
# if CAP_SHAPES
2020-03-02 02:06:15 +00:00
if ( among ( m , moTortoise , moWorldTurtle ) & & where & & where - > stuntime > = 3 )
2019-03-30 12:16:19 +00:00
drawStunStars ( V , where - > stuntime - 2 ) ;
2021-07-17 09:24:38 +00:00
else if ( among ( m , moTortoise , moWorldTurtle , moMutant ) | | m = = moPlayer | | ( where & & ! where - > stuntime ) ) ;
2019-03-30 12:16:19 +00:00
else if ( where & & ! ( isMetalBeast ( m ) & & where - > stuntime = = 1 ) )
drawStunStars ( V , where - > stuntime ) ;
2017-07-10 18:47:38 +00:00
2019-03-30 12:16:19 +00:00
if ( mapeditor : : drawUserShape ( V , mapeditor : : sgMonster , m , darkena ( col , 0 , 0xFF ) , where ) )
2021-04-15 13:26:32 +00:00
return true ;
# endif
if ( ! mmmon | | ! CAP_SHAPES ) {
draw_ascii ( V1 , xch , asciicol , 1.5 ) ;
return true ;
}
2015-08-08 13:57:52 +00:00
2021-04-15 13:26:32 +00:00
# if CAP_SHAPES
2019-03-30 12:16:19 +00:00
switch ( m ) {
case moTortoise : {
int bits = where ? tortoise : : getb ( where ) : tortoise : : last ;
tortoise : : draw ( V , bits , 0 , where ? where - > stuntime : 0 ) ;
if ( tortoise : : seek ( ) & & ! tortoise : : diff ( bits ) & & where )
2021-05-09 00:25:05 +00:00
queue_ring ( V , cgi . shRing , darkena ( 0xFFFFFF , 0 , 0x80 + 0x70 * sintick ( 200 ) ) , PPR : : ITEM ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
2017-07-10 18:47:38 +00:00
2020-03-02 02:06:15 +00:00
case moWorldTurtle : {
tortoise : : draw ( V , - 1 , 0 , where ? where - > stuntime : 0 ) ;
2021-04-15 13:26:32 +00:00
return true ;
2020-03-02 02:06:15 +00:00
}
2019-03-30 12:16:19 +00:00
case moPlayer :
drawPlayer ( m , where , V , col , footphase ) ;
2021-04-15 13:26:32 +00:00
return true ;
2015-08-08 13:57:52 +00:00
2019-03-30 12:17:51 +00:00
case moMimic : case moShadow : case moIllusion :
2019-03-30 12:16:19 +00:00
drawMimic ( m , where , V , col , footphase ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
case moBullet :
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shKnife ) ;
2022-11-12 21:38:45 +00:00
queuepoly ( VBODY * spin270 ( ) , cgi . shKnife , getcs ( ) . swordcolor ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
case moKnight : case moKnightMoved : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
2019-03-30 12:16:19 +00:00
const transmatrix VBS = otherbodyparts ( V , darkena ( 0xC0C0A0 , 0 , 0xC0 ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , cgi . shPBody , darkena ( 0xC0C0A0 , 0 , 0xC0 ) ) ;
2019-03-30 12:16:19 +00:00
if ( ! racing : : on )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , cgi . shPSword , darkena ( 0xFFFF00 , 0 , 0xFF ) ) ;
queuepoly ( VBODY1 * VBS , cgi . shKnightArmor , darkena ( 0xD0D0D0 , 1 , 0xFF ) ) ;
2019-03-30 12:16:19 +00:00
color_t col ;
if ( ! eubinary & & where & & where - > master - > alt )
col = cloakcolor ( roundTableRadius ( where ) ) ;
else
col = cloakcolor ( newRoundTableRadius ( ) ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY2 * VBS , cgi . shKnightCloak , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VHEAD1 , cgi . shPHead , darkena ( 0x703800 , 1 , 0XFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( 0xC0C0A0 , 0 , 0XFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2017-07-10 18:47:38 +00:00
}
2019-03-30 12:16:19 +00:00
case moGolem : case moGolemMoved : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
2022-01-08 17:53:57 +00:00
const transmatrix VBS = otherbodyparts ( V , darkena ( col , 1 , 0XC0 ) , items [ itOrbFish ] & & items [ itOrbEmpathy ] ? moWaterElemental : m , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , cgi . shPBody , darkena ( col , 0 , 0XC0 ) ) ;
queuepoly ( VHEAD , cgi . shGolemhead , darkena ( col , 1 , 0XFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0xC0C000FF , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2017-07-10 18:47:38 +00:00
}
2019-03-30 12:16:19 +00:00
case moEvilGolem : case moIceGolem : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 2 , 0xC0 ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
queuepoly ( VBS , cgi . shPBody , darkena ( col , 0 , 0XC0 ) ) ;
queuepoly ( VHEAD , cgi . shGolemhead , darkena ( col , 1 , 0XFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0xFF0000FF , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2017-07-10 18:47:38 +00:00
}
2017-10-14 17:29:20 +00:00
2019-03-30 12:16:19 +00:00
case moFalsePrincess : case moRoseLady : case moRoseBeauty : {
princess :
bool girl = princessgender ( ) = = GEN_F ;
bool evil = ! isPrincess ( m ) ;
2017-07-10 18:47:38 +00:00
2019-03-30 12:16:19 +00:00
int facecolor = evil ? 0xC0B090FF : 0xD0C080FF ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , girl ? cgi . shFemaleBody : cgi . shPBody ) ;
2022-01-08 17:53:57 +00:00
const transmatrix VBS = otherbodyparts ( V , facecolor , ! evil & & items [ itOrbFish ] & & items [ itOrbEmpathy ] ? moWaterElemental : m , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , girl ? cgi . shFemaleBody : cgi . shPBody , facecolor ) ;
2016-01-02 10:09:13 +00:00
2019-03-30 12:16:19 +00:00
if ( m = = moPrincessArmed )
2022-12-13 18:04:43 +00:00
queuepoly ( VBODY * VBS * lmirror ( ) , vid . cs . charid < 2 ? cgi . shSabre : cgi . shPSword , 0xFFFFFFFF ) ;
2019-03-30 12:16:19 +00:00
if ( ( m = = moFalsePrincess | | m = = moRoseBeauty ) & & where & & where - > cpdist = = 1 )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , cgi . shPKnife , 0xFFFFFFFF ) ;
2016-01-02 10:09:13 +00:00
2019-03-30 12:16:19 +00:00
if ( m = = moRoseLady ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , cgi . shPKnife , 0xFFFFFFFF ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VBODY * VBS * lmirror ( ) , cgi . shPKnife , 0xFFFFFFFF ) ;
2019-03-30 12:16:19 +00:00
}
2017-07-10 18:47:38 +00:00
2019-03-30 12:16:19 +00:00
if ( girl ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY1 * VBS , cgi . shFemaleDress , evil ? 0xC000C0FF : 0x00C000FF ) ;
2019-03-30 12:16:19 +00:00
if ( vid . cs . charid < 2 )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY2 * VBS , cgi . shPrincessDress , ( evil ? 0xC040C0C0 : 0x8080FFC0 ) | UNTRANS ) ;
2019-03-30 12:16:19 +00:00
}
else {
if ( vid . cs . charid < 2 )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY1 * VBS , cgi . shPrinceDress , evil ? 0x802080FF : 0x404040FF ) ;
2019-03-30 12:16:19 +00:00
}
2017-07-10 18:47:38 +00:00
2019-03-30 12:16:19 +00:00
if ( m = = moRoseLady ) {
2019-05-26 16:04:02 +00:00
// queuepoly(V, girl ? cgi.shGoatHead : cgi.shDemon, 0x800000FF);
2019-05-12 18:11:05 +00:00
// make her hair a bit darker to stand out in 3D
2019-08-15 13:05:43 +00:00
queuepoly ( VHEAD1 , girl ? cgi . shFemaleHair : cgi . shPHead , evil ? 0x500050FF : GDIM = = 3 ? 0x666A64FF : 0x332A22FF ) ;
2019-03-30 12:16:19 +00:00
}
else if ( m = = moRoseBeauty ) {
if ( girl ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD1 , cgi . shBeautyHair , 0xF0A0D0FF ) ;
queuepoly ( VHEAD2 , cgi . shFlowerHair , 0xC00000FF ) ;
2019-03-30 12:16:19 +00:00
}
else {
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD1 , cgi . shPHead , 0xF0A0D0FF ) ;
2020-04-17 13:03:23 +00:00
queuepoly ( VBODY * VBS , cgi . shFlowerHand , 0xC00000FF ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY2 * VBS , cgi . shSuspenders , 0xC00000FF ) ;
2019-03-30 12:16:19 +00:00
}
}
else {
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD1 , girl ? cgi . shFemaleHair : cgi . shPHead ,
2019-03-30 12:16:19 +00:00
evil ? 0xC00000FF : 0x332A22FF ) ;
}
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD , cgi . shPFace , facecolor ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , evil ? 0x0000C0FF : 0x00C000FF , facecolor ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moWolf : case moRedFox : case moWolfMoved : case moLavaWolf : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shWolfBody ) ;
2019-03-30 12:16:19 +00:00
if ( mmspatial | | footphase )
animallegs ( VALEGS , moWolf , darkena ( col , 0 , 0xFF ) , footphase ) ;
else
2019-05-26 16:04:02 +00:00
queuepoly ( VALEGS , cgi . shWolfLegs , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VABODY , cgi . shWolfBody , darkena ( col , 0 , 0xFF ) ) ;
2019-03-30 12:16:19 +00:00
if ( m = = moRedFox ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shFoxTail1 , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VABODY , cgi . shFoxTail2 , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
2019-03-30 12:16:19 +00:00
}
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD , cgi . shWolfHead , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , cgi . shWolfEyes , darkena ( col , 3 , 0xFF ) ) ;
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD , cgi . shFamiliarEye , 0xFF ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VAHEAD * lmirror ( ) , cgi . shFamiliarEye , 0xFF ) ;
2019-05-11 13:11:55 +00:00
}
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
2017-07-10 18:47:38 +00:00
2019-03-30 12:16:19 +00:00
case moReptile : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shReptileBody ) ;
2019-03-30 12:16:19 +00:00
animallegs ( VALEGS , moReptile , darkena ( col , 0 , 0xFF ) , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shReptileBody , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , cgi . shReptileHead , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , cgi . shReptileEye , darkena ( col , 3 , 0xFF ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VAHEAD * lmirror ( ) , cgi . shReptileEye , darkena ( col , 3 , 0xFF ) ) ;
2019-09-28 12:18:23 +00:00
if ( GDIM = = 2 ) queuepoly ( VABODY , cgi . shReptileTail , darkena ( col , 2 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
2017-07-10 18:47:38 +00:00
2019-03-30 12:16:19 +00:00
case moSalamander : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shReptileBody ) ;
2019-03-30 12:16:19 +00:00
animallegs ( VALEGS , moReptile , darkena ( 0xD00000 , 1 , 0xFF ) , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shReptileBody , darkena ( 0xD00000 , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , cgi . shReptileHead , darkena ( 0xD00000 , 1 , 0xFF ) ) ;
queuepoly ( VAHEAD , cgi . shReptileEye , darkena ( 0xD00000 , 0 , 0xFF ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VAHEAD * lmirror ( ) , cgi . shReptileEye , darkena ( 0xD00000 , 0 , 0xFF ) ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shReptileTail , darkena ( 0xD08000 , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2017-07-10 18:47:38 +00:00
}
2019-03-30 12:16:19 +00:00
2020-02-26 00:19:49 +00:00
case moFrog : case moPhaser : case moVaulter : {
ShadowV ( V , cgi . shFrogBody ) ;
2022-12-06 00:04:26 +00:00
const shiftmatrix VL = GDIM = = 3 ? V : at_smart_lof ( V , cgi . ALEG0 ) ;
2020-02-26 00:19:49 +00:00
color_t xcolor = darkena ( 0xFF0000 , 1 , 0xFF ) ;
int alpha = ( m = = moPhaser ? 0xC0 : 0xFF ) ;
if ( footphase ) {
2020-02-28 23:05:06 +00:00
queuepoly ( VL , cgi . shFrogJumpFoot , darkena ( col , 0 , alpha ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VL * lmirror ( ) , cgi . shFrogJumpFoot , darkena ( col , 0 , alpha ) ) ;
2020-02-28 23:05:06 +00:00
queuepoly ( VALEGS , cgi . shFrogJumpLeg , xcolor ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VALEGS * lmirror ( ) , cgi . shFrogJumpLeg , xcolor ) ;
2020-02-26 00:19:49 +00:00
}
else {
queuepoly ( VL , cgi . shFrogRearFoot , darkena ( col , 0 , alpha ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VL * lmirror ( ) , cgi . shFrogRearFoot , darkena ( col , 0 , alpha ) ) ;
2020-02-26 00:19:49 +00:00
queuepoly ( VALEGS , cgi . shFrogRearLeg , xcolor ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VALEGS * lmirror ( ) , cgi . shFrogRearLeg , xcolor ) ;
2020-02-26 00:19:49 +00:00
queuepoly ( VALEGS , cgi . shFrogRearLeg2 , xcolor ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VALEGS * lmirror ( ) , cgi . shFrogRearLeg2 , xcolor ) ;
2020-02-26 00:19:49 +00:00
}
queuepoly ( VL , cgi . shFrogFrontFoot , darkena ( col , 0 , alpha ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VL * lmirror ( ) , cgi . shFrogFrontFoot , darkena ( col , 0 , alpha ) ) ;
2020-02-26 00:19:49 +00:00
queuepoly ( VALEGS , cgi . shFrogFrontLeg , xcolor ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VALEGS * lmirror ( ) , cgi . shFrogFrontLeg , xcolor ) ;
2020-02-26 00:19:49 +00:00
queuepoly ( VABODY , cgi . shFrogBody , darkena ( col , 0 , alpha ) ) ;
queuepoly ( VABODY , cgi . shFrogEye , darkena ( col , 3 , alpha ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VABODY * lmirror ( ) , cgi . shFrogEye , darkena ( col , 3 , alpha ) ) ;
2020-02-26 00:19:49 +00:00
queuepoly ( VABODY , cgi . shFrogStripe , xcolor ) ;
2021-04-15 13:26:32 +00:00
return true ;
2020-02-26 00:19:49 +00:00
}
2019-03-30 12:16:19 +00:00
case moVineBeast : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shWolfBody ) ;
2019-03-30 12:16:19 +00:00
if ( mmspatial | | footphase )
animallegs ( VALEGS , moWolf , 0x00FF00FF , footphase ) ;
else
2019-05-26 16:04:02 +00:00
queuepoly ( VALEGS , cgi . shWolfLegs , 0x00FF00FF ) ;
queuepoly ( VABODY , cgi . shWolfBody , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VAHEAD , cgi . shWolfHead , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , cgi . shWolfEyes , 0xFF0000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2017-07-10 18:47:38 +00:00
}
2019-03-30 12:16:19 +00:00
case moMouse : case moMouseMoved : {
2019-05-26 16:04:02 +00:00
queuepoly ( VALEGS , cgi . shMouse , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VALEGS , cgi . shMouseLegs , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VALEGS , cgi . shMouseEyes , 0xFF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2017-07-10 18:47:38 +00:00
}
2019-03-30 12:16:19 +00:00
case moRunDog : case moHunterDog : case moHunterGuard : case moHunterChanging : case moFallingDog : {
if ( ! mmspatial & & ! footphase )
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shDogBody , darkena ( col , 0 , 0xFF ) ) ;
2019-03-30 12:16:19 +00:00
else {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shDogTorso ) ;
queuepoly ( VABODY , cgi . shDogTorso , darkena ( col , 0 , 0xFF ) ) ;
2019-03-30 12:16:19 +00:00
animallegs ( VALEGS , moRunDog , m = = moFallingDog ? 0xFFFFFFFF : darkena ( col , 0 , 0xFF ) , footphase ) ;
2016-08-26 09:58:03 +00:00
}
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD , cgi . shDogHead , darkena ( col , 0 , 0xFF ) ) ;
2019-03-30 12:16:19 +00:00
{
dynamicval < color_t > dp ( poly_outline ) ;
int eyecolor = 0x202020 ;
bool redeyes = false ;
if ( m = = moHunterDog ) eyecolor = 0xFF0000 , redeyes = true ;
if ( m = = moHunterGuard ) eyecolor = 0xFF6000 , redeyes = true ;
if ( m = = moHunterChanging ) eyecolor = 0xFFFF00 , redeyes = true ;
int eyes = darkena ( eyecolor , 0 , 0xFF ) ;
if ( redeyes ) poly_outline = eyes ;
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD , cgi . shWolf1 , eyes ) . flags | = POLY_FORCEWIDE ;
queuepoly ( VAHEAD , cgi . shWolf2 , eyes ) . flags | = POLY_FORCEWIDE ;
2019-03-30 12:16:19 +00:00
}
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD , cgi . shWolf3 , darkena ( m = = moRunDog ? 0x202020 : 0x000000 , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moOrangeDog : {
if ( ! mmspatial & & ! footphase )
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shDogBody , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
else {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shDogTorso ) ;
2019-06-01 17:50:17 +00:00
if ( GDIM = = 2 ) queuepoly ( VABODY , cgi . shDogTorso , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
2019-03-30 12:16:19 +00:00
animallegs ( VALEGS , moRunDog , darkena ( 0xFFFFFF , 0 , 0xFF ) , footphase ) ;
2017-07-10 18:47:38 +00:00
}
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD , cgi . shDogHead , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
2019-06-01 17:50:17 +00:00
queuepoly ( VABODY , cgi . shDogStripes , GDIM = = 2 ? darkena ( 0x303030 , 0 , 0xFF ) : 0xFFFFFFFF ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD , cgi . shWolf1 , darkena ( 0x202020 , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , cgi . shWolf2 , darkena ( 0x202020 , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , cgi . shWolf3 , darkena ( 0x202020 , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2017-07-10 18:47:38 +00:00
}
2019-03-30 12:16:19 +00:00
2020-03-02 02:06:15 +00:00
case moShark : case moGreaterShark : case moCShark :
2019-05-26 16:04:02 +00:00
queuepoly ( VFISH , cgi . shShark , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2020-02-26 00:19:49 +00:00
case moPike :
queuepoly ( VFISH , cgi . shPikeBody , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VFISH , cgi . shPikeEye , darkena ( col , 2 , 0xFF ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VFISH * lmirror ( ) , cgi . shPikeEye , darkena ( col , 2 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
2019-03-30 12:17:51 +00:00
case moEagle : case moParrot : case moBomberbird : case moAlbatross :
2019-03-30 12:16:19 +00:00
case moTameBomberbird : case moWindCrow : case moTameBomberbirdMoved :
2019-04-22 12:41:14 +00:00
case moSandBird : case moAcidBird : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shEagle ) ;
2019-08-15 13:05:43 +00:00
auto & sh = GDIM = = 3 ? cgi . shAnimatedEagle [ wingphase ( 200 ) ] : cgi . shEagle ;
if ( m = = moParrot & & GDIM = = 3 )
2019-04-22 12:41:14 +00:00
queuepolyat ( VBIRD , sh , darkena ( col , 0 , 0xFF ) , PPR : : SUPERLINE ) ;
2019-03-30 12:16:19 +00:00
else
2019-04-22 12:41:14 +00:00
queuepoly ( VBIRD , sh , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-04-22 12:41:14 +00:00
}
2019-03-30 12:16:19 +00:00
case moSparrowhawk : case moWestHawk : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shHawk ) ;
2019-08-15 13:05:43 +00:00
auto & sh = GDIM = = 3 ? cgi . shAnimatedHawk [ wingphase ( 200 ) ] : cgi . shHawk ;
2019-05-16 15:08:12 +00:00
queuepoly ( VBIRD , sh , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2016-08-26 09:58:03 +00:00
}
2019-03-30 12:16:19 +00:00
case moButterfly : {
2019-05-16 15:08:12 +00:00
transmatrix Vwing = wingmatrix ( 100 ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V * Vwing , cgi . shButterflyWing ) ;
2019-08-15 13:05:43 +00:00
if ( GDIM = = 2 )
2019-05-26 16:04:02 +00:00
queuepoly ( VBIRD * Vwing , cgi . shButterflyWing , darkena ( col , 0 , 0xFF ) ) ;
2019-05-16 15:08:12 +00:00
else
2019-05-26 16:04:02 +00:00
queuepoly ( VBIRD , cgi . shAnimatedButterfly [ wingphase ( 100 ) ] , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBIRD , cgi . shButterflyBody , darkena ( col , 2 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2017-07-10 18:47:38 +00:00
}
2019-03-30 12:16:19 +00:00
case moGadfly : {
2019-05-16 15:08:12 +00:00
transmatrix Vwing = wingmatrix ( 100 ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V * Vwing , cgi . shGadflyWing ) ;
2019-08-15 13:05:43 +00:00
queuepoly ( VBIRD * Vwing , GDIM = = 2 ? cgi . shGadflyWing : cgi . shAnimatedGadfly [ wingphase ( 100 ) ] , darkena ( col , 0 , 0xFF ) ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBIRD , cgi . shGadflyBody , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VBIRD , cgi . shGadflyEye , darkena ( col , 2 , 0xFF ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VBIRD * lmirror ( ) , cgi . shGadflyEye , darkena ( col , 2 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moVampire : case moBat : {
// vampires have no shadow and no mirror images
2019-05-26 16:04:02 +00:00
if ( m = = moBat ) ShadowV ( V , cgi . shBatWings ) ;
2019-03-30 12:16:19 +00:00
if ( m = = moBat | | ! inmirrorcount ) {
2019-08-15 13:05:43 +00:00
queuepoly ( VBIRD , GDIM = = 2 ? cgi . shBatWings : cgi . shAnimatedBat [ wingphase ( 100 ) ] , darkena ( 0x303030 , 0 , 0xFF ) ) ;
queuepoly ( VBIRD , GDIM = = 2 ? cgi . shBatBody : cgi . shAnimatedBat2 [ wingphase ( 100 ) ] , darkena ( 0x606060 , 0 , 0xFF ) ) ;
2019-05-26 16:04:02 +00:00
}
/* queuepoly(V, cgi.shBatMouth, darkena(0xC00000, 0, 0xFF));
queuepoly ( V , cgi . shBatFang , darkena ( 0xFFC0C0 , 0 , 0xFF ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( V * lmirror ( ) , cgi . shBatFang , darkena ( 0xFFC0C0 , 0 , 0xFF ) ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( V , cgi . shBatEye , darkena ( 00000000 , 0 , 0xFF ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( V * lmirror ( ) , cgi . shBatEye , darkena ( 00000000 , 0 , 0xFF ) ) ; */
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moGargoyle : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shGargoyleWings ) ;
2019-08-15 13:05:43 +00:00
queuepoly ( VBIRD , GDIM = = 2 ? cgi . shGargoyleWings : cgi . shAnimatedGargoyle [ wingphase ( 300 ) ] , darkena ( col , 0 , 0xD0 ) ) ;
queuepoly ( VBIRD , GDIM = = 2 ? cgi . shGargoyleBody : cgi . shAnimatedGargoyle2 [ wingphase ( 300 ) ] , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moZombie : {
int c = darkena ( col , where & & where - > land = = laHalloween ? 1 : 0 , 0xFF ) ;
const transmatrix VBS = otherbodyparts ( V , c , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
queuepoly ( VBODY * VBS , cgi . shPBody , c ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moTerraWarrior : {
drawTerraWarrior ( V , 7 , ( where ? where - > hitpoints : 7 ) , footphase ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moVariantWarrior : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xC0 ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
queuepoly ( VBS , cgi . shPBody , darkena ( 0xFFD500 , 0 , 0xF0 ) ) ;
if ( ! peace : : on ) queuepoly ( VBS , cgi . shPSword , 0xFFFF00FF ) ;
queuepoly ( VHEAD , cgi . shHood , 0x008000FF ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0xFFFF00FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moDesertman : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xC0 ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
queuepoly ( VBS , cgi . shPBody , darkena ( col , 0 , 0xC0 ) ) ;
if ( ! peace : : on ) queuepoly ( VBS , cgi . shPSword , 0xFFFF00FF ) ;
queuepoly ( VHEAD , cgi . shHood , 0xD0D000C0 | UNTRANS ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x301800FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moMonk : {
const transmatrix VBS = otherbodyparts ( V , darkena ( col , 0 , 0xC0 ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shRaiderBody ) ;
queuepoly ( VBODY * VBS , cgi . shRaiderBody , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBODY1 * VBS , cgi . shRaiderShirt , darkena ( col , 2 , 0xFF ) ) ;
if ( ! peace : : on ) queuepoly ( VBODY * VBS , cgi . shPKnife , 0xFFC0C0C0 ) ;
queuepoly ( VBODY2 * VBS , cgi . shRaiderArmor , darkena ( col , 1 , 0xFF ) ) ;
queuepolyat ( VBODY3 * VBS , cgi . shRatCape2 , darkena ( col , 2 , 0xFF ) , PPR : : MONSTER_ARMOR0 ) ;
queuepoly ( VHEAD1 , cgi . shRaiderHelmet , darkena ( col , 0 , 0XFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( 0xC0C0A0 , 0 , 0XFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moCrusher : {
const transmatrix VBS = otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shRaiderBody ) ;
queuepoly ( VBODY * VBS , cgi . shRaiderBody , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBODY1 * VBS , cgi . shRaiderShirt , darkena ( col , 2 , 0xFF ) ) ;
queuepoly ( VBODY2 * VBS , cgi . shRaiderArmor , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VBODY * VBS , cgi . shFlailTrunk , darkena ( col , 1 , 0XFF ) ) ;
queuepoly ( VBODY1 * VBS , cgi . shHammerHead , darkena ( col , 0 , 0XFF ) ) ;
queuepoly ( VHEAD1 , cgi . shRaiderHelmet , darkena ( col , 0 , 0XFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( 0xC0C0A0 , 0 , 0XFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moPair : {
const transmatrix VBS = otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shRaiderBody ) ;
queuepoly ( VBODY * VBS , cgi . shRaiderBody , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBODY1 * VBS , cgi . shRaiderShirt , darkena ( col , 2 , 0xFF ) ) ;
queuepoly ( VBODY2 * VBS , cgi . shRaiderArmor , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VBODY * VBS , cgi . shPickAxe , darkena ( 0xA0A0A0 , 0 , 0XFF ) ) ;
queuepoly ( VHEAD1 , cgi . shRaiderHelmet , darkena ( col , 0 , 0XFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( 0xC0C0A0 , 0 , 0XFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moAltDemon : case moHexDemon : {
const transmatrix VBS = otherbodyparts ( V , darkena ( col , 0 , 0xC0 ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shRaiderBody ) ;
queuepoly ( VBODY * VBS , cgi . shRaiderBody , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBODY1 * VBS , cgi . shRaiderShirt , darkena ( col , 2 , 0xFF ) ) ;
queuepoly ( VBODY2 * VBS , cgi . shRaiderArmor , darkena ( col , 1 , 0xFF ) ) ;
if ( ! peace : : on ) queuepoly ( VBODY * VBS , cgi . shPSword , 0xFFD0D0D0 ) ;
queuepoly ( VHEAD1 , cgi . shRaiderHelmet , darkena ( col , 0 , 0XFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( 0xC0C0A0 , 0 , 0XFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moSkeleton : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( 0xFFFFFF , 0 , 0xFF ) , moSkeleton , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBS , cgi . shSkeletonBody , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
2019-08-15 13:05:43 +00:00
if ( GDIM = = 2 ) queuepoly ( VHEAD , cgi . shSkull , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
if ( GDIM = = 2 ) queuepoly ( VHEAD1 , cgi . shSkullEyes , 0x000000FF ) ;
2019-05-13 12:22:20 +00:00
humanoid_eyes ( V , 0x000000FF , 0xFFFFFFFF ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shSkeletonBody ) ;
queuepoly ( VBS , cgi . shSabre , 0xFFFFFFFF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2017-07-10 18:47:38 +00:00
}
2019-03-30 12:16:19 +00:00
case moPalace : case moFatGuard : case moVizier : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
2019-02-27 18:15:58 +00:00
const transmatrix VBS = otherbodyparts ( V , darkena ( 0xFFD500 , 0 , 0xFF ) , m , footphase ) ;
2017-07-10 18:47:38 +00:00
if ( m = = moFatGuard ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , cgi . shFatBody , darkena ( 0xC06000 , 0 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
col = 0xFFFFFF ;
if ( ! where | | where - > hitpoints > = 3 )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY1 * VBS , cgi . shKnightCloak , darkena ( 0xFFC0C0 , 1 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
}
else {
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY * VBS , cgi . shPBody , darkena ( 0xFFD500 , 0 , 0xFF ) ) ;
queuepoly ( VBODY1 * VBS , cgi . shKnightArmor , m = = moVizier ? 0xC000C0FF :
2017-07-10 18:47:38 +00:00
darkena ( 0x00C000 , 1 , 0xFF ) ) ;
if ( where & & where - > hitpoints > = 3 )
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY2 * VBS , cgi . shKnightCloak , m = = moVizier ? 0x800080Ff :
2017-07-10 18:47:38 +00:00
darkena ( 0x00FF00 , 1 , 0xFF ) ) ;
}
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD1 , cgi . shTurban1 , darkena ( col , 1 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
if ( ! where | | where - > hitpoints > = 2 )
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD2 , cgi . shTurban2 , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBODY * VBS , cgi . shSabre , 0xFFFFFFFF ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x301800FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moCrystalSage : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , 0xFFFFFFFF , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
queuepoly ( VBS , cgi . shPBody , 0xFFFFFFFF ) ;
queuepoly ( VHEAD1 , cgi . shPHead , 0xFFFFFFFF ) ;
queuepoly ( VHEAD , cgi . shPFace , 0xFFFFFFFF ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0xFFFFFFFF , 0xC0C0C0FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2017-07-10 18:47:38 +00:00
}
2019-03-30 12:16:19 +00:00
case moHedge : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBS , cgi . shPBody , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBS , cgi . shHedgehogBlade , 0xC0C0C0FF ) ;
queuepoly ( VHEAD1 , cgi . shPHead , 0x804000FF ) ;
queuepoly ( VHEAD , cgi . shPFace , 0xF09000FF ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x00D000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moYeti : case moMonkey : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xC0 ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
queuepoly ( VBS , cgi . shYeti , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD1 , cgi . shPHead , darkena ( col , 0 , 0xFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moResearcher : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
queuepoly ( VBS , cgi . shPBody , darkena ( 0xFFFF00 , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD , cgi . shAztecHead , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VHEAD1 , cgi . shAztecCap , darkena ( 0xC000C0 , 0 , 0xFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moFamiliar : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shWolfBody ) ;
queuepoly ( VABODY , cgi . shWolfBody , darkena ( 0xA03000 , 0 , 0xFF ) ) ;
2019-03-30 12:16:19 +00:00
if ( mmspatial | | footphase )
animallegs ( VALEGS , moWolf , darkena ( 0xC04000 , 0 , 0xFF ) , footphase ) ;
else
2019-05-26 16:04:02 +00:00
queuepoly ( VALEGS , cgi . shWolfLegs , darkena ( 0xC04000 , 0 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD , cgi . shFamiliarHead , darkena ( 0xC04000 , 0 , 0xFF ) ) ;
// queuepoly(V, cgi.shCatLegs, darkena(0x902000, 0, 0xFF));
2019-03-30 12:16:19 +00:00
if ( true ) {
2021-07-12 02:56:29 +00:00
queuepoly ( VAHEAD , cgi . shFamiliarEye , darkena ( 0xFFFF00 , 0 , 0xFF ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VAHEAD * lmirror ( ) , cgi . shFamiliarEye , darkena ( 0xFFFF00 , 0 , 0xFF ) ) ;
2019-03-30 12:16:19 +00:00
}
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
2017-05-28 22:16:17 +00:00
2019-03-30 12:16:19 +00:00
case moRanger : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBS , cgi . shPBody , darkena ( col , 0 , 0xC0 ) ) ;
if ( ! peace : : on ) queuepoly ( VBS , cgi . shPSword , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , cgi . shArmor , darkena ( col , 1 , 0xFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moNarciss : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBS , cgi . shFlowerHand , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBS , cgi . shPBody , 0xFFE080FF ) ;
if ( ! peace : : on ) queuepoly ( VBS , cgi . shPKnife , 0xC0C0C0FF ) ;
queuepoly ( VHEAD , cgi . shPFace , 0xFFE080FF ) ;
queuepoly ( VHEAD1 , cgi . shPHead , 0x806A00FF ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moMirrorSpirit : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0x90 ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBS , cgi . shPBody , darkena ( col , 0 , 0x90 ) ) ;
2022-12-13 18:04:43 +00:00
if ( ! peace : : on ) queuepoly ( VBS * lmirror ( ) , cgi . shPSword , darkena ( col , 0 , 0xD0 ) ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD1 , cgi . shPHead , darkena ( col , 1 , 0x90 ) ) ;
queuepoly ( VHEAD2 , cgi . shPFace , darkena ( col , 1 , 0x90 ) ) ;
queuepoly ( VHEAD , cgi . shArmor , darkena ( col , 0 , 0xC0 ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0xFFFFFFFF , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moJiangshi : {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shJiangShi ) ;
2022-11-12 21:38:45 +00:00
auto z2 = WDIM = = 3 ? 0 : GDIM = = 3 ? - abs ( sin ( footphase * TAU ) ) * cgi . human_height / 3 : geom3 : : lev_to_factor ( abs ( sin ( footphase * TAU ) ) * cgi . human_height ) ;
2019-03-30 12:16:19 +00:00
auto V0 = V ;
2022-12-06 00:04:26 +00:00
auto V = at_smart_lof ( V0 , z2 ) ;
2019-03-30 12:16:19 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , m = = moJiangshi ? 0 : footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY , cgi . shJiangShi , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBODY1 , cgi . shJiangShiDress , darkena ( 0x202020 , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , cgi . shTerraHead , darkena ( 0x101010 , 0 , 0xFF ) ) ;
queuepoly ( VHEAD1 , cgi . shPFace , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VHEAD2 , cgi . shJiangShiCap1 , darkena ( 0x800000 , 0 , 0xFF ) ) ;
queuepoly ( VHEAD3 , cgi . shJiangShiCap2 , darkena ( 0x400000 , 0 , 0xFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moGhost : case moSeep : case moFriendlyGhost : {
if ( m = = moFriendlyGhost ) col = fghostcolor ( where ) ;
2019-08-15 13:05:43 +00:00
queuepolyat ( VGHOST , cgi . shGhost , darkena ( col , 0 , m = = moFriendlyGhost ? 0xC0 : 0x80 ) , GDIM = = 3 ? PPR : : SUPERLINE : cgi . shGhost . prio ) ;
queuepolyat ( VGHOST , cgi . shGhostEyes , 0xFF , GDIM = = 3 ? PPR : : SUPERLINE : cgi . shEyes . prio ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moVineSpirit : {
2019-05-26 16:04:02 +00:00
queuepoly ( VGHOST , cgi . shGhost , 0xD0D0D0C0 | UNTRANS ) ;
2019-08-15 13:05:43 +00:00
queuepolyat ( VGHOST , cgi . shGhostEyes , 0xFF0000FF , GDIM = = 3 ? PPR : : SUPERLINE : cgi . shGhostEyes . prio ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moFireFairy : {
col = firecolor ( 0 ) ;
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shFemaleBody ) ;
queuepoly ( VBS , cgi . shFemaleBody , darkena ( col , 0 , 0XC0 ) ) ;
queuepoly ( VHEAD , cgi . shWitchHair , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VHEAD1 , cgi . shPFace , darkena ( col , 0 , 0XFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , darkena ( col , 1 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
2020-02-26 00:20:33 +00:00
case moRusalka : {
col = watercolor ( 0 ) ;
bool girl = princessgender ( ) = = GEN_F ;
if ( girl ) {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , col , m , footphase ) ;
2020-02-26 00:20:33 +00:00
ShadowV ( V , cgi . shFemaleBody ) ;
queuepoly ( VBS , cgi . shFemaleBody , watercolor ( 100 ) ) ;
queuepoly ( VHEAD1 , cgi . shFemaleHair , watercolor ( 150 ) ) ;
// queuepoly(VHEAD2, cgi.shFlowerHair, watercolor(50));
// queuepoly(VHEAD, cgi.shWitchHair, watercolor(150));
queuepoly ( VHEAD1 , cgi . shPFace , watercolor ( 200 ) ) ;
queuepoly ( VHEAD1 , cgi . shWightCloak , watercolor ( 50 ) & 0xFFFFFF80 ) ;
humanoid_eyes ( V , col | 0xFF ) ;
}
else {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , col , m , footphase ) ;
2020-02-26 00:20:33 +00:00
ShadowV ( V , cgi . shPBody ) ;
queuepoly ( VBS , cgi . shPBody , watercolor ( 100 ) ) ;
queuepoly ( VBS , cgi . shSuspenders , watercolor ( 150 ) ) ;
queuepoly ( VHEAD1 , cgi . shPHead , watercolor ( 50 ) ) ;
queuepoly ( VHEAD1 , cgi . shPFace , watercolor ( 200 ) ) ;
queuepoly ( VHEAD1 , cgi . shWightCloak , watercolor ( 50 ) & 0xFFFFFF80 ) ;
humanoid_eyes ( V , col | 0xFF ) ;
}
2021-04-15 13:26:32 +00:00
return true ;
2020-02-26 00:20:33 +00:00
}
2019-03-30 12:16:19 +00:00
case moSlime : {
2019-05-26 16:04:02 +00:00
queuepoly ( VFISH , cgi . shSlime , darkena ( col , 0 , 0x80 ) ) ;
queuepoly ( VSLIMEEYE , cgi . shSlimeEyes , 0xFF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
2019-04-05 12:41:21 +00:00
2019-03-30 12:16:19 +00:00
case moKrakenH : {
2019-05-26 16:04:02 +00:00
queuepoly ( VFISH , cgi . shKrakenHead , darkena ( col , 0 , 0xD0 ) ) ;
queuepoly ( VFISH , cgi . shKrakenEye , 0xFFFFFFC0 | UNTRANS ) ;
queuepoly ( VFISH , cgi . shKrakenEye2 , 0xC0 ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VFISH * lmirror ( ) , cgi . shKrakenEye , 0xFFFFFFC0 | UNTRANS ) ;
queuepoly ( VFISH * lmirror ( ) , cgi . shKrakenEye2 , 0xC0 ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moKrakenT : {
2019-05-26 16:04:02 +00:00
queuepoly ( VFISH , cgi . shSeaTentacle , darkena ( col , 0 , 0xD0 ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moCultist : case moPyroCultist : case moCultistLeader : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
queuepoly ( VBS , cgi . shPBody , darkena ( col , 0 , 0xC0 ) ) ;
if ( ! peace : : on ) queuepoly ( VBS , cgi . shPSword , darkena ( col , 2 , 0xFF ) ) ;
queuepoly ( VHEAD , cgi . shHood , darkena ( col , 1 , 0xFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x00FF00FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moPirate : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
queuepoly ( VBS , cgi . shPBody , darkena ( 0x404040 , 0 , 0xFF ) ) ;
queuepoly ( VBS , cgi . shPirateHook , darkena ( 0xD0D0D0 , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( 0xFFFF80 , 0 , 0xFF ) ) ;
queuepoly ( VHEAD1 , cgi . shEyepatch , darkena ( 0 , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD2 , cgi . shPirateHood , darkena ( col , 0 , 0xFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moRatling : case moRatlingAvenger : {
const transmatrix VBS = otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shYeti ) ;
queuepoly ( VLEG , cgi . shRatTail , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBODY * VBS , cgi . shYeti , darkena ( col , 1 , 0xFF ) ) ;
2019-03-30 12:16:19 +00:00
float t = sintick ( 1000 , where ? where - > cpdist * M_PI : 0 ) ;
int eyecol = t > 0.92 ? 0xFF0000 : 0 ;
2019-08-15 13:05:43 +00:00
if ( GDIM = = 2 ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD , cgi . shRatHead , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , cgi . shWolf1 , darkena ( eyecol , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , cgi . shWolf2 , darkena ( eyecol , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , cgi . shWolf3 , darkena ( 0x202020 , 0 , 0xFF ) ) ;
if ( m = = moRatlingAvenger ) queuepoly ( VHEAD1 , cgi . shRatCape1 , 0x303030FF ) ;
2019-05-12 18:11:17 +00:00
}
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2019-05-12 18:11:17 +00:00
else {
2023-02-04 00:58:13 +00:00
shiftmatrix V1 = V * lzpush ( cgi . AHEAD - zc ( 0.4 ) - zc ( 0.98 ) + cgi . HEAD ) ; // * cpush(0, cgi.scalefactor * (-0.1));
2019-05-26 16:04:02 +00:00
queuepoly ( V1 , cgi . shRatHead , darkena ( col , 0 , 0xFF ) ) ;
2019-05-24 21:49:23 +00:00
/*
2019-05-26 16:04:02 +00:00
queuepoly ( V1 , cgi . shFamiliarEye , darkena ( eyecol , 0 , 0xFF ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( V1 * lmirror ( ) , cgi . shFamiliarEye , darkena ( eyecol , 0 , 0xFF ) ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( V1 , cgi . shWolfEyes , darkena ( col , 3 , 0xFF ) ) ;
2019-05-24 21:49:23 +00:00
*/
2019-05-26 16:04:02 +00:00
queuepoly ( V1 , cgi . shRatEye1 , darkena ( eyecol , 0 , 0xFF ) ) ;
queuepoly ( V1 , cgi . shRatEye2 , darkena ( eyecol , 0 , 0xFF ) ) ;
queuepoly ( V1 , cgi . shRatEye3 , darkena ( 0x202020 , 0 , 0xFF ) ) ;
if ( m = = moRatlingAvenger ) queuepoly ( V1 , cgi . shRatCape1 , 0x303030FF ) ;
2019-05-12 18:11:17 +00:00
}
2019-06-01 14:59:04 +00:00
# endif
2019-03-30 12:16:19 +00:00
if ( m = = moRatlingAvenger ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VBODY1 * VBS , cgi . shRatCape2 , 0x484848FF ) ;
2019-03-30 12:16:19 +00:00
}
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moViking : {
const transmatrix VBS = otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
queuepoly ( VBODY * VBS , cgi . shPBody , darkena ( 0xE00000 , 0 , 0xFF ) ) ;
if ( ! peace : : on ) queuepoly ( VBODY * VBS , cgi . shPSword , darkena ( 0xD0D0D0 , 0 , 0xFF ) ) ;
queuepoly ( VBODY1 * VBS , cgi . shKnightCloak , darkena ( 0x404040 , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , cgi . shVikingHelmet , darkena ( 0xC0C0C0 , 0 , 0XFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( 0xFFFF80 , 0 , 0xFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moOutlaw : {
const transmatrix VBS = otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
queuepoly ( VBODY * VBS , cgi . shPBody , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBODY1 * VBS , cgi . shKnightCloak , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VHEAD1 , cgi . shWestHat1 , darkena ( col , 2 , 0XFF ) ) ;
queuepoly ( VHEAD2 , cgi . shWestHat2 , darkena ( col , 1 , 0XFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( 0xFFFF80 , 0 , 0xFF ) ) ;
queuepoly ( VBODY * VBS , cgi . shGunInHand , darkena ( col , 1 , 0XFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moNecromancer : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shPBody ) ;
queuepoly ( VBS , cgi . shPBody , 0xC00000C0 | UNTRANS ) ;
queuepoly ( VHEAD , cgi . shHood , darkena ( col , 1 , 0xFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0xFF0000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moDraugr : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , 0x483828D0 | UNTRANS , m , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBS , cgi . shPBody , 0x483828D0 | UNTRANS ) ;
queuepoly ( VBS , cgi . shPSword , 0xFFFFD0A0 | UNTRANS ) ;
queuepoly ( VHEAD , cgi . shPHead , 0x483828D0 | UNTRANS ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0xFF0000FF , 0x483828FF ) ;
2019-05-26 16:04:02 +00:00
// queuepoly(V, cgi.shSkull, 0xC06020D0);
//queuepoly(V, cgi.shSkullEyes, 0x000000D0);
// queuepoly(V, cgi.shWightCloak, 0xC0A080A0);
2019-03-30 12:16:19 +00:00
int b = where ? where - > cpdist : 0 ;
b - - ;
if ( b < 0 ) b = 0 ;
if ( b > 6 ) b = 6 ;
2021-07-12 03:02:35 +00:00
queuepoly ( VHEAD1 , cgi . shWightCloak , color_t ( 0x605040A0 | UNTRANS ) + color_t ( 0x10101000 * b ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moVoidBeast : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , 0x080808D0 | UNTRANS , m , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBS , cgi . shPBody , 0x080808D0 | UNTRANS ) ;
queuepoly ( VHEAD , cgi . shPHead , 0x080808D0 | UNTRANS ) ;
queuepoly ( VHEAD , cgi . shWightCloak , 0xFF0000A0 | UNTRANS ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0xFF0000FF , 0x080808FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moGoblin : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shYeti ) ;
queuepoly ( VBS , cgi . shYeti , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD , cgi . shArmor , darkena ( col , 1 , 0XFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x800000FF , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moLancer : case moFlailer : case moMiner : {
2020-07-27 16:49:04 +00:00
shiftmatrix V2 = V ;
2019-03-30 12:16:19 +00:00
if ( m = = moLancer )
2022-11-12 21:38:45 +00:00
V2 = V * spin ( ( where & & where - > type = = 6 ) ? - 60. _deg : - 90. _deg ) ;
2022-12-06 00:04:26 +00:00
shiftmatrix Vh = at_smart_lof ( V2 , cgi . HEAD ) ;
shiftmatrix Vb = at_smart_lof ( V2 , cgi . BODY ) ;
2019-03-30 12:16:19 +00:00
Vb = Vb * otherbodyparts ( V2 , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V2 , cgi . shPBody ) ;
queuepoly ( Vb , cgi . shPBody , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( Vh , m = = moFlailer ? cgi . shArmor : cgi . shHood , darkena ( col , 1 , 0XFF ) ) ;
2019-03-30 12:16:19 +00:00
if ( m = = moMiner )
2019-05-26 16:04:02 +00:00
queuepoly ( Vb , cgi . shPickAxe , darkena ( 0xC0C0C0 , 0 , 0XFF ) ) ;
2019-03-30 12:16:19 +00:00
if ( m = = moLancer )
2019-05-26 16:04:02 +00:00
queuepoly ( Vb , cgi . shPike , darkena ( col , 0 , 0XFF ) ) ;
2019-03-30 12:16:19 +00:00
if ( m = = moFlailer ) {
2019-05-26 16:04:02 +00:00
queuepoly ( Vb , cgi . shFlailBall , darkena ( col , 0 , 0XFF ) ) ;
queuepoly ( Vb , cgi . shFlailChain , darkena ( col , 1 , 0XFF ) ) ;
queuepoly ( Vb , cgi . shFlailTrunk , darkena ( col , 0 , 0XFF ) ) ;
2019-03-30 12:16:19 +00:00
}
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moTroll : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shYeti ) ;
queuepoly ( VBS , cgi . shYeti , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD1 , cgi . shPHead , darkena ( col , 1 , 0XFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( col , 2 , 0XFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x004000FF , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moFjordTroll : case moForestTroll : case moStormTroll : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shYeti ) ;
queuepoly ( VBS , cgi . shYeti , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD1 , cgi . shPHead , darkena ( col , 1 , 0XFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( col , 2 , 0XFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x004000FF , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moDarkTroll : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shYeti ) ;
queuepoly ( VBS , cgi . shYeti , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD1 , cgi . shPHead , darkena ( col , 1 , 0XFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , 0xFFFFFF80 | UNTRANS ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moRedTroll : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shYeti ) ;
2023-03-23 01:31:00 +00:00
queuepoly ( VBS , cgi . shYeti , darkena ( 0xFF8000 , 0 , 0XFF ) ) ;
queuepoly ( VHEAD1 , cgi . shPHead , darkena ( col , 0 , 0xC0 ) ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD , cgi . shPFace , 0xFFFFFF80 | UNTRANS ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moEarthElemental : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shWaterElemental ) ;
queuepoly ( VBS , cgi . shWaterElemental , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD1 , cgi . shFemaleHair , darkena ( col , 0 , 0XFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , 0xF0000080 | UNTRANS ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0xD0D000FF , darkena ( col , 1 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moWaterElemental : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , watercolor ( 50 ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shWaterElemental ) ;
queuepoly ( VBS , cgi . shWaterElemental , watercolor ( 0 ) ) ;
queuepoly ( VHEAD1 , cgi . shFemaleHair , watercolor ( 100 ) ) ;
queuepoly ( VHEAD , cgi . shPFace , watercolor ( 200 ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x0000FFFF , watercolor ( 150 ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moFireElemental : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( firecolor ( 50 ) , 0 , 0xFF ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shWaterElemental ) ;
queuepoly ( VBS , cgi . shWaterElemental , darkena ( firecolor ( 0 ) , 0 , 0xFF ) ) ;
queuepoly ( VHEAD1 , cgi . shFemaleHair , darkena ( firecolor ( 100 ) , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( firecolor ( 200 ) , 0 , 0xFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , darkena ( firecolor ( 200 ) , 0 , 0xFF ) , darkena ( firecolor ( 50 ) , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moAirElemental : {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0x40 ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shWaterElemental ) ;
queuepoly ( VBS , cgi . shWaterElemental , darkena ( col , 0 , 0x80 ) ) ;
queuepoly ( VHEAD1 , cgi . shFemaleHair , darkena ( col , 0 , 0x80 ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( col , 0 , 0x80 ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0xFFFFFFFF , darkena ( col , 1 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moWorm : case moWormwait : case moHexSnake : {
2019-05-26 16:04:02 +00:00
queuepoly ( V , cgi . shWormHead , darkena ( col , 0 , 0xFF ) ) ;
queuepolyat ( V , cgi . shWormEyes , 0xFF , PPR : : ONTENTACLE_EYES ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moDragonHead : {
2019-05-26 16:04:02 +00:00
queuepoly ( V , cgi . shDragonHead , darkena ( col , 0 , 0xFF ) ) ;
queuepolyat ( V , cgi . shDragonEyes , 0xFF , PPR : : ONTENTACLE_EYES ) ;
2019-03-30 12:16:19 +00:00
int noscolor = 0xFF0000FF ;
2019-05-26 16:04:02 +00:00
queuepoly ( V , cgi . shDragonNostril , noscolor ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( V * lmirror ( ) , cgi . shDragonNostril , noscolor ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moDragonTail : {
2019-05-26 16:04:02 +00:00
queuepoly ( V , cgi . shDragonSegment , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
case moTentacle : case moTentaclewait : case moTentacleEscaping : {
2019-05-26 16:04:02 +00:00
queuepoly ( V , cgi . shTentHead , darkena ( col , 0 , 0xFF ) ) ;
ShadowV ( V , cgi . shTentHead , PPR : : GIANTSHADOW ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 12:16:19 +00:00
}
2019-03-30 16:51:37 +00:00
case moAsteroid : {
2019-05-26 16:04:02 +00:00
queuepoly ( V , cgi . shAsteroid [ 1 ] , darkena ( col , 0 , 0xFF ) ) ;
2021-04-15 13:26:32 +00:00
return true ;
2019-03-30 16:51:37 +00:00
}
2021-05-27 11:00:20 +00:00
2021-06-09 02:33:55 +00:00
# if CAP_COMPLEX2
2021-05-29 13:45:37 +00:00
case moAnimatedDie : case moAngryDie : {
2021-05-27 11:00:20 +00:00
if ( where )
dice : : draw_die ( where , V , 1 , darkena ( col , 0 , 0xFF ) ) ;
else
queuepoly ( V , cgi . shDodeca , darkena ( col , 0 , 0xFF ) ) ;
return true ;
}
2021-06-09 02:33:55 +00:00
# endif
2021-05-27 11:00:20 +00:00
2019-03-30 12:16:19 +00:00
default : ;
2017-07-10 18:47:38 +00:00
}
2019-03-30 12:16:19 +00:00
if ( isPrincess ( m ) ) goto princess ;
else if ( isBull ( m ) ) {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shBullBody ) ;
2019-03-30 12:16:19 +00:00
int hoofcol = darkena ( gradient ( 0 , col , 0 , .65 , 1 ) , 0 , 0xFF ) ;
if ( mmspatial | | footphase )
animallegs ( VALEGS , moRagingBull , hoofcol , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shBullBody , darkena ( gradient ( 0 , col , 0 , .80 , 1 ) , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , cgi . shBullHead , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , cgi . shBullHorn , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( VAHEAD * lmirror ( ) , cgi . shBullHorn , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
}
2019-03-30 12:16:19 +00:00
else if ( isBug ( m ) ) {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shBugBody ) ;
2019-03-30 12:16:19 +00:00
if ( ! mmspatial & & ! footphase )
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shBugBody , darkena ( col , 0 , 0xFF ) ) ;
2019-03-30 12:16:19 +00:00
else {
animallegs ( VALEGS , moBug0 , darkena ( col , 0 , 0xFF ) , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shBugAntenna , darkena ( col , 1 , 0xFF ) ) ;
2019-03-30 12:16:19 +00:00
}
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shBugArmor , darkena ( col , 1 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
}
2018-01-04 14:46:06 +00:00
else if ( isSwitch ( m ) ) {
2019-05-26 16:04:02 +00:00
queuepoly ( VFISH , cgi . shJelly , darkena ( col , 0 , 0xD0 ) ) ;
queuepolyat ( VBODY , cgi . shJelly , darkena ( col , 0 , 0xD0 ) , PPR : : MONSTER_BODY ) ;
queuepolyat ( VHEAD , cgi . shJelly , darkena ( col , 0 , 0xD0 ) , PPR : : MONSTER_HEAD ) ;
queuepolyat ( VHEAD , cgi . shSlimeEyes , 0xFF , PPR : : MONSTER_HEAD ) ;
2018-01-04 14:46:06 +00:00
}
2019-03-30 12:16:19 +00:00
else if ( isDemon ( m ) ) {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 0 , 0xC0 ) , m , footphase ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBS , cgi . shPBody , darkena ( col , 1 , 0xC0 ) ) ;
ShadowV ( V , cgi . shPBody ) ;
2017-07-10 18:47:38 +00:00
int acol = col ;
if ( xch = = ' D ' ) acol = 0xD0D0D0 ;
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD , cgi . shDemon , darkena ( acol , 0 , 0xFF ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0xFF0000FF , 0xC00000FF ) ;
2016-01-02 10:09:13 +00:00
}
2017-12-30 14:12:15 +00:00
else if ( isMagneticPole ( m ) ) {
if ( m = = moNorthPole )
2022-11-12 21:38:45 +00:00
queuepolyat ( VBODY * spin180 ( ) , cgi . shTentacle , 0x000000C0 , PPR : : TENTACLE1 ) ;
2019-05-26 16:04:02 +00:00
queuepolyat ( VBODY , cgi . shDisk , darkena ( col , 0 , 0xFF ) , PPR : : MONSTER_BODY ) ;
2017-12-30 14:12:15 +00:00
}
2018-10-25 00:43:14 +00:00
else if ( isMetalBeast ( m ) | | m = = moBrownBug ) {
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shTrylobite ) ;
2017-07-10 18:47:38 +00:00
if ( ! mmspatial )
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shTrylobite , darkena ( col , 1 , 0xC0 ) ) ;
2017-03-23 10:53:57 +00:00
else {
2019-05-26 16:04:02 +00:00
queuepoly ( VABODY , cgi . shTrylobiteBody , darkena ( col , 1 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
animallegs ( VALEGS , moMetalBeast , darkena ( col , 1 , 0xFF ) , footphase ) ;
2017-03-23 10:53:57 +00:00
}
2017-07-10 18:47:38 +00:00
int acol = col ;
2019-05-26 16:04:02 +00:00
queuepoly ( VAHEAD , cgi . shTrylobiteHead , darkena ( acol , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
2021-05-17 12:18:45 +00:00
else if ( m = = moHexer ) {
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
ShadowV ( V , cgi . shFemaleBody ) ;
queuepoly ( VBS , cgi . shFemaleBody , darkena ( 0x800080 , 0 , 0xFF ) ) ;
queuepoly ( VHEAD1 , cgi . shWitchHair , darkena ( 0xFF00FF , 1 , 0xFF ) ) ;
queuepoly ( VHEAD , cgi . shPFace , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
queuepoly ( VBS , cgi . shWitchDress , darkena ( col , 1 , 0XC0 ) ) ;
humanoid_eyes ( V , 0xF000F0FF ) ;
}
2017-07-10 18:47:38 +00:00
else if ( isWitch ( m ) ) {
2020-07-27 16:49:04 +00:00
const shiftmatrix VBS = VBODY * otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
2017-07-10 18:47:38 +00:00
int cc = 0xFF ;
2018-09-10 15:49:51 +00:00
if ( m = = moWitchGhost ) cc = 0x85 + 120 * sintick ( 160 ) ;
2021-05-21 23:26:59 +00:00
if ( m = = moWitchWinter & & where ) drawWinter ( V , 0 , iinf [ itOrbWinter ] . color ) ;
2017-07-10 18:47:38 +00:00
if ( m = = moWitchFlash & & where ) drawFlash ( V ) ;
if ( m = = moWitchSpeed & & where ) drawSpeed ( V ) ;
if ( m = = moWitchFire ) col = firecolor ( 0 ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( V , cgi . shFemaleBody ) ;
queuepoly ( VBS , cgi . shFemaleBody , darkena ( col , 0 , cc ) ) ;
// queuepoly(cV2, ct, cgi.shPSword, darkena(col, 0, 0XFF));
// queuepoly(V, cgi.shHood, darkena(col, 0, 0XC0));
2017-07-10 18:47:38 +00:00
if ( m = = moWitchFire ) col = firecolor ( 100 ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD1 , cgi . shWitchHair , darkena ( col , 1 , cc ) ) ;
2017-07-10 18:47:38 +00:00
if ( m = = moWitchFire ) col = firecolor ( 200 ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VHEAD , cgi . shPFace , darkena ( col , 0 , cc ) ) ;
2017-07-10 18:47:38 +00:00
if ( m = = moWitchFire ) col = firecolor ( 300 ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( VBS , cgi . shWitchDress , darkena ( col , 1 , 0XC0 ) ) ;
2019-05-12 18:08:42 +00:00
humanoid_eyes ( V , 0x000000FF ) ;
2016-01-02 10:09:13 +00:00
}
2017-07-10 18:47:38 +00:00
// just for the HUD glyphs...
2019-03-30 12:16:19 +00:00
else if ( isAnyIvy ( m ) ) {
2022-12-08 19:05:17 +00:00
queuepoly ( VBODY , cgi . shILeaf [ 0 ] , darkena ( col , 0 , 0xFF ) ) ;
2017-03-23 10:53:57 +00:00
}
2016-01-02 10:09:13 +00:00
2021-04-15 13:26:32 +00:00
else
draw_ascii ( V1 , minf [ m ] . glyph , asciicol , 1.5 ) ;
2017-07-10 18:47:38 +00:00
2017-12-01 23:23:15 +00:00
return true ;
# endif
2017-07-10 18:47:38 +00:00
}
2016-01-02 10:09:13 +00:00
2020-07-27 16:49:04 +00:00
bool drawMonsterTypeDH ( eMonster m , cell * where , const shiftmatrix & V , color_t col , bool dh , ld footphase , color_t asciicol ) {
2018-09-04 17:53:42 +00:00
dynamicval < color_t > p ( poly_outline , poly_outline ) ;
2017-07-10 18:47:38 +00:00
if ( dh ) {
poly_outline = OUTLINE_DEAD ;
darken + + ;
}
2019-06-24 10:57:00 +00:00
bool b = drawMonsterType ( m , where , V , col , footphase , asciicol ) ;
2017-07-10 18:47:38 +00:00
if ( dh ) {
darken - - ;
}
return b ;
}
2015-08-08 13:57:52 +00:00
2020-07-27 16:49:04 +00:00
EX shiftmatrix playerV ;
2015-08-08 13:57:52 +00:00
2020-07-27 16:49:04 +00:00
EX bool applyAnimation ( cell * c , shiftmatrix & V , double & footphase , int layer ) {
2017-07-10 18:47:38 +00:00
if ( ! animations [ layer ] . count ( c ) ) return false ;
animation & a = animations [ layer ] [ c ] ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
int td = ticks - a . ltick ;
ld aspd = td / 1000.0 * exp ( vid . mspeed ) ;
2018-01-25 16:19:50 +00:00
ld R ;
again :
2023-02-04 10:28:41 +00:00
auto TC0 = cgi . emb - > anim_tile_center ( ) ;
2019-08-27 14:48:50 +00:00
2020-12-26 17:09:09 +00:00
if ( among ( a . attacking , 1 , 3 ) )
2023-01-08 02:09:40 +00:00
R = hdist ( a . attackat * TC0 , a . wherenow * TC0 ) ;
2018-01-25 16:19:50 +00:00
else
2023-01-08 02:09:40 +00:00
R = hdist ( a . wherenow * TC0 , TC0 ) ;
2017-07-10 18:47:38 +00:00
aspd * = ( 1 + R + ( shmup : : on ? 1 : 0 ) ) ;
2020-12-26 17:09:09 +00:00
if ( a . attacking = = 3 & & aspd > R ) aspd = R ;
2023-01-08 02:09:40 +00:00
2020-12-26 17:09:09 +00:00
if ( ( R < aspd | | std : : isnan ( R ) | | std : : isnan ( aspd ) | | R > 10 ) & & a . attacking ! = 3 ) {
2018-01-25 16:19:50 +00:00
if ( a . attacking = = 1 ) { a . attacking = 2 ; goto again ; }
2017-07-10 18:47:38 +00:00
animations [ layer ] . erase ( c ) ;
return false ;
}
else {
2023-01-08 02:09:40 +00:00
transmatrix T = inverse ( a . wherenow ) ;
2023-02-04 10:28:41 +00:00
ld z = cgi . emb - > anim_center_z ( ) ;
2023-01-26 23:27:10 +00:00
if ( z ) T = lzpush ( - z ) * T ;
2023-01-08 02:09:40 +00:00
2019-08-18 20:27:55 +00:00
hyperpoint wnow ;
2020-12-26 17:09:09 +00:00
if ( a . attacking = = 1 | | a . attacking = = 3 )
2023-01-08 02:09:40 +00:00
wnow = T * a . attackat * TC0 ;
2018-01-25 16:19:50 +00:00
else
2023-01-08 02:09:40 +00:00
wnow = T * TC0 ;
2019-08-18 20:27:55 +00:00
2023-01-08 02:09:40 +00:00
shift_v_towards ( T , shiftless ( wnow ) , aspd , shift_method ( smaAnimation ) ) ;
2023-02-04 10:28:41 +00:00
if ( z ) T = lzpush ( z ) * T ;
2023-01-08 02:09:40 +00:00
a . wherenow = inverse ( T ) ;
fixmatrix ( a . wherenow ) ;
2020-05-15 20:52:52 +00:00
if ( cgflags & qAFFINE ) {
transmatrix T = a . wherenow ;
fixmatrix_euclid ( T ) ;
a . wherenow = inverse ( T ) * a . wherenow ;
for ( int i = 0 ; i < MDIM ; i + + )
a . wherenow [ i ] = lerp ( a . wherenow [ i ] , Id [ i ] , aspd / R ) ;
a . wherenow = T * a . wherenow ;
}
2023-01-08 02:09:40 +00:00
2018-01-25 16:19:50 +00:00
a . footphase + = a . attacking = = 2 ? - aspd : aspd ;
2020-12-26 17:09:09 +00:00
if ( a . attacking = = 3 & & aspd > = R ) {
a . footphase = 0 ;
hyperpoint h1 = a . wherenow * C0 ;
2023-01-08 02:09:40 +00:00
a . wherenow = rgpushxto0 ( h1 ) * lrspintox ( h1 ) ;
2020-12-26 17:09:09 +00:00
}
2017-07-10 18:47:38 +00:00
footphase = a . footphase ;
2023-01-08 02:09:40 +00:00
V = V * a . wherenow * lrspintox ( wnow ) ;
2023-02-04 11:59:51 +00:00
if ( cgi . emb - > is_cylinder ( ) & & ! gproduct ) {
if ( nil ) {
V = V * lzpush ( 1 ) ;
V = V * spin270 ( ) ;
V = V * lzpush ( - 1 ) ;
}
else
V = V * cspin90 ( 1 , 0 ) ;
}
2022-12-13 18:04:43 +00:00
if ( a . mirrored ) V = V * lmirror ( ) ;
if ( a . attacking = = 2 ) V = V * lpispin ( ) ;
2017-07-10 18:47:38 +00:00
a . ltick = ticks ;
return true ;
}
}
2016-01-02 10:09:13 +00:00
2020-07-27 16:49:04 +00:00
double chainAngle ( cell * c , shiftmatrix & V , cell * c2 , double dft , const shiftmatrix & Vwhere ) {
2023-02-04 09:19:13 +00:00
if ( cgi . emb - > no_spin ( ) ) return 0 ;
2017-07-22 23:33:27 +00:00
if ( ! gmatrix0 . count ( c2 ) ) return dft ;
2023-02-04 10:28:41 +00:00
hyperpoint h = cgi . emb - > anim_tile_center ( ) ;
2017-07-10 18:47:38 +00:00
if ( animations [ LAYER_BIG ] . count ( c2 ) ) h = animations [ LAYER_BIG ] [ c2 ] . wherenow * h ;
2020-07-27 16:49:04 +00:00
h = inverse_shift ( V , Vwhere ) * calc_relative_matrix ( c2 , c , C0 ) * h ;
2023-02-04 10:28:41 +00:00
ld z = cgi . emb - > anim_center_z ( ) ;
2023-02-04 09:19:13 +00:00
if ( z ) h = lzpush ( - z ) * h ;
2017-07-10 18:47:38 +00:00
return atan2 ( h [ 1 ] , h [ 0 ] ) ;
}
2016-08-26 09:58:03 +00:00
2017-07-10 18:47:38 +00:00
// equivalent to V = V * spin(-chainAngle(c,V,c2,dft));
2020-07-27 16:49:04 +00:00
bool chainAnimation ( cell * c , cell * c2 , shiftmatrix & V , const shiftmatrix & Vwhere , ld & length ) {
2023-02-04 09:19:13 +00:00
if ( cgi . emb - > no_spin ( ) ) return false ;
2023-02-04 10:28:41 +00:00
hyperpoint h = cgi . emb - > anim_tile_center ( ) ;
2017-07-10 18:47:38 +00:00
if ( animations [ LAYER_BIG ] . count ( c2 ) ) h = animations [ LAYER_BIG ] [ c2 ] . wherenow * h ;
2020-07-27 16:49:04 +00:00
h = inverse_shift ( V , Vwhere ) * h ;
2023-02-04 09:19:13 +00:00
length = hdist ( h , tile_center ( ) ) ;
ld z = cgi . emb - > center_z ( ) ;
if ( z ) h = lzpush ( - z ) * h ;
2017-07-10 18:47:38 +00:00
V = V * rspintox ( h ) ;
return true ;
}
2016-08-26 09:58:03 +00:00
2017-07-10 18:47:38 +00:00
// push down the queue after q-th element, `down` absolute units down,
// based on cell c and transmatrix V
// do change the zoom factor? do change the priorities?
2016-08-26 09:58:03 +00:00
2019-08-09 21:39:36 +00:00
EX int cellcolor ( cell * c ) {
2017-07-10 18:47:38 +00:00
if ( isPlayerOn ( c ) | | isFriendly ( c ) ) return OUTLINE_FRIEND ;
if ( noHighlight ( c - > monst ) ) return OUTLINE_NONE ;
if ( c - > monst ) return OUTLINE_ENEMY ;
if ( c - > wall = = waMirror ) return c - > land = = laMirror ? OUTLINE_TREASURE : OUTLINE_ORB ;
2017-03-23 10:53:57 +00:00
2020-01-30 16:45:05 +00:00
if ( c - > item & & ! itemHiddenFromSight ( c ) ) {
2017-07-10 18:47:38 +00:00
int k = itemclass ( c - > item ) ;
if ( k = = IC_TREASURE )
return OUTLINE_TREASURE ;
else if ( k = = IC_ORB )
return OUTLINE_ORB ;
else
return OUTLINE_OTHER ;
}
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
return OUTLINE_NONE ;
}
2017-03-23 10:53:57 +00:00
2018-01-11 22:18:02 +00:00
int taildist ( cell * c ) {
int s = 0 ;
2022-07-17 10:42:35 +00:00
while ( s < 1000 & & c & & c - > mondir ! = NODIR & & isWorm ( c - > monst ) ) {
2018-08-17 22:46:45 +00:00
s + + ; c = c - > move ( c - > mondir ) ;
2018-01-11 22:18:02 +00:00
}
return s ;
}
int last_wormsegment = - 1 ;
2019-01-06 01:40:45 +00:00
vector < vector < function < void ( ) > > > wormsegments ;
2018-01-11 22:18:02 +00:00
2019-01-06 01:40:45 +00:00
void add_segment ( int d , const function < void ( ) > & s ) {
2018-06-22 12:47:24 +00:00
if ( isize ( wormsegments ) < = d ) wormsegments . resize ( d + 1 ) ;
2018-01-11 22:18:02 +00:00
last_wormsegment = max ( last_wormsegment , d ) ;
wormsegments [ d ] . push_back ( s ) ;
}
void drawWormSegments ( ) {
for ( int i = 0 ; i < = last_wormsegment ; i + + ) {
for ( auto & f : wormsegments [ i ] ) f ( ) ;
wormsegments [ i ] . clear ( ) ;
}
last_wormsegment = - 1 ;
}
2019-08-09 19:00:52 +00:00
EX bool dont_face_pc = false ;
2018-01-30 23:10:44 +00:00
2021-05-27 11:00:20 +00:00
EX shiftmatrix die_target ;
2020-07-27 16:49:04 +00:00
EX bool drawMonster ( const shiftmatrix & Vparam , int ct , cell * c , color_t col , color_t asciicol ) {
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2015-08-08 13:57:52 +00:00
2019-08-09 22:58:50 +00:00
bool darkhistory = history : : includeHistory & & history : : inkillhistory . count ( c ) ;
2021-08-02 19:14:21 +00:00
color_t outline = OUTLINE_NONE ;
if ( doHighlight ( ) ) {
outline =
2017-07-10 18:47:38 +00:00
( isPlayerOn ( c ) | | isFriendly ( c ) ) ? OUTLINE_FRIEND :
noHighlight ( c - > monst ) ? OUTLINE_NONE :
OUTLINE_ENEMY ;
2021-08-02 19:14:21 +00:00
poly_outline = outline ;
}
2017-07-10 18:47:38 +00:00
2021-04-30 17:44:54 +00:00
// highlight faraway enemies if that's needed
if ( vid . faraway_highlight & & c - > cpdist > = 6 & & vid . faraway_highlight < = get_threat_level ( c ) ) {
// basic red-green oscillation
color_t r = ceil ( 255 * abs ( sintick ( 1000 , 0.25 ) ) ) ;
color_t g = ceil ( 255 * abs ( sintick ( 1000 , 0.00 ) ) ) ;
color_t hlc = ( r < < 16 ) + ( g < < 8 ) ;
hlc = gradient ( col , hlc , 0 , vid . faraway_highlight_color , 100 ) ;
if ( c - > cpdist = = 6 )
hlc = gradient ( 0 , hlc , 0 , 1 , 1.5 ) ;
addauraspecial ( tC0 ( Vparam ) , hlc , 0 ) ;
}
2017-07-10 18:47:38 +00:00
bool nospins = false , nospinb = false ;
double footphaseb = 0 , footphase = 0 ;
2020-07-27 16:49:04 +00:00
shiftmatrix Vs = Vparam ; nospins = applyAnimation ( c , Vs , footphase , LAYER_SMALL ) ;
shiftmatrix Vb = Vparam ; nospinb = applyAnimation ( c , Vb , footphaseb , LAYER_BIG ) ;
2017-07-10 18:47:38 +00:00
// nospin = true;
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
eMonster m = c - > monst ;
2019-03-30 12:35:03 +00:00
2019-05-15 12:19:19 +00:00
bool half_elliptic = elliptic & & GDIM = = 3 & & WDIM = = 2 ;
2020-07-27 16:49:04 +00:00
bool mirrored = det ( Vparam . T ) > 0 ;
2019-05-15 12:19:19 +00:00
2021-04-15 13:26:32 +00:00
bool res = m ;
2019-03-30 12:35:03 +00:00
if ( ! m ) ;
2019-05-15 10:41:02 +00:00
2019-05-15 12:19:19 +00:00
else if ( half_elliptic & & mirrored ! = c - > monmirror & & ! isMimic ( m ) ) ;
2017-07-10 18:47:38 +00:00
2019-03-30 12:35:03 +00:00
else if ( isAnyIvy ( c ) | | isWorm ( c ) ) {
2019-02-27 13:43:42 +00:00
2018-06-17 10:15:46 +00:00
if ( ( m = = moHexSnake | | m = = moHexSnakeTail ) & & c - > hitpoints = = 2 ) {
2018-01-05 14:49:50 +00:00
int d = c - > mondir ;
if ( d = = NODIR )
forCellIdEx ( c2 , i , c )
2018-08-17 22:46:45 +00:00
if ( among ( c2 - > monst , moHexSnakeTail , moHexSnake ) & & c2 - > mondir = = c - > c . spin ( i ) )
2018-01-05 14:49:50 +00:00
d = i ;
2018-01-06 22:39:10 +00:00
if ( d = = NODIR ) { d = hrand ( c - > type ) ; createMov ( c , d ) ; }
2017-12-05 18:43:45 +00:00
int c1 = nestcolors [ pattern_threecolor ( c ) ] ;
2018-08-17 22:46:45 +00:00
int c2 = nestcolors [ pattern_threecolor ( c - > move ( d ) ) ] ;
2017-12-05 18:43:45 +00:00
col = ( c1 + c2 ) ; // sum works because they are dark and should be brightened
}
2017-07-10 18:47:38 +00:00
if ( isDragon ( c - > monst ) & & c - > stuntime = = 0 ) col = 0xFF6000 ;
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 )
2019-06-24 10:57:00 +00:00
addradar ( Vparam , minf [ m ] . glyph , asciicol , isFriendly ( m ) ? 0x00FF00FF : 0xFF0000FF ) ;
2019-05-11 13:20:34 +00:00
2020-07-27 16:49:04 +00:00
shiftmatrix Vb0 = Vb ;
2019-08-15 13:05:43 +00:00
if ( c - > mondir ! = NODIR & & GDIM = = 3 & & isAnyIvy ( c ) ) {
2022-12-08 19:05:17 +00:00
auto V1 = at_smart_lof ( Vparam , cgi . ABODY ) ;
auto V2 = at_smart_lof ( Vparam * currentmap - > adj ( c , c - > mondir ) , cgi . ABODY ) ;
queueline ( V1 * tile_center ( ) , V2 * tile_center ( ) , ( col < < 8 ) + 0xFF , 0 ) ;
2019-02-26 21:08:33 +00:00
}
else if ( c - > mondir ! = NODIR ) {
2017-07-10 18:47:38 +00:00
if ( mmmon ) {
2018-01-11 22:18:02 +00:00
ld length ;
2019-11-14 15:51:50 +00:00
cell * c2 = c - > move ( c - > mondir ) ;
if ( nospinb ) {
chainAnimation ( c , c2 , Vb , Vparam * currentmap - > adj ( c , c - > mondir ) , length ) ;
}
2018-01-11 22:18:02 +00:00
else {
2017-07-10 18:47:38 +00:00
Vb = Vb * ddspin ( c , c - > mondir ) ;
2018-01-11 22:18:02 +00:00
length = cellgfxdist ( c , c - > mondir ) ;
}
2018-08-27 17:27:35 +00:00
2023-02-04 09:19:13 +00:00
shiftmatrix Vbn = Vb ;
if ( cgi . emb - > no_spin ( ) & & c - > mondir ! = NODIR ) {
Vbn = Vparam * currentmap - > adj ( c , c - > mondir ) ;
ld dummy ;
applyAnimation ( c - > move ( c - > mondir ) , Vbn , dummy , LAYER_BIG ) ;
}
2022-12-13 18:04:43 +00:00
if ( c - > monmirror ) Vb = Vb * lmirror ( ) ;
2019-05-15 12:19:19 +00:00
2018-08-28 11:45:11 +00:00
if ( mapeditor : : drawUserShape ( Vb , mapeditor : : sgMonster , c - > monst , ( col < < 8 ) + 0xFF , c ) )
2018-08-27 17:27:35 +00:00
return false ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
if ( isIvy ( c ) | | isMutantIvy ( c ) | | c - > monst = = moFriendlyIvy )
2019-05-26 16:04:02 +00:00
queuepoly ( Vb , cgi . shIBranch , ( col < < 8 ) + 0xFF ) ;
2018-01-11 22:18:02 +00:00
/* else if(c->monst < moTentacle && wormstyle == 0) {
2019-05-26 16:04:02 +00:00
ShadowV ( Vb , cgi . shTentacleX , PPR : : GIANTSHADOW ) ;
2022-12-06 00:04:26 +00:00
queuepoly ( at_smart_lof ( Vb , cgi . ABODY ) , cgi . shTentacleX , 0xFF ) ;
queuepoly ( at_smart_lof ( Vb , cgi . ABODY ) , cgi . shTentacle , ( col < < 8 ) + 0xFF ) ;
2018-01-11 22:18:02 +00:00
} */
// else if(c->monst < moTentacle) {
// }
2017-07-10 18:47:38 +00:00
else if ( c - > monst = = moDragonHead | | c - > monst = = moDragonTail ) {
char part = dragon : : bodypart ( c , dragon : : findhead ( c ) ) ;
if ( part ! = ' 2 ' ) {
2022-12-06 00:04:26 +00:00
queuepoly ( at_smart_lof ( Vb , cgi . ABODY ) , cgi . shDragonSegment , darkena ( col , 0 , 0xFF ) ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( Vb , cgi . shDragonSegment , PPR : : GIANTSHADOW ) ;
2017-07-10 18:47:38 +00:00
}
}
else {
if ( c - > monst = = moTentacleGhost ) {
2020-07-27 16:49:04 +00:00
hyperpoint V0 = history : : on ? unshift ( tC0 ( Vs ) ) : inverse_shift ( cwtV , tC0 ( Vs ) ) ;
2022-12-08 18:38:06 +00:00
hyperpoint V1 = lspintox ( V0 ) * V0 ;
2022-12-13 18:04:43 +00:00
Vs = cwtV * lrspintox ( V0 ) * rpushxto0 ( V1 ) * lpispin ( ) ;
2019-06-24 10:57:55 +00:00
drawMonsterType ( moGhost , c , Vs , col , footphase , asciicol ) ;
2017-07-10 18:47:38 +00:00
col = minf [ moTentacletail ] . color ;
}
2018-01-11 22:18:02 +00:00
/*
2022-12-06 00:04:26 +00:00
queuepoly ( at_smart_lof ( Vb , cgi . ABODY ) , cgi . shTentacleX , 0xFFFFFFFF ) ;
queuepoly ( at_smart_lof ( Vb , cgi . ABODY ) , cgi . shTentacle , ( col < < 8 ) + 0xFF ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( Vb , cgi . shTentacleX , PPR : : GIANTSHADOW ) ;
2018-01-11 22:18:02 +00:00
*/
bool hexsnake = c - > monst = = moHexSnake | | c - > monst = = moHexSnakeTail ;
bool thead = c - > monst = = moTentacle | | c - > monst = = moTentaclewait | | c - > monst = = moTentacleEscaping ;
2019-05-26 16:04:02 +00:00
hpcshape & sh = hexsnake ? cgi . shWormSegment : cgi . shSmallWormSegment ;
2018-01-11 22:18:02 +00:00
ld wav = hexsnake ? 0 :
c - > monst < moTentacle ? 1 / 1.5 :
1 ;
2018-09-04 17:53:42 +00:00
color_t col0 = col ;
2018-01-11 22:18:02 +00:00
if ( c - > monst = = moWorm | | c - > monst = = moWormwait )
col0 = minf [ moWormtail ] . color ;
else if ( thead )
col0 = minf [ moTentacletail ] . color ;
add_segment ( taildist ( c ) , [ = ] ( ) {
for ( int i = 11 ; i > = 0 ; i - - ) {
if ( i < 3 & & ( c - > monst = = moTentacle | | c - > monst = = moTentaclewait ) ) continue ;
2021-08-02 19:14:21 +00:00
if ( doHighlight ( ) )
poly_outline = outline ;
2020-07-27 16:49:04 +00:00
shiftmatrix Vbx = Vb ;
2023-02-04 09:19:13 +00:00
if ( cgi . emb - > no_spin ( ) ) {
hyperpoint h = inverse_shift ( Vb , Vbn * tile_center ( ) ) ;
h = cgi . emb - > actual_to_intermediate ( h ) ;
h * = i / 12. ;
Vbx = Vb * cgi . emb - > intermediate_to_actual_translation ( h ) ;
}
else {
if ( WDIM = = 2 ) Vbx = Vbx * spin ( sin ( TAU * i / 12 ) * wav / ( i + .1 ) ) ;
Vbx = Vbx * lxpush ( length * ( i ) / 12.0 ) ;
}
2020-07-27 16:49:04 +00:00
// shiftmatrix Vbx2 = Vnext * xpush(length2 * i / 6.0);
2022-12-13 18:04:43 +00:00
// Vbx = Vbx * rspintox(inverse(Vbx) * Vbx2 * C0) * lpispin();
2018-08-28 12:27:23 +00:00
ShadowV ( Vbx , sh , PPR : : GIANTSHADOW ) ;
2022-12-06 00:04:26 +00:00
queuepoly ( at_smart_lof ( Vbx , cgi . ABODY ) , sh , ( col0 < < 8 ) + 0xFF ) ;
2018-01-11 22:18:02 +00:00
}
} ) ;
2017-07-10 18:47:38 +00:00
}
2015-08-08 13:57:52 +00:00
}
2017-07-10 18:47:38 +00:00
else {
2020-07-27 16:49:04 +00:00
shiftmatrix T = Vparam * ddspin ( c , c - > mondir ) ;
2018-09-04 17:53:42 +00:00
color_t col = darkena ( 0x606020 , 0 , 0xFF ) ;
2017-07-10 18:47:38 +00:00
for ( int u = - 1 ; u < = 1 ; u + + )
2022-11-12 21:38:45 +00:00
queueline ( T * xspinpush0 ( 90. _deg , u * cgi . crossf / 5 ) , T * xspinpush ( 0 , cgi . crossf ) * xspinpush0 ( 90. _deg , u * cgi . crossf / 5 ) , col , 2 + vid . linequality ) ;
2017-07-10 18:47:38 +00:00
}
}
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
if ( mmmon ) {
2019-03-30 12:35:03 +00:00
if ( isAnyIvy ( c ) ) {
2022-12-08 18:38:06 +00:00
if ( mhybrid ) {
2019-08-19 08:33:07 +00:00
queuepoly ( Vb , cgi . shILeaf [ ctof ( c ) ] , darkena ( col , 0 , 0xFF ) ) ;
for ( int a = 0 ; a < c - > type - 2 ; a + + )
2022-11-12 21:38:45 +00:00
queuepoly ( Vb * spin ( a * TAU / ( c - > type - 2 ) ) , cgi . shILeaf [ 2 ] , darkena ( col , 0 , 0xFF ) ) ;
2019-08-19 08:33:07 +00:00
}
else if ( GDIM = = 3 ) {
2022-12-08 19:05:17 +00:00
queuepoly ( face_the_player ( at_smart_lof ( Vb , cgi . ABODY ) ) , cgi . shILeaf [ 1 ] , darkena ( col , 0 , 0xFF ) ) ;
2019-02-26 21:08:33 +00:00
}
else {
2022-12-13 18:04:43 +00:00
if ( c - > monmirror ) Vb = Vb * lmirror ( ) ;
2022-12-06 00:04:26 +00:00
queuepoly ( at_smart_lof ( Vb , cgi . ABODY ) , cgi . shILeaf [ ctof ( c ) ] , darkena ( col , 0 , 0xFF ) ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( Vb , cgi . shILeaf [ ctof ( c ) ] , PPR : : GIANTSHADOW ) ;
2019-02-26 21:08:33 +00:00
}
2017-07-10 18:47:38 +00:00
}
else if ( m = = moWorm | | m = = moWormwait | | m = = moHexSnake ) {
2022-12-13 18:04:43 +00:00
Vb = Vb * lpispin ( ) ;
if ( c - > monmirror ) Vb = Vb * lmirror ( ) ;
2022-12-06 00:04:26 +00:00
shiftmatrix Vbh = at_smart_lof ( Vb , cgi . AHEAD ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( Vbh , cgi . shWormHead , darkena ( col , 0 , 0xFF ) ) ;
queuepolyat ( Vbh , cgi . shWormEyes , 0xFF , PPR : : ONTENTACLE_EYES ) ;
ShadowV ( Vb , cgi . shWormHead , PPR : : GIANTSHADOW ) ;
2017-07-10 18:47:38 +00:00
}
else if ( m = = moDragonHead ) {
2022-12-13 18:04:43 +00:00
if ( c - > monmirror ) Vb = Vb * lmirror ( ) ;
2022-12-06 00:04:26 +00:00
shiftmatrix Vbh = at_smart_lof ( Vb , cgi . AHEAD ) ;
2019-05-26 16:04:02 +00:00
ShadowV ( Vb , cgi . shDragonHead , PPR : : GIANTSHADOW ) ;
queuepoly ( Vbh , cgi . shDragonHead , darkena ( col , c - > hitpoints ? 0 : 1 , 0xFF ) ) ;
2022-12-13 18:04:43 +00:00
queuepolyat ( Vbh /* * lpispin() */ , cgi . shDragonEyes , 0xFF , PPR : : ONTENTACLE_EYES ) ;
2017-07-10 18:47:38 +00:00
int noscolor = ( c - > hitpoints = = 1 & & c - > stuntime = = 1 ) ? 0xFF0000FF : 0xFF ;
2019-05-26 16:04:02 +00:00
queuepoly ( Vbh , cgi . shDragonNostril , noscolor ) ;
2022-12-13 18:04:43 +00:00
queuepoly ( Vbh * lmirror ( ) , cgi . shDragonNostril , noscolor ) ;
2017-07-10 18:47:38 +00:00
}
else if ( m = = moTentacle | | m = = moTentaclewait | | m = = moTentacleEscaping ) {
2022-12-13 18:04:43 +00:00
Vb = Vb * lpispin ( ) ;
if ( c - > monmirror ) Vb = Vb * lmirror ( ) ;
2022-12-06 00:04:26 +00:00
shiftmatrix Vbh = at_smart_lof ( Vb , cgi . AHEAD ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( Vbh , cgi . shTentHead , darkena ( col , 0 , 0xFF ) ) ;
ShadowV ( Vb , cgi . shTentHead , PPR : : GIANTSHADOW ) ;
2017-07-10 18:47:38 +00:00
}
else if ( m = = moDragonTail ) {
cell * c2 = NULL ;
for ( int i = 0 ; i < c - > type ; i + + )
2018-08-17 22:46:45 +00:00
if ( c - > move ( i ) & & isDragon ( c - > move ( i ) - > monst ) & & c - > move ( i ) - > mondir = = c - > c . spin ( i ) )
c2 = c - > move ( i ) ;
2017-07-10 18:47:38 +00:00
int nd = neighborId ( c , c2 ) ;
char part = dragon : : bodypart ( c , dragon : : findhead ( c ) ) ;
if ( part = = ' t ' ) {
if ( nospinb ) {
2018-01-11 22:18:02 +00:00
ld length ;
2019-11-14 15:51:50 +00:00
chainAnimation ( c , c2 , Vb , Vparam * currentmap - > adj ( c , nd ) , length ) ;
2022-12-13 18:04:43 +00:00
Vb = Vb * lpispin ( ) ;
2017-07-10 18:47:38 +00:00
}
else {
2022-11-12 21:38:45 +00:00
Vb = Vb0 * ddspin180 ( c , nd ) ;
2017-07-10 18:47:38 +00:00
}
2022-12-13 18:04:43 +00:00
if ( c - > monmirror ) Vb = Vb * lmirror ( ) ;
2022-12-06 00:04:26 +00:00
shiftmatrix Vbb = at_smart_lof ( Vb , cgi . ABODY ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( Vbb , cgi . shDragonTail , darkena ( col , c - > hitpoints ? 0 : 1 , 0xFF ) ) ;
ShadowV ( Vb , cgi . shDragonTail , PPR : : GIANTSHADOW ) ;
2017-07-10 18:47:38 +00:00
}
else if ( true ) {
if ( nospinb ) {
2018-01-11 22:18:02 +00:00
ld length ;
2019-11-14 15:51:50 +00:00
chainAnimation ( c , c2 , Vb , Vparam * currentmap - > adj ( c , nd ) , length ) ;
2022-12-13 18:04:43 +00:00
Vb = Vb * lpispin ( ) ;
2019-11-14 15:51:50 +00:00
double ang = chainAngle ( c , Vb , c - > move ( c - > mondir ) , currentmap - > spin_angle ( c , c - > mondir ) - currentmap - > spin_angle ( c , nd ) , Vparam ) ;
2017-07-10 18:47:38 +00:00
ang / = 2 ;
Vb = Vb * spin ( M_PI - ang ) ;
}
else {
2019-11-14 15:51:50 +00:00
/* todo what if no spin_angle */
ld hdir0 = currentmap - > spin_angle ( c , nd ) + M_PI ;
ld hdir1 = currentmap - > spin_angle ( c , c - > mondir ) ;
2022-11-12 21:38:45 +00:00
cyclefix ( hdir1 , hdir0 ) ;
2018-08-19 13:52:39 +00:00
Vb = Vb0 * spin ( ( hdir0 + hdir1 ) / 2 + M_PI ) ;
2017-07-10 18:47:38 +00:00
}
2022-12-13 18:04:43 +00:00
if ( c - > monmirror ) Vb = Vb * lmirror ( ) ;
2022-12-06 00:04:26 +00:00
shiftmatrix Vbb = at_smart_lof ( Vb , cgi . ABODY ) ;
2017-07-10 18:47:38 +00:00
if ( part = = ' l ' | | part = = ' 2 ' ) {
2019-05-26 16:04:02 +00:00
queuepoly ( Vbb , cgi . shDragonLegs , darkena ( col , c - > hitpoints ? 0 : 1 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
}
2019-05-26 16:04:02 +00:00
queuepoly ( Vbb , cgi . shDragonWings , darkena ( col , c - > hitpoints ? 0 : 1 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
}
}
2017-12-05 18:43:45 +00:00
else {
2018-01-11 22:18:02 +00:00
if ( c - > monst = = moTentacletail & & c - > mondir = = NODIR ) {
2022-12-13 18:04:43 +00:00
if ( c - > monmirror ) Vb = Vb * lmirror ( ) ;
2022-12-06 00:04:26 +00:00
queuepoly ( GDIM = = 3 ? at_smart_lof ( Vb , cgi . ABODY ) : Vb , cgi . shWormSegment , darkena ( col , 0 , 0xFF ) ) ;
2018-01-11 22:18:02 +00:00
}
else if ( c - > mondir = = NODIR ) {
bool hexsnake = c - > monst = = moHexSnake | | c - > monst = = moHexSnakeTail ;
cell * c2 = NULL ;
for ( int i = 0 ; i < c - > type ; i + + )
2018-08-17 22:46:45 +00:00
if ( c - > move ( i ) & & isWorm ( c - > move ( i ) - > monst ) & & c - > move ( i ) - > mondir = = c - > c . spin ( i ) )
c2 = c - > move ( i ) ;
2018-01-11 22:18:02 +00:00
int nd = neighborId ( c , c2 ) ;
if ( nospinb ) {
ld length ;
2019-11-14 15:51:50 +00:00
chainAnimation ( c , c2 , Vb , Vparam * currentmap - > adj ( c , nd ) , length ) ;
2022-12-13 18:04:43 +00:00
Vb = Vb * lpispin ( ) ;
2018-01-11 22:18:02 +00:00
}
else {
2022-11-12 21:38:45 +00:00
Vb = Vb0 * ddspin180 ( c , nd ) ;
2018-01-11 22:18:02 +00:00
}
2022-12-13 18:04:43 +00:00
if ( c - > monmirror ) Vb = Vb * lmirror ( ) ;
shiftmatrix Vbb = at_smart_lof ( Vb , cgi . ABODY ) * lpispin ( ) ;
2019-05-26 16:04:02 +00:00
hpcshape & sh = hexsnake ? cgi . shWormTail : cgi . shSmallWormTail ;
2018-01-11 22:18:02 +00:00
queuepoly ( Vbb , sh , darkena ( col , 0 , 0xFF ) ) ;
2018-08-28 12:27:23 +00:00
ShadowV ( Vb , sh , PPR : : GIANTSHADOW ) ;
2018-01-11 22:18:02 +00:00
}
2017-12-05 18:43:45 +00:00
}
2017-07-10 18:47:38 +00:00
}
2021-04-15 15:55:46 +00:00
else res = res & & drawMonsterType ( c - > monst , c , Vb , col , footphase , asciicol ) ;
2017-07-10 18:47:38 +00:00
}
2021-04-15 13:26:32 +00:00
2017-07-10 18:47:38 +00:00
else if ( isMimic ( c ) ) {
2017-07-22 23:33:27 +00:00
int xdir = 0 , copies = 1 ;
if ( c - > wall = = waMirrorWall ) {
xdir = mirror : : mirrordir ( c ) ;
copies = 2 ;
if ( xdir = = - 1 ) copies = 6 , xdir = 0 ;
2017-07-10 18:47:38 +00:00
}
2018-08-17 22:46:45 +00:00
for ( auto & m : mirror : : mirrors ) if ( c = = m . second . at )
2017-07-22 23:33:27 +00:00
for ( int d = 0 ; d < copies ; d + + ) {
multi : : cpid = m . first ;
auto cw = m . second ;
2018-08-17 22:46:45 +00:00
if ( d & 1 ) cw = cw . mirrorat ( xdir ) ;
2018-03-24 11:59:01 +00:00
if ( d > = 2 ) cw + = 2 ;
if ( d > = 4 ) cw + = 2 ;
2020-07-27 16:49:04 +00:00
shiftmatrix Vs = Vparam ;
2017-07-22 23:33:27 +00:00
bool mirr = cw . mirrored ;
2019-05-15 12:19:19 +00:00
if ( mirrored ! = mirr & & half_elliptic ) continue ;
2020-07-27 16:49:04 +00:00
shiftmatrix T = shiftless ( Id ) ;
2018-08-21 13:37:59 +00:00
nospins = applyAnimation ( cwt . at , T , footphase , LAYER_SMALL ) ;
if ( nospins )
2020-07-27 16:49:04 +00:00
Vs = Vs * ddspin ( c , cw . spin , 0 ) * iddspin ( cwt . at , cwt . spin , 0 ) * unshift ( T ) ;
2018-08-21 13:37:59 +00:00
else
Vs = Vs * ddspin ( c , cw . spin , 0 ) ;
2022-12-13 18:04:43 +00:00
if ( mirr ) Vs = Vs * lmirror ( ) ;
2017-07-22 23:33:27 +00:00
if ( inmirrorcount & 1 ) mirr = ! mirr ;
2020-07-27 16:49:04 +00:00
col = mirrorcolor ( geometry = = gElliptic ? det ( Vs . T ) < 0 : mirr ) ;
2019-05-11 13:21:48 +00:00
if ( ! mouseout ( ) & & ! nospins & & GDIM = = 2 ) {
2020-09-16 17:48:25 +00:00
shiftpoint P2 = Vs * inverse_shift ( inmirrorcount ? ocwtV : cwtV , mouseh ) ;
2024-03-21 17:44:19 +00:00
queuestr ( P2 , 10 * mapfontscale / 100 , " x " , 0xFF00 ) ;
}
2022-12-13 18:04:43 +00:00
if ( ! nospins & & flipplayer ) Vs = Vs * lpispin ( ) ;
2024-03-21 17:44:19 +00:00
2021-04-15 13:26:32 +00:00
res = res & & drawMonsterType ( moMimic , c , Vs , col , footphase , asciicol ) ;
2022-06-17 07:43:37 +00:00
drawPlayerEffects ( Vs , Vparam , c , c - > monst ) ;
2017-07-10 18:47:38 +00:00
}
}
2024-03-21 17:44:19 +00:00
2017-07-10 18:47:38 +00:00
// illusions face randomly
else if ( c - > monst = = moIllusion ) {
multi : : cpid = 0 ;
2022-12-13 18:04:43 +00:00
if ( c - > monmirror ) Vs = Vs * lmirror ( ) ;
2019-06-24 10:57:00 +00:00
drawMonsterType ( c - > monst , c , Vs , col , footphase , asciicol ) ;
2022-06-17 07:43:37 +00:00
drawPlayerEffects ( Vs , Vparam , c , c - > monst ) ;
2017-07-10 18:47:38 +00:00
}
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
// wolves face the heat
else if ( c - > monst = = moWolf & & c - > cpdist > 1 ) {
if ( ! nospins ) {
int d = 0 ;
double bheat = - 999 ;
2018-08-17 22:46:45 +00:00
for ( int i = 0 ; i < c - > type ; i + + ) if ( c - > move ( i ) & & HEAT ( c - > move ( i ) ) > bheat ) {
bheat = HEAT ( c - > move ( i ) ) ;
2017-07-10 18:47:38 +00:00
d = i ;
2015-08-08 13:57:52 +00:00
}
2019-04-20 23:08:27 +00:00
Vs = Vs * ddspin ( c , d , 0 ) ;
2017-07-10 18:47:38 +00:00
}
2022-12-13 18:04:43 +00:00
if ( c - > monmirror ) Vs = Vs * lmirror ( ) ;
2019-06-24 10:57:00 +00:00
return drawMonsterTypeDH ( m , c , Vs , col , darkhistory , footphase , asciicol ) ;
2017-07-10 18:47:38 +00:00
}
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
else if ( c - > monst = = moKrakenT ) {
if ( c - > hitpoints = = 0 ) col = 0x404040 ;
if ( nospinb ) {
2018-01-11 22:18:02 +00:00
ld length ;
2019-11-14 15:51:50 +00:00
chainAnimation ( c , c - > move ( c - > mondir ) , Vb , Vparam * currentmap - > adj ( c , c - > mondir ) , length ) ;
2022-12-13 18:04:43 +00:00
Vb = Vb * lpispin ( ) ;
2019-05-26 16:04:02 +00:00
Vb = Vb * xpush ( cgi . tentacle_length - cellgfxdist ( c , c - > mondir ) ) ;
2018-05-04 00:47:33 +00:00
}
2018-08-28 15:17:34 +00:00
else if ( NONSTDVAR ) {
2019-11-22 13:34:56 +00:00
transmatrix T = currentmap - > adj ( c , c - > mondir ) ;
2022-12-08 18:38:06 +00:00
Vb = Vb * T * lrspintox ( tC0 ( iso_inverse ( T ) ) ) * xpush ( cgi . tentacle_length ) ;
2017-07-10 18:47:38 +00:00
}
2018-04-03 21:39:18 +00:00
else {
2022-11-12 21:38:45 +00:00
Vb = Vb * ddspin180 ( c , c - > mondir ) ;
2019-05-26 16:04:02 +00:00
Vb = Vb * xpush ( cgi . tentacle_length - cellgfxdist ( c , c - > mondir ) ) ;
2018-04-03 21:39:18 +00:00
}
2022-12-13 18:04:43 +00:00
if ( c - > monmirror ) Vb = Vb * lmirror ( ) ;
2018-05-04 00:47:33 +00:00
2018-08-18 15:35:39 +00:00
// if(ctof(c) && !masterless) Vb = Vb * xpush(hexhexdist - hcrossf);
2019-05-26 16:04:02 +00:00
// return (!BITRUNCATED) ? tessf * gp::scale : (c->type == 6 && (i&1)) ? hexhexdist : cgi.crossf;
2021-04-15 13:26:32 +00:00
res = res & & drawMonsterTypeDH ( m , c , Vb , col , darkhistory , footphase , asciicol ) ;
2017-07-10 18:47:38 +00:00
}
2015-08-08 13:57:52 +00:00
2018-01-05 13:18:14 +00:00
// golems, knights, and hyperbugs don't face the player (mondir-controlled)
// also whatever in the lineview mode, and whatever in the quotient geometry
2021-05-30 11:48:24 +00:00
else if ( isDie ( c - > monst ) ) {
2021-05-27 11:00:20 +00:00
transmatrix U = inverse_shift ( Vparam , Vs ) ;
U = rgpushxto0 ( tC0 ( U ) ) ;
die_target = Vparam ;
res = res & & drawMonsterTypeDH ( m , c , Vparam * U , col , darkhistory , footphase , asciicol ) ;
}
2019-11-27 00:01:20 +00:00
else if ( ( hasFacing ( c ) & & c - > mondir ! = NODIR ) | | history : : on | | quotient | | dont_face_pc ) {
2018-01-05 13:18:14 +00:00
if ( c - > monst = = moKrakenH ) Vs = Vb , nospins = nospinb ;
2022-11-12 21:38:45 +00:00
if ( ! nospins & & c - > mondir < c - > type ) Vs = Vs * ddspin180 ( c , c - > mondir ) ;
2018-01-05 13:18:14 +00:00
if ( c - > monst = = moPair ) Vs = Vs * xpush ( - .12 ) ;
2022-12-13 18:04:43 +00:00
if ( c - > monmirror ) Vs = Vs * lmirror ( ) ;
2022-06-17 07:43:37 +00:00
if ( isFriendly ( c ) ) drawPlayerEffects ( Vs , Vparam , c , c - > monst ) ;
2021-04-15 13:26:32 +00:00
res = res & & drawMonsterTypeDH ( m , c , Vs , col , darkhistory , footphase , asciicol ) ;
2018-01-05 13:18:14 +00:00
}
2019-03-30 12:35:03 +00:00
else {
2017-07-10 18:47:38 +00:00
// other monsters face the player
2019-08-20 17:29:03 +00:00
if ( ! nospins ) {
2020-09-16 17:52:21 +00:00
shiftmatrix & where = ( c - > monst = = moMirrorSpirit & & inmirrorcount ) ? ocwtV : cwtV ;
2023-01-26 23:27:10 +00:00
if ( cgi . emb - > is_euc_in_product ( ) ) { }
2023-01-05 23:09:12 +00:00
else if ( WDIM = = 2 | | mproduct ) {
2022-12-08 18:38:06 +00:00
hyperpoint V0 = inverse_shift ( Vs , where * tile_center ( ) ) ;
2019-08-20 17:29:03 +00:00
ld z = 0 ;
2022-12-08 18:38:06 +00:00
if ( gproduct ) {
2019-08-20 17:29:03 +00:00
auto d = product_decompose ( V0 ) ;
z = d . first ;
V0 = d . second ;
}
2020-07-27 16:49:04 +00:00
if ( hypot_d ( 2 , tC0 ( unshift ( Vs ) ) ) > 1e-3 ) {
2022-12-08 18:38:06 +00:00
Vs = Vs * lrspintox ( V0 ) ;
if ( gproduct ) Vs = orthogonal_move ( Vs , z ) ;
2019-08-20 17:29:03 +00:00
}
2019-02-26 20:11:50 +00:00
}
2019-08-24 12:49:49 +00:00
else if ( ! sl2 ) {
2020-09-16 17:52:21 +00:00
hyperpoint V0 = inverse_shift ( Vs , tC0 ( where ) ) ;
2022-12-08 18:38:06 +00:00
Vs = Vs * lrspintox ( V0 ) ;
2019-02-26 20:11:50 +00:00
// cwtV * rgpushxto0(inverse(cwtV) * tC0(Vs));
}
2017-10-15 22:15:54 +00:00
if ( c - > monst = = moHunterChanging )
2022-12-08 18:38:06 +00:00
Vs = Vs * ( mhybrid ? spin180 ( ) : cspin180 ( WDIM - 2 , WDIM - 1 ) ) ;
2017-07-10 18:47:38 +00:00
}
2022-12-13 18:04:43 +00:00
if ( c - > monmirror ) Vs = Vs * lmirror ( ) ;
2017-07-10 18:47:38 +00:00
if ( c - > monst = = moShadow )
multi : : cpid = c - > hitpoints ;
2021-04-15 13:26:32 +00:00
res = res & & drawMonsterTypeDH ( m , c , Vs , col , darkhistory , footphase , asciicol ) ;
2017-07-10 18:47:38 +00:00
}
2017-08-06 12:50:16 +00:00
for ( int i = 0 ; i < numplayers ( ) ; i + + ) if ( c = = playerpos ( i ) & & ! shmup : : on & & mapeditor : : drawplayer & &
! ( hardcore & & ! canmove ) ) {
2019-05-15 10:41:02 +00:00
bool mirr = multi : : players > 1 ? multi : : player [ i ] . mirrored : cwt . mirrored ;
2019-05-15 12:19:19 +00:00
if ( half_elliptic & & mirr ! = mirrored ) continue ;
2017-07-10 18:47:38 +00:00
if ( ! nospins ) {
Vs = playerV ;
2022-12-13 18:04:43 +00:00
if ( multi : : players > 1 ? multi : : flipped [ i ] : flipplayer ) Vs = Vs * lpispin ( ) ;
2017-07-10 18:47:38 +00:00
}
2018-06-17 15:51:26 +00:00
else {
2022-12-13 18:04:43 +00:00
if ( mirr ) Vs = Vs * lmirror ( ) ;
2018-06-17 15:51:26 +00:00
}
2019-09-06 06:17:38 +00:00
multi : : cpid = i ;
2015-08-08 13:57:52 +00:00
2021-04-15 13:26:32 +00:00
asciicol = getcs ( ) . uicolor > > 8 ;
2022-06-17 07:43:37 +00:00
drawPlayerEffects ( Vs , Vparam , c , moPlayer ) ;
2020-09-16 17:48:25 +00:00
if ( inmirrorcount & & ! mouseout ( ) & & ! nospins & & GDIM = = 2 ) {
hyperpoint h = inverse_shift ( ocwtV , mouseh ) ;
2022-12-13 18:04:43 +00:00
if ( flipplayer ) h = lpispin ( ) * h ;
2020-09-16 17:48:25 +00:00
shiftpoint P2 = Vs * h ;
2024-03-21 17:44:19 +00:00
queuestr ( P2 , mapfontscale / 10 , " x " , 0xFF00 ) ;
2020-09-16 17:48:25 +00:00
}
2017-07-10 18:47:38 +00:00
2019-03-09 14:31:02 +00:00
if ( hide_player ( ) ) {
2019-05-11 17:42:30 +00:00
first_cell_to_draw = false ;
2021-04-15 13:26:32 +00:00
if ( WDIM = = 2 & & GDIM = = 3 ) {
2019-06-24 11:46:27 +00:00
drawPlayer ( moPlayer , c , Vs , col , footphase , true ) ;
2021-04-15 13:26:32 +00:00
res = true ;
}
2019-02-26 11:25:54 +00:00
}
2021-04-15 13:26:32 +00:00
else if ( isWorm ( c - > monst ) ) {
2019-05-26 16:04:02 +00:00
ld depth = geom3 : : factor_to_lev ( wormhead ( c ) = = c ? cgi . AHEAD : cgi . ABODY ) ;
2017-07-10 18:47:38 +00:00
footphase = 0 ;
2020-04-06 06:39:31 +00:00
int q = isize ( ptds ) ;
2021-04-15 15:55:58 +00:00
res = res | drawMonsterType ( moPlayer , c , Vs , col , footphase , asciicol ) ;
2017-07-10 18:47:38 +00:00
pushdown ( c , q , Vs , - depth , true , false ) ;
}
2021-04-15 15:55:58 +00:00
else res = res | drawMonsterType ( moPlayer , c , Vs , col , footphase , asciicol ) ;
2017-07-10 18:47:38 +00:00
}
2019-02-17 17:41:40 +00:00
# endif
2021-04-15 13:26:32 +00:00
return res ;
2017-07-10 18:47:38 +00:00
}
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
# define AURA 180
2017-03-23 10:53:57 +00:00
2017-12-01 23:23:15 +00:00
array < array < int , 4 > , AURA + 1 > aurac ;
2016-01-02 10:09:13 +00:00
2019-10-05 10:33:00 +00:00
int haveaura_cached ;
/** 0 = no aura, 1 = standard aura, 2 = Joukowsky aura */
EX int haveaura ( ) {
if ( ! ( vid . aurastr > 0 & & ! svg : : in & & ( auraNOGL | | vid . usingGL ) ) ) return 0 ;
2020-12-30 13:52:58 +00:00
if ( vrhr : : active ( ) ) return 0 ;
2019-10-05 10:33:00 +00:00
if ( sphere & & mdAzimuthalEqui ( ) ) return 0 ;
2020-04-16 22:53:58 +00:00
if ( among ( pmodel , mdJoukowsky , mdJoukowskyInverted ) & & hyperbolic & & pconf . model_transition < 1 )
2019-10-05 10:33:00 +00:00
return 2 ;
2024-01-07 11:52:50 +00:00
if ( among ( pmodel , mdFisheye , mdFisheye2 ) ) return 1 ;
2020-04-16 22:53:58 +00:00
return pmodel = = mdDisk & & ( ! sphere | | pconf . alpha > 10 ) & & ! euclid ;
2017-07-10 18:47:38 +00:00
}
2017-08-06 12:50:16 +00:00
vector < pair < int , int > > auraspecials ;
int auramemo ;
2019-10-05 10:33:00 +00:00
EX void clearaura ( ) {
haveaura_cached = haveaura ( ) ;
if ( ! haveaura_cached ) return ;
2017-07-10 18:47:38 +00:00
for ( int a = 0 ; a < AURA ; a + + ) for ( int b = 0 ; b < 4 ; b + + )
aurac [ a ] [ b ] = 0 ;
2017-08-06 12:50:16 +00:00
auraspecials . clear ( ) ;
auramemo = 128 * 128 / vid . aurastr ;
}
2020-07-27 16:49:04 +00:00
void apply_joukowsky_aura ( shiftpoint & h ) {
2019-10-05 10:33:00 +00:00
if ( haveaura_cached = = 2 ) {
2018-10-26 19:05:35 +00:00
hyperpoint ret ;
applymodel ( h , ret ) ;
2020-07-27 16:49:04 +00:00
h . h = ret ;
2018-10-26 19:05:35 +00:00
}
2019-10-05 10:33:00 +00:00
if ( nonisotropic ) {
2020-07-27 16:49:04 +00:00
h . h = lp_apply ( inverse_exp ( h , pfNO_DISTANCE ) ) ;
2019-10-05 10:33:00 +00:00
}
2018-10-26 19:05:35 +00:00
}
2020-07-27 16:49:04 +00:00
EX void addauraspecial ( shiftpoint h , color_t col , int dir ) {
2019-10-05 10:33:00 +00:00
if ( ! haveaura_cached ) return ;
2018-10-26 19:05:35 +00:00
apply_joukowsky_aura ( h ) ;
2022-11-12 21:38:45 +00:00
int r = int ( 2 * AURA + dir + atan2 ( h [ 1 ] , h [ 0 ] ) * AURA / TAU ) % AURA ;
2017-08-06 12:50:16 +00:00
auraspecials . emplace_back ( r , col ) ;
2017-07-10 18:47:38 +00:00
}
2016-01-02 10:09:13 +00:00
2020-07-27 16:49:04 +00:00
EX void addaura ( shiftpoint h , color_t col , int fd ) {
2019-10-05 10:33:00 +00:00
if ( ! haveaura_cached ) return ;
2018-10-26 19:05:35 +00:00
apply_joukowsky_aura ( h ) ;
2022-11-12 21:38:45 +00:00
int r = gmod ( atan2 ( h [ 1 ] , h [ 0 ] ) * AURA / TAU , AURA ) ;
2017-08-06 12:50:16 +00:00
aurac [ r ] [ 3 ] + = auramemo < < fd ;
2017-07-10 18:47:38 +00:00
col = darkened ( col ) ;
aurac [ r ] [ 0 ] + = ( col > > 16 ) & 255 ;
aurac [ r ] [ 1 ] + = ( col > > 8 ) & 255 ;
aurac [ r ] [ 2 ] + = ( col > > 0 ) & 255 ;
}
void sumaura ( int v ) {
int auc [ AURA ] ;
for ( int t = 0 ; t < AURA ; t + + ) auc [ t ] = aurac [ t ] [ v ] ;
int val = 0 ;
if ( vid . aurasmoothen < 1 ) vid . aurasmoothen = 1 ;
if ( vid . aurasmoothen > AURA ) vid . aurasmoothen = AURA ;
int SMO = vid . aurasmoothen ;
for ( int t = 0 ; t < SMO ; t + + ) val + = auc [ t ] ;
for ( int t = 0 ; t < AURA ; t + + ) {
int tt = ( t + SMO / 2 ) % AURA ;
aurac [ tt ] [ v ] = val ;
val - = auc [ t ] ;
val + = auc [ ( t + SMO ) % AURA ] ;
}
aurac [ AURA ] [ v ] = aurac [ 0 ] [ v ] ;
}
2018-02-11 18:08:17 +00:00
2020-07-03 12:42:33 +00:00
# if CAP_GL
2018-02-11 18:08:17 +00:00
vector < glhr : : colored_vertex > auravertices ;
2020-07-03 12:42:33 +00:00
# endif
2018-02-10 17:21:19 +00:00
2020-07-03 12:42:33 +00:00
EX void drawaura ( ) {
2020-04-17 13:03:05 +00:00
DEBBI ( DF_GRAPH , ( " draw aura " ) ) ;
2017-07-10 18:47:38 +00:00
if ( ! haveaura ( ) ) return ;
2018-11-17 18:24:02 +00:00
if ( vid . stereo_mode ) return ;
double rad = current_display - > radius ;
2020-04-16 22:53:58 +00:00
if ( sphere & & ! mdAzimuthalEqui ( ) ) rad / = sqrt ( pconf . alpha * pconf . alpha - 1 ) ;
2019-10-05 10:33:00 +00:00
if ( hyperbolic & & pmodel = = mdFisheye ) {
ld h = 1 ;
2020-04-16 22:53:58 +00:00
h / = pconf . fisheye_param ;
2019-10-05 10:33:00 +00:00
ld nrad = h / sqrt ( 2 + h * h ) ;
rad * = nrad ;
}
2017-07-10 18:47:38 +00:00
for ( int v = 0 ; v < 4 ; v + + ) sumaura ( v ) ;
2017-08-06 12:50:16 +00:00
for ( auto & p : auraspecials ) {
int r = p . first ;
aurac [ r ] [ 3 ] = auramemo ;
2018-12-23 13:30:09 +00:00
for ( int k = 0 ; k < 3 ; k + + ) aurac [ r ] [ k ] = ( p . second > > ( 16 - 8 * k ) ) & 255 ;
2017-08-06 12:50:16 +00:00
}
2017-03-23 10:53:57 +00:00
2017-07-22 23:33:27 +00:00
# if CAP_SDL || CAP_GL
2019-05-04 16:28:03 +00:00
ld bak [ 3 ] ;
2017-07-10 18:47:38 +00:00
bak [ 0 ] = ( ( backcolor > > 16 ) & 255 ) / 255. ;
bak [ 1 ] = ( ( backcolor > > 8 ) & 255 ) / 255. ;
bak [ 2 ] = ( ( backcolor > > 0 ) & 255 ) / 255. ;
2017-07-22 23:33:27 +00:00
# endif
2017-07-10 18:47:38 +00:00
2017-07-22 23:33:27 +00:00
# if CAP_SDL
2017-07-10 18:47:38 +00:00
if ( ! vid . usingGL ) {
SDL_LockSurface ( s ) ;
for ( int y = 0 ; y < vid . yres ; y + + )
for ( int x = 0 ; x < vid . xres ; x + + ) {
2017-04-04 09:13:15 +00:00
2018-11-17 18:24:02 +00:00
ld hx = ( x * 1. - current_display - > xcenter ) / rad ;
2020-04-16 22:53:58 +00:00
ld hy = ( y * 1. - current_display - > ycenter ) / rad / pconf . stretch ;
2017-07-10 18:47:38 +00:00
2023-08-14 16:08:28 +00:00
if ( ! models : : camera_straight ) camrotate ( hx , hy ) ;
2017-07-10 18:47:38 +00:00
ld fac = sqrt ( hx * hx + hy * hy ) ;
if ( fac < 1 ) continue ;
ld dd = log ( ( fac - .99999 ) / .00001 ) ;
ld cmul = 1 - dd / 10. ;
if ( cmul > 1 ) cmul = 1 ;
if ( cmul < 0 ) cmul = 0 ;
2015-08-08 13:57:52 +00:00
2022-11-12 21:38:45 +00:00
ld alpha = AURA * atan2 ( hx , hy ) / TAU ;
2017-07-10 18:47:38 +00:00
if ( alpha < 0 ) alpha + = AURA ;
if ( alpha > = AURA ) alpha - = AURA ;
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
int rm = int ( alpha ) ;
2019-05-04 16:28:03 +00:00
ld fr = alpha - rm ;
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
if ( rm < 0 | | rm > = AURA ) continue ;
2018-09-04 17:53:42 +00:00
color_t & p = qpixel ( s , x , y ) ;
2017-07-10 18:47:38 +00:00
for ( int c = 0 ; c < 3 ; c + + ) {
2019-05-04 16:28:03 +00:00
ld c1 = aurac [ rm ] [ 2 - c ] / ( aurac [ rm ] [ 3 ] + .1 ) ;
ld c2 = aurac [ rm + 1 ] [ 2 - c ] / ( aurac [ rm + 1 ] [ 3 ] + .1 ) ;
2017-07-10 18:47:38 +00:00
const ld one = 1 ;
part ( p , c ) = int ( 255 * min ( one , bak [ 2 - c ] + cmul * ( ( c1 + fr * ( c2 - c1 ) - bak [ 2 - c ] ) ) ) ) ;
2016-08-26 09:58:03 +00:00
}
2017-07-10 18:47:38 +00:00
}
SDL_UnlockSurface ( s ) ;
return ;
}
# endif
2016-08-26 09:58:03 +00:00
2017-07-22 23:33:27 +00:00
# if CAP_GL
2017-07-10 18:47:38 +00:00
float cx [ AURA + 1 ] [ 11 ] [ 5 ] ;
2016-01-02 10:09:13 +00:00
2017-07-10 18:47:38 +00:00
double facs [ 11 ] = { 1 , 1.01 , 1.02 , 1.04 , 1.08 , 1.70 , 1.95 , 1.5 , 2 , 6 , 10 } ;
double cmul [ 11 ] = { 1 , .8 , .7 , .6 , .5 , .16 , .12 , .08 , .07 , .06 , 0 } ;
double d2 [ 11 ] = { 0 , 2 , 4 , 6.5 , 7 , 7.5 , 8 , 8.5 , 9 , 9.5 , 10 } ;
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
for ( int d = 0 ; d < 11 ; d + + ) {
double dd = d2 [ d ] ;
cmul [ d ] = ( 1 - dd / 10. ) ;
facs [ d ] = .99999 + .00001 * exp ( dd ) ;
}
facs [ 10 ] = 10 ;
2018-02-08 23:29:20 +00:00
cmul [ 1 ] = cmul [ 0 ] ;
2018-10-26 19:05:35 +00:00
2020-04-16 22:53:58 +00:00
bool inversion = pconf . alpha < = - 1 | | pmodel = = mdJoukowsky ;
bool joukowsky = among ( pmodel , mdJoukowskyInverted , mdJoukowsky ) & & hyperbolic & & pconf . model_transition < 1 ;
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
for ( int r = 0 ; r < = AURA ; r + + ) for ( int z = 0 ; z < 11 ; z + + ) {
2022-11-12 21:38:45 +00:00
float rr = ( TAU * r ) / AURA ;
2018-10-26 19:05:35 +00:00
float rad0 = inversion ? rad / facs [ z ] : rad * facs [ z ] ;
2017-07-10 18:47:38 +00:00
int rm = r % AURA ;
2018-10-26 19:05:35 +00:00
ld c = cos ( rr ) ;
ld s = sin ( rr ) ;
if ( joukowsky ) {
2023-08-08 14:27:52 +00:00
hyperpoint v ( c , s , 0 , 1 ) ;
2018-10-28 01:12:04 +00:00
if ( inversion )
2023-08-14 09:08:37 +00:00
models : : ori_to_scr ( v ) ;
2018-10-28 01:12:04 +00:00
else
2023-08-14 09:08:37 +00:00
models : : scr_to_ori ( v ) ;
2023-08-08 14:27:52 +00:00
ld c1 = v [ 0 ] , s1 = v [ 1 ] ;
2018-10-26 19:05:35 +00:00
2020-04-16 22:53:58 +00:00
ld & mt = pconf . model_transition ;
2018-10-26 19:05:35 +00:00
ld mt2 = 1 - mt ;
ld m = sqrt ( c1 * c1 + s1 * s1 / mt2 / mt2 ) ;
m * = 2 ;
if ( inversion ) rad0 / = m ;
else rad0 * = m ;
}
2020-11-05 15:26:50 +00:00
ld x = rad0 * c ;
2020-11-05 17:26:37 +00:00
ld y = rad0 * s ;
2020-11-05 15:26:50 +00:00
2023-08-14 16:08:28 +00:00
if ( ! models : : camera_straight ) {
hyperpoint p = hyperpoint ( x , y , rad0 , 1 ) ;
2023-08-15 14:01:38 +00:00
p = rot_inverse ( pconf . cam ( ) ) * p ;
2023-08-14 16:08:28 +00:00
x = p [ 0 ] * rad0 / p [ 2 ] ;
y = p [ 1 ] * rad0 / p [ 2 ] ;
2020-11-05 15:26:50 +00:00
}
cx [ r ] [ z ] [ 0 ] = x ;
2020-11-05 17:26:37 +00:00
cx [ r ] [ z ] [ 1 ] = y * pconf . stretch ;
2018-10-26 19:05:35 +00:00
2017-07-10 18:47:38 +00:00
for ( int u = 0 ; u < 3 ; u + + )
cx [ r ] [ z ] [ u + 2 ] = bak [ u ] + ( aurac [ rm ] [ u ] / ( aurac [ rm ] [ 3 ] + .1 ) - bak [ u ] ) * cmul [ z ] ;
}
2018-02-11 18:08:17 +00:00
auravertices . clear ( ) ;
2017-07-10 18:47:38 +00:00
for ( int r = 0 ; r < AURA ; r + + ) for ( int z = 0 ; z < 10 ; z + + ) {
2018-02-11 18:08:17 +00:00
for ( int c = 0 ; c < 6 ; c + + ) {
int br = ( c = = 1 | | c = = 3 | | c = = 5 ) ? r + 1 : r ;
int bz = ( c = = 2 | | c = = 4 | | c = = 5 ) ? z + 1 : z ;
auravertices . emplace_back (
cx [ br ] [ bz ] [ 0 ] , cx [ br ] [ bz ] [ 1 ] , cx [ br ] [ bz ] [ 2 ] , cx [ br ] [ bz ] [ 3 ] , cx [ br ] [ bz ] [ 4 ]
) ;
2017-07-10 18:47:38 +00:00
}
}
2018-09-04 21:27:27 +00:00
glflush ( ) ;
2019-10-21 20:34:20 +00:00
current_display - > next_shader_flags = GF_VARCOLOR ;
dynamicval < eModel > m ( pmodel , mdPixel ) ;
2020-07-27 16:49:04 +00:00
current_display - > set_all ( 0 , 0 ) ;
2018-02-20 10:30:39 +00:00
glhr : : id_modelview ( ) ;
2018-02-11 18:08:17 +00:00
glhr : : prepare ( auravertices ) ;
2018-03-24 14:15:30 +00:00
glhr : : set_depthtest ( false ) ;
2018-06-22 12:47:24 +00:00
glDrawArrays ( GL_TRIANGLES , 0 , isize ( auravertices ) ) ;
2017-07-10 18:47:38 +00:00
# endif
}
2016-01-02 10:09:13 +00:00
2017-07-10 18:47:38 +00:00
// int fnt[100][7];
2016-08-26 09:58:03 +00:00
2017-07-10 18:47:38 +00:00
bool bugsNearby ( cell * c , int dist = 2 ) {
if ( ! ( havewhat & HF_BUG ) ) return false ;
if ( isBug ( c ) ) return true ;
2018-08-17 22:46:45 +00:00
if ( dist ) for ( int t = 0 ; t < c - > type ; t + + ) if ( c - > move ( t ) & & bugsNearby ( c - > move ( t ) , dist - 1 ) ) return true ;
2017-07-10 18:47:38 +00:00
return false ;
}
2017-03-23 10:53:57 +00:00
2019-08-09 20:07:03 +00:00
EX colortable minecolors = {
2017-07-10 18:47:38 +00:00
0xFFFFFF , 0xF0 , 0xF060 , 0xF00000 ,
2019-04-08 12:56:46 +00:00
0x60 , 0x600000 , 0x00C0C0 , 0x000000 , 0x808080 , 0xFFD500
2017-07-10 18:47:38 +00:00
} ;
2017-03-23 10:53:57 +00:00
2019-08-09 20:07:03 +00:00
EX colortable distcolors = {
2017-07-10 18:47:38 +00:00
0xFFFFFF , 0xF0 , 0xF060 , 0xF00000 ,
0xA0A000 , 0xA000A0 , 0x00A0A0 , 0xFFD500
} ;
2016-08-26 09:58:03 +00:00
2021-05-23 13:47:45 +00:00
EX const char * minetexts [ 8 ] = {
2017-07-10 18:47:38 +00:00
" No mines next to you. " ,
" A mine is next to you! " ,
" Two mines next to you! " ,
" Three mines next to you! " ,
" Four mines next to you! " ,
" Five mines next to you! " ,
" Six mines next to you! " ,
" Seven mines next to you! "
} ;
2017-03-23 10:53:57 +00:00
2019-08-09 20:07:03 +00:00
EX int countMinesAround ( cell * c ) {
2017-07-10 18:47:38 +00:00
int mines = 0 ;
2019-04-08 12:58:54 +00:00
for ( cell * c2 : adj_minefield_cells ( c ) )
if ( c2 - > wall = = waMineMine )
2017-07-10 18:47:38 +00:00
mines + + ;
return mines ;
}
2017-03-23 10:53:57 +00:00
2019-08-09 21:08:42 +00:00
EX transmatrix applyPatterndir ( cell * c , const patterns : : patterninfo & si ) {
2023-01-26 23:27:10 +00:00
if ( NONSTDVAR | | bt : : in ( ) | | cgi . emb - > is_euc_in_noniso ( ) ) return Id ;
2022-11-12 21:38:45 +00:00
transmatrix V = ddspin180 ( c , si . dir ) ;
2022-12-13 18:04:43 +00:00
if ( si . reflect ) V = V * lmirror ( ) ;
2019-11-27 00:01:20 +00:00
if ( euclid ) return V ;
2022-11-12 21:38:45 +00:00
return V * iddspin180 ( c , 0 ) ;
2017-07-10 18:47:38 +00:00
}
2017-03-23 10:53:57 +00:00
2019-10-25 10:44:41 +00:00
EX transmatrix applyDowndir ( cell * c , const cellfunction & cf ) {
2022-11-12 21:38:45 +00:00
return ddspin180 ( c , patterns : : downdir ( c , cf ) ) ;
2017-07-10 18:47:38 +00:00
}
2017-03-23 10:53:57 +00:00
2019-11-22 18:00:11 +00:00
void draw_movement_arrows ( cell * c , const transmatrix & V , int df ) {
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
if ( viewdists ) return ;
2020-05-15 13:28:59 +00:00
string keylist = " " ;
const ld keysize = .6 ;
color_t col = getcs ( ) . uicolor ;
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
for ( int d = 0 ; d < 8 ; d + + ) {
2022-11-12 21:38:45 +00:00
movedir md = vectodir ( spin ( - d * 45. _deg ) * smalltangent ( ) ) ;
2019-11-22 18:00:11 +00:00
cellwalker xc = cwt + md . d ;
if ( xc . spin ! = df ) continue ;
xc + = wstep ;
2018-08-17 22:46:45 +00:00
if ( xc . at = = c ) {
2018-07-23 14:07:27 +00:00
transmatrix fixrot = sphereflip * rgpushxto0 ( sphereflip * tC0 ( V ) ) ;
2017-07-10 18:47:38 +00:00
// make it more transparent
col - = ( col & 0xFF ) > > 1 ;
poly_outline = OUTLINE_DEFAULT ;
2020-05-15 13:28:59 +00:00
char key = 0 ;
if ( vid . axes > = 5 )
key = ( vid . axes = = 5 ? keys_wasd : keys_vi ) [ d ] ;
if ( vid . axes > = 5 ) keylist + = key ;
else
2022-11-12 21:38:45 +00:00
queuepoly ( shiftless ( fixrot * spin ( - d * 45. _deg ) ) , cgi . shArrow , col ) ;
2017-03-23 10:53:57 +00:00
2018-12-16 23:04:59 +00:00
if ( ( c - > type & 1 ) & & ( isStunnable ( c - > monst ) | | isPushable ( c - > wall ) ) ) {
2020-07-27 16:49:04 +00:00
transmatrix Centered = rgpushxto0 ( unshift ( tC0 ( cwtV ) ) ) ;
2017-07-10 18:47:38 +00:00
int sd = md . subdir ;
2020-05-15 13:28:59 +00:00
2022-12-08 18:38:06 +00:00
transmatrix T = iso_inverse ( Centered ) * rgpushxto0 ( Centered * tC0 ( V ) ) * lrspintox ( Centered * tC0 ( V ) ) * spin ( - sd * M_PI / S7 ) * xpush ( 0.2 ) ;
2020-05-15 13:28:59 +00:00
if ( vid . axes > = 5 )
2024-03-21 17:44:19 +00:00
queuestr ( shiftless ( T ) , keysize * mapfontscale / 100 , s0 + key , col > > 8 , 1 ) ;
2020-05-15 13:28:59 +00:00
else
2020-07-27 16:49:04 +00:00
queuepoly ( shiftless ( T ) , cgi . shArrow , col ) ;
2017-07-10 18:47:38 +00:00
}
2018-06-17 15:51:26 +00:00
else if ( ! confusingGeometry ( ) ) break ;
2017-07-10 18:47:38 +00:00
}
}
2024-03-21 17:44:19 +00:00
if ( keylist ! = " " ) queuestr ( shiftless ( V ) , keysize * mapfontscale / 100 , keylist , col > > 8 , 1 ) ;
2017-03-23 10:53:57 +00:00
}
2019-10-25 10:44:41 +00:00
EX int celldistAltPlus ( cell * c ) { return 1000000 + celldistAlt ( c ) ; }
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
bool drawstaratvec ( double dx , double dy ) {
return dx * dx + dy * dy > .05 ;
}
2017-03-23 10:53:57 +00:00
2019-10-25 10:44:41 +00:00
EX color_t reptilecolor ( cell * c ) {
2018-08-30 14:08:05 +00:00
int i ;
2017-07-10 18:47:38 +00:00
2019-12-14 10:42:16 +00:00
if ( arcm : : in ( ) )
2018-08-30 14:08:05 +00:00
i = c - > master - > rval0 & 3 ;
else {
2018-08-31 02:18:58 +00:00
i = zebra40 ( c ) ;
2018-08-30 14:08:05 +00:00
2019-11-27 00:01:20 +00:00
if ( ! euclid ) {
2018-08-30 14:08:05 +00:00
if ( i > = 4 & & i < 16 ) i = 0 ;
else if ( i > = 16 & & i < 28 ) i = 1 ;
else if ( i > = 28 & & i < 40 ) i = 2 ;
else i = 3 ;
}
2017-07-10 18:47:38 +00:00
}
2017-03-23 10:53:57 +00:00
2019-10-25 10:44:41 +00:00
color_t reptilecolors [ 4 ] = { 0xe3bb97 , 0xc2d1b0 , 0xebe5cb , 0xA0A0A0 } ;
return reptilecolors [ i ] ;
2017-07-10 18:47:38 +00:00
}
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
ld wavefun ( ld x ) {
return sin ( x ) ;
2022-11-12 21:38:45 +00:00
/* x /= TAU;
2017-07-10 18:47:38 +00:00
x - = ( int ) x ;
if ( x > .5 ) return ( x - .5 ) * 2 ;
else return 0 ; */
}
2017-03-23 10:53:57 +00:00
2021-08-03 02:40:05 +00:00
// Color components in nestcolors must be less than 0x80 (for addition in drawMonster for Rock Snakes)
// and must be divisible by 4 (for brightening of raised cells in celldrawer::setcolors)
EX colortable nestcolors = { 0x7C0000 , 0x007C00 , 0x00007C , 0x404040 , 0x700070 , 0x007070 , 0x707000 , 0x606060 } ;
2017-12-05 18:43:45 +00:00
2018-11-08 20:56:06 +00:00
color_t floorcolors [ landtypes ] ;
2019-09-05 07:01:47 +00:00
EX void init_floorcolors ( ) {
2018-11-08 20:56:06 +00:00
for ( int i = 0 ; i < landtypes ; i + + )
floorcolors [ i ] = linf [ i ] . color ;
floorcolors [ laDesert ] = 0xEDC9AF ;
floorcolors [ laKraken ] = 0x20A020 ;
floorcolors [ laDocks ] = 0x202020 ;
floorcolors [ laCA ] = 0x404040 ;
floorcolors [ laMotion ] = 0xF0F000 ;
floorcolors [ laGraveyard ] = 0x107010 ;
floorcolors [ laWineyard ] = 0x006000 ;
floorcolors [ laLivefjord ] = 0x306030 ;
floorcolors [ laMinefield ] = 0x80A080 ;
floorcolors [ laCaribbean ] = 0x006000 ;
floorcolors [ laAlchemist ] = 0x202020 ;
floorcolors [ laRlyeh ] = 0x004080 ;
floorcolors [ laHell ] = 0xC00000 ;
floorcolors [ laCrossroads ] = 0xFF0000 ;
floorcolors [ laJungle ] = 0x008000 ;
floorcolors [ laZebra ] = 0xE0E0E0 ;
floorcolors [ laCaves ] = 0x202020 ;
floorcolors [ laEmerald ] = 0x202020 ;
floorcolors [ laDeadCaves ] = 0x202020 ;
floorcolors [ laPalace ] = 0x806020 ;
floorcolors [ laHunting ] = 0x40E0D0 / 2 ;
floorcolors [ laBlizzard ] = 0x5050C0 ;
floorcolors [ laCocytus ] = 0x80C0FF ;
floorcolors [ laIce ] = 0x8080FF ;
floorcolors [ laCamelot ] = 0xA0A0A0 ;
floorcolors [ laOvergrown ] = 0x00C020 ;
floorcolors [ laClearing ] = 0x60E080 ;
floorcolors [ laHaunted ] = 0x609F60 ;
2021-05-23 13:53:52 +00:00
floorcolors [ laCursed ] = 0x481848 ;
2021-05-29 18:08:25 +00:00
floorcolors [ laDice ] = 0xC0C0FF ;
2018-11-08 20:56:06 +00:00
2021-05-23 13:53:52 +00:00
floorcolors [ laMirror ] = floorcolors [ laMirrorWall ] = floorcolors [ laMirrorOld ] = 0x808080 ;
2018-11-08 20:56:06 +00:00
}
2019-10-25 10:44:41 +00:00
EX color_t magma_color ( int id ) {
2019-03-09 22:55:03 +00:00
if ( id = = 95 / 4 - 1 ) return 0x200000 ;
else if ( id = = 95 / 4 ) return 0x100000 ;
else if ( id < 48 / 4 ) return gradient ( 0xF0F000 , 0xF00000 , 0 , id , 48 / 4 ) ;
else if ( id < 96 / 4 ) return gradient ( 0xF00000 , 0x400000 , 48 / 4 , id , 95 / 4 - 2 ) ;
else return winf [ waMagma ] . color ;
}
2017-07-10 18:47:38 +00:00
bool noAdjacentChasms ( cell * c ) {
forCellEx ( c2 , c ) if ( c2 - > wall = = waChasm ) return false ;
return true ;
2015-08-08 13:57:52 +00:00
}
2018-04-04 10:46:40 +00:00
// does the current geometry allow nice duals
2019-08-09 19:00:52 +00:00
EX bool has_nice_dual ( ) {
2019-02-17 17:28:20 +00:00
# if CAP_IRR
2018-08-28 15:17:34 +00:00
if ( IRREGULAR ) return irr : : bitruncations_performed > 0 ;
2019-02-17 17:28:20 +00:00
# endif
# if CAP_ARCM
2019-12-14 10:42:16 +00:00
if ( arcm : : in ( ) ) return geosupport_football ( ) > = 2 ;
2019-02-17 17:28:20 +00:00
# endif
2019-12-14 11:05:01 +00:00
if ( bt : : in ( ) ) return false ;
2018-08-28 15:17:34 +00:00
if ( BITRUNCATED ) return true ;
2018-07-10 19:55:54 +00:00
if ( a4 ) return false ;
2018-08-28 15:17:34 +00:00
if ( ( S7 & 1 ) = = 0 ) return true ;
if ( PURE ) return false ;
2019-02-17 17:28:20 +00:00
# if CAP_GP
2018-04-09 15:40:12 +00:00
return ( gp : : param . first + gp : : param . second * 2 ) % 3 = = 0 ;
2019-02-17 17:28:20 +00:00
# else
return false ;
# endif
2018-04-04 10:46:40 +00:00
}
// does the current geometry allow nice duals
2019-08-09 19:00:52 +00:00
EX bool is_nice_dual ( cell * c ) {
2018-04-04 10:46:40 +00:00
return c - > land = = laDual & & has_nice_dual ( ) ;
}
2019-08-09 19:00:52 +00:00
EX bool use_swapped_duals ( ) {
2019-11-27 00:01:20 +00:00
return ( euclid & & ! a4 ) | | GOLDBERG ;
2018-04-04 10:46:40 +00:00
}
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2020-07-27 16:49:04 +00:00
EX void floorShadow ( cell * c , const shiftmatrix & V , color_t col ) {
2019-02-22 20:27:42 +00:00
if ( model_needs_depth ( ) | | noshadow )
2017-07-10 18:47:38 +00:00
return ; // shadows break the depth testing
2018-09-04 17:53:42 +00:00
dynamicval < color_t > p ( poly_outline , OUTLINE_TRANS ) ;
2018-05-07 18:13:56 +00:00
if ( qfi . shape ) {
2019-05-26 16:04:02 +00:00
queuepolyat ( V * qfi . spin * cgi . shadowmulmatrix , * qfi . shape , col , PPR : : WALLSHADOW ) ;
2017-07-10 18:47:38 +00:00
}
2018-08-27 17:27:35 +00:00
else if ( qfi . usershape > = 0 )
2019-05-26 16:04:02 +00:00
mapeditor : : drawUserShape ( V * qfi . spin * cgi . shadowmulmatrix , mapeditor : : sgFloor , qfi . usershape , col , c , PPR : : WALLSHADOW ) ;
2018-08-18 16:01:41 +00:00
else
2018-08-28 12:27:23 +00:00
draw_shapevec ( c , V , qfi . fshape - > shadow , col , PPR : : WALLSHADOW ) ;
2017-07-10 18:47:38 +00:00
}
2019-10-25 10:44:41 +00:00
EX bool use_warp_graphics ( ) {
2019-10-05 16:46:58 +00:00
if ( shmup : : on ) return false ;
if ( geosupport_football ( ) ! = 2 ) return false ;
2021-04-11 20:15:40 +00:00
if ( ls : : chaoticity ( ) > = 75 ) return false ;
2019-10-05 16:46:58 +00:00
return true ;
}
2020-07-27 16:49:04 +00:00
EX void escherSidewall ( cell * c , int sidepar , const shiftmatrix & V , color_t col ) {
2017-07-10 18:47:38 +00:00
if ( sidepar > = SIDE_SLEV & & sidepar < = SIDE_SLEV + 2 ) {
int sl = sidepar - SIDE_SLEV ;
for ( int z = 1 ; z < = 4 ; z + + ) if ( z = = 1 | | ( z = = 4 & & detaillevel = = 2 ) )
2022-12-06 00:04:26 +00:00
draw_qfi ( c , orthogonal_move_fol ( V , zgrad0 ( cgi . slev * sl , cgi . slev * ( sl + 1 ) , z , 4 ) ) , col , PPR : : REDWALL - 4 + z + 4 * sl ) ;
2017-07-10 18:47:38 +00:00
}
else if ( sidepar = = SIDE_WALL ) {
const int layers = 2 < < detaillevel ;
for ( int z = 1 ; z < layers ; z + + )
2022-12-06 00:04:26 +00:00
draw_qfi ( c , orthogonal_move_fol ( V , zgrad0 ( 0 , geom3 : : actual_wall_height ( ) , z , layers ) ) , col , PPR : : WALL3 + z - layers ) ;
2017-07-10 18:47:38 +00:00
}
else if ( sidepar = = SIDE_LAKE ) {
const int layers = 1 < < ( detaillevel - 1 ) ;
if ( detaillevel ) for ( int z = 0 ; z < layers ; z + + )
2022-12-06 00:04:26 +00:00
draw_qfi ( c , orthogonal_move_fol ( V , zgrad0 ( - vid . lake_top , 0 , z , layers ) ) , col , PPR : : FLOOR + z - layers ) ;
2017-07-10 18:47:38 +00:00
}
else if ( sidepar = = SIDE_LTOB ) {
const int layers = 1 < < ( detaillevel - 1 ) ;
if ( detaillevel ) for ( int z = 0 ; z < layers ; z + + )
2022-12-06 00:04:26 +00:00
draw_qfi ( c , orthogonal_move_fol ( V , zgrad0 ( - vid . lake_bottom , - vid . lake_top , z , layers ) ) , col , PPR : : INLAKEWALL + z - layers ) ;
2017-07-10 18:47:38 +00:00
}
else if ( sidepar = = SIDE_BTOI ) {
const int layers = 1 < < detaillevel ;
2022-12-06 00:04:26 +00:00
draw_qfi ( c , orthogonal_move_fol ( V , cgi . INFDEEP ) , col , PPR : : MINUSINF ) ;
2017-07-10 18:47:38 +00:00
for ( int z = 1 ; z < layers ; z + + )
2022-12-06 00:04:26 +00:00
draw_qfi ( c , orthogonal_move_fol ( V , zgrad0 ( - vid . lake_bottom , - vid . lake_top , - z , 1 ) ) , col , PPR : : LAKEBOTTOM + z - layers ) ;
2017-07-10 18:47:38 +00:00
}
}
2020-07-27 16:49:04 +00:00
EX bool placeSidewall ( cell * c , int i , int sidepar , const shiftmatrix & V , color_t col ) {
2018-05-07 18:13:56 +00:00
2019-05-26 16:04:02 +00:00
if ( ! qfi . fshape | | ! qfi . fshape - > is_plain | | ! cgi . validsidepar [ sidepar ] | | qfi . usershape > = 0 ) if ( GDIM = = 2 ) {
2018-05-07 18:13:56 +00:00
escherSidewall ( c , sidepar , V , col ) ;
return true ;
2017-10-29 22:54:26 +00:00
}
2019-05-10 00:52:04 +00:00
if ( ! qfi . fshape ) return true ;
2018-05-07 18:13:56 +00:00
2019-05-26 16:04:02 +00:00
if ( qfi . fshape = = & cgi . shBigTriangle & & pseudohept ( c - > move ( i ) ) ) return false ;
if ( qfi . fshape = = & cgi . shTriheptaFloor & & ! pseudohept ( c ) & & ! pseudohept ( c - > move ( i ) ) ) return false ;
2018-05-07 18:13:56 +00:00
2018-08-28 11:45:11 +00:00
PPR prio ;
2018-08-28 12:27:23 +00:00
/* if(mirr) prio = PPR::GLASS - 2;
else */ if ( sidepar = = SIDE_WALL ) prio = PPR : : WALL3 - 2 ;
else if ( sidepar = = SIDE_WTS3 ) prio = PPR : : WALL3 - 2 ;
else if ( sidepar = = SIDE_LAKE ) prio = PPR : : LAKEWALL ;
else if ( sidepar = = SIDE_LTOB ) prio = PPR : : INLAKEWALL ;
else if ( sidepar = = SIDE_BTOI ) prio = PPR : : BELOWBOTTOM ;
2020-02-26 00:15:30 +00:00
else if ( sidepar = = SIDE_ASHA ) prio = PPR : : ASHALLOW ;
else if ( sidepar = = SIDE_BSHA ) prio = PPR : : BSHALLOW ;
2018-08-28 12:27:23 +00:00
else prio = PPR : : REDWALL - 2 + 4 * ( sidepar - SIDE_SLEV ) ;
2023-05-01 14:10:25 +00:00
if ( ( col & 255 ) < 255 ) prio = PPR : : TRANSPARENT_WALL ;
2017-07-10 18:47:38 +00:00
2023-01-26 23:27:10 +00:00
if ( cgi . emb - > is_in_noniso ( ) ) {
2022-12-13 18:04:43 +00:00
draw_shapevec ( c , V , qfi . fshape - > gpside [ sidepar ] [ i ] , col , prio ) ;
return false ;
}
2019-07-25 10:24:02 +00:00
dynamicval < bool > ncor ( approx_nearcorner , true ) ;
2020-07-27 16:49:04 +00:00
shiftmatrix V2 = V * ddspin_side ( c , i ) ;
2020-03-21 08:28:16 +00:00
2022-12-13 22:27:04 +00:00
if ( NONSTDVAR | | ! standard_tiling ( ) ) {
2019-02-17 17:28:20 +00:00
# if CAP_ARCM
2019-12-14 10:42:16 +00:00
if ( arcm : : in ( ) & & ! PURE )
2020-01-18 15:03:32 +00:00
i = gmod ( i + arcm : : parent_index_of ( c - > master ) / DUALMUL , c - > type ) ;
2019-02-17 17:28:20 +00:00
# endif
2021-07-29 12:07:30 +00:00
if ( currentmap - > strict_tree_rules ( ) ) {
i = rulegen : : get_arb_dir ( c , i ) ;
}
2023-04-27 20:48:58 +00:00
if ( sidepar > = SIDEPARS ) {
println ( hlog , " ERROR: sidepar >= SIDEPARS " , make_pair ( sidepar , SIDEPARS ) ) ;
return false ;
}
if ( i > = isize ( qfi . fshape - > gpside [ sidepar ] ) ) {
println ( hlog , " ERROR: i >= gpside[sidepar] " , make_tuple ( sidepar , i , isize ( qfi . fshape - > gpside [ sidepar ] ) ) ) ;
return false ;
}
2018-05-07 18:13:56 +00:00
draw_shapevec ( c , V2 , qfi . fshape - > gpside [ sidepar ] [ i ] , col , prio ) ;
return false ;
}
2017-10-29 22:54:26 +00:00
2019-07-22 09:21:27 +00:00
queuepolyat ( V2 , qfi . fshape - > side [ sidepar ] [ shvid ( c ) ] , col , prio ) ;
2018-05-07 18:13:56 +00:00
return false ;
2016-01-02 10:09:13 +00:00
}
2019-02-17 17:41:40 +00:00
# endif
2016-01-02 10:09:13 +00:00
2017-07-10 18:47:38 +00:00
bool openorsafe ( cell * c ) {
2020-10-15 14:33:52 +00:00
# if CAP_COMPLEX2
2019-12-08 18:17:28 +00:00
return c - > wall = = waMineOpen | | mine : : marked_safe ( c ) ;
2020-10-15 14:33:52 +00:00
# else
return false ;
# endif
2017-03-23 10:53:57 +00:00
}
2017-07-10 18:47:38 +00:00
# define Dark(x) darkena(x,0,0xFF)
2017-03-23 10:53:57 +00:00
2019-08-09 21:39:36 +00:00
EX color_t stdgridcolor = 0x202020FF ;
2019-03-08 21:40:34 +00:00
2019-10-25 10:44:41 +00:00
EX int gridcolor ( cell * c1 , cell * c2 ) {
2020-04-17 18:34:49 +00:00
if ( cmode & sm : : DRAW & & ! mapeditor : : drawing_tool ) return Dark ( forecolor ) ;
2017-07-10 18:47:38 +00:00
if ( ! c2 )
return 0x202020 > > darken ;
int rd1 = rosedist ( c1 ) , rd2 = rosedist ( c2 ) ;
if ( rd1 ! = rd2 ) {
int r = rd1 + rd2 ;
if ( r = = 1 ) return Dark ( 0x802020 ) ;
if ( r = = 3 ) return Dark ( 0xC02020 ) ;
if ( r = = 2 ) return Dark ( 0xF02020 ) ;
2017-06-18 16:51:46 +00:00
}
2019-05-21 23:13:54 +00:00
if ( chasmgraph ( c1 ) ! = chasmgraph ( c2 ) & & c1 - > land ! = laAsteroids & & c2 - > land ! = laAsteroids )
2017-07-10 18:47:38 +00:00
return Dark ( 0x808080 ) ;
2017-12-21 14:14:54 +00:00
if ( c1 - > land = = laAlchemist & & c2 - > land = = laAlchemist & & c1 - > wall ! = c2 - > wall & & ! c1 - > item & & ! c2 - > item )
2017-07-10 18:47:38 +00:00
return Dark ( 0xC020C0 ) ;
if ( ( c1 - > land = = laWhirlpool | | c2 - > land = = laWhirlpool ) & & ( celldistAlt ( c1 ) ! = celldistAlt ( c2 ) ) )
return Dark ( 0x2020A0 ) ;
if ( c1 - > land = = laMinefield & & c2 - > land = = laMinefield & & ( openorsafe ( c1 ) ! = openorsafe ( c2 ) ) )
return Dark ( 0xA0A0A0 ) ;
2019-03-08 21:40:34 +00:00
if ( ! darken ) return stdgridcolor ;
2017-07-10 18:47:38 +00:00
return Dark ( 0x202020 ) ;
2017-06-18 16:51:46 +00:00
}
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2020-07-27 16:49:04 +00:00
EX void pushdown ( cell * c , int & q , const shiftmatrix & V , double down , bool rezoom , bool repriority ) {
2019-05-08 18:40:41 +00:00
2019-05-10 01:16:40 +00:00
# if MAXMDIM >= 4
2019-05-08 18:40:41 +00:00
if ( GDIM = = 3 ) {
for ( int i = q ; i < isize ( ptds ) ; i + + ) {
auto pp = dynamic_cast < dqi_poly * > ( & * ptds [ q + + ] ) ;
if ( ! pp ) continue ;
auto & ptd = * pp ;
2023-01-05 23:09:12 +00:00
ptd . V = ptd . V * lzpush ( + down ) ;
2019-05-08 18:40:41 +00:00
}
return ;
}
2019-05-10 01:16:40 +00:00
# endif
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
// since we might be changing priorities, we have to make sure that we are sorting correctly
if ( down > 0 & & repriority ) {
int qq = q + 1 ;
2018-06-22 12:47:24 +00:00
while ( qq < isize ( ptds ) )
2018-09-04 17:53:42 +00:00
if ( qq > q & & ptds [ qq ] - > prio < ptds [ qq - 1 ] - > prio ) {
2017-07-10 18:47:38 +00:00
swap ( ptds [ qq ] , ptds [ qq - 1 ] ) ;
qq - - ;
2016-08-26 09:58:03 +00:00
}
2017-07-10 18:47:38 +00:00
else qq + + ;
2017-06-18 16:51:46 +00:00
}
2018-06-22 12:47:24 +00:00
while ( q < isize ( ptds ) ) {
2018-09-04 17:53:42 +00:00
auto pp = dynamic_cast < dqi_poly * > ( & * ptds [ q + + ] ) ;
if ( ! pp ) continue ;
auto & ptd = * pp ;
double z2 ;
2017-07-10 18:47:38 +00:00
2020-07-27 16:49:04 +00:00
double z = zlevel ( tC0 ( ptd . V . T ) ) ;
2018-09-04 17:53:42 +00:00
double lev = geom3 : : factor_to_lev ( z ) ;
double nlev = lev - down ;
double xyscale = rezoom ? geom3 : : scale_at_lev ( lev ) / geom3 : : scale_at_lev ( nlev ) : 1 ;
z2 = geom3 : : lev_to_factor ( nlev ) ;
double zscale = z2 / z ;
// xyscale = xyscale + (zscale-xyscale) * (1+sin(ticks / 1000.0)) / 2;
2020-07-27 16:49:04 +00:00
ptd . V . T = xyzscale ( V . T , xyscale * zscale , zscale )
2020-09-16 03:57:05 +00:00
* z_inverse ( V . T ) * unshift ( ptd . V , V . shift ) ;
2017-07-10 18:47:38 +00:00
2018-09-04 17:53:42 +00:00
if ( ! repriority ) ;
2019-05-29 14:27:24 +00:00
else if ( nlev < - vid . lake_bottom - 1e-3 ) {
2018-09-04 17:53:42 +00:00
ptd . prio = PPR : : BELOWBOTTOM_FALLANIM ;
if ( c - > wall ! = waChasm )
ptd . color = 0 ; // disappear!
}
2019-05-29 14:27:24 +00:00
else if ( nlev < - vid . lake_top - 1e-3 )
2018-09-04 17:53:42 +00:00
ptd . prio = PPR : : INLAKEWALL_FALLANIM ;
else if ( nlev < 0 )
ptd . prio = PPR : : LAKEWALL_FALLANIM ;
2017-03-23 10:53:57 +00:00
}
2015-08-08 13:57:52 +00:00
}
2019-02-17 17:41:40 +00:00
# endif
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
// 1 : (floor, water); 2 : (water, bottom); 4 : (bottom, inf)
2016-01-02 10:09:13 +00:00
2019-10-25 10:44:41 +00:00
EX int shallow ( cell * c ) {
2017-07-10 18:47:38 +00:00
if ( cellUnstable ( c ) ) return 0 ;
else if (
c - > wall = = waReptile ) return 1 ;
else if ( c - > wall = = waReptileBridge | |
c - > wall = = waGargoyleFloor | |
c - > wall = = waGargoyleBridge | |
c - > wall = = waTempFloor | |
c - > wall = = waTempBridge | |
2017-09-03 10:01:31 +00:00
c - > wall = = waPetrifiedBridge | |
2017-07-10 18:47:38 +00:00
c - > wall = = waFrozenLake )
return 5 ;
return 7 ;
2017-03-23 10:53:57 +00:00
}
2017-07-10 18:47:38 +00:00
bool allemptynear ( cell * c ) {
if ( c - > wall ) return false ;
forCellEx ( c2 , c ) if ( c2 - > wall ) return false ;
return true ;
2016-01-02 10:09:13 +00:00
}
2019-08-09 19:00:52 +00:00
EX bool bright ;
2022-03-07 03:01:59 +00:00
EX int canvasdark ;
2018-03-25 16:33:21 +00:00
2017-10-17 10:54:59 +00:00
// how much to darken
2019-10-25 10:44:41 +00:00
EX int getfd ( cell * c ) {
2018-03-25 16:33:21 +00:00
if ( bright ) return 0 ;
2020-02-26 00:40:40 +00:00
if ( among ( c - > land , laAlchemist , laHell , laVariant , laEclectic ) & & WDIM = = 2 & & GDIM = = 3 ) return 0 ;
2017-10-17 10:54:59 +00:00
switch ( c - > land ) {
2022-03-07 03:01:59 +00:00
case laCanvas :
return min ( 2 , max ( 0 , canvasdark ) ) ;
2017-10-17 10:54:59 +00:00
case laRedRock :
case laReptile :
return 0 ;
2017-12-05 18:43:45 +00:00
case laSnakeNest :
return realred ( c - > wall ) ? 0 : 1 ;
2017-10-17 10:54:59 +00:00
case laTerracotta :
case laMercuryRiver :
2017-10-17 18:41:17 +00:00
return ( c - > wall = = waMercury & & wmspatial ) ? 0 : 1 ;
2017-10-17 10:54:59 +00:00
case laKraken :
2017-12-29 00:10:47 +00:00
case laDocks :
2017-10-17 10:54:59 +00:00
case laBurial :
case laIvoryTower :
case laDungeon :
case laMountain :
case laEndorian :
case laCaribbean :
case laWhirlwind :
case laRose :
case laWarpSea :
case laTortoise :
case laDragon :
case laHalloween :
case laHunting :
case laOcean :
case laLivefjord :
case laWhirlpool :
case laAlchemist :
case laIce :
case laGraveyard :
case laBlizzard :
case laRlyeh :
case laTemple :
case laWineyard :
case laDeadCaves :
case laPalace :
case laCA :
2017-10-30 08:05:16 +00:00
case laDual :
2018-10-25 00:43:14 +00:00
case laBrownian :
2017-10-17 10:54:59 +00:00
return 1 ;
2019-01-11 01:25:54 +00:00
case laVariant :
if ( isWateryOrBoat ( c ) ) return 1 ;
return 2 ;
2017-10-17 10:54:59 +00:00
case laTrollheim :
default :
return 2 ;
}
}
2017-12-05 18:43:45 +00:00
2019-08-10 08:57:14 +00:00
EX bool just_gmatrix ;
2018-04-04 10:46:40 +00:00
2019-10-25 10:44:41 +00:00
EX int colorhash ( color_t i ) {
2018-08-30 17:14:04 +00:00
return ( i * 0x471211 + i * i * 0x124159 + i * i * i * 0x982165 ) & 0xFFFFFF ;
}
2024-05-07 20:18:54 +00:00
EX int mine_opacity = 255 ;
2019-08-10 08:57:14 +00:00
EX bool isWall3 ( cell * c , color_t & wcol ) {
2024-03-24 19:03:02 +00:00
if ( c - > wall = = waRose ) { wcol = gradient ( 0 , wcol , - 5 - 5 * ( 7 - rosephase ) , sintick ( 50 * ( 8 - rosephase ) ) , 1 ) ; }
2019-02-27 13:43:42 +00:00
if ( isWall ( c ) ) return true ;
2023-03-28 20:54:46 +00:00
if ( c - > wall = = waChasm & & c - > land = = laMemory & & ( anyshiftclick | | ! ( cgflags & qFRACTAL ) ) ) { wcol = 0x606000 ; return true ; }
2019-02-27 13:43:42 +00:00
if ( c - > wall = = waInvisibleFloor ) return false ;
2019-02-27 15:36:56 +00:00
// if(chasmgraph(c)) return true;
2024-05-07 20:18:54 +00:00
if ( among ( c - > wall , waMirror , waCloud ) ) return true ;
if ( among ( c - > wall , waMineUnknown , waMineMine ) & & mine_opacity = = 255 ) return true ;
2019-02-27 13:43:42 +00:00
return false ;
}
2019-10-12 09:21:00 +00:00
EX bool isWall3 ( cell * c ) { color_t dummy ; return isWall3 ( c , dummy ) ; }
2019-10-25 10:44:41 +00:00
EX bool isSulphuric ( eWall w ) { return among ( w , waSulphur , waSulphurC ) ; }
2019-03-04 17:01:48 +00:00
2019-03-10 17:38:55 +00:00
// 'land color', but a bit twisted for Alchemist Lab
color_t lcolor ( cell * c ) {
if ( isAlch ( c - > wall ) & & ! c - > item ) return winf [ c - > wall ] . color ;
return floorcolors [ c - > land ] ;
}
2019-10-25 10:44:41 +00:00
EX color_t transcolor ( cell * c , cell * c2 , color_t wcol ) {
2019-03-10 17:38:55 +00:00
color_t dummy ;
if ( isWall3 ( c2 , dummy ) ) return 0 ;
2019-04-13 11:30:09 +00:00
if ( c - > land ! = c2 - > land & & c - > land ! = laNone & & c2 - > land ! = laNone ) {
2019-03-10 17:38:55 +00:00
if ( c > c2 ) return 0 ;
2019-05-11 15:21:17 +00:00
if ( c - > land = = laBarrier ) return darkena3 ( lcolor ( c2 ) , 0 , 0x40 ) ;
if ( c2 - > land = = laBarrier ) return darkena3 ( lcolor ( c ) , 0 , 0x40 ) ;
return darkena3 ( gradient ( lcolor ( c ) , lcolor ( c2 ) , 0 , 1 , 2 ) , 0 , 0x40 ) ;
2019-03-09 22:55:03 +00:00
}
2019-07-30 11:01:41 +00:00
if ( sol & & c - > land = = laWineyard & & c2 - > master - > distance < c - > master - > distance )
return 0x00800040 ;
2019-04-20 23:06:37 +00:00
if ( isAlch ( c ) & & ! c - > item & & ( c2 - > item | | ! isAlch ( c2 ) ) ) return darkena3 ( winf [ c - > wall ] . color , 0 , 0x40 ) ;
2019-03-09 22:55:03 +00:00
if ( c - > wall = = c2 - > wall ) return 0 ;
2019-04-20 23:06:37 +00:00
if ( isFire ( c ) & & ! isFire ( c2 ) ) return darkena3 ( wcol , 0 , 0x30 ) ;
if ( c - > wall = = waLadder ) return darkena3 ( wcol , 0 , 0x30 ) ;
2020-01-28 12:01:42 +00:00
if ( c - > land = = laZebra & & c2 - > land = = laZebra & & c2 - > wall = = waTrapdoor ) return 0x202020A0 ;
2019-03-09 22:55:03 +00:00
2019-03-10 17:38:55 +00:00
if ( c - > wall = = waChasm & & c2 - > wall ! = waChasm ) return 0x606060A0 ;
if ( isWateryOrBoat ( c ) & & ! isWateryOrBoat ( c2 ) ) return 0x0000C060 ;
2019-04-20 23:06:37 +00:00
if ( isSulphuric ( c - > wall ) & & ! isSulphuric ( c2 - > wall ) ) return darkena3 ( winf [ c - > wall ] . color , 0 , 0x40 ) ;
2019-03-23 21:25:35 +00:00
if ( among ( c - > wall , waCanopy , waSolidBranch , waWeakBranch ) & & ! among ( c2 - > wall , waCanopy , waSolidBranch , waWeakBranch ) ) return 0x00C00060 ;
2019-04-20 23:06:37 +00:00
if ( c - > wall = = waFloorA & & c2 - > wall = = waFloorB & & ! c - > item & & ! c2 - > item ) return darkena3 ( 0xFF00FF , 0 , 0x80 ) ;
2019-08-07 22:20:02 +00:00
if ( realred ( c - > wall ) | | realred ( c2 - > wall ) ) {
2019-03-09 22:55:03 +00:00
int l = snakelevel ( c ) - snakelevel ( c2 ) ;
2019-04-20 23:06:37 +00:00
if ( l > 0 ) return darkena3 ( floorcolors [ laRedRock ] , 0 , 0x30 * l ) ;
2019-03-09 22:55:03 +00:00
}
2019-08-07 22:20:02 +00:00
if ( among ( c - > wall , waRubble , waDeadfloor2 ) & & ! snakelevel ( c2 ) ) return darkena3 ( winf [ c - > wall ] . color , 0 , 0x40 ) ;
2019-04-20 23:06:37 +00:00
if ( c - > wall = = waMagma & & c2 - > wall ! = waMagma ) return darkena3 ( magma_color ( lavatide ( c , - 1 ) / 4 ) , 0 , 0x80 ) ;
2024-05-07 20:18:54 +00:00
if ( among ( c - > wall , waMineUnknown , waMineMine ) & & ! among ( c2 - > wall , waMineMine , waMineUnknown ) & & mine_opacity > 0 & & mine_opacity < 255 )
return 0xFFFFFF00 | mine_opacity ;
2019-03-09 22:55:03 +00:00
return 0 ;
2019-03-04 17:01:48 +00:00
}
2019-02-27 15:29:30 +00:00
// how much should be the d-th wall darkened in 3D
2019-10-25 10:44:41 +00:00
EX int get_darkval ( cell * c , int d ) {
2022-12-08 18:38:06 +00:00
if ( mhybrid ) {
2019-08-18 19:30:52 +00:00
return d > = c - > type - 2 ? 4 : 0 ;
}
2019-03-02 23:43:31 +00:00
const int darkval_hbt [ 9 ] = { 0 , 2 , 2 , 0 , 6 , 6 , 8 , 8 , 0 } ;
const int darkval_s12 [ 12 ] = { 0 , 1 , 2 , 3 , 4 , 5 , 0 , 1 , 2 , 3 , 4 , 5 } ;
2019-03-01 17:53:20 +00:00
const int darkval_e6 [ 6 ] = { 0 , 4 , 6 , 0 , 4 , 6 } ;
const int darkval_e12 [ 12 ] = { 0 , 4 , 6 , 0 , 4 , 6 , 0 , 4 , 6 , 0 , 4 , 6 } ;
const int darkval_e14 [ 14 ] = { 0 , 0 , 0 , 4 , 6 , 4 , 6 , 0 , 0 , 0 , 6 , 4 , 6 , 4 } ;
2019-03-13 12:12:49 +00:00
const int darkval_hh [ 14 ] = { 0 , 0 , 0 , 1 , 1 , 1 , 2 , 2 , 2 , 3 , 3 , 3 , 1 , 0 } ;
const int darkval_hrec [ 7 ] = { 0 , 0 , 2 , 4 , 2 , 4 , 0 } ;
2019-07-25 21:08:04 +00:00
const int darkval_sol [ 8 ] = { 0 , 2 , 4 , 4 , 0 , 2 , 4 , 4 } ;
2019-11-08 14:34:51 +00:00
const int darkval_arnold [ 12 ] = { 0 , 2 , 0 , 2 , 4 , 5 , 0 , 2 , 0 , 2 , 4 , 5 } ;
2019-12-14 11:12:24 +00:00
const int darkval_kite [ 12 ] = { 0 , 2 , 0 , 2 , 4 , 4 , 6 , 6 , 6 , 6 , 6 , 6 } ;
2019-08-06 19:01:37 +00:00
const int darkval_nil [ 8 ] = { 6 , 6 , 0 , 3 , 6 , 6 , 0 , 3 } ;
2019-10-01 03:03:46 +00:00
const int darkval_nih [ 11 ] = { 0 , 2 , 0 , 2 , 4 , 6 , 6 , 6 , 6 , 6 , 6 } ;
2022-02-17 20:00:10 +00:00
# if MAXMDIM >= 4
2021-11-07 08:07:51 +00:00
if ( among ( variation , eVariation : : dual_subcubes , eVariation : : bch , eVariation : : bch_oct , eVariation : : coxeter ) ) {
2021-07-07 21:32:22 +00:00
int v = reg3 : : get_face_vertex_count ( c , d ) ;
2021-07-07 16:26:14 +00:00
return v - 3 ;
}
2022-02-17 20:00:10 +00:00
# endif
2019-03-02 23:43:31 +00:00
if ( sphere ) return darkval_s12 [ d ] ;
2019-03-01 17:53:20 +00:00
if ( euclid & & S7 = = 6 ) return darkval_e6 [ d ] ;
if ( euclid & & S7 = = 12 ) return darkval_e12 [ d ] ;
if ( euclid & & S7 = = 14 ) return darkval_e14 [ d ] ;
2019-03-13 12:12:49 +00:00
if ( geometry = = gHoroHex ) return darkval_hh [ d ] ;
if ( geometry = = gHoroRec ) return darkval_hrec [ d ] ;
2019-12-14 11:12:24 +00:00
if ( kite : : in ( ) ) return darkval_kite [ d ] ;
2021-03-25 09:57:48 +00:00
if ( asonov : : in ( ) ) return darkval_arnold [ d ] ;
2019-07-25 21:08:04 +00:00
if ( sol ) return darkval_sol [ d ] ;
2019-10-01 03:03:46 +00:00
if ( nih ) return darkval_nih [ d ] ;
2019-12-14 11:05:01 +00:00
if ( bt : : in ( ) ) return darkval_hbt [ d ] ;
2019-03-02 23:43:31 +00:00
if ( hyperbolic & & S7 = = 6 ) return darkval_e6 [ d ] ;
if ( hyperbolic & & S7 = = 12 ) return darkval_s12 [ d ] ;
2019-08-06 19:01:37 +00:00
if ( nil ) return darkval_nil [ d ] ;
2019-03-02 23:43:31 +00:00
return 0 ;
2019-02-27 15:29:30 +00:00
}
2020-07-27 16:49:04 +00:00
EX ld mousedist ( shiftmatrix T ) {
if ( GDIM = = 2 ) return hdist ( mouseh , tC0 ( T ) ) ;
2022-12-08 21:52:00 +00:00
shiftpoint T1 = orthogonal_move_fol ( T , cgi . FLOOR ) * tile_center ( ) ;
2019-05-09 15:02:50 +00:00
hyperpoint h1 ;
applymodel ( T1 , h1 ) ;
2022-12-13 22:28:48 +00:00
if ( mouseaim_sensitivity ) return sqhypot_d ( 2 , h1 ) + ( point_behind ( T1 ) ? 1e10 : 0 ) ;
2022-12-13 22:27:59 +00:00
h1 = h1 - point2 ( ( mousex - current_display - > xcenter ) / current_display - > radius , ( mousey - current_display - > ycenter ) / current_display - > radius ) ;
2019-07-31 14:14:01 +00:00
return sqhypot_d ( 2 , h1 ) + ( point_behind ( T1 ) ? 1e10 : 0 ) ;
2019-05-09 15:02:50 +00:00
}
2021-03-09 15:04:53 +00:00
vector < vector < hyperpoint > > clipping_plane_sets ;
2019-08-09 19:00:52 +00:00
EX int noclipped ;
2019-05-11 13:06:48 +00:00
2020-05-25 00:27:23 +00:00
EX bool frustum_culling = true ;
2021-03-09 15:04:53 +00:00
EX ld threshold , xyz_threshold ;
EX bool clip_checked = false ;
2023-11-30 11:32:24 +00:00
EX bool other_stereo_mode ( ) {
2024-01-07 08:13:31 +00:00
return vid . stereo_mode ! = sOFF ;
2023-11-30 11:32:24 +00:00
}
2019-05-11 13:06:48 +00:00
void make_clipping_planes ( ) {
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2021-03-09 15:04:53 +00:00
clip_checked = false ;
2023-11-30 11:32:24 +00:00
if ( ! frustum_culling | | PIU ( sphere ) | | experimental | | other_stereo_mode ( ) | | gproduct | | embedded_plane ) return ;
2020-11-19 17:20:06 +00:00
2021-03-09 15:04:53 +00:00
if ( WDIM = = 3 & & pmodel = = mdPerspective & & ! nonisotropic & & ! in_s2xe ( ) )
threshold = sin_auto ( cgi . corner_bonus ) , xyz_threshold = 0 , clip_checked = true ;
else if ( pmodel = = mdGeodesic & & sn : : in ( ) )
threshold = .6 , xyz_threshold = 3 , clip_checked = true ;
else if ( pmodel = = mdGeodesic & & nil )
threshold = 2 , xyz_threshold = 3 , clip_checked = true ;
else return ;
2021-07-07 16:26:40 +00:00
2021-03-09 15:04:53 +00:00
clipping_plane_sets . clear ( ) ;
auto add_clipping_plane_txy = [ ] ( transmatrix T , const transmatrix & nlp , ld x1 , ld y1 , ld x2 , ld y2 ) {
2019-05-11 13:06:48 +00:00
ld z1 = 1 , z2 = 1 ;
hyperpoint sx = point3 ( y1 * z2 - y2 * z1 , z1 * x2 - z2 * x1 , x1 * y2 - x2 * y1 ) ;
sx / = hypot_d ( 3 , sx ) ;
sx [ 3 ] = 0 ;
2021-03-09 15:04:53 +00:00
sx = T * sx ;
2022-12-25 11:14:36 +00:00
if ( nisot : : local_perspective_used ) sx = ortho_inverse ( nlp ) * sx ;
2021-03-09 15:04:53 +00:00
clipping_plane_sets . back ( ) . push_back ( sx ) ;
} ;
2021-03-09 15:22:22 +00:00
# if CAP_VR
2021-03-09 15:04:53 +00:00
auto add_clipping_plane_proj = [ & ] ( transmatrix T , const transmatrix & nlp , const transmatrix & iproj , ld x1 , ld y1 , ld x2 , ld y2 ) {
hyperpoint h1 = iproj * point31 ( x1 , y1 , .5 ) ;
hyperpoint h2 = iproj * point31 ( x2 , y2 , .5 ) ;
h1 / = h1 [ 2 ] ; h2 / = h2 [ 2 ] ;
add_clipping_plane_txy ( T , nlp , h1 [ 0 ] , h1 [ 1 ] , h2 [ 0 ] , h2 [ 1 ] ) ;
} ;
2021-03-09 15:22:22 +00:00
# endif
2021-03-09 15:04:53 +00:00
auto clipping_planes_screen = [ & ] ( const transmatrix & T , const transmatrix & nlp ) {
ld tx = current_display - > tanfov ;
ld ty = tx * current_display - > ysize / current_display - > xsize ;
clipping_plane_sets . push_back ( { } ) ;
add_clipping_plane_txy ( T , nlp , + tx , + ty , - tx , + ty ) ;
add_clipping_plane_txy ( T , nlp , - tx , + ty , - tx , - ty ) ;
add_clipping_plane_txy ( T , nlp , - tx , - ty , + tx , - ty ) ;
add_clipping_plane_txy ( T , nlp , + tx , - ty , + tx , + ty ) ;
2019-05-11 13:06:48 +00:00
} ;
2021-03-09 15:04:53 +00:00
bool stdview = true ;
# if CAP_VR
if ( vrhr : : active ( ) ) {
for ( auto p : vrhr : : frusta ) {
if ( p . screen )
clipping_planes_screen ( inverse ( p . pre ) , p . nlp ) ;
else {
auto iproj = inverse ( p . proj ) ;
auto ipre = inverse ( p . pre ) ;
clipping_plane_sets . push_back ( { } ) ;
add_clipping_plane_proj ( ipre , p . nlp , iproj , 1 , 1 , 0 , 1 ) ;
add_clipping_plane_proj ( ipre , p . nlp , iproj , 0 , 1 , 0 , 0 ) ;
add_clipping_plane_proj ( ipre , p . nlp , iproj , 0 , 0 , 1 , 0 ) ;
add_clipping_plane_proj ( ipre , p . nlp , iproj , 1 , 0 , 1 , 1 ) ;
}
stdview = false ;
}
}
# endif
if ( stdview ) clipping_planes_screen ( Id , NLP ) ;
2019-06-01 14:59:04 +00:00
# endif
2019-05-11 13:06:48 +00:00
}
2021-03-09 15:04:53 +00:00
bool clipped_by ( const hyperpoint & H , const vector < hyperpoint > & v ) {
for ( auto & cpoint : v ) if ( ( H | cpoint ) < - threshold ) return true ;
return false ;
}
bool clipped_by ( const hyperpoint & H , const vector < vector < hyperpoint > > & vv ) {
for ( auto & cps : vv ) if ( ! clipped_by ( H , cps ) ) return false ;
return true ;
}
2019-10-25 10:44:41 +00:00
bool celldrawer : : cell_clipped ( ) {
2021-03-09 15:04:53 +00:00
if ( ! clip_checked ) return false ;
hyperpoint H = unshift ( tC0 ( V ) ) ;
if ( xyz_threshold & & abs ( H [ 0 ] ) < = xyz_threshold & & abs ( H [ 1 ] ) < = xyz_threshold & & abs ( H [ 2 ] ) < = xyz_threshold ) {
2019-10-25 10:44:41 +00:00
noclipped + + ;
2021-03-09 15:04:53 +00:00
return false ;
2019-10-25 10:44:41 +00:00
}
2021-03-09 15:04:53 +00:00
if ( clipped_by ( H , clipping_plane_sets ) ) {
drawcell_in_radar ( ) ;
return true ;
2019-10-25 10:44:41 +00:00
}
2021-03-09 15:04:53 +00:00
noclipped + + ;
2019-10-25 10:44:41 +00:00
return false ;
}
2020-01-02 15:51:32 +00:00
EX ld precise_width = .5 ;
2020-01-19 10:49:35 +00:00
int grid_depth = 0 ;
2020-01-25 23:48:56 +00:00
EX bool fat_edges = false ;
2020-07-27 16:49:04 +00:00
EX void gridline ( const shiftmatrix & V1 , const hyperpoint h1 , const shiftmatrix & V2 , const hyperpoint h2 , color_t col , int prec ) {
transmatrix U2 = unshift ( V2 , V1 . shift ) ;
2022-04-26 14:12:43 +00:00
int c1 = safe_classify_ideals ( h1 ) ;
int c2 = safe_classify_ideals ( h2 ) ;
ld d = ( c1 < = 0 | | c2 < = 0 ) ? 99 : hdist ( V1 . T * h1 , U2 * h2 ) ;
2020-01-25 23:48:56 +00:00
2020-01-29 17:18:51 +00:00
# if MAXMDIM >= 4
2023-06-10 09:05:57 +00:00
if ( GDIM = = 3 & & fat_edges ) {
if ( nonisotropic ) {
auto nV1 = V1 * rgpushxto0 ( h1 ) ;
hyperpoint U2 = inverse_shift ( nV1 , V2 * rgpushxto0 ( h2 ) ) * C0 ;
auto & p = cgi . get_pipe_noniso ( U2 , vid . linewidth , ePipeEnd : : ball ) ;
queuepoly ( nV1 , p , col ) ;
return ;
}
2020-07-27 16:49:04 +00:00
shiftmatrix T = V1 * rgpushxto0 ( h1 ) ;
transmatrix S = rspintox ( inverse_shift ( T , V2 ) * h2 ) ;
2022-07-14 09:28:24 +00:00
transmatrix U = rspintoc ( inverse_shift ( T * S , shiftless ( C0 ) ) , 2 , 1 ) ;
2023-06-10 09:05:57 +00:00
auto & p = queuepoly ( T * S * U , cgi . get_pipe_iso ( d , vid . linewidth , ePipeEnd : : ball ) , col ) ;
2020-04-15 14:21:30 +00:00
p . intester = xpush0 ( d / 2 ) ;
2020-01-25 23:48:56 +00:00
return ;
}
2020-01-29 17:18:51 +00:00
# endif
2020-01-25 23:48:56 +00:00
2020-01-19 10:49:35 +00:00
while ( d > precise_width & & d < 100 & & grid_depth < 10 ) {
2020-07-27 16:49:04 +00:00
if ( V1 . shift ! = V2 . shift | | ! eqmatrix ( V1 . T , V2 . T , 1e-6 ) ) { gridline ( V1 , h1 , V1 , inverse_shift ( V1 , V2 ) * h2 , col , prec ) ; return ; }
2022-04-26 14:12:43 +00:00
hyperpoint h ;
if ( c1 < = 0 & & c2 < = 0 ) {
h = closest_to_zero ( h1 , h2 ) ;
if ( safe_classify_ideals ( h ) < = 0 ) return ;
h = normalize ( h ) ;
}
else if ( c2 < = 0 ) {
dynamicval < int > dw ( grid_depth , 99 ) ;
for ( ld a = 0 ; a < ideal_limit ; a + = precise_width )
gridline ( V1 , towards_inf ( h1 , h2 , a ) , V1 , towards_inf ( h1 , h2 , a + precise_width ) , col , prec ) ;
return ;
}
else if ( c1 < = 0 ) {
dynamicval < int > dw ( grid_depth , 99 ) ;
for ( ld a = 0 ; a < ideal_limit ; a + = precise_width )
gridline ( V1 , towards_inf ( h2 , h1 , a ) , V1 , towards_inf ( h2 , h1 , a + precise_width ) , col , prec ) ;
return ;
}
else h = midz ( h1 , h2 ) ;
2020-01-19 10:49:35 +00:00
grid_depth + + ;
2020-01-02 15:51:32 +00:00
gridline ( V1 , h1 , V1 , h , col , prec ) ;
gridline ( V1 , h , V1 , h2 , col , prec ) ;
2020-01-19 10:49:35 +00:00
grid_depth - - ;
2020-01-02 15:51:32 +00:00
return ;
}
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2019-05-11 17:43:46 +00:00
if ( WDIM = = 2 & & GDIM = = 3 ) {
2019-05-26 16:04:02 +00:00
ld eps = cgi . human_height / 100 ;
queueline ( V1 * orthogonal_move ( h1 , cgi . FLOOR + eps ) , V2 * orthogonal_move ( h2 , cgi . FLOOR + eps ) , col , prec ) ;
queueline ( V1 * orthogonal_move ( h1 , cgi . WALL - eps ) , V2 * orthogonal_move ( h2 , cgi . WALL - eps ) , col , prec ) ;
2019-05-11 17:43:46 +00:00
}
else
2019-06-01 14:59:04 +00:00
# endif
2019-05-21 23:13:02 +00:00
queueline ( V1 * h1 , V2 * h2 , col , prec ) ;
2019-05-11 21:53:16 +00:00
}
2020-07-27 16:49:04 +00:00
EX void gridline ( const shiftmatrix & V , const hyperpoint h1 , const hyperpoint h2 , color_t col , int prec ) {
2019-05-21 23:13:02 +00:00
gridline ( V , h1 , V , h2 , col , prec ) ;
2019-05-11 17:43:46 +00:00
}
2021-07-12 18:54:16 +00:00
EX subcellshape & generate_subcellshape_if_needed ( cell * c , int id ) {
if ( isize ( cgi . subshapes ) < = id ) cgi . subshapes . resize ( id + 1 ) ;
auto & ss = cgi . subshapes [ id ] ;
if ( ! ss . faces . empty ( ) ) return ss ;
2022-12-08 18:38:06 +00:00
cell * c1 = mhybrid ? hybrid : : get_where ( c ) . first : c ;
2021-07-12 18:54:16 +00:00
2022-12-08 18:38:06 +00:00
if ( mhybrid | | WDIM = = 2 ) for ( int i = 0 ; i < c1 - > type ; i + + ) {
2021-07-12 18:54:16 +00:00
hyperpoint w ;
auto f = [ & ] {
/* mirror image of C0 in the axis h1-h2 */
hyperpoint h1 = get_corner_position ( c1 , i ) ;
hyperpoint h2 = get_corner_position ( c1 , i + 1 ) ;
transmatrix T = gpushxto0 ( h1 ) ;
2022-12-08 18:38:06 +00:00
T = lspintox ( T * h2 ) * T ;
2021-07-12 18:54:16 +00:00
w = T * C0 ;
w [ 1 ] = - w [ 1 ] ;
w = iso_inverse ( T ) * w ;
} ;
2022-12-08 18:38:06 +00:00
if ( mproduct ) PIU ( f ( ) ) ;
2021-07-12 18:54:16 +00:00
else f ( ) ;
ss . walltester . push_back ( w ) ;
}
2021-09-16 19:30:26 +00:00
2022-12-08 18:38:06 +00:00
if ( mhybrid | | WDIM = = 2 ) {
2021-09-16 19:30:26 +00:00
ss . walltester . push_back ( C0 ) ;
ss . walltester . push_back ( C0 ) ;
}
2021-07-12 18:54:16 +00:00
for ( int i = 0 ; i < c1 - > type ; i + + )
ss . faces . push_back ( { hybrid : : get_corner ( c1 , i , 0 , - 1 ) , hybrid : : get_corner ( c1 , i , 0 , + 1 ) , hybrid : : get_corner ( c1 , i , 1 , + 1 ) , hybrid : : get_corner ( c1 , i , 1 , - 1 ) } ) ;
2024-06-21 11:46:31 +00:00
ss . angle_of_zero = - PIU ( atan2 ( currentmap - > adj ( c1 , 0 ) * C0 ) ) ;
2021-07-12 18:54:16 +00:00
for ( int a : { 0 , 1 } ) {
vector < hyperpoint > l ;
int z = a ? 1 : - 1 ;
hyperpoint ctr = zpush0 ( z * cgi . plevel / 2 ) ;
for ( int i = 0 ; i < c1 - > type ; i + + )
2022-12-08 18:38:06 +00:00
if ( mproduct | | WDIM = = 2 )
2021-07-12 18:54:16 +00:00
l . push_back ( hybrid : : get_corner ( c1 , i , 0 , z ) ) ;
else {
l . push_back ( ctr ) ;
2022-10-11 18:00:13 +00:00
l . push_back ( hybrid : : get_corner ( c1 , i + 1 , 0 , z ) ) ;
l . push_back ( hybrid : : get_corner ( c1 , i , 1 , z ) ) ;
2021-07-12 18:54:16 +00:00
l . push_back ( ctr ) ;
l . push_back ( hybrid : : get_corner ( c1 , i , 1 , z ) ) ;
l . push_back ( hybrid : : get_corner ( c1 , i , 0 , z ) ) ;
}
if ( a = = 0 ) std : : reverse ( l . begin ( ) + 1 , l . end ( ) ) ;
2024-06-10 22:07:45 +00:00
if ( a = = 1 ) std : : rotate ( l . begin ( ) , l . begin ( ) + 3 , l . end ( ) ) ;
2021-07-12 18:54:16 +00:00
ss . faces . push_back ( l ) ;
}
ss . compute_hept ( ) ;
return ss ;
}
2021-07-09 08:09:31 +00:00
int hrmap : : wall_offset ( cell * c ) {
int id = currentmap - > full_shvid ( c ) ;
2022-12-08 18:38:06 +00:00
if ( WDIM = = 3 & & ! mhybrid & & ! reg3 : : in ( ) ) return 0 ;
2021-07-09 15:09:04 +00:00
2021-07-09 08:09:31 +00:00
if ( isize ( cgi . walloffsets ) < = id ) cgi . walloffsets . resize ( id + 1 , { - 1 , nullptr } ) ;
auto & wop = cgi . walloffsets [ id ] ;
int & wo = wop . first ;
if ( ! wop . second ) wop . second = c ;
if ( wo = = - 1 ) {
2021-07-12 18:54:16 +00:00
auto & ss = generate_subcellshape_if_needed ( c , id ) ;
2021-07-09 08:09:31 +00:00
wo = isize ( cgi . shWall3D ) ;
2021-07-12 18:54:16 +00:00
2021-07-09 08:09:31 +00:00
if ( ! cgi . wallstart . empty ( ) ) cgi . wallstart . pop_back ( ) ;
2021-07-12 18:54:16 +00:00
cgi . reserve_wall3d ( wo + isize ( ss . faces ) ) ;
2021-07-09 08:09:31 +00:00
2024-06-21 11:46:31 +00:00
rk_shape = & ss ;
2021-07-12 18:54:16 +00:00
for ( int i = 0 ; i < isize ( ss . faces ) ; i + + ) {
2024-06-10 22:06:16 +00:00
cgi . make_wall ( wo , i , ss . faces [ i ] ) ;
2021-07-12 18:54:16 +00:00
cgi . walltester [ wo + i ] = ss . walltester [ i ] ;
2021-07-09 08:09:31 +00:00
}
2021-07-12 18:54:16 +00:00
2021-07-09 08:09:31 +00:00
cgi . wallstart . push_back ( isize ( cgi . raywall ) ) ;
cgi . compute_cornerbonus ( ) ;
cgi . extra_vertices ( ) ;
}
return wo ;
2019-07-25 10:19:52 +00:00
}
2020-07-27 16:49:04 +00:00
EX void queue_transparent_wall ( const shiftmatrix & V , hpcshape & sh , color_t color ) {
2019-05-13 11:18:55 +00:00
auto & poly = queuepolyat ( V , sh , color , PPR : : TRANSPARENT_WALL ) ;
2020-07-27 16:49:04 +00:00
shiftpoint h = V * sh . intester ;
2019-07-28 09:07:21 +00:00
if ( in_perspective ( ) )
2019-05-13 11:18:55 +00:00
poly . subprio = int ( hdist0 ( h ) * 100000 ) ;
else {
hyperpoint h2 ;
applymodel ( h , h2 ) ;
poly . subprio = int ( h2 [ 2 ] * 100000 ) ;
}
}
2019-06-01 14:59:04 +00:00
# if MAXMDIM >= 4
2019-10-25 10:44:41 +00:00
EX int ceiling_category ( cell * c ) {
2019-05-20 11:40:56 +00:00
switch ( c - > land ) {
case laNone :
case laMemory :
case laMirrorWall2 :
case laMirrored :
case laMirrored2 :
case landtypes :
return 0 ;
/* starry levels */
case laIce :
case laCrossroads :
case laCrossroads2 :
case laCrossroads3 :
case laCrossroads4 :
case laCrossroads5 :
case laJungle :
case laGraveyard :
case laMotion :
case laRedRock :
case laZebra :
case laHunting :
case laEAir :
case laStorms :
case laMountain :
case laHaunted :
case laHauntedWall :
case laHauntedBorder :
case laWhirlwind :
case laBurial :
case laHalloween :
case laReptile :
case laVolcano :
case laBlizzard :
case laDual :
case laWestWall :
case laAsteroids :
return 1 ;
2019-06-01 17:26:02 +00:00
case laPower :
2019-05-20 11:40:56 +00:00
case laWineyard :
case laDesert :
case laAlchemist :
case laDryForest :
case laCaribbean :
case laMinefield :
case laOcean :
case laWhirlpool :
case laLivefjord :
case laEWater :
case laOceanWall :
case laWildWest :
case laOvergrown :
case laClearing :
case laRose :
case laWarpCoast :
case laWarpSea :
case laEndorian :
case laTortoise :
case laPrairie :
2019-06-01 15:01:04 +00:00
case laDragon :
2019-05-20 11:40:56 +00:00
case laSnakeNest :
case laDocks :
case laKraken :
case laBrownian :
2019-06-01 15:01:04 +00:00
case laHell :
2019-06-13 15:25:11 +00:00
case laVariant :
2020-05-15 23:06:47 +00:00
case laFrog :
case laWet :
2019-05-20 11:40:56 +00:00
return 2 ;
case laBarrier :
case laCaves :
case laMirror :
case laMirrorOld :
case laCocytus :
case laEmerald :
case laDeadCaves :
case laHive :
case laCamelot :
case laIvoryTower :
case laEFire :
case laEEarth :
case laElementalWall :
case laTrollheim :
case laDungeon :
case laBull :
case laCA :
case laMirrorWall :
case laTerracotta :
case laMercuryRiver :
case laMagnetic :
case laSwitch :
2020-05-15 23:06:47 +00:00
case laEclectic :
2019-05-20 11:40:56 +00:00
return 3 ;
2021-03-31 12:35:43 +00:00
case laCanvas :
if ( canvas_default_wall = = waInvisibleFloor ) return 0 ;
return 3 ;
2019-05-20 11:40:56 +00:00
2019-05-24 23:36:49 +00:00
case laPalace :
2019-05-25 01:37:27 +00:00
case laPrincessQuest :
2019-05-20 11:40:56 +00:00
default :
return 4 ;
2019-06-17 17:36:29 +00:00
case laRuins :
return 6 ;
case laTemple :
case laRlyeh :
return 7 ;
2019-05-20 11:40:56 +00:00
}
}
2019-11-03 13:19:11 +00:00
# endif
2020-07-27 16:49:04 +00:00
EX void set_detail_level ( const shiftmatrix & V ) {
2019-10-25 10:44:41 +00:00
ld dist0 = hdist0 ( tC0 ( V ) ) - 1e-6 ;
if ( vid . use_smart_range ) detaillevel = 2 ;
else if ( dist0 < vid . highdetail ) detaillevel = 2 ;
else if ( dist0 < vid . middetail ) detaillevel = 1 ;
else detaillevel = 0 ;
2019-08-09 23:56:00 +00:00
2019-10-25 10:44:41 +00:00
if ( ( cmode & sm : : NUMBER ) & & ( dialog : : editingDetail ( ) ) ) {
color_t col =
dist0 < vid . highdetail ? 0xFF80FF80 :
dist0 > = vid . middetail ? 0xFFFF8080 :
0XFFFFFF80 ;
queuepoly ( V , cgi . shHeptaMarker , darkena ( col & 0xFFFFFF , 0 , 0xFF ) ) ;
2019-06-01 15:01:04 +00:00
}
}
2019-10-25 10:44:41 +00:00
struct flashdata {
int t ;
int size ;
cell * where ;
double angle ;
double angle2 ;
int spd ; // 0 for flashes, >0 for particles
color_t color ;
2019-12-25 21:01:57 +00:00
string text ;
2019-10-25 10:44:41 +00:00
flashdata ( int _t , int _s , cell * _w , color_t col , int sped ) {
t = _t ; size = _s ; where = _w ; color = col ;
angle = rand ( ) % 1000 ; spd = sped ;
if ( GDIM = = 3 ) angle2 = acos ( ( rand ( ) % 1000 - 499.5 ) / 500 ) ;
2019-06-01 15:01:04 +00:00
}
2019-10-25 10:44:41 +00:00
} ;
2019-06-01 15:01:04 +00:00
2019-10-25 10:44:41 +00:00
vector < flashdata > flashes ;
2019-05-28 23:06:01 +00:00
2022-07-17 10:42:51 +00:00
auto ahgf = addHook ( hooks_removecells , 1 , [ ] ( ) {
eliminate_if ( flashes , [ ] ( flashdata & f ) { return is_cell_removed ( f . where ) ; } ) ;
} ) ;
2019-12-25 21:01:57 +00:00
EX void drawBubble ( cell * c , color_t col , string s , ld size ) {
2020-02-29 16:58:59 +00:00
LATE ( drawBubble ( c , col , s , size ) ; )
2019-12-26 08:40:28 +00:00
auto fd = flashdata ( ticks , 1000 , c , col , 0 ) ;
2019-12-25 21:01:57 +00:00
fd . text = s ;
fd . angle = size ;
flashes . push_back ( fd ) ;
}
2019-10-25 10:44:41 +00:00
EX void drawFlash ( cell * c ) {
flashes . push_back ( flashdata ( ticks , 1000 , c , iinf [ itOrbFlash ] . color , 0 ) ) ;
2019-06-17 17:36:29 +00:00
}
2019-10-25 10:44:41 +00:00
EX void drawBigFlash ( cell * c ) {
flashes . push_back ( flashdata ( ticks , 2000 , c , 0xC0FF00 , 0 ) ) ;
2019-05-20 11:40:56 +00:00
}
2019-10-25 10:44:41 +00:00
EX void drawParticleSpeed ( cell * c , color_t col , int speed ) {
2020-02-29 16:58:59 +00:00
LATE ( drawParticleSpeed ( c , col , speed ) ; )
2019-10-25 10:44:41 +00:00
if ( vid . particles & & ! confusingGeometry ( ) )
flashes . push_back ( flashdata ( ticks , rand ( ) % 16 , c , col , speed ) ) ;
}
EX void drawParticle ( cell * c , color_t col , int maxspeed IS ( 100 ) ) {
drawParticleSpeed ( c , col , 1 + rand ( ) % maxspeed ) ;
}
2020-02-29 19:20:08 +00:00
EX void drawDirectionalParticle ( cell * c , int dir , color_t col , int maxspeed IS ( 100 ) ) {
LATE ( drawDirectionalParticle ( c , dir , col , maxspeed ) ; )
if ( vid . particles & & ! confusingGeometry ( ) ) {
int speed = 1 + rand ( ) % maxspeed ;
auto fd = flashdata ( ticks , rand ( ) % 16 , c , col , speed ) ;
fd . angle = - atan2 ( tC0 ( currentmap - > adj ( c , dir ) ) ) ;
2022-11-12 21:38:45 +00:00
fd . angle + = TAU * ( rand ( ) % 100 - rand ( ) % 100 ) / 100 / c - > type ;
2020-02-29 19:20:08 +00:00
flashes . push_back ( fd ) ;
}
}
2019-10-25 10:44:41 +00:00
EX void drawParticles ( cell * c , color_t col , int qty , int maxspeed IS ( 100 ) ) {
if ( vid . particles )
while ( qty - - ) drawParticle ( c , col , maxspeed ) ;
}
EX void drawFireParticles ( cell * c , int qty , int maxspeed IS ( 100 ) ) {
if ( vid . particles )
for ( int i = 0 ; i < qty ; i + + )
drawParticle ( c , firegradient ( i / ( qty - 1. ) ) , maxspeed ) ;
}
EX void fallingFloorAnimation ( cell * c , eWall w IS ( waNone ) , eMonster m IS ( moNone ) ) {
if ( ! wmspatial ) return ;
2020-02-29 16:58:59 +00:00
LATE ( fallingFloorAnimation ( c , w , m ) ; )
2019-10-25 10:44:41 +00:00
fallanim & fa = fallanims [ c ] ;
fa . t_floor = ticks ;
fa . walltype = w ; fa . m = m ;
// drawParticles(c, darkenedby(linf[c->land].color, 1), 4, 50);
}
EX void fallingMonsterAnimation ( cell * c , eMonster m , int id IS ( multi : : cpid ) ) {
if ( ! mmspatial ) return ;
2020-02-29 16:58:59 +00:00
LATE ( fallingMonsterAnimation ( c , m , id ) ; )
2019-10-25 10:44:41 +00:00
fallanim & fa = fallanims [ c ] ;
fa . t_mon = ticks ;
fa . m = m ;
fa . pid = id ;
// drawParticles(c, darkenedby(linf[c->land].color, 1), 4, 50);
2019-05-16 15:41:37 +00:00
}
2017-03-23 10:53:57 +00:00
2019-10-25 10:44:41 +00:00
void celldrawer : : draw_fallanims ( ) {
2019-11-03 13:19:56 +00:00
poly_outline = OUTLINE_NONE ;
2019-10-25 10:44:41 +00:00
if ( fallanims . count ( c ) ) {
int q = isize ( ptds ) ;
int maxtime = euclid | | sphere ? 20000 : 1500 ;
fallanim & fa = fallanims [ c ] ;
bool erase = true ;
if ( fa . t_floor ) {
int t = ( ticks - fa . t_floor ) ;
if ( t < = maxtime ) {
erase = false ;
if ( GDIM = = 3 )
draw_shapevec ( c , V , qfi . fshape - > levels [ 0 ] , darkena ( fcol , fd , 0xFF ) , PPR : : WALL ) ;
else if ( fa . walltype = = waNone ) {
draw_qfi ( c , V , darkena ( fcol , fd , 0xFF ) , PPR : : FLOOR ) ;
2017-07-10 18:47:38 +00:00
}
2019-10-25 10:44:41 +00:00
else {
celldrawer ddalt ;
eWall w = c - > wall ; int p = c - > wparam ;
c - > wall = fa . walltype ; c - > wparam = fa . m ;
2019-11-25 19:05:52 +00:00
ddalt . c = c ;
2019-10-25 10:44:41 +00:00
ddalt . setcolors ( ) ;
int starcol = c - > wall = = waVinePlant ? 0x60C000 : ddalt . wcol ;
c - > wall = w ; c - > wparam = p ;
2022-12-06 00:04:26 +00:00
draw_qfi ( c , orthogonal_move_fol ( V , cgi . WALL ) , darkena ( starcol , fd , 0xFF ) , PPR : : WALL3 ) ;
queuepolyat ( orthogonal_move_fol ( V , cgi . WALL ) , cgi . shWall [ ct6 ] , darkena ( ddalt . wcol , 0 , 0xFF ) , PPR : : WALL3A ) ;
2019-10-25 10:44:41 +00:00
forCellIdEx ( c2 , i , c )
if ( placeSidewall ( c , i , SIDE_WALL , V , darkena ( ddalt . wcol , 1 , 0xFF ) ) ) break ;
2017-07-10 18:47:38 +00:00
}
2019-10-25 10:44:41 +00:00
pushdown ( c , q , V , t * t / 1000000. + t / 1000. , true , true ) ;
2017-07-10 18:47:38 +00:00
}
}
2019-10-25 10:44:41 +00:00
if ( fa . t_mon ) {
dynamicval < int > d ( multi : : cpid , fa . pid ) ;
int t = ( ticks - fa . t_mon ) ;
if ( t < = maxtime ) {
erase = false ;
c - > stuntime = 0 ;
2020-07-27 16:49:04 +00:00
shiftmatrix V2 = V ;
2019-10-25 10:44:41 +00:00
double footphase = t / 200.0 ;
applyAnimation ( c , V2 , footphase , LAYER_SMALL ) ;
drawMonsterType ( fa . m , c , V2 , minf [ fa . m ] . color , footphase , NOCOLOR ) ;
pushdown ( c , q , V2 , t * t / 1000000. + t / 1000. , true , true ) ;
2017-07-10 18:47:38 +00:00
}
}
2019-10-25 10:44:41 +00:00
if ( erase ) fallanims . erase ( c ) ;
}
}
2017-07-10 18:47:38 +00:00
2019-02-17 17:41:40 +00:00
# if CAP_QUEUE
2020-07-27 16:49:04 +00:00
EX void queuecircleat1 ( cell * c , const shiftmatrix & V , double rad , color_t col ) {
2019-05-08 16:33:08 +00:00
if ( WDIM = = 3 ) {
2019-02-26 10:57:50 +00:00
dynamicval < color_t > p ( poly_outline , col ) ;
2021-07-09 08:09:31 +00:00
int ofs = currentmap - > wall_offset ( c ) ;
2019-02-26 21:20:51 +00:00
for ( int i = 0 ; i < c - > type ; i + + ) {
2019-12-06 13:03:02 +00:00
queuepolyat ( V , cgi . shWireframe3D [ ofs + i ] , 0 , PPR : : SUPERLINE ) ;
2019-02-26 21:20:51 +00:00
}
2019-02-26 10:57:50 +00:00
return ;
}
2019-05-09 15:03:28 +00:00
if ( spatial_graphics | | GDIM = = 3 ) {
2022-12-06 00:04:26 +00:00
vector < hyperpoint > corners ( c - > type + 1 ) ;
for ( int i = 0 ; i < c - > type ; i + + ) corners [ i ] = get_corner_position ( c , i , 3 / rad ) ;
2019-05-09 15:03:28 +00:00
corners [ c - > type ] = corners [ 0 ] ;
for ( int i = 0 ; i < c - > type ; i + + ) {
2022-12-06 00:04:26 +00:00
queueline ( V * orthogonal_move_fol ( corners [ i ] , cgi . FLOOR ) , V * orthogonal_move_fol ( corners [ i + 1 ] , cgi . FLOOR ) , col , 2 , PPR : : SUPERLINE ) ;
queueline ( V * orthogonal_move_fol ( corners [ i ] , cgi . WALL ) , V * orthogonal_move_fol ( corners [ i + 1 ] , cgi . WALL ) , col , 2 , PPR : : SUPERLINE ) ;
queueline ( V * orthogonal_move_fol ( corners [ i ] , cgi . FLOOR ) , V * orthogonal_move_fol ( corners [ i ] , cgi . WALL ) , col , 2 , PPR : : SUPERLINE ) ;
2019-05-09 15:03:28 +00:00
}
return ;
}
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2018-11-17 18:24:02 +00:00
if ( vid . stereo_mode | | sphere ) {
2018-09-04 17:53:42 +00:00
dynamicval < color_t > p ( poly_outline , col ) ;
2019-12-06 13:03:02 +00:00
queuepolyat ( V * spintick ( 100 ) , cgi . shGem [ 1 ] , 0 , PPR : : LINE ) ;
2018-07-23 12:04:32 +00:00
return ;
}
2019-02-17 17:41:40 +00:00
# endif
2019-12-06 13:03:02 +00:00
queuecircle ( V , rad , col ) ;
2017-07-10 18:47:38 +00:00
if ( ! wmspatial ) return ;
if ( highwall ( c ) )
2022-12-06 00:04:26 +00:00
queuecircle ( orthogonal_move_fol ( V , cgi . WALL ) , rad , col ) ;
2017-07-10 18:47:38 +00:00
int sl ;
if ( ( sl = snakelevel ( c ) ) ) {
2022-12-06 00:04:26 +00:00
queuecircle ( orthogonal_move_fol ( V , cgi . SLEV [ sl ] ) , rad , col ) ;
2016-01-02 10:09:13 +00:00
}
2017-07-10 18:47:38 +00:00
if ( chasmgraph ( c ) )
2022-12-06 00:04:26 +00:00
queuecircle ( orthogonal_move_fol ( V , cgi . LAKE ) , rad , col ) ;
2016-08-26 09:58:03 +00:00
}
2019-12-06 13:03:02 +00:00
EX void queuecircleat ( cell * c , double rad , color_t col ) {
if ( ! c ) return ;
2021-07-18 21:37:56 +00:00
for ( const shiftmatrix & V : hr : : span_at ( current_display - > all_drawn_copies , c ) )
queuecircleat1 ( c , V , rad , col ) ;
2019-12-06 13:03:02 +00:00
}
# endif
2016-01-02 10:09:13 +00:00
2020-05-03 18:56:41 +00:00
# if ISMOBILE
2017-07-10 18:47:38 +00:00
# define MOBON (clicked)
# else
# define MOBON true
2016-01-02 10:09:13 +00:00
# endif
2019-08-09 20:07:03 +00:00
EX cell * forwardcell ( ) {
2020-11-19 17:20:06 +00:00
# if CAP_VR
2020-12-30 13:20:30 +00:00
if ( vrhr : : active ( ) ) {
2020-11-19 17:20:06 +00:00
return vrhr : : forward_cell ;
}
# endif
2019-02-26 11:28:54 +00:00
movedir md = vectodir ( move_destination_vec ( 6 ) ) ;
cellwalker xc = cwt + md . d + wstep ;
return xc . at ;
}
2020-09-15 17:13:51 +00:00
EX bool draw_centerover = true ;
2020-12-30 02:26:01 +00:00
EX bool should_draw_mouse_cursor ( ) {
if ( ! mousing | | inHighQual ) return false ;
if ( outofmap ( mouseh . h ) ) return false ;
if ( rug : : rugged & & ! rug : : renderonce ) return true ;
return false ;
}
2019-08-09 20:07:03 +00:00
EX void drawMarkers ( ) {
2017-03-23 10:53:57 +00:00
2017-10-15 22:43:23 +00:00
if ( ! ( cmode & sm : : NORMAL ) ) return ;
2020-12-30 02:26:01 +00:00
if ( should_draw_mouse_cursor ( ) ) {
2021-03-06 10:46:13 +00:00
for ( int i : player_indices ( ) ) {
2020-12-30 02:26:01 +00:00
queueline ( ggmatrix ( playerpos ( i ) ) * ( WDIM = = 2 & & GDIM = = 3 ? zpush0 ( cgi . WALL ) : C0 ) , mouseh , 0xFF00FF , grid_prec ( ) + 1 ) ;
}
}
2018-01-02 10:15:42 +00:00
2018-09-06 20:34:35 +00:00
callhooks ( hooks_markers ) ;
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2018-08-18 15:38:07 +00:00
viewmat ( ) ;
2019-02-17 17:41:40 +00:00
# endif
2018-08-18 15:38:07 +00:00
2019-02-17 17:41:40 +00:00
# if CAP_QUEUE
2018-01-02 10:15:42 +00:00
for ( cell * c1 : crush_now )
queuecircleat ( c1 , .8 , darkena ( minf [ moCrusher ] . color , 0 , 0xFF ) ) ;
2019-02-17 17:41:40 +00:00
# endif
2017-05-27 19:40:40 +00:00
2017-07-10 18:47:38 +00:00
if ( ! inHighQual ) {
2016-01-02 10:09:13 +00:00
2018-11-17 18:24:02 +00:00
bool ok = ! ISPANDORA | | mousepressed ;
2019-02-17 17:41:40 +00:00
ignore ( ok ) ;
2017-07-10 18:47:38 +00:00
2019-02-17 17:41:40 +00:00
# if CAP_QUEUE
2021-07-18 21:37:56 +00:00
if ( haveMount ( ) )
for ( const shiftmatrix & V : hr : : span_at ( current_display - > all_drawn_copies , dragon : : target ) ) {
2024-03-21 17:44:19 +00:00
queuestr ( V , mapfontscale / 100 , " X " ,
2021-07-18 21:37:56 +00:00
gradient ( 0 , iinf [ itOrbDomination ] . color , - 1 , sintick ( dragon : : whichturn = = turncount ? 75 : 150 ) , 1 ) ) ;
}
2019-02-17 17:41:40 +00:00
# endif
2016-01-02 10:09:13 +00:00
2017-07-10 18:47:38 +00:00
/* for(int i=0; i<12; i++) if(c->type == 5 && c->master == &dodecahedron[i])
2019-12-26 22:38:28 +00:00
queuestr ( xc , yc , sc , 4 * vid . fsize , s0 + ( ' A ' + i ) , iinf [ itOrbDomination ] . color ) ; */
2017-05-27 19:40:40 +00:00
2018-11-17 18:24:02 +00:00
if ( 1 ) {
using namespace yendor ;
if ( yii < isize ( yi ) & & ! yi [ yii ] . found ) {
cell * keycell = NULL ;
2024-05-08 18:49:16 +00:00
int last_i = 0 ;
for ( int i = 0 ; i < YDIST ; i + + )
2018-11-17 18:24:02 +00:00
if ( yi [ yii ] . path [ i ] - > cpdist < = get_sightrange_ambush ( ) ) {
2024-05-08 18:49:16 +00:00
keycell = yi [ yii ] . path [ i ] ; last_i = i ;
2018-11-17 18:24:02 +00:00
}
if ( keycell ) {
2024-05-08 18:49:16 +00:00
for ( int i = last_i + 1 ; i < YDIST ; i + + ) {
2018-11-17 18:24:02 +00:00
cell * c = yi [ yii ] . path [ i ] ;
if ( inscreenrange ( c ) )
keycell = c ;
}
2020-07-27 16:49:04 +00:00
shiftpoint H = tC0 ( ggmatrix ( keycell ) ) ;
2019-02-17 17:41:40 +00:00
# if CAP_QUEUE
2024-03-24 10:14:05 +00:00
queue_goal_text ( H , 2 , " X " , 0x10101 * int ( 128 + 100 * sintick ( 150 ) ) ) ;
2019-08-02 20:09:45 +00:00
int cd = celldistance ( yi [ yii ] . key ( ) , cwt . at ) ;
if ( cd = = DISTANCE_UNKNOWN ) for ( int i2 = 0 ; i2 < YDIST ; i2 + + ) {
int cd2 = celldistance ( cwt . at , yi [ yii ] . path [ i2 ] ) ;
if ( cd2 ! = DISTANCE_UNKNOWN ) {
cd = cd2 + ( YDIST - 1 - i2 ) ;
}
}
2024-03-24 10:14:05 +00:00
queue_goal_text ( H , 1 , its ( cd ) , 0x10101 * int ( 128 - 100 * sintick ( 150 ) ) ) ;
2019-02-17 17:41:40 +00:00
# endif
2018-11-17 18:24:02 +00:00
addauraspecial ( H , iinf [ itOrbYendor ] . color , 0 ) ;
2024-05-09 19:07:44 +00:00
addradar ( ggmatrix ( keycell ) , ' X ' , iinf [ itKey ] . color , kind_outline ( itKey ) , true ) ;
2017-08-06 12:50:16 +00:00
}
2017-05-27 19:40:40 +00:00
}
2017-07-10 18:47:38 +00:00
}
2018-11-17 18:24:02 +00:00
2018-11-17 18:30:50 +00:00
# if CAP_RACING
2018-11-24 14:35:02 +00:00
racing : : markers ( ) ;
2018-11-17 18:30:50 +00:00
# endif
2019-02-17 17:41:40 +00:00
# if CAP_QUEUE
2019-05-08 16:33:08 +00:00
if ( lmouseover & & vid . drawmousecircle & & ok & & DEFAULTCONTROL & & MOBON & & WDIM = = 2 ) {
2020-12-29 03:42:09 +00:00
cell * at = lmouseover ;
# if CAP_VR
2020-12-30 13:20:30 +00:00
if ( vrhr : : active ( ) & & vrhr : : forward_cell )
2020-12-29 03:42:09 +00:00
at = vrhr : : forward_cell ;
# endif
queuecircleat ( at , .8 , darkena ( lmouseover - > cpdist > 1 ? 0x00FFFF : 0xFF0000 , 0 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
}
2017-05-27 19:40:40 +00:00
2019-12-26 09:29:41 +00:00
if ( global_pushto & & vid . drawmousecircle & & ok & & DEFAULTCONTROL & & MOBON & & WDIM = = 2 ) {
queuecircleat ( global_pushto , .6 , darkena ( 0xFFD500 , 0 , 0xFF ) ) ;
2017-07-10 18:47:38 +00:00
}
2019-02-17 17:41:40 +00:00
# endif
2017-05-27 19:40:40 +00:00
2019-02-17 17:41:40 +00:00
# if CAP_SDLJOY && CAP_QUEUE
2019-05-08 16:33:08 +00:00
if ( joydir . d > = 0 & & WDIM = = 2 )
2018-09-10 15:49:51 +00:00
queuecircleat ( cwt . at - > modmove ( joydir . d + cwt . spin ) , .78 - .02 * sintick ( 199 ) ,
2017-07-10 18:47:38 +00:00
darkena ( 0x00FF00 , 0 , 0xFF ) ) ;
2017-07-22 23:33:27 +00:00
# endif
2016-01-02 10:09:13 +00:00
2017-07-22 23:33:27 +00:00
bool m = true ;
2019-02-17 17:41:40 +00:00
ignore ( m ) ;
2017-07-22 23:33:27 +00:00
# if CAP_MODEL
m = netgen : : mode = = 0 ;
# endif
2019-02-17 17:41:40 +00:00
# if CAP_QUEUE
2020-09-15 17:13:51 +00:00
if ( centerover & & ! playermoved & & m & & ! anims : : any_animation ( ) & & WDIM = = 2 & & draw_centerover )
2019-11-13 23:26:50 +00:00
queuecircleat ( centerover , .70 - .06 * sintick ( 200 ) ,
2018-09-10 15:58:36 +00:00
darkena ( int ( 175 + 25 * sintick ( 200 ) ) , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
2017-07-10 18:47:38 +00:00
if ( multi : : players > 1 | | multi : : alwaysuse ) for ( int i = 0 ; i < numplayers ( ) ; i + + ) {
multi : : cpid = i ;
if ( multi : : players = = 1 ) multi : : player [ i ] = cwt ;
cell * ctgt = multi : : multiPlayerTarget ( i ) ;
2018-09-10 15:49:51 +00:00
queuecircleat ( ctgt , .40 - .06 * sintick ( 200 , i / numplayers ( ) ) , getcs ( ) . uicolor ) ;
2017-07-10 18:47:38 +00:00
}
2019-02-17 17:41:40 +00:00
# endif
2016-01-02 10:09:13 +00:00
2017-07-10 18:47:38 +00:00
// process mouse
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2020-05-15 13:28:59 +00:00
if ( ( vid . axes > = 4 | | ( vid . axes = = 1 & & ! mousing ) ) & & ! shmup : : on & & GDIM = = 2 ) {
2017-07-10 18:47:38 +00:00
if ( multi : : players = = 1 ) {
2020-07-27 16:49:04 +00:00
forCellIdAll ( c2 , d , cwt . at ) if ( gmatrix . count ( cwt . at ) ) draw_movement_arrows ( c2 , unshift ( gmatrix [ cwt . at ] ) * currentmap - > adj ( cwt . at , d ) , d ) ;
2017-07-10 18:47:38 +00:00
}
else if ( multi : : players > 1 ) for ( int p = 0 ; p < multi : : players ; p + + ) {
2020-05-15 13:28:59 +00:00
if ( multi : : playerActive ( p ) & & ( vid . axes > = 4 | | ! drawstaratvec ( multi : : mdx [ p ] , multi : : mdy [ p ] ) ) )
2019-12-06 13:03:02 +00:00
forCellIdAll ( c2 , d , multi : : player [ p ] . at ) if ( gmatrix . count ( cwt . at ) ) {
2017-07-10 18:47:38 +00:00
multi : : cpid = p ;
2020-07-27 16:49:04 +00:00
dynamicval < shiftmatrix > ttm ( cwtV , multi : : whereis [ p ] ) ;
2017-07-10 18:47:38 +00:00
dynamicval < cellwalker > tcw ( cwt , multi : : player [ p ] ) ;
2020-07-27 16:49:04 +00:00
draw_movement_arrows ( c2 , unshift ( gmatrix [ cwt . at ] ) * currentmap - > adj ( cwt . at , d ) , d ) ;
2017-07-10 18:47:38 +00:00
}
2017-03-23 10:53:57 +00:00
}
}
2019-02-26 10:57:50 +00:00
2019-06-25 08:30:31 +00:00
if ( GDIM = = 3 & & ! inHighQual & & ! shmup : : on & & vid . axes3 & & playermoved ) {
2019-02-26 13:56:07 +00:00
cell * c = forwardcell ( ) ;
2020-11-19 17:20:06 +00:00
if ( c ) queuecircleat ( c , .8 , getcs ( ) . uicolor ) ;
2019-02-26 10:57:50 +00:00
}
2019-03-10 17:38:30 +00:00
2019-02-17 17:41:40 +00:00
# endif
2019-06-24 20:28:20 +00:00
2022-12-08 18:38:06 +00:00
if ( mhybrid & & ! shmup : : on ) {
2019-08-19 08:55:02 +00:00
using namespace sword ;
int & ang = sword : : dir [ multi : : cpid ] . angle ;
ang % = sword_angles ;
int adj = 1 - ( ( sword_angles / cwt . at - > type ) & 1 ) ;
2021-07-18 21:37:56 +00:00
if ( items [ itOrbSword ] )
for ( const shiftmatrix & V : hr : : span_at ( current_display - > all_drawn_copies , cwt . at ) )
queuestr ( V * spin ( M_PI + ( - adj - 2 * ang ) * M_PI / sword_angles ) * xpush0 ( cgi . sword_size ) , vid . fsize * 2 , " + " , iinf [ itOrbSword ] . color ) ;
if ( items [ itOrbSword2 ] )
for ( const shiftmatrix & V : hr : : span_at ( current_display - > all_drawn_copies , cwt . at ) )
queuestr ( V * spin ( ( - adj - 2 * ang ) * M_PI / sword_angles ) * xpush0 ( - cgi . sword_size ) , vid . fsize * 2 , " + " , iinf [ itOrbSword2 ] . color ) ;
2019-08-19 08:55:02 +00:00
}
if ( SWORDDIM = = 3 & & ! shmup : : on ) {
2021-07-18 21:37:56 +00:00
if ( items [ itOrbSword ] )
for ( const shiftmatrix & V : hr : : span_at ( current_display - > all_drawn_copies , cwt . at ) )
queuestr ( V * sword : : dir [ multi : : cpid ] . T * xpush0 ( cgi . sword_size ) , vid . fsize * 2 , " + " , iinf [ itOrbSword ] . color ) ;
if ( items [ itOrbSword2 ] )
for ( const shiftmatrix & V : hr : : span_at ( current_display - > all_drawn_copies , cwt . at ) )
queuestr ( V * sword : : dir [ multi : : cpid ] . T * xpush0 ( - cgi . sword_size ) , vid . fsize * 2 , " + " , iinf [ itOrbSword2 ] . color ) ;
2019-06-24 20:28:20 +00:00
}
2016-08-26 09:58:03 +00:00
}
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
monsterToSummon = moNone ;
orbToTarget = itNone ;
2016-08-26 09:58:03 +00:00
2017-07-12 17:50:39 +00:00
if ( mouseover & & targetclick ) {
2019-09-06 06:17:38 +00:00
multi : : cpid = 0 ;
2017-07-10 18:47:38 +00:00
orbToTarget = targetRangedOrb ( mouseover , roCheck ) ;
2019-02-17 17:41:40 +00:00
# if CAP_QUEUE
2023-10-29 07:00:19 +00:00
if ( bow : : fire_mode ) {
queuestr ( mousex , mousey , 0 , vid . fsize , " + " , getcs ( ) . bowcolor > > 8 ) ;
orbToTarget = itNone ;
}
else if ( orbToTarget = = itOrbSummon ) {
2017-07-10 18:47:38 +00:00
monsterToSummon = summonedAt ( mouseover ) ;
2019-12-26 22:38:28 +00:00
queuestr ( mousex , mousey , 0 , vid . fsize , s0 + minf [ monsterToSummon ] . glyph , minf [ monsterToSummon ] . color ) ;
2017-07-10 18:47:38 +00:00
queuecircleat ( mouseover , 0.6 , darkena ( minf [ monsterToSummon ] . color , 0 , 0xFF ) ) ;
}
else if ( orbToTarget ) {
2019-12-26 22:38:28 +00:00
queuestr ( mousex , mousey , 0 , vid . fsize , " @ " , iinf [ orbToTarget ] . color ) ;
2017-07-10 18:47:38 +00:00
queuecircleat ( mouseover , 0.6 , darkena ( iinf [ orbToTarget ] . color , 0 , 0xFF ) ) ;
}
2019-02-17 17:41:40 +00:00
# endif
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2017-07-10 18:47:38 +00:00
if ( orbToTarget & & rand ( ) % 200 < ticks - lastt ) {
if ( orbToTarget = = itOrbDragon )
drawFireParticles ( mouseover , 2 ) ;
else if ( orbToTarget = = itOrbSummon ) {
drawParticles ( mouseover , iinf [ orbToTarget ] . color , 1 ) ;
drawParticles ( mouseover , minf [ monsterToSummon ] . color , 1 ) ;
}
else {
drawParticles ( mouseover , iinf [ orbToTarget ] . color , 2 ) ;
}
}
2019-01-03 02:20:20 +00:00
if ( items [ itOrbAir ] & & mouseover - > cpdist > 1 ) {
cell * c1 = mouseover ;
2024-03-19 17:52:16 +00:00
int dir = c1 - > monst = = moVoidBeast ? - 1 : 1 ;
2019-01-03 02:20:20 +00:00
for ( int it = 0 ; it < 10 ; it + + ) {
int di ;
2024-03-19 17:52:16 +00:00
auto mib = blowoff_destination_dir ( c1 , di , dir ) ;
2019-11-22 17:48:51 +00:00
if ( ! mib . proper ( ) ) break ;
auto & c2 = mib . t ;
2020-07-27 16:49:04 +00:00
shiftmatrix T1 = ggmatrix ( c1 ) ;
shiftmatrix T2 = ggmatrix ( c2 ) ;
2022-12-08 18:38:06 +00:00
shiftmatrix T = T1 * lrspintox ( inverse_shift ( T1 , T2 * C0 ) ) * xpush ( hdist ( T1 * C0 , T2 * C0 ) * fractick ( 50 , 0 ) ) ;
2019-01-03 02:20:20 +00:00
color_t aircol = ( orbToTarget = = itOrbAir ? 0x8080FF40 : 0x8080FF20 ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( T , cgi . shDisk , aircol ) ;
2019-01-03 02:20:20 +00:00
c1 = c2 ;
}
}
2019-02-17 17:41:40 +00:00
# endif
2017-07-10 18:47:38 +00:00
}
}
2016-08-26 09:58:03 +00:00
2017-07-10 18:47:38 +00:00
void drawFlashes ( ) {
2019-02-17 18:39:44 +00:00
# if CAP_QUEUE
2018-06-22 12:47:24 +00:00
for ( int k = 0 ; k < isize ( flashes ) ; k + + ) {
2019-12-06 13:03:02 +00:00
bool kill = true ;
2017-07-10 18:47:38 +00:00
flashdata & f = flashes [ k ] ;
2019-12-08 18:33:17 +00:00
bool copies = false ;
2021-07-18 21:37:56 +00:00
for ( const shiftmatrix & V : hr : : span_at ( current_display - > all_drawn_copies , f . where ) ) {
2019-12-08 18:33:17 +00:00
copies = true ;
2021-07-18 21:37:56 +00:00
draw_flash ( f , V , kill ) ;
}
forCellIdEx ( c2 , id , f . where ) {
if ( ! copies ) {
for ( const shiftmatrix & V : hr : : span_at ( current_display - > all_drawn_copies , c2 ) ) {
draw_flash ( f , V * currentmap - > iadj ( f . where , id ) , kill ) ;
copies = true ;
}
}
2017-07-10 18:47:38 +00:00
}
2020-04-06 07:48:34 +00:00
if ( f . t > ticks - 800 & & ! copies ) {
kill = false ;
}
2017-07-10 18:47:38 +00:00
if ( kill ) {
2018-06-22 12:47:24 +00:00
f = flashes [ isize ( flashes ) - 1 ] ;
2017-07-10 18:47:38 +00:00
flashes . pop_back ( ) ; k - - ;
}
2016-08-26 09:58:03 +00:00
}
2019-02-17 17:41:40 +00:00
# endif
2017-07-10 18:47:38 +00:00
}
2015-08-08 13:57:52 +00:00
2019-12-08 18:33:17 +00:00
# if CAP_QUEUE
2020-01-02 15:54:28 +00:00
always_false static_bubbles ;
2020-07-27 16:49:04 +00:00
EX void draw_flash ( struct flashdata & f , const shiftmatrix & V , bool & kill ) {
2019-12-08 18:33:17 +00:00
int tim = ticks - f . t ;
2020-01-02 15:54:28 +00:00
2019-12-08 18:33:17 +00:00
if ( tim < = f . size & & ! f . spd ) kill = false ;
2019-12-25 21:01:57 +00:00
if ( f . text ! = " " ) {
2020-01-02 15:54:28 +00:00
if ( static_bubbles ) {
tim = 0 ; kill = false ;
}
2019-12-26 22:32:27 +00:00
color_t col = f . color ;
dynamicval < color_t > p ( poly_outline , poly_outline ) ;
int r = 2 ;
apply_neon ( col , r ) ;
2019-12-25 22:10:36 +00:00
if ( GDIM = = 3 | | sphere )
2024-03-21 17:44:19 +00:00
queuestr ( V , ( 1 - tim * 1. / f . size ) * f . angle * mapfontscale / 100 , f . text , col , r ) ;
2019-12-25 22:10:36 +00:00
else if ( ! kill ) {
2020-07-27 16:49:04 +00:00
shiftpoint h = tC0 ( V ) ;
2019-12-25 22:10:36 +00:00
if ( hdist0 ( h ) > .1 ) {
2020-07-27 16:49:04 +00:00
transmatrix V2 = rspintox ( h . h ) * xpush ( hdist0 ( h . h ) * ( 1 / ( 1 - tim * 1. / f . size ) ) ) ;
2024-03-21 17:44:19 +00:00
queuestr ( shiftless ( V2 , h . shift ) , f . angle * mapfontscale / 100 , f . text , col , r ) ;
2019-12-25 22:10:36 +00:00
}
}
2020-01-02 15:54:28 +00:00
if ( static_bubbles ) {
ld rad [ 25 ] ;
for ( int a = 0 ; a < 24 ; a + + ) rad [ a ] = ( 0.5 + randd ( ) * .3 + 0.5 * ( a & 1 ) ) / ( 2.8 + celldistance ( f . where , cwt . at ) * .2 ) ;
rad [ 24 ] = rad [ 0 ] ;
2022-11-12 21:38:45 +00:00
for ( int a = 0 ; a < 24 ; a + + ) curvepoint ( xspinpush0 ( TAU * a / 24 , rad [ a ] ) ) ;
2020-07-27 16:49:04 +00:00
queuecurve ( V , 0xFF , 0xFF0000FF , PPR : : SUPERLINE ) ;
2020-01-02 15:54:28 +00:00
}
2019-12-25 21:01:57 +00:00
}
else if ( f . spd ) {
2019-12-08 18:33:17 +00:00
# if CAP_SHAPES
if ( tim < = 300 ) kill = false ;
int partcol = darkena ( f . color , 0 , GDIM = = 3 ? 255 : max ( 255 - tim * 255 / 300 , 0 ) ) ;
poly_outline = OUTLINE_DEFAULT ;
ld t = f . spd * tim * cgi . scalefactor / 50000. ;
2020-07-27 16:49:04 +00:00
shiftmatrix T =
2019-12-08 18:33:17 +00:00
GDIM = = 2 ? V * spin ( f . angle ) * xpush ( t ) :
V * cspin ( 0 , 1 , f . angle ) * cspin ( 0 , 2 , f . angle2 ) * cpush ( 2 , t ) ;
queuepoly ( T , cgi . shParticle [ f . size ] , partcol ) ;
# endif
}
else if ( f . size = = 1000 ) {
for ( int u = 0 ; u < = tim ; u + + ) {
if ( ( u - tim ) % 50 ) continue ;
if ( u < tim - 150 ) continue ;
ld rad = u * 3 / 1000. ;
rad = rad * ( 5 - rad ) / 2 ;
rad * = cgi . hexf ;
int flashcol = f . color ;
if ( u > 500 ) flashcol = gradient ( flashcol , 0 , 500 , u , 1100 ) ;
flashcol = darkena ( flashcol , 0 , 0xFF ) ;
# if MAXMDIM >= 4
if ( GDIM = = 3 )
2023-02-04 00:58:13 +00:00
queueball ( V * lzpush ( cgi . GROIN1 ) , rad , flashcol , itDiamond ) ;
2019-12-08 18:33:17 +00:00
else
# endif
{
2022-11-12 21:38:45 +00:00
PRING ( a ) curvepoint ( xspinpush0 ( a * cgi . S_step , rad ) ) ;
2020-07-27 16:49:04 +00:00
queuecurve ( V , flashcol , 0x8080808 , PPR : : LINE ) ;
2019-12-08 18:33:17 +00:00
}
}
}
else if ( f . size = = 2000 ) {
for ( int u = 0 ; u < = tim ; u + + ) {
if ( ( u - tim ) % 50 ) continue ;
if ( u < tim - 250 ) continue ;
ld rad = u * 3 / 2000. ;
rad = rad * ( 5 - rad ) * 1.25 ;
rad * = cgi . hexf ;
int flashcol = f . color ;
if ( u > 1000 ) flashcol = gradient ( flashcol , 0 , 1000 , u , 2200 ) ;
flashcol = darkena ( flashcol , 0 , 0xFF ) ;
# if MAXMDIM >= 4
if ( GDIM = = 3 )
2023-02-04 00:58:13 +00:00
queueball ( V * lzpush ( cgi . GROIN1 ) , rad , flashcol , itRuby ) ;
2019-12-08 18:33:17 +00:00
else
# endif
{
2022-11-12 21:38:45 +00:00
PRING ( a ) curvepoint ( xspinpush0 ( a * cgi . S_step , rad ) ) ;
2020-07-27 16:49:04 +00:00
queuecurve ( V , flashcol , 0x8080808 , PPR : : LINE ) ;
2019-12-08 18:33:17 +00:00
}
}
}
}
# endif
2019-08-09 20:07:03 +00:00
EX bool allowIncreasedSight ( ) {
2018-04-18 18:53:52 +00:00
if ( cheater | | autocheat ) return true ;
2017-08-18 00:58:55 +00:00
if ( peace : : on ) return true ;
# if CAP_TOUR
if ( tour : : on ) return true ;
# endif
if ( randomPatternsMode ) return true ;
2019-01-11 14:01:36 +00:00
if ( racing : : on ) return true ;
2020-03-22 11:02:58 +00:00
if ( quotient | | ! hyperbolic | | arcm : : in ( ) | | arb : : in ( ) ) return true ;
2019-05-08 16:33:08 +00:00
if ( WDIM = = 3 ) return true ;
2020-04-02 10:56:26 +00:00
if ( ! canmove ) return true ;
2017-08-18 00:58:55 +00:00
return false ;
}
2019-08-09 20:07:03 +00:00
EX bool allowChangeRange ( ) {
2018-04-11 13:49:49 +00:00
if ( cheater | | peace : : on | | randomPatternsMode ) return true ;
# if CAP_TOUR
if ( tour : : on ) return true ;
# endif
2019-01-11 14:01:36 +00:00
if ( racing : : on ) return true ;
2020-03-22 11:02:58 +00:00
if ( arcm : : in ( ) | | arb : : in ( ) ) return true ;
2019-05-08 16:33:08 +00:00
if ( WDIM = = 3 ) return true ;
2018-04-11 13:49:49 +00:00
return false ;
}
2019-08-09 20:07:03 +00:00
EX purehookset hooks_drawmap ;
2017-12-01 23:23:15 +00:00
2019-08-09 20:07:03 +00:00
EX transmatrix actual_view_transform ;
2019-04-29 01:34:21 +00:00
2019-08-20 16:02:03 +00:00
EX ld wall_radar ( cell * c , transmatrix T , transmatrix LPe , ld max ) {
2019-08-25 18:45:27 +00:00
if ( ! in_perspective ( ) | | ! vid . use_wall_radar ) return max ;
2019-08-26 07:06:39 +00:00
transmatrix ori ;
2022-12-08 18:38:06 +00:00
if ( gproduct ) ori = ortho_inverse ( LPe ) ;
2019-05-11 21:52:18 +00:00
ld step = max / 20 ;
2019-04-29 01:34:21 +00:00
ld fixed_yshift = 0 ;
for ( int i = 0 ; i < 20 ; i + + ) {
2022-12-17 10:47:10 +00:00
T = shift_object ( T , ori , ztangent ( - step ) , shift_method ( smaWallRadar ) ) ;
2019-11-14 18:33:55 +00:00
virtualRebase ( c , T ) ;
2019-04-29 01:34:21 +00:00
color_t col ;
2019-05-26 16:04:02 +00:00
if ( isWall3 ( c , col ) | | ( WDIM = = 2 & & GDIM = = 3 & & tC0 ( T ) [ 2 ] > cgi . FLOOR ) ) {
2022-12-17 10:47:10 +00:00
T = shift_object ( T , ori , ztangent ( step ) , shift_method ( smaWallRadar ) ) ;
2019-04-29 01:34:21 +00:00
step / = 2 ; i = 17 ;
if ( step < 1e-3 ) break ;
}
else fixed_yshift + = step ;
}
return fixed_yshift ;
}
2022-10-11 18:00:33 +00:00
/** if this is set to ON, just transform non-isotropic spaces according to View, and apply NLP to view */
EX bool nonisotropic_weird_transforms ;
2023-02-05 09:31:58 +00:00
EX void decide_lpu ( ) {
2022-12-25 11:14:36 +00:00
nisot : : local_perspective_used = gproduct ;
2023-02-05 09:31:58 +00:00
}
EX void make_actual_view ( ) {
decide_lpu ( ) ;
2022-12-25 11:14:36 +00:00
if ( ! nisot : : local_perspective_used ) NLP = Id ;
2017-12-16 08:03:50 +00:00
sphereflip = Id ;
2022-12-04 13:48:12 +00:00
sphere_flipped = flip_sphere ( ) ;
if ( sphere_flipped ) sphereflip [ LDIM ] [ LDIM ] = - 1 ;
2019-05-11 21:52:18 +00:00
actual_view_transform = sphereflip ;
if ( vid . yshift & & WDIM = = 2 ) actual_view_transform = ypush ( vid . yshift ) * actual_view_transform ;
2019-05-10 01:16:40 +00:00
# if MAXMDIM >= 4
2019-05-11 21:52:18 +00:00
if ( GDIM = = 3 ) {
2019-05-29 14:27:24 +00:00
ld max = WDIM = = 2 ? vid . camera : vid . yshift ;
2019-08-20 16:02:03 +00:00
if ( max ) {
2020-09-16 03:57:05 +00:00
transmatrix Start = view_inverse ( actual_view_transform * View ) ;
2019-11-14 16:20:55 +00:00
ld d = wall_radar ( centerover , Start , NLP , max ) ;
2020-09-16 03:57:05 +00:00
actual_view_transform = get_shift_view_of ( ztangent ( d ) , actual_view_transform * View ) * view_inverse ( View ) ;
2019-08-20 16:02:03 +00:00
}
2022-12-17 19:18:49 +00:00
hyperpoint h = tC0 ( view_inverse ( actual_view_transform * View ) ) ;
2023-01-07 10:45:40 +00:00
2023-01-26 23:27:10 +00:00
camera_level = cgi . emb - > get_logical_z ( h ) ;
2022-12-17 19:18:49 +00:00
2022-12-17 17:40:33 +00:00
camera_sign = cgi . FLOOR > cgi . WALL ;
2019-05-11 21:52:18 +00:00
}
2022-12-25 11:14:36 +00:00
if ( ( nonisotropic | | ( hyperbolic & & bt : : in ( ) & & ! nisot : : geodesic_movement ) ) & & ! nonisotropic_weird_transforms ) {
2019-08-03 09:36:38 +00:00
transmatrix T = actual_view_transform * View ;
2020-09-16 03:57:05 +00:00
transmatrix T2 = eupush ( tC0 ( view_inverse ( T ) ) ) ;
2019-11-14 16:20:55 +00:00
NLP = T * T2 ;
2020-09-16 03:57:05 +00:00
actual_view_transform = ortho_inverse ( NLP ) * actual_view_transform ;
2022-12-25 11:14:36 +00:00
nisot : : local_perspective_used = true ;
2019-08-03 09:36:38 +00:00
}
2019-05-10 01:16:40 +00:00
# endif
2023-01-29 15:09:00 +00:00
cgi . emb - > set_radar_transform ( ) ;
2019-10-12 11:14:38 +00:00
Viewbase = View ;
2019-08-20 14:09:16 +00:00
}
2020-07-27 16:49:04 +00:00
EX shiftmatrix cview ( ld base_shift IS ( 0 ) ) {
return shiftless ( actual_view_transform * View , base_shift ) ;
2017-12-16 08:03:50 +00:00
}
2021-09-17 23:39:30 +00:00
EX int point_direction ;
2022-10-27 08:33:47 +00:00
EX int through_wall ( cell * c , hyperpoint at ) {
2022-10-27 07:45:03 +00:00
ld dist = hdist0 ( at ) ;
int nei = - 1 ;
2022-10-27 08:33:47 +00:00
for ( int i = 0 ; i < c - > type ; i + + ) {
ld dist1 = hdist0 ( currentmap - > ray_iadj ( c , i ) * at ) ;
2022-10-27 07:45:03 +00:00
if ( dist1 < dist ) nei = i , dist = dist1 ;
}
return nei ;
}
2019-08-09 20:07:03 +00:00
EX void precise_mouseover ( ) {
2022-10-27 07:45:03 +00:00
if ( WDIM = = 3 & & ( cmode & ( sm : : EDIT_INSIDE_WALLS | sm : : EDIT_BEFORE_WALLS ) ) ) {
transmatrix T = view_inverse ( View ) ;
transmatrix ori = Id ;
2022-12-08 18:38:06 +00:00
if ( gproduct ) ori = ortho_inverse ( NLP ) ;
2022-10-27 07:45:03 +00:00
ld step = 0.2 ;
cell * c = centerover ;
for ( int i = 0 ; i < 100 ; i + + ) {
2022-12-17 10:35:28 +00:00
apply_shift_object ( T , ori , ztangent ( step ) ) ;
2022-10-27 08:33:47 +00:00
int pd = through_wall ( c , T * C0 ) ;
2022-10-27 07:45:03 +00:00
if ( pd ! = - 1 ) {
color_t col ;
cell * c1 = c - > cmove ( pd ) ;
if ( isWall3 ( c1 , col ) ) {
mouseover = c ;
mouseover2 = c1 ;
point_direction = pd ;
if ( cmode & sm : : EDIT_INSIDE_WALLS ) {
swap ( mouseover , mouseover2 ) ;
2022-10-27 08:12:14 +00:00
}
else {
2022-10-27 07:45:03 +00:00
point_direction = c - > c . spin ( pd ) ;
}
return ;
}
else {
T = currentmap - > iadj ( c , pd ) * T ;
c = c1 ;
}
}
}
}
2019-05-09 15:02:50 +00:00
if ( WDIM = = 3 ) {
2019-11-13 23:26:50 +00:00
mouseover2 = mouseover = centerover ;
2019-02-26 13:56:07 +00:00
ld best = HUGE_VAL ;
2020-07-27 16:49:04 +00:00
shiftpoint h = shiftless ( direct_exp ( lp_iapply ( ztangent ( 0.01 ) ) ) ) ;
2021-09-17 23:39:30 +00:00
point_direction = - 1 ;
2019-09-09 17:22:43 +00:00
2020-07-27 16:49:04 +00:00
shiftmatrix cov = ggmatrix ( mouseover2 ) ;
2019-12-06 12:05:54 +00:00
forCellIdEx ( c1 , i , mouseover2 ) {
2020-07-27 16:49:04 +00:00
shiftpoint h1 = tC0 ( cov * currentmap - > adj ( mouseover2 , i ) ) ;
ld dist = geo_dist ( h , h1 ) - geo_dist ( shiftless ( C0 ) , h1 ) ;
2021-09-17 23:39:30 +00:00
if ( dist < best ) mouseover = c1 , best = dist , point_direction = i ;
2019-02-26 13:56:07 +00:00
}
return ;
}
2018-08-19 20:53:51 +00:00
if ( ! mouseover ) return ;
2019-05-09 15:02:50 +00:00
if ( GDIM = = 3 ) return ;
2018-08-19 20:53:51 +00:00
cell * omouseover = mouseover ;
for ( int loop = 0 ; loop < 10 ; loop + + ) {
bool found = false ;
if ( ! gmatrix . count ( mouseover ) ) return ;
2020-07-27 16:49:04 +00:00
hyperpoint r_mouseh = inverse_shift ( gmatrix [ mouseover ] , mouseh ) ;
2018-08-19 20:53:51 +00:00
for ( int i = 0 ; i < mouseover - > type ; i + + ) {
2020-09-21 10:00:25 +00:00
hyperpoint h1 = get_corner_position ( mouseover , gmod ( i - 1 , mouseover - > type ) ) ;
2018-08-19 20:53:51 +00:00
hyperpoint h2 = get_corner_position ( mouseover , i ) ;
2020-09-21 10:00:25 +00:00
if ( det3 ( build_matrix ( h1 , h2 , C0 , C0 ) ) * det3 ( build_matrix ( h1 , h2 , r_mouseh , C0 ) ) < 0 ) {
2018-08-19 20:53:51 +00:00
mouseover2 = mouseover ;
mouseover = mouseover - > move ( i ) ;
found = true ;
break ;
}
}
if ( ! found ) return ;
}
// probably some error... just return the original
mouseover = omouseover ;
}
2019-10-12 11:14:38 +00:00
EX transmatrix Viewbase ;
2019-10-23 21:10:50 +00:00
EX bool no_wall_rendering ;
2019-10-21 22:37:57 +00:00
2022-03-27 12:32:29 +00:00
EX bool set_multi = false ;
EX hyperpoint multi_point ;
EX void center_multiplayer_map ( const vector < hyperpoint > & hs ) {
hyperpoint h = Hypc ;
for ( auto h1 : hs ) h + = h1 ;
h / = isize ( hs ) ;
2023-01-26 23:27:10 +00:00
h = cgi . emb - > normalize_flat ( h ) ;
2022-03-27 12:32:29 +00:00
cwtV = shiftless ( rgpushxto0 ( h ) ) ;
if ( isize ( hs ) = = 2 ) {
set_multi = true ;
multi_point = hs [ 1 ] ;
}
}
2019-08-09 19:00:52 +00:00
EX void drawthemap ( ) {
2019-05-27 05:19:04 +00:00
check_cgi ( ) ;
cgi . require_shapes ( ) ;
2019-05-12 23:57:40 +00:00
DEBBI ( DF_GRAPH , ( " draw the map " ) ) ;
2019-03-13 13:04:06 +00:00
last_firelimit = firelimit ;
firelimit = 0 ;
2017-07-04 13:38:33 +00:00
2021-04-07 18:25:27 +00:00
make_clipping_planes ( ) ;
2022-03-27 18:35:09 +00:00
current_display - > radarpoints . clear ( ) ;
current_display - > radarlines . clear ( ) ;
2017-12-01 23:23:15 +00:00
callhooks ( hooks_drawmap ) ;
2017-07-10 18:47:38 +00:00
frameid + + ;
2018-11-01 17:59:25 +00:00
cells_drawn = 0 ;
2019-05-15 13:49:09 +00:00
cells_generated = 0 ;
2019-05-11 13:06:48 +00:00
noclipped = 0 ;
2019-05-11 17:42:30 +00:00
first_cell_to_draw = true ;
2017-09-03 19:12:44 +00:00
2018-04-03 21:34:47 +00:00
if ( sightrange_bonus > 0 & & ! allowIncreasedSight ( ) )
sightrange_bonus = 0 ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
swap ( gmatrix0 , gmatrix ) ;
gmatrix . clear ( ) ;
2019-12-06 13:03:02 +00:00
current_display - > all_drawn_copies . clear ( ) ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
wmspatial = vid . wallmode = = 4 | | vid . wallmode = = 5 ;
wmescher = vid . wallmode = = 3 | | vid . wallmode = = 5 ;
wmplain = vid . wallmode = = 2 | | vid . wallmode = = 4 ;
2020-01-30 16:45:05 +00:00
wmascii = vid . wallmode = = 0 | | vid . wallmode = = 6 ;
wmascii3 = vid . wallmode = = 6 ;
2017-07-10 18:47:38 +00:00
wmblack = vid . wallmode = = 1 ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
mmitem = vid . monmode > = 1 ;
mmmon = vid . monmode > = 2 ;
2020-09-15 18:39:15 +00:00
mmspatial = vid . monmode > = 3 ;
mmhigh = vid . highlightmode > = 1 ;
if ( hiliteclick ) mmhigh = ! mmhigh ;
2018-12-05 18:57:35 +00:00
spatial_graphics = wmspatial | | mmspatial ;
2019-08-15 13:05:43 +00:00
spatial_graphics = spatial_graphics & & GDIM = = 2 ;
2019-02-17 17:45:42 +00:00
# if CAP_RUG
2018-12-05 18:57:35 +00:00
if ( rug : : rugged & & ! rug : : spatial_rug ) spatial_graphics = false ;
2019-02-17 17:45:42 +00:00
# endif
2018-12-05 18:57:35 +00:00
if ( non_spatial_model ( ) )
spatial_graphics = false ;
2020-04-16 22:53:58 +00:00
if ( pmodel = = mdDisk & & abs ( pconf . alpha ) < 1e-6 ) spatial_graphics = false ;
2018-12-05 18:57:35 +00:00
if ( ! spatial_graphics ) wmspatial = mmspatial = false ;
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 ) wmspatial = mmspatial = true ;
2016-01-02 10:09:13 +00:00
2017-07-10 18:47:38 +00:00
for ( int m = 0 ; m < motypes ; m + + ) if ( isPrincess ( eMonster ( m ) ) )
minf [ m ] . name = princessgender ( ) ? " Princess " : " Prince " ;
2019-10-21 22:37:57 +00:00
2020-03-21 18:05:17 +00:00
# if CAP_RAY
2019-10-25 12:50:48 +00:00
ray : : in_use = ray : : requested ( ) ;
2019-11-03 13:19:11 +00:00
# endif
2019-10-25 12:50:48 +00:00
no_wall_rendering = ray : : in_use ;
// ray::comparison_mode = true;
if ( ray : : comparison_mode ) no_wall_rendering = false ;
2016-08-26 09:58:03 +00:00
2017-07-10 18:47:38 +00:00
iinf [ itSavedPrincess ] . name = minf [ moPrincess ] . name ;
2016-01-02 10:09:13 +00:00
2017-07-10 18:47:38 +00:00
for ( int i = 0 ; i < NUM_GS ; i + + ) {
genderswitch_t & g = genderswitch [ i ] ;
if ( g . gender ! = princessgender ( ) ) continue ;
minf [ g . m ] . help = g . desc ;
minf [ g . m ] . name = g . name ;
2016-01-02 10:09:13 +00:00
}
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
if ( mapeditor : : autochoose ) mapeditor : : ew = mapeditor : : ewsearch ;
mapeditor : : ewsearch . dist = 1e30 ;
modist = 1e20 ; mouseover = NULL ;
modist2 = 1e20 ; mouseover2 = NULL ;
2017-07-12 16:03:53 +00:00
2018-04-11 11:16:40 +00:00
compute_graphical_distance ( ) ;
2017-07-10 18:47:38 +00:00
for ( int i = 0 ; i < multi : : players ; i + + ) {
multi : : ccdist [ i ] = 1e20 ; multi : : ccat [ i ] = NULL ;
}
2015-08-08 13:57:52 +00:00
2019-12-27 10:14:25 +00:00
downseek . reset ( ) ;
2017-08-06 12:50:16 +00:00
2017-07-22 23:33:27 +00:00
# if ISMOBILE
2017-07-10 18:47:38 +00:00
mouseovers = XLAT ( " No info about this... " ) ;
# endif
2019-05-09 15:02:50 +00:00
if ( mouseout ( ) & & ! mousepan )
2017-07-10 18:47:38 +00:00
modist = - 5 ;
playerfound = false ;
// playerfoundL = false;
// playerfoundR = false;
2017-10-04 19:26:26 +00:00
arrowtraps . clear ( ) ;
2016-08-26 09:58:03 +00:00
2019-08-20 14:09:16 +00:00
make_actual_view ( ) ;
2020-07-27 17:36:19 +00:00
currentmap - > draw_all ( ) ;
2018-01-11 22:18:02 +00:00
drawWormSegments ( ) ;
2017-09-30 09:46:41 +00:00
drawBlizzards ( ) ;
2017-10-04 19:26:26 +00:00
drawArrowTraps ( ) ;
2018-08-19 20:53:51 +00:00
precise_mouseover ( ) ;
2017-07-16 21:00:55 +00:00
ivoryz = false ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
linepatterns : : drawAll ( ) ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
callhooks ( hooks_frame ) ;
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
drawMarkers ( ) ;
drawFlashes ( ) ;
2015-08-08 13:57:52 +00:00
2020-04-17 18:04:33 +00:00
mapeditor : : draw_dtshapes ( ) ;
2022-03-27 12:32:29 +00:00
set_multi = false ;
2020-04-17 18:04:33 +00:00
2017-07-10 18:47:38 +00:00
if ( multi : : players > 1 & & ! shmup : : on ) {
2022-03-27 09:09:05 +00:00
if ( multi : : split_screen )
cwtV = multi : : whereis [ subscreens : : current_player ] ;
else if ( multi : : centerplayer ! = - 1 )
2019-09-06 06:17:38 +00:00
cwtV = multi : : whereis [ multi : : centerplayer ] ;
2017-07-10 18:47:38 +00:00
else {
2022-03-27 12:32:29 +00:00
vector < hyperpoint > pts ;
for ( int p = 0 ; p < multi : : players ; p + + ) if ( multi : : playerActive ( p ) )
2022-12-08 18:38:06 +00:00
pts . push_back ( unshift ( multi : : whereis [ p ] * tile_center ( ) ) ) ;
2022-03-27 12:32:29 +00:00
center_multiplayer_map ( pts ) ;
2017-07-10 18:47:38 +00:00
}
2016-08-26 09:58:03 +00:00
}
2017-04-04 09:13:15 +00:00
2017-07-10 18:47:38 +00:00
if ( shmup : : on ) {
2022-03-27 09:09:05 +00:00
if ( multi : : split_screen )
cwtV = shmup : : pc [ subscreens : : current_player ] - > pat ;
else if ( multi : : players = = 1 )
2017-07-10 18:47:38 +00:00
cwtV = shmup : : pc [ 0 ] - > pat ;
2022-03-27 09:09:05 +00:00
else if ( multi : : centerplayer ! = - 1 )
2019-09-06 06:17:38 +00:00
cwtV = shmup : : pc [ multi : : centerplayer ] - > pat ;
2017-04-04 09:13:15 +00:00
else {
2022-03-27 12:32:29 +00:00
vector < hyperpoint > pts ;
for ( int p = 0 ; p < multi : : players ; p + + )
2022-12-08 18:38:06 +00:00
pts . push_back ( unshift ( shmup : : pc [ p ] - > pat * tile_center ( ) ) ) ;
2022-03-27 12:32:29 +00:00
center_multiplayer_map ( pts ) ;
2017-04-04 09:13:15 +00:00
}
}
2017-07-10 18:47:38 +00:00
2017-07-22 23:33:27 +00:00
# if CAP_SDL
2021-03-06 13:53:25 +00:00
const Uint8 * keystate = SDL12_GetKeyState ( NULL ) ;
2017-07-10 18:47:38 +00:00
lmouseover = mouseover ;
2021-05-27 10:59:21 +00:00
lmouseover_distant = lmouseover ;
2021-03-06 13:53:25 +00:00
bool useRangedOrb = ( ! ( vid . shifttarget & 1 ) & & haveRangedOrb ( ) & & lmouseover & & lmouseover - > cpdist > 1 ) | | ( keystate [ SDL12 ( SDLK_RSHIFT , SDL_SCANCODE_RSHIFT ) ] | keystate [ SDL12 ( SDLK_LSHIFT , SDL_SCANCODE_LSHIFT ) ] ) ;
2020-01-29 17:21:12 +00:00
if ( ! useRangedOrb & & ! ( cmode & sm : : MAP ) & & ! ( cmode & sm : : DRAW ) & & DEFAULTCONTROL & & ! mouseout ( ) & & ! dual : : state ) {
2018-12-23 02:14:48 +00:00
dynamicval < eGravity > gs ( gravity_state , gravity_state ) ;
2017-07-10 18:47:38 +00:00
void calcMousedest ( ) ;
calcMousedest ( ) ;
cellwalker cw = cwt ; bool f = flipplayer ;
items [ itWarning ] + = 2 ;
movepcto ( mousedest . d , mousedest . subdir , true ) ;
items [ itWarning ] - = 2 ;
2017-07-22 23:33:27 +00:00
if ( cw . spin ! = cwt . spin ) mirror : : act ( - mousedest . d , mirror : : SPINSINGLE ) ;
2017-07-10 18:47:38 +00:00
cwt = cw ; flipplayer = f ;
2018-08-17 22:46:45 +00:00
lmouseover = mousedest . d > = 0 ? cwt . at - > modmove ( cwt . spin + mousedest . d ) : cwt . at ;
2017-07-10 18:47:38 +00:00
}
# endif
2017-03-23 10:53:57 +00:00
}
2019-08-09 19:00:52 +00:00
EX void drawmovestar ( double dx , double dy ) {
2017-03-23 10:53:57 +00:00
2019-05-12 23:57:40 +00:00
DEBBI ( DF_GRAPH , ( " draw movestar " ) ) ;
2017-07-10 18:47:38 +00:00
if ( viewdists ) return ;
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 ) return ;
2016-08-26 09:58:03 +00:00
2017-07-10 18:47:38 +00:00
if ( ! playerfound ) return ;
2016-08-26 09:58:03 +00:00
2017-07-10 18:47:38 +00:00
if ( shmup : : on ) return ;
2017-07-22 23:33:27 +00:00
# if CAP_RUG
2017-07-10 18:47:38 +00:00
if ( rug : : rugged & & multi : : players = = 1 & & ! multi : : alwaysuse ) return ;
# endif
2016-08-26 09:58:03 +00:00
2022-12-08 18:38:06 +00:00
shiftpoint H = cwtV * tile_center ( ) ;
2017-07-10 18:47:38 +00:00
ld R = sqrt ( H [ 0 ] * H [ 0 ] + H [ 1 ] * H [ 1 ] ) ;
2020-07-27 16:49:04 +00:00
shiftmatrix Centered ;
2016-08-26 09:58:03 +00:00
2019-11-27 00:01:20 +00:00
if ( euclid )
2020-07-27 16:49:04 +00:00
Centered = shiftless ( eupush ( H . h ) ) ;
2017-07-10 18:47:38 +00:00
else if ( R > 1e-9 ) Centered = rgpushxto0 ( H ) ;
2020-07-27 16:49:04 +00:00
else Centered = shiftless ( Id ) ;
2016-01-02 10:09:13 +00:00
2019-02-22 19:58:40 +00:00
Centered = Centered * rgpushxto0 ( hpxy ( dx * 5 , dy * 5 ) ) ;
2017-07-10 18:47:38 +00:00
if ( multi : : cpid > = 0 ) multi : : crosscenter [ multi : : cpid ] = Centered ;
2016-08-26 09:58:03 +00:00
2017-07-10 18:47:38 +00:00
int rax = vid . axes ;
if ( rax = = 1 ) rax = drawstaratvec ( dx , dy ) ? 2 : 0 ;
2016-08-26 09:58:03 +00:00
2020-05-15 13:28:59 +00:00
if ( rax = = 0 | | vid . axes > = 4 ) return ;
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
int starcol = getcs ( ) . uicolor ;
2019-02-17 17:41:40 +00:00
ignore ( starcol ) ;
if ( 0 ) ;
2017-12-01 23:23:15 +00:00
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2019-02-17 17:41:40 +00:00
else if ( vid . axes = = 3 )
2019-05-26 16:04:02 +00:00
queuepoly ( Centered , cgi . shMovestar , starcol ) ;
2017-12-01 23:23:15 +00:00
# endif
2016-08-26 09:58:03 +00:00
2017-07-10 18:47:38 +00:00
else for ( int d = 0 ; d < 8 ; d + + ) {
2019-02-17 17:41:40 +00:00
# if CAP_QUEUE
2018-09-04 17:53:42 +00:00
color_t col = starcol ;
2017-07-22 23:33:27 +00:00
# if ISPANDORA
2017-07-10 18:47:38 +00:00
if ( leftclick & & ( d = = 2 | | d = = 6 | | d = = 1 | | d = = 7 ) ) col & = 0xFFFFFF3F ;
if ( rightclick & & ( d = = 2 | | d = = 6 | | d = = 3 | | d = = 5 ) ) col & = 0xFFFFFF3F ;
if ( ! leftclick & & ! rightclick & & ( d & 1 ) ) col & = 0xFFFFFF3F ;
2015-08-08 13:57:52 +00:00
# endif
2022-11-12 21:38:45 +00:00
queueline ( tC0 ( Centered ) , Centered * xspinpush0 ( d * 45. _deg , cgi . scalefactor / 2 ) , col , 3 + vid . linequality ) ;
2017-12-01 23:23:15 +00:00
# endif
2016-01-02 10:09:13 +00:00
}
}
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
// old style joystick control
2015-08-08 13:57:52 +00:00
2019-09-06 06:17:02 +00:00
EX bool dronemode ;
2015-08-08 13:57:52 +00:00
2018-07-09 16:59:12 +00:00
purehookset hooks_calcparam ;
2019-09-09 13:31:49 +00:00
EX int corner_centering ;
2019-10-06 22:08:37 +00:00
EX bool permaside ;
2022-09-24 07:12:23 +00:00
EX bool old_center ;
2023-03-23 08:29:46 +00:00
EX ld min_scale = 1e-6 ;
2023-05-15 00:39:46 +00:00
EX int forced_center_down = ISANDROID ? 2 : ISIOS ? 40 : 40 ;
2023-11-30 11:32:24 +00:00
EX ld get_stereo_param ( ) {
if ( among ( vid . stereo_mode , sPanini , sStereographic ) ) return vid . stereo_param ;
return 0 ;
}
2019-08-09 19:00:52 +00:00
EX void calcparam ( ) {
2018-11-17 18:24:02 +00:00
2019-05-12 23:57:40 +00:00
DEBBI ( DF_GRAPH , ( " calc param " ) ) ;
2018-11-17 18:24:02 +00:00
auto cd = current_display ;
2018-11-17 23:35:50 +00:00
cd - > xtop = vid . xres * cd - > xmin ;
cd - > ytop = vid . yres * cd - > ymin ;
cd - > xsize = vid . xres * ( cd - > xmax - cd - > xmin ) ;
cd - > ysize = vid . yres * ( cd - > ymax - cd - > ymin ) ;
cd - > xcenter = cd - > xtop + cd - > xsize / 2 ;
cd - > ycenter = cd - > ytop + cd - > ysize / 2 ;
2018-09-10 15:24:58 +00:00
2023-03-23 08:29:46 +00:00
if ( abs ( pconf . scale ) < min_scale ) pconf . scale = 1 ;
2017-05-27 19:40:40 +00:00
2018-11-17 23:35:50 +00:00
ld realradius = min ( cd - > xsize / 2 , cd - > ysize / 2 ) ;
2017-12-14 01:53:29 +00:00
2023-05-15 00:39:46 +00:00
cd - > scrsize = realradius ;
if ( ! inHighQual ) cd - > scrsize - = forced_center_down ;
2017-03-23 10:53:57 +00:00
2019-10-06 22:08:37 +00:00
current_display - > sidescreen = permaside ;
2015-08-08 13:57:52 +00:00
2022-09-24 07:12:23 +00:00
if ( vid . xres < vid . yres - 2 * vid . fsize & & ! inHighQual & & ( old_center | | ! in_perspective ( ) ) ) {
2020-04-06 06:46:32 +00:00
cd - > ycenter = lerp ( vid . fsize + cd - > scrsize , vid . yres - cd - > scrsize - vid . fsize , .8 ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else {
2020-12-30 13:20:30 +00:00
bool ok = ! vrhr : : active ( ) ;
2022-07-12 12:41:54 +00:00
if ( vid . xres > vid . yres * 4 / 3 + 16 & & ( cmode & sm : : SIDE ) & & ok & & ! ( ( cmode & sm : : MAYDARK ) & & centered_menus ) )
2018-11-27 01:33:10 +00:00
current_display - > sidescreen = true ;
2017-07-22 23:33:27 +00:00
# if CAP_TOUR
2020-11-19 17:20:06 +00:00
if ( tour : : on & & ( tour : : slides [ tour : : currentslide ] . flags & tour : : SIDESCREEN ) & & ok )
2018-11-27 01:33:10 +00:00
current_display - > sidescreen = true ;
2017-03-23 10:53:57 +00:00
# endif
2024-07-27 19:05:10 +00:00
if ( ( cmode & sm : : DIALOG_OFFMAP ) & & ! centered_menus & & vid . xres > vid . yres * 11 / 10 )
current_display - > sidescreen = true ;
2017-03-23 10:53:57 +00:00
2018-11-27 01:33:10 +00:00
if ( current_display - > sidescreen ) cd - > xcenter = vid . yres / 2 ;
2017-03-23 10:53:57 +00:00
}
2018-02-20 21:11:39 +00:00
2020-04-16 22:53:58 +00:00
cd - > radius = pconf . scale * cd - > scrsize ;
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 & & in_perspective ( ) ) cd - > radius = cd - > scrsize ;
2018-11-17 18:24:02 +00:00
realradius = min ( realradius , cd - > radius ) ;
2017-03-23 10:53:57 +00:00
2020-04-16 22:53:58 +00:00
ld aradius = sphere ? cd - > radius / ( pconf . alpha - 1 ) : cd - > radius ;
2021-05-09 00:25:41 +00:00
# if MAXMDIM >= 4
2024-06-16 16:12:52 +00:00
if ( euclid & & hybrid : : drawing_underlying ) aradius * = 2.5 ;
2021-05-09 00:25:41 +00:00
# endif
2019-09-09 13:31:49 +00:00
2018-11-17 18:24:02 +00:00
if ( dronemode ) { cd - > ycenter - = cd - > radius ; cd - > ycenter + = vid . fsize / 2 ; cd - > ycenter + = vid . fsize / 2 ; cd - > radius * = 2 ; }
2017-12-25 09:26:50 +00:00
2019-09-09 13:31:49 +00:00
if ( corner_centering ) {
cd - > ycenter = cd - > ytop + cd - > ysize - vid . fsize - aradius ;
if ( corner_centering = = 1 )
cd - > xcenter = cd - > xtop + vid . fsize + aradius ;
if ( corner_centering = = 2 )
cd - > xcenter = cd - > xtop + cd - > xsize - vid . fsize - aradius ;
}
2020-04-16 22:53:58 +00:00
cd - > xcenter + = cd - > scrsize * pconf . xposition ;
cd - > ycenter + = cd - > scrsize * pconf . yposition ;
2019-09-09 13:31:49 +00:00
2020-11-01 20:20:54 +00:00
ld fov = vid . fov * degree / 2 ;
2023-11-30 11:32:24 +00:00
cd - > tanfov = sin ( fov ) / ( cos ( fov ) + get_stereo_param ( ) ) ;
2018-02-03 12:41:49 +00:00
2024-07-09 22:03:00 +00:00
set_cfont ( ) ;
2018-07-09 16:59:12 +00:00
callhooks ( hooks_calcparam ) ;
2019-04-23 13:03:17 +00:00
reset_projection ( ) ;
2017-07-10 18:47:38 +00:00
}
2017-03-23 10:53:57 +00:00
2020-04-10 22:41:57 +00:00
EX function < void ( ) > wrap_drawfullmap = drawfullmap ;
2018-01-25 16:22:04 +00:00
2018-02-26 12:17:06 +00:00
bool force_sphere_outline = false ;
2019-08-09 19:00:52 +00:00
EX void drawfullmap ( ) {
2018-11-08 15:28:17 +00:00
2019-05-12 23:57:40 +00:00
DEBBI ( DF_GRAPH , ( " draw full map " ) ) ;
2018-11-08 15:28:17 +00:00
2019-05-27 05:19:04 +00:00
check_cgi ( ) ;
cgi . require_shapes ( ) ;
2018-11-08 15:28:17 +00:00
ptds . clear ( ) ;
/*
2019-08-09 22:58:50 +00:00
if ( models : : on ) {
2018-11-08 15:28:17 +00:00
char ch = ' A ' ;
2019-08-09 22:58:50 +00:00
for ( auto & v : history : : v ) {
2019-05-26 16:04:02 +00:00
queuepoly ( ggmatrix ( v - > base ) * v - > at , cgi . shTriangle , 0x306090C0 ) ;
2019-12-26 22:38:28 +00:00
queuestr ( ggmatrix ( v - > base ) * v - > at * C0 , 10 , s0 + ( ch + + ) , 0xFF0000 ) ;
2018-11-08 15:28:17 +00:00
}
}
*/
2019-02-17 18:39:44 +00:00
# if CAP_QUEUE
2018-11-08 15:28:17 +00:00
draw_boundary ( 0 ) ;
draw_boundary ( 1 ) ;
draw_model_elements ( ) ;
2020-07-03 12:48:36 +00:00
# if MAXMDIM >= 4 && CAP_GL
2019-06-01 15:01:04 +00:00
prepare_sky ( ) ;
# endif
2019-02-17 17:41:40 +00:00
# endif
2018-11-08 15:28:17 +00:00
2017-12-09 02:48:30 +00:00
/* if(vid.wallmode < 2 && !euclid && !patterns::whichShape) {
2018-06-22 12:47:24 +00:00
int ls = isize ( lines ) ;
2017-07-10 18:47:38 +00:00
if ( ISMOBILE ) ls / = 10 ;
for ( int t = 0 ; t < ls ; t + + ) queueline ( View * lines [ t ] . P1 , View * lines [ t ] . P2 , lines [ t ] . col > > ( darken + 1 ) ) ;
} */
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
clearaura ( ) ;
2018-07-09 16:10:28 +00:00
if ( ! nomap ) drawthemap ( ) ;
2022-09-17 14:45:43 +00:00
else callhooks ( hooks_frame ) ;
2017-07-10 18:47:38 +00:00
if ( ! inHighQual ) {
2017-07-12 17:50:39 +00:00
if ( ( cmode & sm : : NORMAL ) & & ! rug : : rugged ) {
2017-07-10 18:47:38 +00:00
if ( multi : : players > 1 ) {
2020-07-27 16:49:04 +00:00
auto bcwtV = cwtV ;
2017-07-10 18:47:38 +00:00
for ( int i = 0 ; i < multi : : players ; i + + ) if ( multi : : playerActive ( i ) )
cwtV = multi : : whereis [ i ] , multi : : cpid = i , drawmovestar ( multi : : mdx [ i ] , multi : : mdy [ i ] ) ;
cwtV = bcwtV ;
}
else if ( multi : : alwaysuse )
drawmovestar ( multi : : mdx [ 0 ] , multi : : mdy [ 0 ] ) ;
else
drawmovestar ( 0 , 0 ) ;
}
2017-07-22 23:33:27 +00:00
# if CAP_EDIT
2017-07-12 17:50:39 +00:00
if ( cmode & sm : : DRAW ) mapeditor : : drawGrid ( ) ;
2017-07-22 23:33:27 +00:00
# endif
2017-03-23 10:53:57 +00:00
}
2017-07-16 21:00:55 +00:00
2017-07-10 18:47:38 +00:00
drawaura ( ) ;
2019-02-17 17:41:40 +00:00
# if CAP_QUEUE
2017-07-10 18:47:38 +00:00
drawqueue ( ) ;
2019-02-17 17:41:40 +00:00
# endif
2017-03-23 10:53:57 +00:00
}
2015-08-08 13:57:52 +00:00
2019-06-28 08:22:48 +00:00
# if ISMOBILE
extern bool wclick ;
# endif
2020-09-11 09:14:32 +00:00
EX bool just_refreshing ;
2022-07-05 09:51:06 +00:00
EX int menu_darkening = 2 ;
2022-07-12 12:41:54 +00:00
EX bool centered_menus = false ;
2024-05-28 13:09:00 +00:00
EX string menu_format = " " ;
2022-07-05 09:51:06 +00:00
EX void gamescreen ( ) {
if ( cmode & sm : : NOSCR ) {
emptyscreen ( ) ;
return ;
}
2017-11-07 15:42:31 +00:00
2020-09-11 09:14:32 +00:00
if ( just_refreshing ) return ;
2019-03-09 15:20:06 +00:00
if ( subscreens : : split ( [ = ] ( ) {
2018-11-17 18:30:50 +00:00
calcparam ( ) ;
compute_graphical_distance ( ) ;
2022-07-05 09:51:06 +00:00
gamescreen ( ) ;
2018-11-17 23:36:31 +00:00
} ) ) {
2019-03-09 15:20:06 +00:00
if ( racing : : on ) return ;
// create the gmatrix
View = subscreens : : player_displays [ 0 ] . view_matrix ;
2019-11-13 23:26:50 +00:00
centerover = subscreens : : player_displays [ 0 ] . precise_center ;
2019-03-09 15:20:06 +00:00
just_gmatrix = true ;
2020-07-27 17:36:19 +00:00
currentmap - > draw_all ( ) ;
2019-03-09 15:20:06 +00:00
just_gmatrix = false ;
2018-11-17 23:36:31 +00:00
return ;
}
2019-05-28 23:09:38 +00:00
2020-11-01 19:23:14 +00:00
auto gx = vid . xres ;
auto gy = vid . yres ;
2019-05-28 23:09:38 +00:00
if ( dual : : split ( [ = ] ( ) {
2020-11-01 19:23:14 +00:00
vid . xres = gx ;
vid . yres = gy ;
2022-07-05 09:51:06 +00:00
dual : : in_subscreen ( [ = ] ( ) { gamescreen ( ) ; } ) ;
2019-05-28 23:09:38 +00:00
} ) ) {
calcparam ( ) ;
return ;
}
2020-11-01 19:23:14 +00:00
calcparam ( ) ;
2022-07-05 09:51:06 +00:00
darken = 0 ;
if ( ! inHighQual & & ! vrhr : : active ( ) ) {
if ( ( cmode & sm : : MAYDARK ) & & ! current_display - > sidescreen )
darken + = menu_darkening ;
else if ( cmode & sm : : DARKEN )
darken + = menu_darkening ;
}
if ( vid . highlightmode = = ( hiliteclick ? 0 : 2 ) )
darken + + ;
if ( darken > = 8 ) {
emptyscreen ( ) ;
return ;
2017-11-07 15:42:31 +00:00
}
2019-08-09 22:58:50 +00:00
if ( history : : includeHistory ) history : : restore ( ) ;
2017-07-04 13:38:33 +00:00
2018-09-10 15:58:36 +00:00
anims : : apply ( ) ;
2017-07-22 23:33:27 +00:00
# if CAP_RUG
2017-07-10 18:47:38 +00:00
if ( rug : : rugged ) {
2022-09-24 07:12:34 +00:00
if ( ! nomap ) rug : : actDraw ( ) ;
2017-07-22 23:33:27 +00:00
} else
2017-07-04 13:38:33 +00:00
# endif
2018-01-25 16:22:04 +00:00
wrap_drawfullmap ( ) ;
2018-09-10 15:58:36 +00:00
anims : : rollback ( ) ;
2015-08-08 13:57:52 +00:00
2019-08-09 22:58:50 +00:00
if ( history : : includeHistory ) history : : restoreBack ( ) ;
2017-04-08 15:18:29 +00:00
2017-07-10 18:47:38 +00:00
poly_outline = OUTLINE_DEFAULT ;
2017-07-22 23:33:27 +00:00
# if ISMOBILE
2017-07-10 18:47:38 +00:00
buttonclicked = false ;
2020-11-14 12:17:55 +00:00
if ( ( cmode & sm : : NORMAL ) & & vid . stereo_mode ! = sLR & & ! inHighQual ) {
2017-07-10 18:47:38 +00:00
if ( andmode = = 0 & & shmup : : on ) {
using namespace shmupballs ;
calc ( ) ;
drawCircle ( xmove , yb , rad , OUTLINE_FORE ) ;
drawCircle ( xmove , yb , rad / 2 , OUTLINE_FORE ) ;
drawCircle ( xfire , yb , rad , 0xFF0000FF ) ;
drawCircle ( xfire , yb , rad / 2 , 0xFF0000FF ) ;
2017-04-14 18:12:23 +00:00
}
2017-07-10 18:47:38 +00:00
else {
2021-05-23 12:33:25 +00:00
if ( ! haveMobileCompass ( ) ) displayabutton ( - 1 , + 1 , andmode = = 0 & & useRangedOrb ? XLAT ( " FIRE " ) : andmode = = 0 & & WDIM = = 3 & & wclick ? XLAT ( " WAIT " ) : XLAT ( " MOVE " ) , andmode = = 0 ? BTON : BTOFF ) ;
displayabutton ( + 1 , + 1 , rug : : rugged ? XLAT ( " RUG " ) : andmode = = 1 ? XLAT ( " BACK " ) : GDIM = = 3 ? XLAT ( " CAM " ) : XLAT ( " DRAG " ) , andmode = = 1 ? BTON : BTOFF ) ;
2015-08-08 13:57:52 +00:00
}
2017-07-10 18:47:38 +00:00
displayabutton ( - 1 , - 1 , XLAT ( " INFO " ) , andmode = = 12 ? BTON : BTOFF ) ;
displayabutton ( + 1 , - 1 , XLAT ( " MENU " ) , andmode = = 3 ? BTON : BTOFF ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
# endif
2017-07-10 18:47:38 +00:00
darken = 0 ;
2017-12-25 09:26:50 +00:00
2018-01-05 16:30:03 +00:00
# if CAP_TEXTURE
2018-03-17 20:12:46 +00:00
if ( texture : : config . tstate = = texture : : tsAdjusting )
texture : : config . drawRawTexture ( ) ;
2018-01-05 16:30:03 +00:00
# endif
2020-11-19 17:20:06 +00:00
# if CAP_VR
2021-02-06 18:11:53 +00:00
vrhr : : size_and_draw_ui_box ( ) ;
2020-11-19 17:20:06 +00:00
# endif
2017-07-10 18:47:38 +00:00
}
2015-08-08 13:57:52 +00:00
2021-02-07 17:32:39 +00:00
EX void emptyscreen ( ) {
ptds . clear ( ) ;
ray : : in_use = false ;
drawqueue ( ) ;
}
2023-03-25 08:24:47 +00:00
EX int nohelp ;
2020-09-11 09:16:59 +00:00
EX bool no_find_player ;
2018-03-02 12:03:50 +00:00
2019-08-09 19:00:52 +00:00
EX void normalscreen ( ) {
2017-07-10 18:47:38 +00:00
help = " @ " ;
2017-07-12 16:03:53 +00:00
2019-12-25 10:53:50 +00:00
mouseovers = standard_help ( ) ;
2017-07-12 16:03:53 +00:00
2017-07-22 23:33:27 +00:00
# if CAP_TOUR
2022-06-16 21:13:54 +00:00
if ( tour : : on ) mouseovers = ( tour : : slides [ tour : : currentslide ] . flags & tour : : NOTITLE ) ? " " : tour : : tourhelp ;
2017-07-12 16:03:53 +00:00
# endif
2020-07-27 16:49:04 +00:00
if ( GDIM = = 3 | | ! outofmap ( mouseh . h ) ) getcstat = ' - ' ;
2017-07-12 17:50:39 +00:00
cmode = sm : : NORMAL | sm : : DOTOUR | sm : : CENTER ;
2018-09-23 11:48:59 +00:00
if ( viewdists & & show_distance_lists ) cmode | = sm : : SIDE | sm : : MAYDARK ;
2022-07-05 09:51:06 +00:00
gamescreen ( ) ; drawStats ( ) ;
2024-05-28 13:09:00 +00:00
if ( menu_format ! = " " )
displayButton ( vid . xres - 8 , vid . yres - vid . fsize , eval_programmable_string ( menu_format ) , ' v ' , 16 ) ;
2024-05-16 15:26:49 +00:00
else if ( nomenukey | | ISMOBILE )
2017-07-10 18:47:38 +00:00
;
2017-07-22 23:33:27 +00:00
# if CAP_TOUR
2017-07-10 18:47:38 +00:00
else if ( tour : : on )
displayButton ( vid . xres - 8 , vid . yres - vid . fsize , XLAT ( " (ESC) tour menu " ) , SDLK_ESCAPE , 16 ) ;
2015-08-08 13:57:52 +00:00
# endif
2024-05-16 14:12:28 +00:00
else
2017-07-10 18:47:38 +00:00
displayButton ( vid . xres - 8 , vid . yres - vid . fsize , XLAT ( " (v) menu " ) , ' v ' , 16 ) ;
keyhandler = handleKeyNormal ;
2017-07-12 16:03:53 +00:00
2021-04-15 15:56:17 +00:00
if ( ! playerfound & & ! anims : : any_on ( ) & & ! sphere & & ! no_find_player & & mapeditor : : drawplayer )
2021-05-23 12:33:25 +00:00
displayButton ( current_display - > xcenter , current_display - > ycenter , mousing ? XLAT ( " find the player " ) : XLAT ( " press SPACE to find the player " ) , ' ' , 8 ) ;
2018-08-21 16:23:31 +00:00
2022-03-27 17:12:10 +00:00
if ( ! mapeditor : : drawplayer & & playermoved & & ! no_find_player )
displayButton ( current_display - > xcenter , current_display - > ycenter , XLAT ( " move the camera with arrow keys and Home/End " ) , PSEUDOKEY_NOHINT , 8 ) ;
2017-07-12 16:03:53 +00:00
describeMouseover ( ) ;
2016-01-02 10:09:13 +00:00
}
2019-08-09 23:15:41 +00:00
EX vector < function < void ( ) > > screens = { normalscreen } ;
# if HDR
template < class T > void pushScreen ( const T & x ) { screens . push_back ( x ) ; }
inline void popScreen ( ) { if ( isize ( screens ) > 1 ) screens . pop_back ( ) ; }
inline void popScreenAll ( ) { while ( isize ( screens ) > 1 ) popScreen ( ) ; }
2019-09-08 08:08:05 +00:00
typedef void ( * cfunction ) ( ) ;
2019-08-09 23:15:41 +00:00
# endif
2015-08-08 13:57:52 +00:00
2019-09-08 08:08:05 +00:00
EX cfunction current_screen_cfunction ( ) {
auto tgt = screens . back ( ) . target < cfunction > ( ) ;
if ( ! tgt ) return nullptr ;
return * tgt ;
}
2019-08-10 08:57:14 +00:00
# if HDR
namespace sm {
2023-08-23 17:44:37 +00:00
static constexpr int NORMAL = 1 ;
static constexpr int MISSION = 2 ;
static constexpr int HELP = 4 ;
static constexpr int MAP = 8 ;
static constexpr int DRAW = 16 ;
static constexpr int NUMBER = 32 ;
static constexpr int SHMUPCONFIG = 64 ;
static constexpr int OVERVIEW = 128 ;
static constexpr int SIDE = 256 ;
static constexpr int DOTOUR = 512 ;
static constexpr int CENTER = 1024 ;
static constexpr int ZOOMABLE = 4096 ;
static constexpr int TORUSCONFIG = 8192 ;
2024-07-27 19:05:10 +00:00
static constexpr int MAYDARK = 16384 ; // use together with SIDE; if the screen is not wide or centered_menus is set, it will disable SIDE and instead darken the screen
2023-08-23 17:44:37 +00:00
static constexpr int DIALOG_STRICT_X = 32768 ; // do not interpret dialog clicks outside of the X region
static constexpr int EXPANSION = ( 1 < < 16 ) ;
static constexpr int HEXEDIT = ( 1 < < 17 ) ;
static constexpr int VR_MENU = ( 1 < < 18 ) ; // always show the menu in VR
static constexpr int SHOWCURSOR = ( 1 < < 19 ) ; // despite MAP/DRAW always show the cursor, no panning
static constexpr int PANNING = ( 1 < < 20 ) ; // smooth scrolling works
static constexpr int DARKEN = ( 1 < < 21 ) ; // darken the game background
static constexpr int NOSCR = ( 1 < < 22 ) ; // do not show the game background
static constexpr int AUTO_VALUES = ( 1 < < 23 ) ; // automatic place for values
static constexpr int NARROW_LINES = ( 1 < < 24 ) ; // do make the lines narrower if we needed to reduce width
static constexpr int EDIT_BEFORE_WALLS = ( 1 < < 25 ) ; // mouseover targets before walls
static constexpr int EDIT_INSIDE_WALLS = ( 1 < < 26 ) ; // mouseover targets inside walls
static constexpr int DIALOG_WIDE = ( 1 < < 27 ) ; // make dialogs wide
static constexpr int MOUSEAIM = ( 1 < < 28 ) ; // mouse aiming active here
2024-07-27 19:05:10 +00:00
static constexpr int DIALOG_OFFMAP = ( 1 < < 29 ) ; // try hard to keep dialogs off the map
2020-02-23 01:51:27 +00:00
}
2019-08-10 08:57:14 +00:00
# endif
2019-08-09 20:07:03 +00:00
EX int cmode ;
2015-08-08 13:57:52 +00:00
2022-05-17 07:43:45 +00:00
EX bool dont_display_minecount = false ;
2022-07-23 13:36:27 +00:00
EX color_t titlecolor ;
2019-08-09 19:00:52 +00:00
EX void drawscreen ( ) {
2015-08-08 13:57:52 +00:00
2019-05-12 23:57:40 +00:00
DEBBI ( DF_GRAPH , ( " drawscreen " ) ) ;
2021-05-21 23:24:28 +00:00
# if CAP_GL
2020-11-08 10:49:19 +00:00
GLWRAP ;
2021-05-21 23:24:28 +00:00
# endif
2016-08-26 09:58:03 +00:00
2019-05-12 23:57:40 +00:00
if ( vid . xres = = 0 | | vid . yres = = 0 ) return ;
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
calcparam ( ) ;
2017-11-06 18:24:02 +00:00
// rug::setVidParam();
2017-07-22 23:33:27 +00:00
# if CAP_GL
2017-07-10 18:47:38 +00:00
if ( vid . usingGL ) setGLProjection ( ) ;
# endif
2021-03-09 12:12:53 +00:00
2021-06-01 08:08:16 +00:00
# if CAP_XGD
if ( ! vid . usingGL ) {
gdpush ( 5 ) ; gdpush ( backcolor ) ;
}
# endif
2021-03-09 12:12:53 +00:00
# if CAP_VR
vrhr : : clear ( ) ;
# endif
2017-07-10 18:47:38 +00:00
2017-07-22 23:33:27 +00:00
# if CAP_SDL
2017-07-10 18:47:38 +00:00
// SDL_LockSurface(s);
// unsigned char *b = (unsigned char*) s->pixels;
// int n = vid.xres * vid.yres * 4;
// while(n) *b >>= 1, b++, n--;
// memset(s->pixels, 0, vid.xres * vid.yres * 4);
2017-07-22 23:33:27 +00:00
# if CAP_GL
if ( ! vid . usingGL )
# endif
SDL_FillRect ( s , NULL , backcolor ) ;
2017-03-23 10:53:57 +00:00
# endif
2017-07-10 18:47:38 +00:00
2019-08-09 19:00:52 +00:00
// displaynum(vx,100, 0, 24, 0xc0c0c0, celldist(cwt.at), ":");
2017-07-10 18:47:38 +00:00
lgetcstat = getcstat ;
getcstat = 0 ; inslider = false ;
2017-03-23 10:53:57 +00:00
2017-07-12 16:03:53 +00:00
mouseovers = " " ;
2017-07-12 17:50:39 +00:00
cmode = 0 ;
2024-06-28 10:20:26 +00:00
reset_handlers ( ) ;
2018-06-22 12:47:24 +00:00
if ( ! isize ( screens ) ) pushScreen ( normalscreen ) ;
2017-07-10 18:47:38 +00:00
screens . back ( ) ( ) ;
2016-01-02 10:09:13 +00:00
2017-07-22 23:33:27 +00:00
# if !ISMOBILE
2018-09-04 17:53:42 +00:00
color_t col = linf [ cwt . at - > land ] . color ;
2018-08-17 22:46:45 +00:00
if ( cwt . at - > land = = laRedRock ) col = 0xC00000 ;
2022-07-23 13:36:27 +00:00
if ( titlecolor ) col = titlecolor ;
2024-05-27 13:54:12 +00:00
if ( nohelp ! = 1 ) {
int size = vid . fsize ;
while ( size > 3 & & textwidth ( size , mouseovers ) > vid . xres ) size - - ;
displayfr ( vid . xres / 2 , vid . fsize , 2 , size , mouseovers , col , 8 ) ;
}
2017-07-12 16:03:53 +00:00
# endif
2017-07-10 18:47:38 +00:00
drawmessages ( ) ;
2017-03-23 10:53:57 +00:00
2017-07-12 17:50:39 +00:00
bool normal = cmode & sm : : NORMAL ;
if ( ( havewhat & HF_BUG ) & & darken = = 0 & & normal ) for ( int k = 0 ; k < 3 ; k + + )
2017-07-10 18:47:38 +00:00
displayfr ( vid . xres / 2 + vid . fsize * 5 * ( k - 1 ) , vid . fsize * 2 , 2 , vid . fsize ,
its ( hive : : bugcount [ k ] ) , minf [ moBug0 + k ] . color , 8 ) ;
bool minefieldNearby = false ;
2019-04-08 12:56:46 +00:00
int mines [ MAXPLAYER ] , tmines = 0 ;
2017-07-10 18:47:38 +00:00
for ( int p = 0 ; p < numplayers ( ) ; p + + ) {
mines [ p ] = 0 ;
cell * c = playerpos ( p ) ;
if ( ! c ) continue ;
2019-04-08 12:58:54 +00:00
for ( cell * c2 : adj_minefield_cells ( c ) ) {
if ( c2 - > land = = laMinefield )
2017-07-10 18:47:38 +00:00
minefieldNearby = true ;
2019-04-08 12:58:54 +00:00
if ( c2 - > wall = = waMineMine ) {
2017-07-10 18:47:38 +00:00
bool ep = false ;
if ( ! ep ) mines [ p ] + + , tmines + + ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
}
2017-07-10 18:47:38 +00:00
}
2016-01-02 10:09:13 +00:00
2018-12-23 02:14:48 +00:00
if ( ( minefieldNearby | | tmines ) & & ! items [ itOrbAether ] & & ! last_gravity_state & & darken = = 0 & & normal ) {
2017-07-10 18:47:38 +00:00
string s ;
2019-04-08 12:56:46 +00:00
if ( tmines > 9 ) tmines = 9 ;
2022-10-06 11:47:00 +00:00
color_t col = minecolors [ tmines ] ;
2017-03-23 10:53:57 +00:00
2017-07-10 18:47:38 +00:00
if ( tmines = = 7 ) seenSevenMines = true ;
2017-03-23 10:53:57 +00:00
2022-05-17 07:43:45 +00:00
if ( ! dont_display_minecount ) for ( int p : player_indices ( ) )
2017-07-10 18:47:38 +00:00
displayfr ( vid . xres * ( p + .5 ) / numplayers ( ) ,
2018-11-17 18:24:02 +00:00
current_display - > ycenter - current_display - > radius * 3 / 4 , 2 ,
2017-07-10 18:47:38 +00:00
vid . fsize ,
2022-10-06 11:47:00 +00:00
mines [ p ] > 7 ? its ( mines [ p ] ) : XLAT ( minetexts [ mines [ p ] ] ) , minecolors [ mines [ p ] ] , 8 ) ;
2015-08-08 13:57:52 +00:00
2022-05-17 07:43:45 +00:00
if ( minefieldNearby & & ! shmup : : on & & cwt . at - > land ! = laMinefield & & cwt . peek ( ) - > land ! = laMinefield & & ! dont_display_minecount ) {
2018-11-17 18:24:02 +00:00
displayfr ( vid . xres / 2 , current_display - > ycenter - current_display - > radius * 3 / 4 - vid . fsize * 3 / 2 , 2 ,
2017-07-10 18:47:38 +00:00
vid . fsize ,
XLAT ( " WARNING: you are entering a minefield! " ) ,
col , 8 ) ;
2017-03-23 10:53:57 +00:00
}
2017-07-10 18:47:38 +00:00
}
2015-08-08 13:57:52 +00:00
2017-07-10 18:47:38 +00:00
// SDL_UnlockSurface(s);
2017-03-23 10:53:57 +00:00
2018-09-04 21:27:27 +00:00
glflush ( ) ;
2019-05-12 23:57:40 +00:00
DEBB ( DF_GRAPH , ( " swapbuffers " ) ) ;
2020-11-19 17:20:06 +00:00
# if CAP_VR
vrhr : : submit ( ) ;
# endif
2021-03-06 13:53:25 +00:00
2021-05-21 23:24:28 +00:00
# if CAP_SDL
2021-03-06 13:53:25 +00:00
present_screen ( ) ;
2021-05-21 23:24:28 +00:00
# endif
2021-02-04 20:30:08 +00:00
2021-02-06 18:12:04 +00:00
# if CAP_VR
2021-02-04 20:30:08 +00:00
vrhr : : handoff ( ) ;
2021-02-06 18:12:04 +00:00
# endif
2017-07-10 18:47:38 +00:00
//printf("\ec");
}
2015-08-08 13:57:52 +00:00
2019-08-09 19:00:52 +00:00
EX void restartGraph ( ) {
2019-05-12 23:57:40 +00:00
DEBBI ( DF_INIT , ( " restartGraph " ) ) ;
2017-07-10 18:47:38 +00:00
2018-04-21 17:35:17 +00:00
if ( ! autocheat ) linepatterns : : clearAll ( ) ;
2022-12-17 16:37:26 +00:00
if ( currentmap ) resetview ( ) ;
2017-03-23 10:53:57 +00:00
}
2015-08-08 13:57:52 +00:00
2019-08-09 19:00:52 +00:00
EX void clearAnimations ( ) {
2018-01-13 18:20:46 +00:00
for ( int i = 0 ; i < ANIMLAYERS ; i + + ) animations [ i ] . clear ( ) ;
flashes . clear ( ) ;
fallanims . clear ( ) ;
}
2020-04-11 18:40:12 +00:00
auto graphcm = addHook ( hooks_clearmemory , 0 , [ ] ( ) {
2019-05-12 23:57:40 +00:00
DEBBI ( DF_MEMORY , ( " clear graph memory " ) ) ;
2019-11-13 23:26:50 +00:00
mouseover = centerover = lmouseover = NULL ;
2019-12-06 13:03:02 +00:00
gmatrix . clear ( ) ; gmatrix0 . clear ( ) ; current_display - > all_drawn_copies . clear ( ) ;
2018-01-13 18:20:46 +00:00
clearAnimations ( ) ;
2019-05-28 23:09:38 +00:00
} )
+ addHook ( hooks_gamedata , 0 , [ ] ( gamedata * gd ) {
gd - > store ( mouseover ) ;
gd - > store ( lmouseover ) ;
gd - > store ( animations ) ;
gd - > store ( flashes ) ;
gd - > store ( fallanims ) ;
2022-03-27 18:35:09 +00:00
gd - > store ( current_display - > radar_transform ) ;
2019-05-30 14:12:38 +00:00
gd - > store ( actual_view_transform ) ;
2017-07-10 18:47:38 +00:00
} ) ;
2017-03-23 10:53:57 +00:00
//=== animation
2019-08-09 21:08:42 +00:00
# if HDR
struct animation {
int ltick ;
double footphase ;
transmatrix wherenow ;
2020-12-26 17:09:09 +00:00
int attacking ; /** 0 = no attack animation, 1 = first phase, 2 = second phase, 3 = hugging */
2019-08-09 21:08:42 +00:00
transmatrix attackat ;
bool mirrored ;
2021-06-06 08:35:55 +00:00
eItem thrown_item ; /** for thrown items */
2019-08-09 21:08:42 +00:00
} ;
// we need separate animation layers for Orb of Domination and Tentacle+Ghost,
// and also to mark Boats
2021-06-06 08:35:55 +00:00
# define ANIMLAYERS 4
2019-08-09 21:08:42 +00:00
# define LAYER_BIG 0 // for worms and krakens
# define LAYER_SMALL 1 // for others
# define LAYER_BOAT 2 // mark that a boat has moved
2021-06-06 08:35:55 +00:00
# define LAYER_THROW 3 // for thrown items
2019-08-09 21:08:42 +00:00
# endif
EX array < map < cell * , animation > , ANIMLAYERS > animations ;
2017-03-23 10:53:57 +00:00
2019-08-09 20:37:11 +00:00
EX int revhint ( cell * c , int hint ) {
2018-08-17 22:46:45 +00:00
if ( hint > = 0 & & hint < c - > type ) return c - > c . spin ( hint ) ;
2018-06-17 15:51:26 +00:00
else return hint ;
}
2019-11-22 15:32:05 +00:00
EX transmatrix adj ( const movei & m ) {
if ( m . proper ( ) ) return currentmap - > adj ( m . s , m . d ) ;
else return currentmap - > relative_matrix ( m . t , m . s , C0 ) ;
}
EX transmatrix iadj ( const movei & m ) {
if ( m . proper ( ) ) return currentmap - > iadj ( m . s , m . d ) ;
else return currentmap - > relative_matrix ( m . s , m . t , C0 ) ;
}
EX void animateMovement ( const movei & m , int layer ) {
2018-01-25 16:19:50 +00:00
if ( vid . mspeed > = 5 ) return ; // no animations!
2020-02-29 16:58:59 +00:00
LATE ( animateMovement ( m , layer ) ; )
2019-11-22 15:37:32 +00:00
transmatrix T = iadj ( m ) ;
2019-11-22 18:39:50 +00:00
bool found_s = animations [ layer ] . count ( m . s ) ;
2019-11-22 15:32:05 +00:00
animation & a = animations [ layer ] [ m . t ] ;
2019-11-22 18:39:50 +00:00
if ( found_s ) {
2019-11-22 15:32:05 +00:00
a = animations [ layer ] [ m . s ] ;
2018-06-17 15:51:26 +00:00
a . wherenow = T * a . wherenow ;
2020-12-25 05:08:19 +00:00
if ( m . s ! = m . t )
animations [ layer ] . erase ( m . s ) ;
2018-06-17 15:51:26 +00:00
a . attacking = 0 ;
}
else {
a . ltick = ticks ;
a . wherenow = T ;
a . footphase = 0 ;
2019-05-15 12:19:19 +00:00
a . mirrored = false ;
}
2019-11-22 15:32:05 +00:00
if ( m . proper ( ) & & m . s - > c . mirror ( m . d ) )
a . mirrored = ! a . mirrored ;
}
2021-06-06 08:35:55 +00:00
EX void animate_item_throw ( cell * from , cell * to , eItem it ) {
bool steps = false ;
again :
if ( from ! = to ) {
forCellIdEx ( c1 , i , from ) if ( celldistance ( c1 , to ) < celldistance ( from , to ) ) {
animateMovement ( movei ( from , i ) , LAYER_THROW ) ;
from = c1 ;
steps = true ;
goto again ;
}
}
if ( steps ) {
animation & a = animations [ LAYER_THROW ] [ to ] ;
a . thrown_item = it ;
}
}
2020-12-26 17:09:09 +00:00
EX void animateAttackOrHug ( const movei & m , int layer , int phase , ld ratio , ld delta ) {
2020-02-29 16:58:59 +00:00
LATE ( animateAttack ( m , layer ) ; )
2018-06-17 15:51:26 +00:00
if ( vid . mspeed > = 5 ) return ; // no animations!
2019-11-22 15:46:37 +00:00
transmatrix T = iadj ( m ) ;
2019-11-22 15:32:05 +00:00
bool newanim = ! animations [ layer ] . count ( m . s ) ;
animation & a = animations [ layer ] [ m . s ] ;
2020-12-26 17:09:09 +00:00
a . attacking = phase ;
2023-01-08 02:09:40 +00:00
auto TC0 = tile_center ( ) ;
a . attackat = lrspintox ( iso_inverse ( T ) * TC0 ) * lxpush ( hdist ( TC0 , T * TC0 ) * ratio + delta ) ;
2018-06-17 15:51:26 +00:00
if ( newanim ) a . wherenow = Id , a . ltick = ticks , a . footphase = 0 ;
}
2020-12-26 17:09:09 +00:00
EX void animateAttack ( const movei & m , int layer ) {
animateAttackOrHug ( m , layer , 1 , 1 / 3. , 0 ) ;
}
EX void animateHug ( const movei & m , int layer ) {
animateAttackOrHug ( m , layer , 3 , 0.5 , - 0.0713828 * cgi . scalefactor ) ;
}
2017-03-23 10:53:57 +00:00
vector < pair < cell * , animation > > animstack ;
2019-11-22 15:32:05 +00:00
EX void indAnimateMovement ( const movei & m , int layer ) {
2017-03-23 10:53:57 +00:00
if ( vid . mspeed > = 5 ) return ; // no animations!
2020-02-29 16:58:59 +00:00
LATE ( indAnimateMovement ( m , layer ) ; )
2019-11-22 15:32:05 +00:00
if ( animations [ layer ] . count ( m . t ) ) {
animation res = animations [ layer ] [ m . t ] ;
animations [ layer ] . erase ( m . t ) ;
animateMovement ( m , layer ) ;
if ( animations [ layer ] . count ( m . t ) )
animstack . push_back ( make_pair ( m . t , animations [ layer ] [ m . t ] ) ) ;
animations [ layer ] [ m . t ] = res ;
2017-03-23 10:53:57 +00:00
}
else {
2019-11-22 15:32:05 +00:00
animateMovement ( m , layer ) ;
if ( animations [ layer ] . count ( m . t ) ) {
animstack . push_back ( make_pair ( m . t , animations [ layer ] [ m . t ] ) ) ;
animations [ layer ] . erase ( m . t ) ;
2017-03-23 10:53:57 +00:00
}
}
}
2019-08-09 19:00:52 +00:00
EX void commitAnimations ( int layer ) {
2020-02-29 16:58:59 +00:00
LATE ( commitAnimations ( layer ) ; )
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( animstack ) ; i + + )
2017-03-23 10:53:57 +00:00
animations [ layer ] [ animstack [ i ] . first ] = animstack [ i ] . second ;
animstack . clear ( ) ;
}
2019-08-09 20:07:03 +00:00
EX void drawBug ( const cellwalker & cw , color_t col ) {
2019-02-17 18:39:44 +00:00
# if CAP_SHAPES
2017-08-06 12:50:16 +00:00
initquickqueue ( ) ;
2020-07-27 16:49:04 +00:00
shiftmatrix V = ggmatrix ( cw . at ) ;
2022-11-12 21:38:45 +00:00
if ( cw . spin ) V = V * ddspin180 ( cw . at , cw . spin ) ;
2019-05-26 16:04:02 +00:00
queuepoly ( V , cgi . shBugBody , col ) ;
2017-08-06 12:50:16 +00:00
quickqueue ( ) ;
2017-12-01 23:23:15 +00:00
# endif
2017-08-06 12:50:16 +00:00
}
2019-08-09 19:00:52 +00:00
EX bool inscreenrange ( cell * c ) {
2018-04-06 21:28:58 +00:00
if ( sphere ) return true ;
2019-11-13 23:26:50 +00:00
if ( euclid ) return celldistance ( centerover , c ) < = get_sightrange_ambush ( ) ;
2019-08-06 10:00:46 +00:00
if ( nonisotropic ) return gmatrix . count ( c ) ;
2019-10-12 12:40:33 +00:00
if ( geometry = = gCrystal344 ) return gmatrix . count ( c ) ;
2019-11-13 23:26:50 +00:00
return heptdistance ( centerover , c ) < = 8 ;
2017-08-06 12:50:16 +00:00
}
2019-05-08 19:09:22 +00:00
# if MAXMDIM >= 4
2019-12-06 13:03:02 +00:00
auto hooksw = addHook ( hooks_swapdim , 100 , [ ] { clearAnimations ( ) ; gmatrix . clear ( ) ; gmatrix0 . clear ( ) ; current_display - > all_drawn_copies . clear ( ) ; } ) ;
2019-05-08 19:09:22 +00:00
# endif
2018-06-10 23:58:31 +00:00
}