2016-08-26 09:58:03 +00:00
// Hyperbolic Rogue -- graphics
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
// Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details
// basic graphics:
2017-03-23 10:53:57 +00:00
bool quitsaves ( ) { return ( items [ itOrbSafety ] & & havesave ) ; }
bool wmspatial , wmescher , wmplain , wmblack , wmascii ;
bool mmspatial , mmhigh , mmmon , mmitem ;
int maxreclevel , reclevel ;
int lastt ;
int backcolor = 0 ;
int detaillevel = 0 ;
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 K(c) (c->type==6?0:1)
# ifdef ROGUEVIZ
# define DOSHMUP (shmup::on || rogueviz::on)
# else
# define DOSHMUP shmup::on
# endif
2015-08-08 13:57:52 +00:00
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 ;
# define COLORBAR "###"
2015-08-08 13:57:52 +00:00
2017-05-27 19:40:40 +00:00
# ifndef NOSDL
2015-08-08 13:57:52 +00:00
SDL_Surface * s ;
2016-01-02 10:09:13 +00:00
SDL_Joystick * sticks [ 8 ] ;
int numsticks ;
2017-05-27 19:40:40 +00:00
# ifndef NOTTF
TTF_Font * font [ 256 ] ;
# endif
2015-08-08 13:57:52 +00:00
# endif
2016-08-26 09:58:03 +00:00
ld shiftmul = 1 ;
bool inHighQual ; // taking high quality screenshot
2017-05-28 22:16:17 +00:00
bool auraNOGL ; // aura without GL
2015-08-08 13:57:52 +00:00
// R:239, G:208, B:207
2016-01-02 10:09:13 +00:00
unsigned int skincolors [ ] = { 7 , 0xD0D0D0FF , 0xEFD0C9FF , 0xC77A58FF , 0xA58869FF , 0x602010FF , 0xFFDCB1FF , 0xEDE4C8FF } ;
unsigned int haircolors [ ] = { 8 , 0x686868FF , 0x8C684AFF , 0xF2E1AEFF , 0xB55239FF , 0xFFFFFFFF , 0x804000FF , 0x502810FF , 0x301800FF } ;
unsigned int dresscolors [ ] = { 6 , 0xC00000FF , 0x00C000FF , 0x0000C0FF , 0xC0C000FF , 0xC0C0C0FF , 0x202020FF } ;
2016-08-26 09:58:03 +00:00
unsigned int dresscolors2 [ ] = { 7 , 0x8080FFC0 , 0x80FF80C0 , 0xFF8080C0 , 0xFFFF80C0 , 0xFF80FFC0 , 0x80FFFFC0 , 0xFFFFFF80 } ;
2016-01-02 10:09:13 +00:00
unsigned int swordcolors [ ] = { 6 , 0xC0C0C0FF , 0xFFFFFFFF , 0xFFC0C0FF , 0xC0C0FFFF , 0x808080FF , 0x202020FF } ;
2016-08-26 09:58:03 +00:00
unsigned int eyecolors [ ] = { 4 , 0x00C000FF , 0x0000C0FF , 0xC00000FF , 0xC0C000FF } ;
2015-08-08 13:57:52 +00:00
// is the player using mouse? (used for auto-cross)
bool mousing = true ;
// is the mouse button pressed?
bool mousepressed = false ;
2017-03-23 10:53:57 +00:00
bool mousemoved = false ;
bool actonrelease = false ;
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
emtype cmode = emNormal , lastmode = emNormal ; // last mode in Help
2015-08-08 13:57:52 +00:00
//
int axestate ;
int ticks ;
2017-03-23 10:53:57 +00:00
int frameid ;
2015-08-08 13:57:52 +00:00
videopar vid ;
int default_language ;
2016-08-26 09:58:03 +00:00
charstyle & getcs ( ) {
2017-03-23 10:53:57 +00:00
if ( multi : : players > 1 & & multi : : cpid > = 0 & & multi : : cpid < multi : : players )
return multi : : scs [ multi : : cpid ] ;
2016-08-26 09:58:03 +00:00
else
return vid . cs ;
}
2017-04-08 15:18:29 +00:00
bool camelotcheat ;
2016-08-26 09:58:03 +00:00
int playergender ( ) {
return ( getcs ( ) . charid & 1 ) ? GEN_F : GEN_M ;
}
2016-01-02 10:09:13 +00:00
int princessgender ( ) {
2016-08-26 09:58:03 +00:00
int g = playergender ( ) ;
if ( vid . samegender ) return g ;
return g = = GEN_M ? GEN_F : GEN_M ;
2016-01-02 10:09:13 +00:00
}
2015-08-08 13:57:52 +00:00
int lang ( ) {
if ( vid . language > = 0 )
return vid . language ;
return default_language ;
}
2017-03-23 10:53:57 +00:00
eItem orbToTarget ;
eMonster monsterToSummon ;
2015-08-08 13:57:52 +00:00
int sightrange = 7 ;
2017-03-23 10:53:57 +00:00
bool overgenerate = false ; // generate a bigger area with high sightrange
cell * mouseover , * mouseover2 , * lmouseover , * centerover ;
2016-01-02 10:09:13 +00:00
ld modist , modist2 , centdist ;
2015-08-08 13:57:52 +00:00
string mouseovers ;
2016-01-02 10:09:13 +00:00
movedir mousedest , joydir ;
int mousex , mousey , joyx , joyy , panjoyx , panjoyy ;
2015-08-08 13:57:52 +00:00
bool autojoy = true ;
hyperpoint mouseh ;
2017-03-23 10:53:57 +00:00
bool leftclick , rightclick , targetclick , hiliteclick , anyshiftclick , wheelclick ,
forcetarget , lshiftclick , lctrlclick ;
2015-08-08 13:57:52 +00:00
bool gtouched ;
bool revcontrol ;
2017-03-23 10:53:57 +00:00
int getcstat ; ld getcshift ; bool inslider ;
2015-08-08 13:57:52 +00:00
int ZZ ;
string help ;
2017-05-28 22:16:17 +00:00
# ifndef NOLAMBDAS
2017-05-27 19:40:40 +00:00
function < void ( ) > help_delegate ;
# endif
2015-08-08 13:57:52 +00:00
int andmode = 0 ;
int darken = 0 ;
2017-03-23 10:53:57 +00:00
struct fallanim {
int t_mon , t_floor ;
eWall walltype ;
eMonster m ;
fallanim ( ) { t_floor = 0 ; t_mon = 0 ; walltype = waNone ; }
} ;
map < cell * , fallanim > fallanims ;
2016-01-02 10:09:13 +00:00
bool doHighlight ( ) {
2017-03-23 10:53:57 +00:00
return ( hiliteclick & & darken < 2 ) ? ! mmhigh : mmhigh ;
2016-01-02 10:09:13 +00:00
}
2017-05-27 19:40:40 +00:00
# ifndef NOSDL
2015-08-08 13:57:52 +00:00
int & qpixel ( SDL_Surface * surf , int x , int y ) {
if ( x < 0 | | y < 0 | | x > = surf - > w | | y > = surf - > h ) return ZZ ;
char * p = ( char * ) surf - > pixels ;
p + = y * surf - > pitch ;
int * pi = ( int * ) ( p ) ;
return pi [ x ] ;
}
int qpixel3 ( SDL_Surface * surf , int x , int y ) {
if ( x < 0 | | y < 0 | | x > = surf - > w | | y > = surf - > h ) return ZZ ;
char * p = ( char * ) surf - > pixels ;
p + = y * surf - > pitch ;
p + = x ;
int * pi = ( int * ) ( p ) ;
return pi [ 0 ] ;
}
2017-05-27 19:40:40 +00:00
# endif
2015-08-08 13:57:52 +00:00
2017-05-27 19:40:40 +00:00
# ifndef EXTERNALFONT
# ifndef NOTTF
2015-08-08 13:57:52 +00:00
void loadfont ( int siz ) {
if ( ! font [ siz ] ) {
2017-03-23 10:53:57 +00:00
# ifdef WEB
font [ siz ] = TTF_OpenFont ( " sans-serif " , siz ) ;
# else
2015-08-08 13:57:52 +00:00
font [ siz ] = TTF_OpenFont ( " DejaVuSans-Bold.ttf " , siz ) ;
2017-03-23 10:53:57 +00:00
# endif
2016-08-26 09:58:03 +00:00
// Destination set by ./configure (in the GitHub repository)
2016-01-02 10:09:13 +00:00
# ifdef FONTDESTDIR
2015-08-08 13:57:52 +00:00
if ( font [ siz ] = = NULL ) {
2015-08-09 20:36:13 +00:00
font [ siz ] = TTF_OpenFont ( FONTDESTDIR , siz ) ;
2016-01-02 10:09:13 +00:00
}
# endif
if ( font [ siz ] = = NULL ) {
printf ( " error: Font file not found \n " ) ;
exit ( 1 ) ;
2015-08-08 13:57:52 +00:00
}
}
}
2017-05-27 19:40:40 +00:00
# endif
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
int gl_width ( int size , const char * s ) ;
2015-08-08 13:57:52 +00:00
int textwidth ( int siz , const string & str ) {
if ( size ( str ) = = 0 ) return 0 ;
2017-03-23 10:53:57 +00:00
2017-05-27 19:40:40 +00:00
# ifdef NOTTF
2017-03-23 10:53:57 +00:00
return gl_width ( siz , str . c_str ( ) ) ;
# else
2015-08-08 13:57:52 +00:00
loadfont ( siz ) ;
int w , h ;
TTF_SizeUTF8 ( font [ siz ] , str . c_str ( ) , & w , & h ) ;
// printf("width = %d [%d]\n", w, size(str));
return w ;
2017-03-23 10:53:57 +00:00
# endif
2015-08-08 13:57:52 +00:00
}
# endif
2017-03-23 10:53:57 +00:00
int textwidth ( int siz , const string & str ) ;
2015-08-08 13:57:52 +00:00
# ifdef IOS
int textwidth ( int siz , const string & str ) {
return mainfont - > getSize ( str , siz / 36.0 ) . width ;
}
# endif
2016-08-26 09:58:03 +00:00
int gradient ( int c0 , int c1 , ld v0 , ld v , ld v1 ) ;
# ifdef LOCAL
double fadeout = 1 ;
# endif
2015-08-08 13:57:52 +00:00
int darkened ( int c ) {
2016-08-26 09:58:03 +00:00
# ifdef LOCAL
c = gradient ( 0 , c , 0 , fadeout , 1 ) ;
# endif
// c = ((c & 0xFFFF) << 8) | ((c & 0xFF0000) >> 16);
// c = ((c & 0xFFFF) << 8) | ((c & 0xFF0000) >> 16);
2015-08-08 13:57:52 +00:00
for ( int i = 0 ; i < darken ; i + + ) c & = 0xFEFEFE , c > > = 1 ;
return c ;
}
int darkenedby ( int c , int lev ) {
for ( int i = 0 ; i < lev ; i + + ) c & = 0xFEFEFE , c > > = 1 ;
return c ;
}
int darkena ( int c , int lev , int a ) {
for ( int i = 0 ; i < lev ; i + + ) c & = 0xFEFEFE , c > > = 1 ;
return ( c < < 8 ) + a ;
}
# ifdef GL
2017-03-23 10:53:57 +00:00
bool cameraangle_on ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
void setcameraangle ( bool b ) {
if ( cameraangle_on ! = b ) {
glMatrixMode ( GL_PROJECTION ) ;
cameraangle_on = b ;
ld cam = vid . camera_angle * M_PI / 180 ;
GLfloat cc = cos ( cam ) ;
GLfloat ss = sin ( cam * ( b ? 1 : - 1 ) ) ;
GLfloat yzspin [ 16 ] = {
1 , 0 , 0 , 0 ,
0 , cc , ss , 0 ,
0 , - ss , cc , 0 ,
0 , 0 , 0 , 1
} ;
glMultMatrixf ( yzspin ) ;
}
2015-08-08 13:57:52 +00:00
}
void selectEyeGL ( int ed ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " selectEyeGL \n " ) ) ;
2015-08-08 13:57:52 +00:00
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
glTranslatef ( ( vid . xcenter * 2. ) / vid . xres - 1 , 1 - ( vid . ycenter * 2. ) / vid . yres , 0 ) ;
2017-03-23 10:53:57 +00:00
if ( pmodel ) {
vid . scrdist = 4 * vid . radius ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
// simulate glOrtho
GLfloat ortho [ 16 ] = {
GLfloat ( 2. / vid . xres ) , 0 , 0 , 0 ,
0 , GLfloat ( - 2. / vid . yres ) , 0 , 0 ,
0 , 0 , GLfloat ( .4 / vid . scrdist ) , 0 ,
0 , 0 , 0 , 1 } ;
vid . scrdist = - vid . scrdist ;
glMultMatrixf ( ortho ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
}
else {
float ve = ed * vid . eye ;
ve * = 2 ; // vid.xres; ve /= vid.radius;
if ( ve )
glTranslatef ( - ( ve * vid . radius ) * ( vid . alpha - ( vid . radius * 1. / vid . xres ) * vid . eye ) / vid . xres , 0 , 0 ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
float lowdepth = .1 ;
float hidepth = 1e9 ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
// simulate glFrustum
GLfloat frustum [ 16 ] = {
GLfloat ( vid . yres * 1. / vid . xres ) , 0 , 0 , 0 ,
0 , 1 , 0 , 0 ,
0 , 0 , - ( hidepth + lowdepth ) / ( hidepth - lowdepth ) , - 1 ,
0 , 0 , - 2 * lowdepth * hidepth / ( hidepth - lowdepth ) , 0 } ;
glMultMatrixf ( frustum ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
GLfloat sc = vid . radius / ( vid . yres / 2. ) ;
GLfloat mat [ 16 ] = { sc , 0 , 0 , 0 , 0 , - sc , 0 , 0 , 0 , 0 , - 1 , 0 , 0 , 0 , 0 , 1 } ;
glMultMatrixf ( mat ) ;
if ( ve ) glTranslatef ( ve , 0 , vid . eye ) ;
vid . scrdist = vid . yres * sc / 2 ;
}
cameraangle_on = false ;
2015-08-08 13:57:52 +00:00
}
void selectEyeMask ( int ed ) {
if ( ed = = 0 ) {
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
}
else if ( ed = = 1 ) {
glColorMask ( GL_TRUE , GL_FALSE , GL_FALSE , GL_TRUE ) ;
}
else if ( ed = = - 1 ) {
glColorMask ( GL_FALSE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
}
}
void setGLProjection ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " setGLProjection \n " ) ) ;
2015-08-08 13:57:52 +00:00
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
2017-03-23 10:53:57 +00:00
unsigned char * c = ( unsigned char * ) ( & backcolor ) ;
glClearColor ( c [ 2 ] / 255.0 , c [ 1 ] / 255.0 , c [ 0 ] / 255.0 , 1 ) ;
2015-08-08 13:57:52 +00:00
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
glEnable ( GL_BLEND ) ;
2017-03-23 10:53:57 +00:00
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
if ( pmodel = = mdBall | | pmodel = = mdHyperboloid ) {
# ifdef GL_ES
glClearDepthf ( 1.0f ) ;
# else
glClearDepth ( 1.0f ) ;
# endif
glEnable ( GL_DEPTH_TEST ) ;
glDepthFunc ( GL_LEQUAL ) ;
}
else
glDisable ( GL_DEPTH_TEST ) ;
2015-08-08 13:57:52 +00:00
selectEyeGL ( 0 ) ;
}
void buildpolys ( ) ;
2017-05-27 19:40:40 +00:00
# ifdef MOBILE
# define EXTERNALFONT
# endif
# ifndef EXTERNALFONT
2015-08-08 13:57:52 +00:00
struct glfont_t {
GLuint * textures ; // Holds The Texture Id's
//GLuint list_base; // Holds The First Display List ID
int widths [ 128 + NUMEXTRA ] ;
int heights [ 128 + NUMEXTRA ] ;
float tx [ 128 + NUMEXTRA ] ;
float ty [ 128 + NUMEXTRA ] ;
} ;
glfont_t * glfont [ 256 ] ;
inline int next_p2 ( int a )
{
int rval = 1 ;
// rval<<=1 Is A Prettier Way Of Writing rval*=2;
while ( rval < a ) rval < < = 1 ;
return rval ;
}
void glError ( const char * GLcall , const char * file , const int line ) {
GLenum errCode = glGetError ( ) ;
if ( errCode ! = GL_NO_ERROR ) {
2017-03-23 10:53:57 +00:00
// fprintf(stderr, "OPENGL ERROR #%i: in file %s on line %i :: %s\n",errCode,file, line, GLcall);
2015-08-08 13:57:52 +00:00
}
}
# define GLERR(call) glError(call, __FILE__, __LINE__)
2017-05-27 19:40:40 +00:00
# ifdef NOTTF
# define FIXEDSIZE
# endif
# ifdef CREATEFONT
# define FIXEDSIZE
# endif
# ifdef FIXEDSIZE
# include "nofont.cpp"
# endif
2015-08-08 13:57:52 +00:00
void init_glfont ( int size ) {
if ( glfont [ size ] ) return ;
2016-08-26 09:58:03 +00:00
DEBB ( DF_INIT , ( debugfile , " init GL font: %d \n " , size ) ) ;
2015-08-08 13:57:52 +00:00
glfont [ size ] = new glfont_t ;
glfont_t & f ( * ( glfont [ size ] ) ) ;
f . textures = new GLuint [ 128 + NUMEXTRA ] ;
//f.list_base = glGenLists(128);
glGenTextures ( 128 + NUMEXTRA , f . textures ) ;
2017-05-27 19:40:40 +00:00
# ifndef NOTTF
2015-08-08 13:57:52 +00:00
loadfont ( size ) ;
if ( ! font [ size ] ) return ;
char str [ 2 ] ; str [ 1 ] = 0 ;
SDL_Color white ;
white . r = white . g = white . b = 255 ;
2017-03-23 10:53:57 +00:00
# endif
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
// glListBase(0);
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
for ( int ch = 1 ; ch < 128 + NUMEXTRA ; ch + + ) {
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( ch < 32 ) continue ;
2017-05-27 19:40:40 +00:00
# ifdef NOTTF
int otwidth , otheight , tpix [ 3000 ] , tpixindex = 0 ;
2017-03-23 10:53:57 +00:00
loadCompressedChar ( otwidth , otheight , tpix ) ;
# else
2015-08-08 13:57:52 +00:00
SDL_Surface * txt ;
if ( ch < 128 ) {
str [ 0 ] = ch ;
txt = TTF_RenderText_Blended ( font [ size ] , str , white ) ;
}
else {
txt = TTF_RenderUTF8_Blended ( font [ size ] , natchars [ ch - 128 ] , white ) ;
}
if ( txt = = NULL ) continue ;
2017-05-27 19:40:40 +00:00
# ifdef CREATEFONT
generateFont ( ch , txt ) ;
# endif
2017-03-23 10:53:57 +00:00
int otwidth = txt - > w ;
int otheight = txt - > h ;
# endif
int twidth = next_p2 ( otwidth ) ;
int theight = next_p2 ( otheight ) ;
2017-05-27 19:40:40 +00:00
# ifdef NOTTF
2017-03-23 10:53:57 +00:00
int expanded_data [ twidth * theight ] ;
# else
2015-08-08 13:57:52 +00:00
Uint16 expanded_data [ twidth * theight ] ;
2017-03-23 10:53:57 +00:00
# endif
2015-08-08 13:57:52 +00:00
for ( int j = 0 ; j < theight ; j + + ) for ( int i = 0 ; i < twidth ; i + + ) {
2017-05-27 19:40:40 +00:00
# ifdef NOTTF
2017-03-23 10:53:57 +00:00
expanded_data [ ( i + j * twidth ) ] = ( i > = otwidth | | j > = otheight ) ? 0 : tpix [ tpixindex + + ] ;
# else
2015-08-08 13:57:52 +00:00
expanded_data [ ( i + j * twidth ) ] =
( i > = txt - > w | | j > = txt - > h ) ? 0 : ( ( qpixel ( txt , i , j ) > > 24 ) & 0xFF ) * 0x101 ;
2017-03-23 10:53:57 +00:00
# endif
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
/* if(ch == '@') {
for ( int j = 0 ; j < theight ; j + + ) {
for ( int i = 0 ; i < twidth ; i + + ) printf ( " %4x " , expanded_data [ ( i + j * twidth ) ] ) ;
printf ( " \n " ) ;
}
} */
2015-08-08 13:57:52 +00:00
// printf("b\n");
2017-03-23 10:53:57 +00:00
f . widths [ ch ] = otwidth ;
f . heights [ ch ] = otheight ;
2015-08-08 13:57:52 +00:00
glBindTexture ( GL_TEXTURE_2D , f . textures [ ch ] ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , twidth , theight , 0 ,
2017-05-27 19:40:40 +00:00
# ifdef NOTTF
2017-03-23 10:53:57 +00:00
GL_RGBA , GL_UNSIGNED_BYTE ,
# else
GL_LUMINANCE_ALPHA , GL_UNSIGNED_BYTE ,
# endif
expanded_data ) ;
2015-08-08 13:57:52 +00:00
// printf("c\n");
2017-03-23 10:53:57 +00:00
float x = ( float ) otwidth / ( float ) twidth ;
float y = ( float ) otheight / ( float ) theight ;
2015-08-08 13:57:52 +00:00
f . tx [ ch ] = x ;
f . ty [ ch ] = y ;
/* glNewList(f.list_base+ch,GL_COMPILE);
glBindTexture ( GL_TEXTURE_2D , f . textures [ ch ] ) ;
//glPushMatrix();
// glTranslatef(bitmap_glyph->left,0,0);
// glTranslatef(0,bitmap_glyph->top-bitmap.rows,0);
// printf("d\n");
glBegin ( GL_QUADS ) ;
float eps = 0 ;
glTexCoord2d ( eps , eps ) ; glVertex2f ( 0 , txt - > h ) ;
glTexCoord2d ( eps , y - 0 ) ; glVertex2f ( 0 , 0 ) ;
glTexCoord2d ( x - eps , y - 0 ) ; glVertex2f ( txt - > w , 0 ) ;
glTexCoord2d ( x - eps , 0 ) ; glVertex2f ( txt - > w , txt - > h ) ;
glEnd ( ) ;
glEndList ( ) ; */
//glPopMatrix();
2017-05-27 19:40:40 +00:00
# ifndef NOTTF
2015-08-08 13:57:52 +00:00
SDL_FreeSurface ( txt ) ;
2017-03-23 10:53:57 +00:00
# endif
2015-08-08 13:57:52 +00:00
}
//printf("init size=%d ok\n", size);
GLERR ( " initfont " ) ;
}
int getnext ( const char * s , int & i ) {
for ( int k = 0 ; k < NUMEXTRA ; k + + )
if ( s [ i ] = = natchars [ k ] [ 0 ] & & s [ i + 1 ] = = natchars [ k ] [ 1 ] ) {
i + = 2 ; return 128 + k ;
}
if ( s [ i ] < 0 & & s [ i + 1 ] < 0 ) {
printf ( " Unknown character: '%c%c' \n " , s [ i ] , s [ i + 1 ] ) ;
i + = 2 ; return ' ? ' ;
}
return s [ i + + ] ;
}
2017-03-23 10:53:57 +00:00
GLfloat tver [ 24 ] ;
int gl_width ( int size , const char * s ) {
int gsiz = size ;
if ( size > vid . fsize | | size > 72 ) gsiz = 72 ;
2017-05-27 19:40:40 +00:00
# ifdef FIXEDSIZE
2017-03-23 10:53:57 +00:00
gsiz = 36 ;
# endif
init_glfont ( gsiz ) ;
2017-05-27 19:40:40 +00:00
# ifndef NOTTF
2017-03-23 10:53:57 +00:00
if ( ! font [ gsiz ] ) return 0 ;
# endif
glfont_t & f ( * glfont [ gsiz ] ) ;
int x = 0 ;
for ( int i = 0 ; s [ i ] ; ) {
int tabid = getnext ( s , i ) ;
x + = f . widths [ tabid ] * size / gsiz ;
}
return x ;
}
2015-08-08 13:57:52 +00:00
bool gl_print ( int x , int y , int shift , int size , const char * s , int color , int align ) {
2017-03-23 10:53:57 +00:00
int gsiz = size ;
if ( size > vid . fsize | | size > 72 ) gsiz = 72 ;
2017-05-27 19:40:40 +00:00
# ifdef FIXEDSIZE
2017-03-23 10:53:57 +00:00
gsiz = 36 ;
# endif
init_glfont ( gsiz ) ;
2017-05-27 19:40:40 +00:00
# ifndef NOTTF
2017-03-23 10:53:57 +00:00
if ( ! font [ gsiz ] ) return false ;
# endif
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
glfont_t & f ( * glfont [ gsiz ] ) ;
2015-08-08 13:57:52 +00:00
glDisable ( GL_LIGHTING ) ;
glEnable ( GL_TEXTURE_2D ) ;
glMatrixMode ( GL_MODELVIEW ) ;
2017-03-23 10:53:57 +00:00
glcolor2 ( ( color < < 8 ) | 0xFF ) ;
2015-08-08 13:57:52 +00:00
int tsize = 0 ;
2017-03-23 10:53:57 +00:00
for ( int i = 0 ; s [ i ] ; ) tsize + = f . widths [ getnext ( s , i ) ] * size / gsiz ;
2015-08-08 13:57:52 +00:00
x - = tsize * align / 16 ;
2017-03-23 10:53:57 +00:00
y + = f . heights [ 32 ] * size / ( gsiz * 2 ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
int ysiz = f . heights [ 32 ] * size / gsiz ;
bool clicked = ( mousex > = x & & mousey < = y & & mousex < = x + tsize & & mousey > = y - ysiz ) ;
/* extern bool markcorner;
if ( clicked & & markcorner ) {
markcorner = false ;
int w = tsize , h = - ysiz ;
displaystr ( x , y , 1 , 10 , " X " , 0xFFFFFF , 8 ) ;
displaystr ( x + w , y , 1 , 10 , " X " , 0xFFFFFF , 8 ) ;
displaystr ( x , y + h , 1 , 10 , " X " , 0xFFFFFF , 8 ) ;
displaystr ( x + w , y + h , 1 , 10 , " X " , 0xFFFFFF , 8 ) ;
markcorner = true ;
} */
2015-08-08 13:57:52 +00:00
for ( int i = 0 ; s [ i ] ; ) {
// glListBase(f.list_base);
// glCallList(s[i]); // s[i]);
int tabid = getnext ( s , i ) ;
float fx = f . tx [ tabid ] ;
float fy = f . ty [ tabid ] ;
2017-03-23 10:53:57 +00:00
int wi = f . widths [ tabid ] * size / gsiz ;
int hi = f . heights [ tabid ] * size / gsiz ;
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
GLERR ( " pre-print " ) ;
2015-08-08 13:57:52 +00:00
for ( int ed = ( vid . goteyes & & shift ) ? - 1 : 0 ; ed < 2 ; ed + = 2 ) {
glPushMatrix ( ) ;
glTranslatef ( x - ed * shift - vid . xcenter , y - vid . ycenter , vid . scrdist ) ;
selectEyeMask ( ed ) ;
glBindTexture ( GL_TEXTURE_2D , f . textures [ tabid ] ) ;
2017-03-23 10:53:57 +00:00
# if 1
tver [ 1 ] = tver [ 10 ] = - hi ;
tver [ 6 ] = tver [ 9 ] = wi ;
tver [ 12 + 4 ] = tver [ 12 + 7 ] = fy ;
tver [ 12 + 6 ] = tver [ 12 + 9 ] = fx ;
activateVertexArray ( tver , 8 ) ;
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
glTexCoordPointer ( 3 , GL_FLOAT , 0 , & tver [ 12 ] ) ;
glDrawArrays ( GL_TRIANGLE_FAN , 0 , 4 ) ;
glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
# else
2015-08-08 13:57:52 +00:00
glBegin ( GL_QUADS ) ;
glTexCoord2d ( 0 , 0 ) ; glVertex2f ( 0 , - hi ) ;
glTexCoord2d ( 0 , fy ) ; glVertex2f ( 0 , 0 ) ;
glTexCoord2d ( fx , fy ) ; glVertex2f ( wi , 0 ) ;
glTexCoord2d ( fx , 0 ) ; glVertex2f ( wi , - hi ) ;
glEnd ( ) ;
2017-03-23 10:53:57 +00:00
# endif
2015-08-08 13:57:52 +00:00
glPopMatrix ( ) ;
}
if ( vid . goteyes ) selectEyeMask ( 0 ) ;
GLERR ( " print " ) ;
// int tabid = s[i];
2017-03-23 10:53:57 +00:00
x + = wi ;
2015-08-08 13:57:52 +00:00
/*
printf ( " point %d,%d \n " , x , y ) ;
glBegin ( GL_POINTS ) ;
glVertex3f ( rand ( ) % 100 - rand ( ) % 100 , rand ( ) % 100 - rand ( ) % 100 , 100 ) ;
glEnd ( ) ; */
}
glDisable ( GL_TEXTURE_2D ) ;
return clicked ;
}
# endif
void resetGL ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_INIT , ( debugfile , " reset GL \n " ) ) ;
2017-05-27 19:40:40 +00:00
# ifndef EXTERNALFONT
2015-08-08 13:57:52 +00:00
for ( int i = 0 ; i < 128 ; i + + ) if ( glfont [ i ] ) {
delete glfont [ i ] ;
glfont [ i ] = NULL ;
}
# endif
buildpolys ( ) ;
}
# endif
# ifndef MOBILE
bool displaystr ( int x , int y , int shift , int size , const char * str , int color , int align ) {
2017-05-27 19:40:40 +00:00
2015-08-08 13:57:52 +00:00
if ( strlen ( str ) = = 0 ) return false ;
2017-03-23 10:53:57 +00:00
if ( size < 4 | | size > 255 ) {
2015-08-08 13:57:52 +00:00
return false ;
}
# ifdef GL
if ( vid . usingGL ) return gl_print ( x , y , shift , size , str , color , align ) ;
# endif
2017-05-27 19:40:40 +00:00
# ifdef NOTTF
static bool towarn = true ;
if ( towarn ) towarn = false , printf ( " WARNING: NOTTF works only with OpenGL! \n " ) ;
return false ;
# else
2015-08-08 13:57:52 +00:00
SDL_Color col ;
col . r = ( color > > 16 ) & 255 ;
col . g = ( color > > 8 ) & 255 ;
col . b = ( color > > 0 ) & 255 ;
col . r > > = darken ; col . g > > = darken ; col . b > > = darken ;
loadfont ( size ) ;
2016-01-02 10:09:13 +00:00
SDL_Surface * txt = ( vid . usingAA ? TTF_RenderUTF8_Blended : TTF_RenderUTF8_Solid ) ( font [ size ] , str , col ) ;
2015-08-08 13:57:52 +00:00
if ( txt = = NULL ) return false ;
SDL_Rect rect ;
rect . w = txt - > w ;
rect . h = txt - > h ;
rect . x = x - rect . w * align / 16 ;
rect . y = y - rect . h / 2 ;
bool clicked = ( mousex > = rect . x & & mousey > = rect . y & & mousex < = rect . x + rect . w & & mousey < = rect . y + rect . h ) ;
if ( shift ) {
SDL_Surface * txt2 = SDL_DisplayFormat ( txt ) ;
SDL_LockSurface ( txt2 ) ;
SDL_LockSurface ( s ) ;
int c0 = qpixel ( txt2 , 0 , 0 ) ;
for ( int yy = 0 ; yy < rect . h ; yy + + )
for ( int xx = 0 ; xx < rect . w ; xx + + ) if ( qpixel ( txt2 , xx , yy ) ! = c0 )
qpixel ( s , rect . x + xx - shift , rect . y + yy ) | = color & 0xFF0000 ,
qpixel ( s , rect . x + xx + shift , rect . y + yy ) | = color & 0x00FFFF ;
SDL_UnlockSurface ( s ) ;
SDL_UnlockSurface ( txt2 ) ;
SDL_FreeSurface ( txt2 ) ;
}
else {
SDL_BlitSurface ( txt , NULL , s , & rect ) ;
}
SDL_FreeSurface ( txt ) ;
return clicked ;
2017-05-27 19:40:40 +00:00
# endif
2015-08-08 13:57:52 +00:00
}
bool displaystr ( int x , int y , int shift , int size , const string & s , int color , int align ) {
return displaystr ( x , y , shift , size , s . c_str ( ) , color , align ) ;
}
bool displayfr ( int x , int y , int b , int size , const string & s , int color , int align ) {
displaystr ( x - b , y , 0 , size , s , 0 , align ) ;
displaystr ( x + b , y , 0 , size , s , 0 , align ) ;
displaystr ( x , y - b , 0 , size , s , 0 , align ) ;
displaystr ( x , y + b , 0 , size , s , 0 , align ) ;
return displaystr ( x , y , 0 , size , s , color , align ) ;
}
bool displaychr ( int x , int y , int shift , int size , char chr , int col ) {
char buf [ 2 ] ;
buf [ 0 ] = chr ; buf [ 1 ] = 0 ;
return displaystr ( x , y , shift , size , buf , col , 8 ) ;
}
# else
vector < int > graphdata ;
void gdpush ( int t ) {
graphdata . push_back ( t ) ;
}
bool displaychr ( int x , int y , int shift , int size , char chr , int col ) {
gdpush ( 2 ) ; gdpush ( x ) ; gdpush ( y ) ; gdpush ( 8 ) ;
gdpush ( col ) ; gdpush ( size ) ; gdpush ( 0 ) ;
gdpush ( 1 ) ; gdpush ( chr ) ;
return false ;
}
void gdpush_utf8 ( const string & s ) {
2016-08-26 09:58:03 +00:00
int g = ( int ) graphdata . size ( ) , q = 0 ;
2015-08-08 13:57:52 +00:00
gdpush ( ( int ) s . size ( ) ) ; for ( int i = 0 ; i < s . size ( ) ; i + + ) {
2016-08-26 09:58:03 +00:00
# ifdef ANDROID
2015-08-08 13:57:52 +00:00
unsigned char uch = ( unsigned char ) s [ i ] ;
if ( uch > = 192 & & uch < 224 ) {
int u = ( ( s [ i ] - 192 ) & 31 ) < < 6 ;
i + + ;
u + = ( s [ i ] - 128 ) & 63 ;
gdpush ( u ) ; q + + ;
}
2016-08-26 09:58:03 +00:00
else
# endif
{
2015-08-08 13:57:52 +00:00
gdpush ( s [ i ] ) ; q + + ;
}
}
graphdata [ g ] = q ;
}
bool displayfr ( int x , int y , int b , int size , const string & s , int color , int align ) {
gdpush ( 2 ) ; gdpush ( x ) ; gdpush ( y ) ; gdpush ( align ) ;
gdpush ( color ) ; gdpush ( size ) ; gdpush ( b ) ;
gdpush_utf8 ( s ) ;
2016-08-26 09:58:03 +00:00
int mx = mousex - x ;
int my = mousey - y ;
2017-03-23 10:53:57 +00:00
int len = textwidth ( size , s ) ;
2015-08-08 13:57:52 +00:00
return
2017-03-23 10:53:57 +00:00
mx > = - len * align / 32 & & mx < = + len * ( 16 - align ) / 32 & &
2015-08-08 13:57:52 +00:00
my > = - size * 3 / 4 & & my < = + size * 3 / 4 ;
}
bool displaystr ( int x , int y , int shift , int size , const string & s , int color , int align ) {
2016-08-26 09:58:03 +00:00
return displayfr ( x , y , 0 , size , s , color , align ) ;
}
bool displaystr ( int x , int y , int shift , int size , char const * s , int color , int align ) {
return displayfr ( x , y , 0 , size , s , color , align ) ;
2015-08-08 13:57:52 +00:00
}
# endif
bool displaynum ( int x , int y , int shift , int size , int col , int val , string title ) {
char buf [ 64 ] ;
sprintf ( buf , " %d " , val ) ;
bool b1 = displayfr ( x - 8 , y , 1 , size , buf , col , 16 ) ;
bool b2 = displayfr ( x , y , 1 , size , title , col , 0 ) ;
if ( ( b1 | | b2 ) & & gtouched ) {
col ^ = 0x00FFFF ;
displayfr ( x - 8 , y , 1 , size , buf , col , 16 ) ;
displayfr ( x , y , 1 , size , title , col , 0 ) ;
}
return b1 | | b2 ;
}
struct msginfo {
int stamp ;
char flashout ;
char spamtype ;
2017-03-23 10:53:57 +00:00
int quantity ;
2015-08-08 13:57:52 +00:00
string msg ;
} ;
vector < msginfo > msgs ;
2017-03-23 10:53:57 +00:00
vector < msginfo > gamelog ;
2015-08-08 13:57:52 +00:00
void flashMessages ( ) {
for ( int i = 0 ; i < size ( msgs ) ; i + + )
if ( msgs [ i ] . stamp < ticks - 1000 & & ! msgs [ i ] . flashout ) {
msgs [ i ] . flashout = true ;
msgs [ i ] . stamp = ticks ;
}
}
2017-03-23 10:53:57 +00:00
void addMessageToLog ( msginfo & m , vector < msginfo > & log ) {
if ( size ( log ) ! = 0 ) {
msginfo & last = log [ size ( log ) - 1 ] ;
if ( last . msg = = m . msg ) {
int q = m . quantity + last . quantity ;
last = m ; last . quantity = q ;
return ;
}
}
if ( size ( log ) < 200 )
log . push_back ( m ) ;
else {
for ( int i = 0 ; i < size ( log ) - 1 ; i + + ) swap ( log [ i ] , log [ i + 1 ] ) ;
log [ size ( log ) - 1 ] = m ;
}
}
void clearMessages ( ) { msgs . clear ( ) ; }
2015-08-08 13:57:52 +00:00
void addMessage ( string s , char spamtype ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_MSG , ( debugfile , " addMessage: %s \n " , s . c_str ( ) ) ) ;
2017-03-23 10:53:57 +00:00
2015-08-08 13:57:52 +00:00
msginfo m ;
m . msg = s ; m . spamtype = spamtype ; m . flashout = false ; m . stamp = ticks ;
2017-03-23 10:53:57 +00:00
m . quantity = 1 ;
addMessageToLog ( m , gamelog ) ;
addMessageToLog ( m , msgs ) ;
2015-08-08 13:57:52 +00:00
}
void drawmessages ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " draw messages \n " ) ) ;
2015-08-08 13:57:52 +00:00
int i = 0 ;
int t = ticks ;
for ( int j = 0 ; j < size ( msgs ) ; j + + ) {
int age = msgs [ j ] . flashout * ( t - msgs [ j ] . stamp ) ;
if ( msgs [ j ] . spamtype ) {
for ( int i = j + 1 ; i < size ( msgs ) ; i + + ) if ( msgs [ i ] . spamtype = = msgs [ j ] . spamtype )
msgs [ j ] . flashout = 2 ;
}
if ( age < 256 * vid . flashtime ) {
int x = vid . xres / 2 ;
int y = vid . yres - vid . fsize * ( size ( msgs ) - j ) - ( ISIOS ? 4 : 0 ) ;
2017-03-23 10:53:57 +00:00
string s = msgs [ j ] . msg ;
if ( msgs [ j ] . quantity > 1 ) s + = " (x " + its ( msgs [ j ] . quantity ) + " ) " ;
displayfr ( x , y , 1 , vid . fsize , s , 0x10101 * ( 255 - age / vid . flashtime ) , 8 ) ;
2015-08-08 13:57:52 +00:00
msgs [ i + + ] = msgs [ j ] ;
}
}
msgs . resize ( i ) ;
}
2017-03-23 10:53:57 +00:00
eModel pmodel = mdDisk ;
2016-08-26 09:58:03 +00:00
ld ghx , ghy , ghgx , ghgy ;
hyperpoint ghpm = C0 ;
2017-03-23 10:53:57 +00:00
void ghcheck ( hyperpoint & ret , const hyperpoint & H ) {
if ( hypot ( ret [ 0 ] - ghx , ret [ 1 ] - ghy ) < hypot ( ghgx - ghx , ghgy - ghy ) ) {
ghpm = H ; ghgx = ret [ 0 ] ; ghgy = ret [ 1 ] ;
2016-08-26 09:58:03 +00:00
}
}
2017-05-27 19:40:40 +00:00
void camrotate ( ld & hx , ld & hy ) {
ld cam = vid . camera_angle * M_PI / 180 ;
GLfloat cc = cos ( cam ) ;
GLfloat ss = sin ( cam ) ;
ld ux = hx , uy = hy * cc + ss , uz = cc - ss * hy ;
hx = ux / uz , hy = uy / uz ;
}
2015-08-08 13:57:52 +00:00
hyperpoint gethyper ( ld x , ld y ) {
2016-08-26 09:58:03 +00:00
2017-04-14 18:12:23 +00:00
ld hx = ( x - vid . xcenter ) / vid . radius ;
ld hy = ( y - vid . ycenter ) / vid . radius ;
2016-08-26 09:58:03 +00:00
if ( pmodel ) {
2017-04-14 18:12:23 +00:00
ghx = hx , ghy = hy ;
2016-08-26 09:58:03 +00:00
return ghpm ;
}
2015-08-08 13:57:52 +00:00
if ( euclid )
return hpxy ( hx * ( EUCSCALE + vid . alphax ) , hy * ( EUCSCALE + vid . alphax ) ) ;
2017-05-27 19:40:40 +00:00
if ( vid . camera_angle ) camrotate ( hx , hy ) ;
2017-03-23 10:53:57 +00:00
2015-08-08 13:57:52 +00:00
ld hr = hx * hx + hy * hy ;
2017-03-23 10:53:57 +00:00
if ( hr > .9999 & & ! sphere ) return Hypc ;
2015-08-08 13:57:52 +00:00
// hz*hz-(hx/(hz+alpha))^2 - (hy/(hz+alpha))^2 =
// hz*hz-hr*(hz+alpha)^2 == 1
// hz*hz - hr*hr*hz*Hz
2017-03-23 10:53:57 +00:00
ld A , B , C ;
ld curv = sphere ? 1 : - 1 ;
A = 1 + curv * hr ;
B = 2 * hr * vid . alphax * - curv ;
C = 1 - curv * hr * vid . alphax * vid . alphax ;
2015-08-08 13:57:52 +00:00
// Az^2 - Bz = C
B / = A ; C / = A ;
// z^2 - Bz = C
// z^2 - Bz + (B^2/4) = C + (B^2/4)
// z = (B/2) + sqrt(C + B^2/4)
2017-03-23 10:53:57 +00:00
ld rootsign = 1 ;
if ( sphere & & vid . alphax > 1 ) rootsign = - 1 ;
ld hz = B / 2 + rootsign * sqrt ( C + B * B / 4 ) ;
2015-08-08 13:57:52 +00:00
hyperpoint H ;
H [ 0 ] = hx * ( hz + vid . alphax ) ;
H [ 1 ] = hy * ( hz + vid . alphax ) ;
H [ 2 ] = hz ;
return H ;
}
2017-03-23 10:53:57 +00:00
void ballmodel ( hyperpoint & ret , double alpha , double d , double zl ) {
hyperpoint H = ypush ( geom3 : : camera ) * xpush ( d ) * ypush ( zl ) * C0 ;
ld tzh = vid . ballproj + H [ 2 ] ;
ld ax = H [ 0 ] / tzh ;
ld ay = H [ 1 ] / tzh ;
ld ball = vid . ballangle * M_PI / 180 ;
ld ca = cos ( alpha ) , sa = sin ( alpha ) ;
ld cb = cos ( ball ) , sb = sin ( ball ) ;
ret [ 0 ] = ax * ca ;
ret [ 1 ] = ay * cb + ax * sa * sb ;
ret [ 2 ] = - ax * sa * cb - ay * sb ;
}
void applymodel ( hyperpoint H , hyperpoint & ret ) {
2015-08-08 13:57:52 +00:00
ld tz = euclid ? ( EUCSCALE + vid . alphax ) : vid . alphax + H [ 2 ] ;
if ( tz < 1e-3 & & tz > - 1e-3 ) tz = 1000 ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( pmodel = = mdUnchanged ) {
for ( int i = 0 ; i < 3 ; i + + ) ret [ i ] = H [ i ] / vid . radius ;
return ;
}
if ( pmodel = = mdBall ) {
ld zlev = zlevel ( H ) ;
using namespace hyperpoint_vec ;
H = H / zlev ;
ld zl = geom3 : : depth - geom3 : : factor_to_lev ( zlev ) ;
double alpha = atan2 ( H [ 1 ] , H [ 0 ] ) ;
double d = hdist0 ( H ) ;
ballmodel ( ret , alpha , d , zl ) ;
2017-04-14 18:12:23 +00:00
ghcheck ( ret , H ) ;
2017-03-23 10:53:57 +00:00
return ;
}
if ( pmodel = = mdHyperboloid ) {
ld ball = vid . ballangle * M_PI / 180 ;
ld cb = cos ( ball ) , sb = sin ( ball ) ;
ret [ 0 ] = H [ 0 ] / 3 ;
ret [ 1 ] = ( 1 - H [ 2 ] ) / 3 * cb + H [ 1 ] / 3 * sb ;
ret [ 2 ] = H [ 1 ] / 3 * cb - ( 1 - H [ 2 ] ) / 3 * sb ;
2017-04-14 18:12:23 +00:00
ghcheck ( ret , H ) ;
2017-03-23 10:53:57 +00:00
return ;
}
if ( pmodel = = mdDisk ) {
2017-05-27 19:40:40 +00:00
if ( ! vid . camera_angle ) {
ret [ 0 ] = H [ 0 ] / tz ;
ret [ 1 ] = H [ 1 ] / tz ;
ret [ 2 ] = ( 1 - vid . beta / tz ) ;
}
else {
ld tx = H [ 0 ] ;
ld ty = H [ 1 ] ;
ld cam = vid . camera_angle * M_PI / 180 ;
GLfloat cc = cos ( cam ) ;
GLfloat ss = sin ( cam ) ;
ld ux = tx , uy = ty * cc - ss * tz , uz = tz * cc + ss * ty ;
ret [ 0 ] = ux / uz ;
ret [ 1 ] = uy / uz ;
ret [ 2 ] = 1 - vid . beta / uz ;
}
2017-03-23 10:53:57 +00:00
return ;
}
ld zlev = 1 ;
if ( wmspatial | | mmspatial ) {
zlev = zlevel ( H ) ;
using namespace hyperpoint_vec ;
H = H / zlev ;
}
if ( pmodel = = mdEquidistant | | pmodel = = mdEquiarea ) {
ld rad = sqrt ( H [ 0 ] * H [ 0 ] + H [ 1 ] * H [ 1 ] ) ;
ld d = hdist0 ( H ) ;
if ( pmodel = = 6 & & sphere )
d = sqrt ( 2 * ( 1 - cos ( d ) ) ) * 1.25 ; // /1.5 to make it fit on the screen better
else if ( pmodel = = 6 )
d = sqrt ( 2 * ( cosh ( d ) - 1 ) ) / 1.5 ;
ret [ 0 ] = d * H [ 0 ] / rad / 4 ;
ret [ 1 ] = d * H [ 1 ] / rad / 4 ;
ret [ 2 ] = 0 ;
if ( zlev ! = 1 & & vid . goteyes )
ret [ 2 ] = geom3 : : factor_to_lev ( zlev ) ;
ghcheck ( ret , H ) ;
2016-08-26 09:58:03 +00:00
return ;
}
2017-03-23 10:53:57 +00:00
tz = H [ 2 ] + vid . alphax ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( pmodel = = mdPolygonal | | pmodel = = mdPolynomial ) {
2016-08-26 09:58:03 +00:00
pair < long double , long double > p = polygonal : : compute ( H [ 0 ] / tz , H [ 1 ] / tz ) ;
2017-03-23 10:53:57 +00:00
ret [ 0 ] = p . first ;
ret [ 1 ] = p . second ;
ret [ 2 ] = 0 ;
ghcheck ( ret , H ) ;
2016-08-26 09:58:03 +00:00
return ;
}
// Poincare to half-plane
ld x0 , y0 ;
x0 = H [ 0 ] / tz ;
y0 = H [ 1 ] / tz ;
y0 + = 1 ;
double rad = x0 * x0 + y0 * y0 ;
y0 / = rad ;
x0 / = rad ;
y0 - = .5 ;
2017-03-23 10:53:57 +00:00
if ( pmodel = = mdHalfplane ) {
ret [ 0 ] = x0 ;
if ( wmspatial | | mmspatial ) y0 * = zlev ;
ret [ 1 ] = 1 - y0 ;
ret [ 2 ] = 0 ;
if ( zlev ! = 1 & & vid . goteyes )
ret [ 2 ] = y0 * geom3 : : factor_to_lev ( zlev ) ;
ghcheck ( ret , H ) ;
2016-08-26 09:58:03 +00:00
return ;
}
// center
x0 * = 2 ; y0 * = 2 ;
// half-plane to band
double tau = ( log ( ( x0 + 1 ) * ( x0 + 1 ) + y0 * y0 ) - log ( ( x0 - 1 ) * ( x0 - 1 ) + y0 * y0 ) ) / 2 ;
double u = ( 1 - x0 * x0 - y0 * y0 ) ;
u = ( 1 - x0 * x0 - y0 * y0 + sqrt ( u * u + 4 * y0 * y0 ) ) ;
2017-03-23 10:53:57 +00:00
double yv = 2 * y0 / u ;
double sigma = 2 * atan ( yv * zlev ) - M_PI / 2 ;
2016-08-26 09:58:03 +00:00
x0 = tau ; y0 = sigma ;
2017-03-23 10:53:57 +00:00
/* if(zlev != 1) {
double alp = ( y0 * y0 ) / ( 1 - y0 * y0 ) ;
double gx = alp + sqrt ( alp * alp - 1 ) ;
double gy = y0 * ( gx + 1 ) ;
double yr = zlev * gy / ( zlev * gx + 1 ) ;
printf ( " zlev = %10.5lf y0 = %20.10lf yr = %20.10lf \n " , double ( zlev ) , ( double ) y0 , yr ) ;
y0 = yr ;
} */
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
ret [ 0 ] = x0 / M_PI * 2 ;
2017-04-14 18:12:23 +00:00
ret [ 1 ] = - y0 / M_PI * 2 ;
2017-03-23 10:53:57 +00:00
ret [ 2 ] = 0 ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( zlev ! = 1 & & vid . goteyes )
ret [ 2 ] = geom3 : : factor_to_lev ( zlev ) / ( 1 + yv * yv ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
ghcheck ( ret , H ) ;
2016-08-26 09:58:03 +00:00
}
2017-03-23 10:53:57 +00:00
int dlit ;
2015-08-08 13:57:52 +00:00
// game-related graphics
transmatrix View ; // current rotation, relative to viewctr
transmatrix cwtV ; // player-relative view
2017-03-23 10:53:57 +00:00
transmatrix sphereflip ; // on the sphere, flip
2015-08-08 13:57:52 +00:00
heptspin viewctr ; // heptagon and rotation where the view is centered at
bool playerfound ; // has player been found in the last drawing?
ld spina ( cell * c , int dir ) {
return 2 * M_PI * dir / c - > type ;
}
int gradient ( int c0 , int c1 , ld v0 , ld v , ld v1 ) {
int vv = int ( 256 * ( ( v - v0 ) / ( v1 - v0 ) ) ) ;
int c = 0 ;
for ( int a = 0 ; a < 3 ; a + + ) {
int p0 = ( c0 > > ( 8 * a ) ) & 255 ;
int p1 = ( c1 > > ( 8 * a ) ) & 255 ;
int p = ( p0 * ( 256 - vv ) + p1 * vv + 127 ) > > 8 ;
c + = p < < ( 8 * a ) ;
}
return c ;
}
// cloak color
int cloakcolor ( int rtr ) {
rtr - = 28 ;
rtr / = 2 ;
rtr % = 10 ;
if ( rtr < 0 ) rtr + = 10 ;
// rtr = time(NULL) % 10;
int cc [ 10 ] = {
0x8080FF , 0x80FFFF , 0x80FF80 , 0xFF8080 , 0xFF80FF , 0xFFFF80 ,
0xFFFFC0 , 0xFFD500 , 0x421C52 , 0
} ;
return cc [ rtr ] ;
}
2017-03-23 10:53:57 +00:00
int firegradient ( double p ) {
return gradient ( 0xFFFF00 , 0xFF0000 , 0 , p , 1 ) ;
}
2015-08-08 13:57:52 +00:00
int firecolor ( int phase ) {
return gradient ( 0xFFFF00 , 0xFF0000 , - 1 , sin ( ( phase + ticks ) / 100.0 ) , 1 ) ;
}
2016-01-02 10:09:13 +00:00
int watercolor ( int phase ) {
return 0x0080C0FF + 256 * int ( 63 * sin ( ( ticks + phase ) / 50. ) ) ;
}
int aircolor ( int phase ) {
2017-03-23 10:53:57 +00:00
return 0x8080FF00 | int ( 32 + 32 * sin ( ticks / 200.0 + 2 * phase * M_PI / ( S21 + .0 ) ) ) ;
}
int fghostcolor ( int phase , cell * c ) {
phase + = ( int ) ( size_t ) c ;
phase % = 4000 ;
if ( phase < 0 ) phase + = 4000 ;
if ( phase < 1000 ) return gradient ( 0xFFFF80 , 0xA0C0FF , 0 , phase , 1000 ) ;
else if ( phase < 2000 ) return gradient ( 0xA0C0FF , 0xFF80FF , 1000 , phase , 2000 ) ;
else if ( phase < 3000 ) return gradient ( 0xFF80FF , 0xFF8080 , 2000 , phase , 3000 ) ;
else if ( phase < 4000 ) return gradient ( 0xFF8080 , 0xFFFF80 , 3000 , phase , 4000 ) ;
return 0xFFD500 ;
2016-01-02 10:09:13 +00:00
}
int weakfirecolor ( int phase ) {
return gradient ( 0xFF8000 , 0xFF0000 , - 1 , sin ( ( phase + ticks ) / 500.0 ) , 1 ) ;
}
int fc ( int ph , int col , int z ) {
2015-08-08 13:57:52 +00:00
if ( items [ itOrbFire ] ) col = darkena ( firecolor ( ph ) , 0 , 0xFF ) ;
2017-03-23 10:53:57 +00:00
if ( items [ itOrbAether ] ) col = ( col & ~ 0XFF ) | ( col & 0xFF ) / 2 ;
for ( int i = 0 ; i < numplayers ( ) ; i + + ) if ( multi : : playerActive ( i ) )
if ( items [ itOrbFish ] & & isWatery ( playerpos ( i ) ) & & z ! = 3 ) return watercolor ( ph ) ;
2016-01-02 10:09:13 +00:00
if ( invismove )
col =
shmup : : on ?
( col & ~ 0XFF ) | ( int ( ( col & 0xFF ) * .25 ) )
: ( col & ~ 0XFF ) | ( int ( ( col & 0xFF ) * ( 100 + 100 * sin ( ticks / 500. ) ) ) / 200 ) ;
2015-08-08 13:57:52 +00:00
return col ;
}
2017-03-23 10:53:57 +00:00
int lightat , safetyat ;
2015-08-08 13:57:52 +00:00
void drawLightning ( ) { lightat = ticks ; }
void drawSafety ( ) { safetyat = ticks ; }
double eurad = 0.52 ;
2017-03-23 10:53:57 +00:00
double q3 = sqrt ( double ( 3 ) ) ;
2015-08-08 13:57:52 +00:00
bool outofmap ( hyperpoint h ) {
if ( euclid )
return h [ 0 ] * h [ 0 ] + h [ 1 ] * h [ 1 ] > 15 * eurad ;
2017-03-23 10:53:57 +00:00
else if ( sphere )
return h [ 2 ] < .1 & & h [ 2 ] > - .1 & & h [ 1 ] > - .1 & & h [ 1 ] < .1 & & h [ 0 ] > - .1 & & h [ 0 ] < .1 ;
2015-08-08 13:57:52 +00:00
else
return h [ 2 ] < .5 ;
}
2016-08-26 09:58:03 +00:00
void drawShield ( const transmatrix & V , eItem it ) {
2015-08-08 13:57:52 +00:00
float ds = ticks / 300. ;
2017-03-23 10:53:57 +00:00
int col = iinf [ it ] . color ;
if ( it = = itOrbShield & & items [ itOrbTime ] & & ! orbused [ it ] )
2016-01-02 10:09:13 +00:00
col = ( col & 0xFEFEFE ) / 2 ;
2017-03-23 10:53:57 +00:00
if ( sphere & & cwt . c - > land = = laHalloween & & ! wmblack & & ! wmascii )
col = 0 ;
2016-08-26 09:58:03 +00:00
double d = it = = itOrbShield ? hexf : hexf - .1 ;
2017-03-23 10:53:57 +00:00
int mt = sphere ? 7 : 5 ;
for ( int a = 0 ; a < = S84 * mt ; a + + )
curvepoint ( V * ddi0 ( a , d + sin ( ds + M_PI * 2 * a / 4 / mt ) * .1 ) ) ;
queuecurve ( darkena ( col , 0 , 0xFF ) , 0x8080808 , PPR_LINE ) ;
2015-08-08 13:57:52 +00:00
}
void drawSpeed ( const transmatrix & V ) {
2016-01-02 10:09:13 +00:00
ld ds = ticks / 10. ;
2017-03-23 10:53:57 +00:00
int col = darkena ( iinf [ itOrbSpeed ] . color , 0 , 0xFF ) ;
for ( int b = 0 ; b < S84 ; b + = S14 ) {
for ( int a = 0 ; a < = S84 ; a + + )
curvepoint ( V * ddi0 ( ds + b + a , hexf * a / S84 ) ) ;
queuecurve ( col , 0x8080808 , PPR_LINE ) ;
}
2015-08-08 13:57:52 +00:00
}
void drawSafety ( const transmatrix & V , int ct ) {
ld ds = ticks / 50. ;
2017-03-23 10:53:57 +00:00
int col = darkena ( iinf [ itOrbSafety ] . color , 0 , 0xFF ) ;
2015-08-08 13:57:52 +00:00
for ( int a = 0 ; a < ct ; a + + )
2017-03-23 10:53:57 +00:00
queueline ( V * ddi0 ( ds + a * S84 / ct , 2 * hexf ) , V * ddi0 ( ds + ( a + ( ct - 1 ) / 2 ) * S84 / ct , 2 * hexf ) , col ) ;
2015-08-08 13:57:52 +00:00
}
void drawFlash ( const transmatrix & V ) {
float ds = ticks / 300. ;
2017-03-23 10:53:57 +00:00
int col = darkena ( iinf [ itOrbFlash ] . color , 0 , 0xFF ) ;
2015-08-08 13:57:52 +00:00
col & = ~ 1 ;
for ( int u = 0 ; u < 5 ; u + + ) {
ld rad = hexf * ( 2.5 + .5 * sin ( ds + u * .3 ) ) ;
2017-03-23 10:53:57 +00:00
for ( int a = 0 ; a < = S84 ; a + + ) curvepoint ( V * ddi0 ( a , rad ) ) ;
queuecurve ( col , 0x8080808 , PPR_LINE ) ;
2015-08-08 13:57:52 +00:00
}
}
2016-01-02 10:09:13 +00:00
void drawLove ( const transmatrix & V , int hdir ) {
float ds = ticks / 300. ;
2017-03-23 10:53:57 +00:00
int col = darkena ( iinf [ itOrbLove ] . color , 0 , 0xFF ) ;
2016-01-02 10:09:13 +00:00
col & = ~ 1 ;
for ( int u = 0 ; u < 5 ; u + + ) {
2017-03-23 10:53:57 +00:00
for ( int a = 0 ; a < = S84 ; a + + ) {
double d = ( 1 + cos ( a * M_PI / S42 ) ) / 2 ;
int z = a ; if ( z > S42 ) z = S84 - z ;
2016-01-02 10:09:13 +00:00
if ( z < = 10 ) d + = ( 10 - z ) * ( 10 - z ) * ( 10 - z ) / 3000. ;
ld rad = hexf * ( 2.5 + .5 * sin ( ds + u * .3 ) ) * d ;
2017-03-23 10:53:57 +00:00
curvepoint ( V * ddi0 ( S42 + hdir + a - 1 , rad ) ) ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
queuecurve ( col , 0x8080808 , PPR_LINE ) ;
2016-01-02 10:09:13 +00:00
}
}
2015-08-08 13:57:52 +00:00
void drawWinter ( const transmatrix & V , int hdir ) {
float ds = ticks / 300. ;
2017-03-23 10:53:57 +00:00
int col = darkena ( iinf [ itOrbWinter ] . color , 0 , 0xFF ) ;
2015-08-08 13:57:52 +00:00
for ( int u = 0 ; u < 20 ; u + + ) {
ld rad = 6 * sin ( ds + u * 2 * M_PI / 20 ) ;
2017-03-23 10:53:57 +00:00
queueline ( V * ddi0 ( S42 + hdir + rad , hexf * .5 ) , V * ddi0 ( S42 + hdir + rad , hexf * 3 ) , col , 2 ) ;
2015-08-08 13:57:52 +00:00
}
}
void drawLightning ( const transmatrix & V ) {
2017-03-23 10:53:57 +00:00
int col = darkena ( iinf [ itOrbLightning ] . color , 0 , 0xFF ) ;
2015-08-08 13:57:52 +00:00
for ( int u = 0 ; u < 20 ; u + + ) {
ld leng = 0.5 / ( 0.1 + ( rand ( ) % 100 ) / 100.0 ) ;
2017-03-23 10:53:57 +00:00
ld rad = rand ( ) % S84 ;
queueline ( V * ddi0 ( rad , hexf * 0.3 ) , V * ddi0 ( rad , hexf * leng ) , col , 2 ) ;
2015-08-08 13:57:52 +00:00
}
}
int displaydir ( cell * c , int d ) {
if ( euclid )
2017-03-23 10:53:57 +00:00
return - d * S84 / c - > type ;
2015-08-08 13:57:52 +00:00
else
2017-03-23 10:53:57 +00:00
return S42 - d * S84 / c - > type ;
}
2017-05-27 19:40:40 +00:00
transmatrix ddspin ( cell * c , int d , int bonus ) {
2017-03-23 10:53:57 +00:00
int hdir = displaydir ( c , d ) + bonus ;
return getspinmatrix ( hdir ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
# ifdef WEB
Uint8 * SDL_GetKeyState ( void * v ) { static Uint8 tab [ 1024 ] ; return tab ; }
# endif
2016-01-02 10:09:13 +00:00
# include "shmup.cpp"
2016-08-26 09:58:03 +00:00
# include "conformal.cpp"
2017-03-23 10:53:57 +00:00
# include "rug.cpp"
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
void drawPlayerEffects ( const transmatrix & V , cell * c , bool onplayer ) {
if ( ! onplayer & & ! items [ itOrbEmpathy ] ) return ;
2017-03-23 10:53:57 +00:00
if ( items [ itOrbShield ] > ( shmup : : on ? 0 : ORBBASE ) ) drawShield ( V , itOrbShield ) ;
if ( items [ itOrbShell ] > ( shmup : : on ? 0 : ORBBASE ) ) drawShield ( V , itOrbShell ) ;
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
if ( items [ itOrbSpeed ] ) drawSpeed ( V ) ;
int ct = c - > type ;
2017-03-23 10:53:57 +00:00
if ( onplayer & & ( items [ itOrbSword ] | | items [ itOrbSword2 ] ) ) {
using namespace sword ;
double esh = euclid ? M_PI - M_PI * 3 / S84 + 2.5 * M_PI / S42 : 0 ;
if ( shmup : : on ) {
if ( items [ itOrbSword ] )
queuepoly ( V * spin ( esh + shmup : : pc [ multi : : cpid ] - > swordangle ) , shMagicSword , darkena ( iinf [ itOrbSword ] . color , 0 , 0xC0 + 0x30 * sin ( ticks / 200.0 ) ) ) ;
if ( items [ itOrbSword2 ] )
queuepoly ( V * spin ( esh + shmup : : pc [ multi : : cpid ] - > swordangle + M_PI ) , shMagicSword , darkena ( iinf [ itOrbSword2 ] . color , 0 , 0xC0 + 0x30 * sin ( ticks / 200.0 ) ) ) ;
}
else {
int & ang = angle [ multi : : cpid ] ;
ang % = S42 ;
transmatrix Vnow = gmatrix [ c ] * rgpushxto0 ( inverse ( gmatrix [ c ] ) * tC0 ( V ) ) ;
if ( ! euclid ) for ( int a = 0 ; a < S42 ; a + + ) {
int dda = S42 + ( - 1 - 2 * a ) ;
if ( a = = ang & & items [ itOrbSword ] ) continue ;
if ( purehepta & & a % 3 ! = ang % 3 ) continue ;
if ( ( a + S21 ) % S42 = = ang & & items [ itOrbSword2 ] ) continue ;
bool longer = sword : : pos ( cwt . c , a - 1 ) ! = sword : : pos ( cwt . c , a + 1 ) ;
int col = darkena ( 0xC0C0C0 , 0 , 0xFF ) ;
queueline ( Vnow * ddi0 ( dda , purehepta ? 0.6 : longer ? 0.36 : 0.4 ) , Vnow * ddi0 ( dda , purehepta ? 0.7 : longer ? 0.44 : 0.42 ) , col , 1 ) ;
}
if ( items [ itOrbSword ] )
queuepoly ( Vnow * spin ( esh + M_PI + ( - 1 - 2 * ang ) * 2 * M_PI / S84 ) , shMagicSword , darkena ( iinf [ itOrbSword ] . color , 0 , 0x80 + 0x70 * sin ( ticks / 200.0 ) ) ) ;
if ( items [ itOrbSword2 ] )
queuepoly ( Vnow * spin ( esh + ( - 1 - 2 * ang ) * 2 * M_PI / S84 ) , shMagicSword , darkena ( iinf [ itOrbSword2 ] . color , 0 , 0x80 + 0x70 * sin ( ticks / 200.0 ) ) ) ;
}
}
2016-08-26 09:58:03 +00:00
if ( onplayer & & items [ itOrbSafety ] ) drawSafety ( V , ct ) ;
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
if ( onplayer & & items [ itOrbFlash ] ) drawFlash ( V ) ;
2017-03-23 10:53:57 +00:00
if ( onplayer & & items [ itOrbLove ] ) drawLove ( V , 0 ) ; // displaydir(c, cwt.spin));
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
if ( items [ itOrbWinter ] )
2017-03-23 10:53:57 +00:00
drawWinter ( V , 0 ) ; // displaydir(c, cwt.spin));
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( onplayer & & items [ itOrbLightning ] ) drawLightning ( V ) ;
2016-01-02 10:09:13 +00:00
if ( safetyat > 0 ) {
int tim = ticks - safetyat ;
if ( tim > 2500 ) safetyat = 0 ;
for ( int u = tim ; u < = 2500 ; u + + ) {
if ( ( u - tim ) % 250 ) continue ;
ld rad = hexf * u / 250 ;
2017-03-23 10:53:57 +00:00
int col = darkena ( iinf [ itOrbSafety ] . color , 0 , 0xFF ) ;
for ( int a = 0 ; a < S84 ; a + + )
queueline ( V * ddi0 ( a , rad ) , V * ddi0 ( a + 1 , rad ) , col , 0 ) ;
2016-01-02 10:09:13 +00:00
}
}
}
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
void drawStunStars ( const transmatrix & V , int t ) {
for ( int i = 0 ; i < 3 * t ; i + + ) {
transmatrix V2 = V * spin ( M_PI * 2 * i / ( 3 * t ) + M_PI * ticks / 600. ) ;
2017-03-23 10:53:57 +00:00
queuepolyat ( V2 , shFlailBall , 0xFFFFFFFF , PPR_STUNSTARS ) ;
2016-01-02 10:09:13 +00:00
}
}
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
bool drawUserShape ( transmatrix V , int group , int id , int color ) {
# ifdef MOBILE
return false ;
# else
usershape * us = usershapes [ group ] [ id ] ;
if ( ! us ) return false ;
for ( int i = 0 ; i < USERLAYERS ; i + + ) {
usershapelayer & ds ( us - > d [ i ] ) ;
hpcshape & sh ( ds . sh ) ;
2017-03-23 10:53:57 +00:00
2016-01-02 10:09:13 +00:00
if ( sh . s ! = sh . e )
2017-03-23 10:53:57 +00:00
queuepoly ( V , sh , ds . color ? ds . color : color ) ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
# ifndef NOEDIT
2016-01-02 10:09:13 +00:00
if ( cmode = = emDraw & & mapeditor : : editingShape ( group , id ) ) {
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
usershapelayer & ds ( usershapes [ group ] [ id ] - > d [ mapeditor : : dslayer ] ) ;
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
/* for(int a=0; a<size(ds.list); a++) {
hyperpoint P2 = V * ds . list [ a ] ;
int xc , yc , sc ;
getcoord ( P2 , xc , yc , sc ) ;
queuechr ( xc , yc , sc , 10 , ' x ' ,
a = = 0 ? 0x00FF00 :
a = = size ( ds . list ) - 1 ? 0xFF0000 :
0xFFFF00 ) ;
} */
2016-01-02 10:09:13 +00:00
hyperpoint mh = inverse ( mapeditor : : drawtrans ) * mouseh ;
for ( int a = 0 ; a < ds . rots ; a + + )
for ( int b = 0 ; b < ( ds . sym ? 2 : 1 ) ; b + + ) {
if ( outofmap ( mouseh ) ) break ;
hyperpoint P2 = V * spin ( 2 * M_PI * a / ds . rots ) * ( b ? Mirror * mh : mh ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
queuechr ( P2 , 10 , ' x ' , 0xFF00FF ) ;
2015-08-08 13:57:52 +00:00
}
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
# endif
2016-01-02 10:09:13 +00:00
return true ;
# endif
}
2016-08-26 09:58:03 +00:00
string csnameid ( int id ) {
if ( id = = 0 ) return XLAT ( " male " ) ;
if ( id = = 1 ) return XLAT ( " female " ) ;
if ( id = = 2 ) return XLAT ( " Prince " ) ;
if ( id = = 3 ) return XLAT ( " Princess " ) ;
if ( id = = 4 | | id = = 5 ) return XLAT ( " cat " ) ;
if ( id = = 6 | | id = = 7 ) return XLAT ( " dog " ) ;
2017-03-23 10:53:57 +00:00
if ( id = = 8 | | id = = 9 ) return XLATN ( " Familiar " ) ;
2016-08-26 09:58:03 +00:00
return XLAT ( " none " ) ;
}
string csname ( charstyle & cs ) {
return csnameid ( cs . charid ) ;
}
namespace tortoise {
// small is 0 or 2
void draw ( const transmatrix & V , int bits , int small , int stuntime ) {
int eyecolor = getBit ( bits , tfEyeHue ) ? 0xFF0000 : 0xC0C0C0 ;
int shellcolor = getBit ( bits , tfShellHue ) ? 0x00C040 : 0xA06000 ;
int scutecolor = getBit ( bits , tfScuteHue ) ? 0x00C040 : 0xA06000 ;
int skincolor = getBit ( bits , tfSkinHue ) ? 0x00C040 : 0xA06000 ;
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 ) ;
for ( int i = 0 ; i < 12 ; i + + ) {
int col =
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 ;
queuepoly ( V , shTortoise [ i ] [ b + small ] , d ) ;
if ( ( i > = 5 & & i < = 7 ) | | ( i > = 9 & & i < = 10 ) )
queuepoly ( V * Mirror , shTortoise [ i ] [ b + small ] , d ) ;
if ( i = = 8 ) {
for ( int k = 0 ; k < stuntime ; k + + ) {
eyecolor & = 0xFEFEFE ;
eyecolor > > = 1 ;
}
queuepoly ( V , shTortoise [ 12 ] [ b + small ] , darkena ( eyecolor , 0 , 0xFF ) ) ;
queuepoly ( V * Mirror , shTortoise [ 12 ] [ b + small ] , darkena ( eyecolor , 0 , 0xFF ) ) ;
}
}
}
int getMatchColor ( int bits ) {
int mcol = 1 ;
double d = tortoise : : getScent ( bits ) ;
if ( d > 0 ) mcol = 0xFFFFFF ;
else if ( d < 0 ) mcol = 0 ;
int dd = 0xFF * ( atan ( fabs ( d ) / 2 ) / ( M_PI / 2 ) ) ;
2017-03-23 10:53:57 +00:00
/* poly_outline = OUTLINE_TRANS;
2016-08-26 09:58:03 +00:00
queuepoly ( V , shHeptaMarker , darkena ( mcol , 0 , dd ) ) ;
poly_outline = OUTLINE_NONE ; */
return gradient ( 0x487830 , mcol , 0 , dd , 0xFF ) ;
}
} ;
2017-03-23 10:53:57 +00:00
double footfun ( double d ) {
d - = floor ( d ) ;
return
d < .25 ? d :
d < .75 ? .5 - d :
d - 1 ;
}
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
bool ivoryz ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
void animallegs ( const transmatrix & V , eMonster mo , int col , double footphase ) {
footphase / = SCALE ;
bool dog = mo = = moRunDog ;
bool bug = mo = = moBug0 | | mo = = moMetalBeast ;
if ( bug ) footphase * = 2.5 ;
double rightfoot = footfun ( footphase / .4 / 2 ) / 4 * 2 ;
double leftfoot = footfun ( footphase / .4 / 2 - ( bug ? .5 : dog ? .1 : .25 ) ) / 4 * 2 ;
if ( bug ) rightfoot / = 2.5 , leftfoot / = 2.5 ;
if ( ! footphase ) rightfoot = leftfoot = 0 ;
transmatrix VAML = mmscale ( V , 1.04 ) ;
hpcshape * sh [ 6 ] [ 4 ] = {
{ & shDogFrontPaw , & shDogRearPaw , & shDogFrontLeg , & shDogRearLeg } ,
{ & shWolfFrontPaw , & shWolfRearPaw , & shWolfFrontLeg , & shWolfRearLeg } ,
{ & shReptileFrontFoot , & shReptileRearFoot , & shReptileFrontLeg , & shReptileRearLeg } ,
{ & shBugLeg , NULL , NULL , NULL } ,
{ & shTrylobiteFrontClaw , & shTrylobiteRearClaw , & shTrylobiteFrontLeg , & shTrylobiteRearLeg } ,
{ & shBullFrontHoof , & shBullRearHoof , & shBullFrontHoof , & shBullRearHoof } ,
} ;
hpcshape * * x = sh [ mo = = moRagingBull ? 5 : mo = = moBug0 ? 3 : mo = = moMetalBeast ? 4 : mo = = moRunDog ? 0 : mo = = moReptile ? 2 : 1 ] ;
if ( x [ 0 ] ) queuepolyat ( V * xpush ( rightfoot ) , * x [ 0 ] , col , PPR_MONSTER_FOOT ) ;
if ( x [ 0 ] ) queuepolyat ( V * Mirror * xpush ( leftfoot ) , * x [ 0 ] , col , PPR_MONSTER_FOOT ) ;
if ( x [ 1 ] ) queuepolyat ( V * xpush ( - rightfoot ) , * x [ 1 ] , col , PPR_MONSTER_FOOT ) ;
if ( x [ 1 ] ) queuepolyat ( V * Mirror * xpush ( - leftfoot ) , * x [ 1 ] , col , PPR_MONSTER_FOOT ) ;
if ( x [ 2 ] ) queuepolyat ( VAML * xpush ( rightfoot / 2 ) , * x [ 2 ] , col , PPR_MONSTER_FOOT ) ;
if ( x [ 2 ] ) queuepolyat ( VAML * Mirror * xpush ( leftfoot / 2 ) , * x [ 2 ] , col , PPR_MONSTER_FOOT ) ;
if ( x [ 3 ] ) queuepolyat ( VAML * xpush ( - rightfoot / 2 ) , * x [ 3 ] , col , PPR_MONSTER_FOOT ) ;
if ( x [ 3 ] ) queuepolyat ( VAML * Mirror * xpush ( - leftfoot / 2 ) , * x [ 3 ] , col , PPR_MONSTER_FOOT ) ;
}
void ShadowV ( const transmatrix & V , const hpcshape & bp , int prio ) {
if ( mmspatial ) {
if ( pmodel = = mdHyperboloid | | pmodel = = mdBall )
return ; // shadows break the depth testing
int p = poly_outline ; poly_outline = OUTLINE_TRANS ;
queuepolyat ( V , bp , SHADOW_MON , prio ) ;
poly_outline = p ;
}
}
void otherbodyparts ( const transmatrix & V , int col , eMonster who , double footphase ) {
# define VFOOT V
# define VLEG mmscale(V, geom3::LEG)
# define VGROIN mmscale(V, geom3::GROIN)
# define VBODY mmscale(V, geom3::BODY)
# define VNECK mmscale(V, geom3::NECK)
# define VHEAD mmscale(V, geom3::HEAD)
# define VALEGS V
# define VABODY mmscale(V, geom3::ABODY)
# define VAHEAD mmscale(V, geom3::AHEAD)
# define VFISH V
# define VBIRD mmscale(V, geom3::BIRD + .05 * sin((int) (size_t(where)) + ticks / 1000.))
# define VGHOST mmscale(V, geom3::GHOST)
# define VSLIMEEYE mscale(V, geom3::FLATEYE)
// if(!mmspatial && !footphase && who != moSkeleton) return;
footphase / = SCALE ;
double rightfoot = footfun ( footphase / .4 / 2.5 ) / 4 * 2.5 ;
// todo
if ( detaillevel > = 2 ) {
transmatrix VL = mmscale ( V , geom3 : : LEG1 ) ;
queuepoly ( VL * xpush ( rightfoot * 3 / 4 ) , shHumanLeg , col ) ;
queuepoly ( VL * Mirror * xpush ( - rightfoot * 3 / 4 ) , shHumanLeg , col ) ;
}
if ( true ) {
transmatrix VL = mmscale ( V , geom3 : : LEG ) ;
queuepoly ( VL * xpush ( rightfoot / 2 ) , shHumanLeg , col ) ;
queuepoly ( VL * Mirror * xpush ( - rightfoot / 2 ) , shHumanLeg , col ) ;
}
if ( detaillevel > = 2 ) {
transmatrix VL = mmscale ( V , geom3 : : LEG3 ) ;
queuepoly ( VL * xpush ( rightfoot / 4 ) , shHumanLeg , col ) ;
queuepoly ( VL * Mirror * xpush ( - rightfoot / 4 ) , shHumanLeg , col ) ;
}
if ( who = = moWaterElemental ) {
double fishtail = footfun ( footphase / .4 ) / 4 * 1.5 ;
queuepoly ( VFOOT * xpush ( fishtail ) , shFishTail , watercolor ( 100 ) ) ;
}
else if ( who = = moSkeleton ) {
queuepoly ( VFOOT * xpush ( rightfoot ) , shSkeletalFoot , col ) ;
queuepoly ( VFOOT * Mirror * xpush ( - rightfoot ) , shSkeletalFoot , col ) ;
return ;
}
else if ( isTroll ( who ) | | who = = moMonkey | | who = = moYeti | | who = = moRatling | | who = = moRatlingAvenger | | who = = moGoblin ) {
queuepoly ( VFOOT * xpush ( rightfoot ) , shYetiFoot , col ) ;
queuepoly ( VFOOT * Mirror * xpush ( - rightfoot ) , shYetiFoot , col ) ;
}
else {
queuepoly ( VFOOT * xpush ( rightfoot ) , shHumanFoot , col ) ;
queuepoly ( VFOOT * Mirror * xpush ( - rightfoot ) , shHumanFoot , col ) ;
}
if ( ! mmspatial ) return ;
if ( detaillevel > = 2 & & who ! = moZombie )
queuepoly ( mmscale ( V , geom3 : : NECK1 ) , shHumanNeck , col ) ;
if ( detaillevel > = 1 ) {
queuepoly ( VGROIN , shHumanGroin , col ) ;
if ( who ! = moZombie ) queuepoly ( VNECK , shHumanNeck , col ) ;
}
if ( detaillevel > = 2 ) {
queuepoly ( mmscale ( V , geom3 : : GROIN1 ) , shHumanGroin , col ) ;
if ( who ! = moZombie ) queuepoly ( mmscale ( V , geom3 : : NECK3 ) , shHumanNeck , col ) ;
}
}
bool drawstar ( cell * c ) {
for ( int t = 0 ; t < c - > type ; t + + )
if ( c - > mov [ t ] & & c - > mov [ t ] - > wall ! = waSulphur & & c - > mov [ t ] - > wall ! = waSulphurC & &
c - > mov [ t ] - > wall ! = waBarrier )
return false ;
return true ;
}
2017-05-28 22:16:17 +00:00
bool drawItemType ( eItem it , cell * c , const transmatrix & V , int icol , int ticks , bool hidden ) {
char xch = iinf [ it ] . glyph ;
int ct6 = c ? c - > type - 6 : 0 ;
hpcshape * xsh =
( it = = itPirate | | it = = itKraken ) ? & shPirateX :
( it = = itBuggy | | it = = itBuggy2 ) ? & shPirateX :
it = = itHolyGrail ? & shGrail :
isElementalShard ( it ) ? & shElementalShard :
( it = = itBombEgg | | it = = itTrollEgg ) ? & shEgg :
it = = itDodeca ? & shDodeca :
xch = = ' * ' ? & shGem [ ct6 ] :
it = = itTreat ? & shTreat :
it = = itSlime ? & shEgg :
xch = = ' % ' ? & shDaisy : xch = = ' $ ' ? & shStar : xch = = ' ; ' ? & shTriangle :
xch = = ' ! ' ? & shTriangle : it = = itBone ? & shNecro : it = = itStatue ? & shStatue :
it = = itIvory ? & shFigurine :
xch = = ' ? ' ? & shBookCover :
it = = itKey ? & shKey :
it = = itRevolver ? & shGun :
NULL ;
if ( c & & doHighlight ( ) ) {
int k = itemclass ( it ) ;
if ( k = = IC_TREASURE )
poly_outline = OUTLINE_TREASURE ;
else if ( k = = IC_ORB )
poly_outline = OUTLINE_ORB ;
else
poly_outline = OUTLINE_OTHER ;
}
if ( c & & conformal : : includeHistory & & eq ( c - > aitmp , sval ) ) poly_outline = OUTLINE_DEAD ;
if ( ! mmitem & & it ) return true ;
else if ( it = = itSavedPrincess ) {
drawMonsterType ( moPrincess , c , V , icol , 0 ) ;
return false ;
}
else if ( it = = itStrongWind ) {
queuepoly ( V * spin ( ticks / 750. ) , shFan , darkena ( icol , 0 , 255 ) ) ;
}
else if ( it = = itWarning ) {
queuepoly ( V * spin ( ticks / 750. ) , shTriangle , darkena ( icol , 0 , 255 ) ) ;
}
else if ( it = = itBabyTortoise ) {
int bits = c ? tortoise : : babymap [ c ] : tortoise : : last ;
int over = c & & c - > monst = = moTortoise ;
tortoise : : draw ( V * spin ( ticks / 5000. ) * ypush ( crossf * .15 ) , bits , over ? 4 : 2 , 0 ) ;
// queuepoly(V, shHeptaMarker, darkena(tortoise::getMatchColor(bits), 0, 0xC0));
}
else if ( it = = itCompass ) {
transmatrix V2 ;
if ( euclid ) V2 = V * spin ( M_PI / 2 ) ; // todo incorrect
else V2 = V * rspintox ( inverse ( V ) * pirateCoords ) ;
V2 = V2 * spin ( M_PI * sin ( ticks / 100. ) / 30 ) ;
queuepoly ( V2 , shCompass1 , 0xFF8080FF ) ;
queuepoly ( V2 , shCompass2 , 0xFFFFFFFF ) ;
queuepoly ( V2 , shCompass3 , 0xFF0000FF ) ;
queuepoly ( V2 * pispin , shCompass3 , 0x000000FF ) ;
xsh = NULL ;
}
else if ( it = = itPalace ) {
transmatrix V2 = V * spin ( ticks / 1500. ) ;
queuepoly ( V2 , shMFloor3 [ ct6 ] , 0xFFD500FF ) ;
queuepoly ( V2 , shMFloor4 [ ct6 ] , darkena ( icol , 0 , 0xFF ) ) ;
queuepoly ( V2 , shGem [ ct6 ] , 0xFFD500FF ) ;
xsh = NULL ;
}
else if ( drawUserShape ( V , 2 , it , darkena ( icol , 0 , 0xFF ) ) ) ;
else if ( it = = itRose ) {
for ( int u = 0 ; u < 4 ; u + + )
queuepoly ( V * spin ( ticks / 1500. ) * spin ( 2 * M_PI / 3 / 4 * u ) , shRose , darkena ( icol , 0 , hidden ? 0x30 : 0xA0 ) ) ;
}
else if ( it = = itBarrow & & c ) {
for ( int i = 0 ; i < c - > landparam ; i + + )
queuepolyat ( V * spin ( 2 * M_PI * i / c - > landparam ) * xpush ( .15 ) * spin ( ticks / 1500. ) , * xsh , darkena ( icol , 0 , hidden ? 0x40 :
( highwall ( c ) & & wmspatial ) ? 0x60 : 0xFF ) ,
PPR_HIDDEN ) ;
// queuepoly(V*spin(M_PI+(1-2*ang)*2*M_PI/S84), shMagicSword, darkena(0xC00000, 0, 0x80 + 0x70 * sin(ticks / 200.0)));
}
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 ;
transmatrix V2 = V * spin ( ticks / 1500. ) ;
if ( xsh = = & shBookCover & & mmitem )
queuepoly ( V2 , shBook , 0x805020FF ) ;
queuepoly ( V2 , * xsh , darkena ( icol , 0 , hidden ? ( it = = itKraken ? 0xC0 : 0x40 ) : 0xF0 ) ) ;
if ( it = = itZebra )
queuepolyat ( V * spin ( ticks / 1500. + M_PI / ( ct6 + 6 ) ) , * xsh , darkena ( 0x202020 , 0 , hidden ? 0x40 : 0xF0 ) , PPR_ITEMb ) ;
}
else if ( xch = = ' o ' ) {
if ( it = = itOrbFire ) icol = firecolor ( 100 ) ;
queuepoly ( V , shDisk , darkena ( icol , 0 , hidden ? 0x20 : 0xC0 ) ) ;
if ( it = = itOrbFire ) icol = firecolor ( 200 ) ;
if ( it = = itOrbFriend | | it = = itOrbDiscord ) icol = 0xC0C0C0 ;
if ( it = = itOrbFrog ) icol = 0xFF0000 ;
if ( it = = itOrbDash ) icol = 0xFF0000 ;
if ( it = = itOrbFreedom ) icol = 0xC0FF00 ;
if ( it = = itOrbAir ) icol = 0xFFFFFF ;
if ( it = = itOrbUndeath ) icol = minf [ moFriendlyGhost ] . color ;
if ( it = = itOrbRecall ) icol = 0x101010 ;
hpcshape & sh =
isRangedOrb ( it ) ? shTargetRing :
isOffensiveOrb ( it ) ? shSawRing :
isFriendOrb ( it ) ? shPeaceRing :
isUtilityOrb ( it ) ? shGearRing :
isDirectionalOrb ( it ) ? shSpearRing :
it = = itOrb37 ? shHeptaRing :
shRing ;
queuepoly ( V * spin ( ticks / 1500. ) , sh , darkena ( icol , 0 , int ( 0x80 + 0x70 * sin ( ticks / 300. ) ) ) ) ;
}
else if ( it ) return true ;
return false ;
}
2017-03-23 10:53:57 +00:00
bool drawMonsterType ( eMonster m , cell * where , const transmatrix & V , int col , double footphase ) {
char xch = minf [ m ] . glyph ;
# ifndef NOEDIT
if ( where = = mapeditor : : drawcell )
2016-01-02 10:09:13 +00:00
mapeditor : : drawtrans = V ;
# endif
2017-03-23 10:53:57 +00:00
if ( m = = moTortoise & & where & & where - > stuntime > = 3 )
2016-08-26 09:58:03 +00:00
drawStunStars ( V , where - > stuntime - 2 ) ;
2017-03-23 10:53:57 +00:00
else if ( m = = moTortoise | | m = = moPlayer | | ( where & & ! where - > stuntime ) ) ;
else if ( where & & ! ( isMetalBeast ( m ) & & where - > stuntime = = 1 ) )
2016-01-02 10:09:13 +00:00
drawStunStars ( V , where - > stuntime ) ;
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
if ( m = = moTortoise ) {
2017-05-28 22:16:17 +00:00
int bits = where ? tortoise : : getb ( where ) : tortoise : : last ;
2017-03-23 10:53:57 +00:00
tortoise : : draw ( V , bits , 0 , where ? where - > stuntime : 0 ) ;
2017-05-28 22:16:17 +00:00
if ( tortoise : : seek ( ) & & ! tortoise : : diff ( bits ) & & where )
2016-08-26 09:58:03 +00:00
queuepoly ( V , shRing , darkena ( 0xFFFFFF , 0 , 0x80 + 0x70 * sin ( ticks / 200.0 ) ) ) ;
}
else if ( m = = moPlayer ) {
charstyle & cs = getcs ( ) ;
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
bool havus = drawUserShape ( V , 0 , cs . charid , cs . skincolor ) ;
2016-01-02 10:09:13 +00:00
if ( mapeditor : : drawplayer & & ! havus ) {
2017-03-23 10:53:57 +00:00
if ( cs . charid > = 8 ) {
queuepoly ( VABODY , shWolfBody , fc ( 0 , cs . skincolor , 0 ) ) ;
if ( ! mmspatial & & ! footphase )
queuepoly ( VALEGS , shWolfLegs , fc ( 150 , cs . dresscolor , 4 ) ) ;
else {
ShadowV ( V , shWolfBody ) ;
animallegs ( VALEGS , moWolf , fc ( 500 , cs . dresscolor , 4 ) , footphase ) ;
}
queuepoly ( VAHEAD , shFamiliarHead , fc ( 500 , cs . haircolor , 2 ) ) ;
if ( ! shmup : : on | | shmup : : curtime > = shmup : : getPlayer ( ) - > nextshot ) {
int col = items [ itOrbDiscord ] ? watercolor ( 0 ) : fc ( 314 , cs . swordcolor , 3 ) ;
queuepoly ( VAHEAD , shFamiliarEye , col ) ;
queuepoly ( VAHEAD * Mirror , shFamiliarEye , col ) ;
}
}
else if ( cs . charid > = 6 ) {
if ( ! mmspatial & & ! footphase )
queuepoly ( VABODY , shDogBody , fc ( 0 , cs . skincolor , 0 ) ) ;
else {
ShadowV ( V , shDogTorso ) ;
queuepoly ( VABODY , shDogTorso , fc ( 0 , cs . skincolor , 0 ) ) ;
animallegs ( VALEGS , moRunDog , fc ( 500 , cs . dresscolor , 4 ) , footphase ) ;
}
queuepoly ( VAHEAD , shDogHead , fc ( 150 , cs . haircolor , 2 ) ) ;
2016-08-26 09:58:03 +00:00
if ( ! shmup : : on | | shmup : : curtime > = shmup : : getPlayer ( ) - > nextshot ) {
2017-03-23 10:53:57 +00:00
int col = items [ itOrbDiscord ] ? watercolor ( 0 ) : fc ( 314 , cs . swordcolor , 3 ) ;
queuepoly ( VAHEAD , shWolf1 , col ) ;
queuepoly ( VAHEAD , shWolf2 , col ) ;
queuepoly ( VAHEAD , shWolf3 , col ) ;
2016-08-26 09:58:03 +00:00
}
}
else if ( cs . charid > = 4 ) {
2017-03-23 10:53:57 +00:00
queuepoly ( VABODY , shCatBody , fc ( 0 , cs . skincolor , 0 ) ) ;
queuepoly ( VAHEAD , shCatHead , fc ( 150 , cs . haircolor , 2 ) ) ;
if ( ! mmspatial & & ! footphase )
queuepoly ( VALEGS , shCatLegs , fc ( 500 , cs . dresscolor , 4 ) ) ;
else {
ShadowV ( V , shCatBody ) ;
animallegs ( VALEGS , moRunDog , fc ( 500 , cs . dresscolor , 4 ) , footphase ) ;
}
2016-08-26 09:58:03 +00:00
if ( ! shmup : : on | | shmup : : curtime > = shmup : : getPlayer ( ) - > nextshot ) {
2017-03-23 10:53:57 +00:00
int col = items [ itOrbDiscord ] ? watercolor ( 0 ) : fc ( 314 , cs . swordcolor , 3 ) ;
queuepoly ( VAHEAD * xpush ( .04 ) , shWolf1 , col ) ;
queuepoly ( VAHEAD * xpush ( .04 ) , shWolf2 , col ) ;
2016-08-26 09:58:03 +00:00
}
}
else {
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , fc ( 0 , cs . skincolor , 0 ) , items [ itOrbFish ] ? moWaterElemental : moPlayer , footphase ) ;
queuepoly ( VBODY , ( cs . charid & 1 ) ? shFemaleBody : shPBody , fc ( 0 , cs . skincolor , 0 ) ) ;
ShadowV ( V , ( cs . charid & 1 ) ? shFemaleBody : shPBody ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( items [ itOrbHorns ] ) {
queuepoly ( VBODY , shBullHead , items [ itOrbDiscord ] ? watercolor ( 0 ) : 0xFF000030 ) ;
queuepoly ( VBODY , shBullHorn , items [ itOrbDiscord ] ? watercolor ( 0 ) : 0xFF000040 ) ;
queuepoly ( VBODY * Mirror , shBullHorn , items [ itOrbDiscord ] ? watercolor ( 0 ) : 0xFF000040 ) ;
}
2016-01-02 10:09:13 +00:00
if ( items [ itOrbThorns ] )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shHedgehogBladePlayer , items [ itOrbDiscord ] ? watercolor ( 0 ) : 0x00FF00FF ) ;
2016-01-02 10:09:13 +00:00
else if ( ! shmup : : on & & items [ itOrbDiscord ] )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , cs . charid > = 2 ? shSabre : shPSword , watercolor ( 0 ) ) ;
2016-08-26 09:58:03 +00:00
else if ( items [ itRevolver ] )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shGunInHand , fc ( 314 , cs . swordcolor , 3 ) ) ; // 3 not colored
2016-01-02 10:09:13 +00:00
else if ( ! shmup : : on )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , cs . charid > = 2 ? shSabre : shPSword , fc ( 314 , cs . swordcolor , 3 ) ) ; // 3 not colored
2016-01-02 10:09:13 +00:00
else if ( shmup : : curtime > = shmup : : getPlayer ( ) - > nextshot )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shPKnife , fc ( 314 , cs . swordcolor , 3 ) ) ; // 3 not colored
if ( items [ itOrbBeauty ] ) {
if ( cs . charid & 1 )
queuepoly ( VHEAD , shFlowerHair , darkena ( iinf [ itOrbBeauty ] . color , 0 , 0xFF ) ) ;
else
queuepoly ( VBODY , shFlowerHand , darkena ( iinf [ itOrbBeauty ] . color , 0 , 0xFF ) ) ;
}
if ( where & & where - > land = = laWildWest ) {
queuepoly ( VHEAD , shWestHat1 , darkena ( cs . swordcolor , 1 , 0XFF ) ) ;
queuepoly ( VHEAD , shWestHat2 , darkena ( cs . swordcolor , 0 , 0XFF ) ) ;
2016-08-26 09:58:03 +00:00
}
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( cheater & & ! autocheat ) {
queuepoly ( VHEAD , ( cs . charid & 1 ) ? shGoatHead : shDemon , darkena ( 0xFFFF00 , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
// queuepoly(V, shHood, darkena(0xFF00, 1, 0xFF));
}
else {
2017-03-23 10:53:57 +00:00
queuepoly ( VHEAD , shPFace , fc ( 500 , cs . skincolor , 1 ) ) ;
queuepoly ( VHEAD , ( cs . charid & 1 ) ? shFemaleHair : shPHead , fc ( 150 , cs . haircolor , 2 ) ) ;
2015-08-08 13:57:52 +00:00
}
2016-08-26 09:58:03 +00:00
if ( cs . charid & 1 )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shFemaleDress , fc ( 500 , cs . dresscolor , 4 ) ) ;
2016-08-26 09:58:03 +00:00
if ( cs . charid = = 2 )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shPrinceDress , fc ( 400 , cs . dresscolor , 5 ) ) ;
2016-08-26 09:58:03 +00:00
if ( cs . charid = = 3 )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shPrincessDress , fc ( 400 , cs . dresscolor2 , 5 ) ) ;
2016-08-26 09:58:03 +00:00
}
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
if ( knighted )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shKnightCloak , darkena ( cloakcolor ( knighted ) , 1 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
if ( tortoise : : seek ( ) )
2017-03-23 10:53:57 +00:00
tortoise : : draw ( VBODY * ypush ( - crossf * .25 ) , tortoise : : seekbits , 4 , 0 ) ;
2016-08-26 09:58:03 +00:00
2016-01-02 10:09:13 +00:00
}
}
else if ( drawUserShape ( V , 1 , m , darkena ( col , 0 , 0xFF ) ) ) return false ;
2016-08-26 09:58:03 +00:00
else if ( isMimic ( m ) | | m = = moShadow | | m = = moIllusion ) {
charstyle & cs = getcs ( ) ;
2017-03-23 10:53:57 +00:00
2016-08-26 09:58:03 +00:00
if ( drawUserShape ( V , 0 , ( cs . charid & 1 ) ? 1 : 0 , darkena ( col , 0 , 0x80 ) ) ) return false ;
2017-03-23 10:53:57 +00:00
if ( cs . charid > = 8 ) {
queuepoly ( VABODY , shWolfBody , darkena ( col , 0 , 0xC0 ) ) ;
ShadowV ( V , shWolfBody ) ;
if ( mmspatial | | footphase )
animallegs ( VALEGS , moWolf , darkena ( col , 0 , 0xC0 ) , footphase ) ;
else
queuepoly ( VABODY , shWolfLegs , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VABODY , shFamiliarHead , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VAHEAD , shFamiliarEye , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VAHEAD * Mirror , shFamiliarEye , darkena ( col , 0 , 0xC0 ) ) ;
}
else if ( cs . charid > = 6 ) {
ShadowV ( V , shDogBody ) ;
queuepoly ( VAHEAD , shDogHead , darkena ( col , 0 , 0xC0 ) ) ;
if ( mmspatial | | footphase ) {
animallegs ( VALEGS , moRunDog , darkena ( col , 0 , 0xC0 ) , footphase ) ;
queuepoly ( VABODY , shDogTorso , darkena ( col , 0 , 0xC0 ) ) ;
}
else
queuepoly ( VABODY , shDogBody , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VABODY , shWolf1 , darkena ( col , 1 , 0xC0 ) ) ;
queuepoly ( VABODY , shWolf2 , darkena ( col , 1 , 0xC0 ) ) ;
queuepoly ( VABODY , shWolf3 , darkena ( col , 1 , 0xC0 ) ) ;
2016-08-26 09:58:03 +00:00
}
else if ( cs . charid > = 4 ) {
2017-03-23 10:53:57 +00:00
ShadowV ( V , shCatBody ) ;
queuepoly ( VABODY , shCatBody , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VAHEAD , shCatHead , darkena ( col , 0 , 0xC0 ) ) ;
if ( mmspatial | | footphase )
animallegs ( VALEGS , moRunDog , darkena ( col , 0 , 0xC0 ) , footphase ) ;
else
queuepoly ( VALEGS , shCatLegs , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VAHEAD * xpush ( .04 ) , shWolf1 , darkena ( col , 1 , 0xC0 ) ) ;
queuepoly ( VAHEAD * xpush ( .04 ) , shWolf2 , darkena ( col , 1 , 0xC0 ) ) ;
2016-08-26 09:58:03 +00:00
}
else {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0x40 ) , m , footphase ) ;
queuepoly ( VBODY , ( cs . charid & 1 ) ? shFemaleBody : shPBody , darkena ( col , 0 , 0X80 ) ) ;
2016-08-26 09:58:03 +00:00
if ( ! shmup : : on )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , ( cs . charid > = 2 ? shSabre : shPSword ) , darkena ( col , 0 , 0XC0 ) ) ;
2016-08-26 09:58:03 +00:00
else if ( shmup : : curtime > = shmup : : getPlayer ( ) - > nextshot )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shPKnife , darkena ( col , 0 , 0XC0 ) ) ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
queuepoly ( VHEAD , ( cs . charid & 1 ) ? shFemaleHair : shPHead , darkena ( col , 1 , 0XC0 ) ) ;
queuepoly ( VHEAD , shPFace , darkena ( col , 0 , 0XC0 ) ) ;
2016-08-26 09:58:03 +00:00
if ( cs . charid & 1 )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shFemaleDress , darkena ( col , 1 , 0XC0 ) ) ;
2016-08-26 09:58:03 +00:00
if ( cs . charid = = 2 )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shPrinceDress , darkena ( col , 1 , 0XC0 ) ) ;
2016-08-26 09:58:03 +00:00
if ( cs . charid = = 3 )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shPrincessDress , darkena ( col , 1 , 0XC0 ) ) ;
2016-08-26 09:58:03 +00:00
}
2016-01-02 10:09:13 +00:00
}
else if ( m = = moBullet ) {
2017-03-23 10:53:57 +00:00
ShadowV ( V , shKnife ) ;
queuepoly ( VBODY * spin ( - M_PI / 4 ) , shKnife , getcs ( ) . swordcolor ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( m = = moKnight | | m = = moKnightMoved ) {
2017-03-23 10:53:57 +00:00
ShadowV ( V , shPBody ) ;
otherbodyparts ( V , darkena ( 0xC0C0A0 , 0 , 0xC0 ) , m , footphase ) ;
queuepoly ( VBODY , shPBody , darkena ( 0xC0C0A0 , 0 , 0xC0 ) ) ;
queuepoly ( VBODY , shPSword , darkena ( 0xFFFF00 , 0 , 0xFF ) ) ;
queuepoly ( VBODY , shKnightArmor , darkena ( 0xD0D0D0 , 1 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
int col ;
2017-03-23 10:53:57 +00:00
if ( ! euclid & & where & & where - > master - > alt )
2016-01-02 10:09:13 +00:00
col = cloakcolor ( roundTableRadius ( where ) ) ;
else
col = cloakcolor ( newRoundTableRadius ( ) ) ;
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shKnightCloak , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VHEAD , shPHead , darkena ( 0x703800 , 1 , 0XFF ) ) ;
queuepoly ( VHEAD , shPFace , darkena ( 0xC0C0A0 , 0 , 0XFF ) ) ;
2016-01-02 10:09:13 +00:00
return false ;
}
2017-03-31 19:41:09 +00:00
else if ( m = = moGolem | | m = = moGolemMoved ) {
2017-03-23 10:53:57 +00:00
ShadowV ( V , shPBody ) ;
otherbodyparts ( V , darkena ( col , 1 , 0XC0 ) , m , footphase ) ;
queuepoly ( VBODY , shPBody , darkena ( col , 0 , 0XC0 ) ) ;
queuepoly ( VHEAD , shGolemhead , darkena ( col , 1 , 0XFF ) ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( isPrincess ( m ) | | m = = moFalsePrincess | | m = = moRoseLady | | m = = moRoseBeauty ) {
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
bool girl = princessgender ( ) = = GEN_F ;
bool evil = ! isPrincess ( m ) ;
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
int facecolor = evil ? 0xC0B090FF : 0xD0C080FF ;
2017-03-23 10:53:57 +00:00
ShadowV ( V , girl ? shFemaleBody : shPBody ) ;
otherbodyparts ( V , facecolor , m , footphase ) ;
queuepoly ( VBODY , girl ? shFemaleBody : shPBody , facecolor ) ;
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
if ( m = = moPrincessArmed )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , vid . cs . charid < 2 ? shSabre : shPSword , 0xFFFFFFFF ) ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( ( m = = moFalsePrincess | | m = = moRoseBeauty ) & & where & & where - > cpdist = = 1 )
queuepoly ( VBODY , shPKnife , 0xFFFFFFFF ) ;
2016-08-26 09:58:03 +00:00
if ( m = = moRoseLady ) {
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shPKnife , 0xFFFFFFFF ) ;
queuepoly ( VBODY * Mirror , shPKnife , 0xFFFFFFFF ) ;
2016-08-26 09:58:03 +00:00
}
2017-05-28 22:55:44 +00:00
if ( girl ) {
queuepoly ( VBODY , shFemaleDress , evil ? 0xC000C0FF : 0x00C000FF ) ;
if ( vid . cs . charid < 2 )
queuepoly ( VBODY , shPrincessDress , evil ? 0xC040C0C0 : 0x8080FFC0 ) ;
}
else {
if ( vid . cs . charid < 2 )
queuepoly ( VBODY , shPrinceDress , evil ? 0x802080FF : 0x404040FF ) ;
}
2016-08-26 09:58:03 +00:00
if ( m = = moRoseLady ) {
// queuepoly(V, girl ? shGoatHead : shDemon, 0x800000FF);
2017-03-23 10:53:57 +00:00
queuepoly ( VHEAD , girl ? shFemaleHair : shPHead , evil ? 0x500050FF : 0x332A22FF ) ;
2016-08-26 09:58:03 +00:00
}
else if ( m = = moRoseBeauty ) {
if ( girl ) {
2017-03-23 10:53:57 +00:00
queuepoly ( VHEAD , shBeautyHair , 0xF0A0D0FF ) ;
queuepoly ( VHEAD , shFlowerHair , 0xC00000FF ) ;
2016-08-26 09:58:03 +00:00
}
else {
2017-03-23 10:53:57 +00:00
queuepoly ( VHEAD , shPHead , 0xF0A0D0FF ) ;
queuepoly ( VHEAD , shFlowerHand , 0xC00000FF ) ;
queuepoly ( VBODY , shSuspenders , 0xC00000FF ) ;
2016-08-26 09:58:03 +00:00
}
}
else {
2017-03-23 10:53:57 +00:00
queuepoly ( VHEAD , girl ? shFemaleHair : shPHead ,
2016-08-26 09:58:03 +00:00
evil ? 0xC00000FF : 0x332A22FF ) ;
}
2017-03-23 10:53:57 +00:00
queuepoly ( VHEAD , shPFace , facecolor ) ;
2016-01-02 10:09:13 +00:00
}
2017-03-31 19:41:09 +00:00
else if ( m = = moWolf | | m = = moRedFox | | m = = moWolfMoved ) {
2017-03-23 10:53:57 +00:00
ShadowV ( V , shWolfBody ) ;
if ( mmspatial | | footphase )
animallegs ( VALEGS , moWolf , darkena ( col , 0 , 0xFF ) , footphase ) ;
else
queuepoly ( VALEGS , shWolfLegs , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VABODY , shWolfBody , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shWolfHead , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shWolfEyes , darkena ( col , 3 , 0xFF ) ) ;
}
else if ( isBull ( m ) ) {
ShadowV ( V , shBullBody ) ;
int hoofcol = darkena ( gradient ( 0 , col , 0 , .65 , 1 ) , 0 , 0xFF ) ;
if ( mmspatial | | footphase )
animallegs ( VALEGS , moRagingBull , hoofcol , footphase ) ;
queuepoly ( VABODY , shBullBody , darkena ( gradient ( 0 , col , 0 , .80 , 1 ) , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shBullHead , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shBullHorn , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD * Mirror , shBullHorn , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
}
else if ( m = = moReptile ) {
ShadowV ( V , shReptileBody ) ;
animallegs ( VALEGS , moReptile , darkena ( col , 0 , 0xFF ) , footphase ) ;
queuepoly ( VABODY , shReptileBody , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shReptileHead , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shReptileEye , darkena ( col , 3 , 0xFF ) ) ;
queuepoly ( VAHEAD * Mirror , shReptileEye , darkena ( col , 3 , 0xFF ) ) ;
queuepoly ( VABODY , shReptileTail , darkena ( col , 2 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moVineBeast ) {
2017-03-23 10:53:57 +00:00
ShadowV ( V , shWolfBody ) ;
if ( mmspatial | | footphase )
animallegs ( VALEGS , moWolf , 0x00FF00FF , footphase ) ;
else
queuepoly ( VALEGS , shWolfLegs , 0x00FF00FF ) ;
queuepoly ( VABODY , shWolfBody , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VAHEAD , shWolfHead , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shWolfEyes , 0xFF0000FF ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( m = = moMouse | | m = = moMouseMoved ) {
2017-03-23 10:53:57 +00:00
queuepoly ( VALEGS , shMouse , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VALEGS , shMouseLegs , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VALEGS , shMouseEyes , 0xFF ) ;
2016-01-02 10:09:13 +00:00
}
else if ( isBug ( m ) ) {
2017-03-23 10:53:57 +00:00
ShadowV ( V , shBugBody ) ;
if ( ! mmspatial & & ! footphase )
queuepoly ( VABODY , shBugBody , darkena ( col , 0 , 0xFF ) ) ;
else {
animallegs ( VALEGS , moBug0 , darkena ( col , 0 , 0xFF ) , footphase ) ;
queuepoly ( VABODY , shBugAntenna , darkena ( col , 1 , 0xFF ) ) ;
}
queuepoly ( VABODY , shBugArmor , darkena ( col , 1 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moRunDog ) {
2017-03-23 10:53:57 +00:00
if ( ! mmspatial & & ! footphase )
queuepoly ( VABODY , shDogBody , darkena ( col , 0 , 0xFF ) ) ;
else {
ShadowV ( V , shDogTorso ) ;
queuepoly ( VABODY , shDogTorso , darkena ( col , 0 , 0xFF ) ) ;
animallegs ( VALEGS , moRunDog , darkena ( col , 0 , 0xFF ) , footphase ) ;
}
queuepoly ( VAHEAD , shDogHead , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shWolf1 , darkena ( 0x202020 , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shWolf2 , darkena ( 0x202020 , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shWolf3 , darkena ( 0x202020 , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moOrangeDog ) {
2017-03-23 10:53:57 +00:00
if ( ! mmspatial & & ! footphase )
queuepoly ( VABODY , shDogBody , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
else {
ShadowV ( V , shDogTorso ) ;
queuepoly ( VABODY , shDogTorso , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
animallegs ( VALEGS , moRunDog , darkena ( 0xFFFFFF , 0 , 0xFF ) , footphase ) ;
}
queuepoly ( VAHEAD , shDogHead , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
queuepoly ( VABODY , shDogStripes , darkena ( 0x303030 , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shWolf1 , darkena ( 0x202020 , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shWolf2 , darkena ( 0x202020 , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shWolf3 , darkena ( 0x202020 , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moShark | | m = = moGreaterShark | | m = = moCShark )
2017-03-23 10:53:57 +00:00
queuepoly ( VFISH , shShark , darkena ( col , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
else if ( m = = moEagle | | m = = moParrot | | m = = moBomberbird | | m = = moAlbatross | |
2017-03-31 19:41:09 +00:00
m = = moTameBomberbird | | m = = moWindCrow | | m = = moTameBomberbirdMoved ) {
2017-03-23 10:53:57 +00:00
ShadowV ( V , shEagle ) ;
queuepoly ( VBIRD , shEagle , darkena ( col , 0 , 0xFF ) ) ;
}
else if ( m = = moSparrowhawk ) {
ShadowV ( V , shHawk ) ;
queuepoly ( VBIRD , shHawk , darkena ( col , 0 , 0xFF ) ) ;
}
else if ( m = = moButterfly ) {
transmatrix Vwing = Id ;
Vwing [ 1 ] [ 1 ] = .85 + .15 * sin ( ticks / 100.0 ) ;
ShadowV ( V * Vwing , shButterflyWing ) ;
queuepoly ( VBIRD * Vwing , shButterflyWing , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBIRD , shButterflyBody , darkena ( col , 2 , 0xFF ) ) ;
}
else if ( m = = moGadfly ) {
transmatrix Vwing = Id ;
Vwing [ 1 ] [ 1 ] = .85 + .15 * sin ( ticks / 100.0 ) ;
ShadowV ( V * Vwing , shGadflyWing ) ;
queuepoly ( VBIRD * Vwing , shGadflyWing , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBIRD , shGadflyBody , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VBIRD , shGadflyEye , darkena ( col , 2 , 0xFF ) ) ;
queuepoly ( VBIRD * Mirror , shGadflyEye , darkena ( col , 2 , 0xFF ) ) ;
}
else if ( m = = moVampire | | m = = moBat ) {
if ( m = = moBat ) ShadowV ( V , shBatWings ) ; // but vampires have no shadow
queuepoly ( VBIRD , shBatWings , darkena ( 0x303030 , 0 , 0xFF ) ) ;
queuepoly ( VBIRD , shBatBody , darkena ( 0x606060 , 0 , 0xFF ) ) ;
/* queuepoly(V, shBatMouth, darkena(0xC00000, 0, 0xFF));
queuepoly ( V , shBatFang , darkena ( 0xFFC0C0 , 0 , 0xFF ) ) ;
queuepoly ( V * Mirror , shBatFang , darkena ( 0xFFC0C0 , 0 , 0xFF ) ) ;
queuepoly ( V , shBatEye , darkena ( 00000000 , 0 , 0xFF ) ) ;
queuepoly ( V * Mirror , shBatEye , darkena ( 00000000 , 0 , 0xFF ) ) ; */
}
2016-01-02 10:09:13 +00:00
else if ( m = = moGargoyle ) {
2017-03-23 10:53:57 +00:00
ShadowV ( V , shGargoyleWings ) ;
queuepoly ( VBIRD , shGargoyleWings , darkena ( col , 0 , 0xD0 ) ) ;
queuepoly ( VBIRD , shGargoyleBody , darkena ( col , 0 , 0xFF ) ) ;
}
else if ( m = = moZombie ) {
2017-05-28 22:16:17 +00:00
int c = darkena ( col , where & & where - > land = = laHalloween ? 1 : 0 , 0xFF ) ;
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , c , m , footphase ) ;
ShadowV ( V , shPBody ) ;
queuepoly ( VBODY , shPBody , c ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moDesertman ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0xC0 ) , m , footphase ) ;
ShadowV ( V , shPBody ) ;
queuepoly ( VBODY , shPBody , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VBODY , shPSword , 0xFFFF00FF ) ;
queuepoly ( VHEAD , shHood , 0xD0D000C0 ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moPalace | | m = = moFatGuard | | m = = moVizier | | m = = moSkeleton ) {
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shSabre , 0xFFFFFFFF ) ;
2016-01-02 10:09:13 +00:00
if ( m = = moSkeleton ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( 0xFFFFFF , 0 , 0xFF ) , moSkeleton , footphase ) ;
queuepoly ( VBODY , shSkeletonBody , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , shSkull , darkena ( 0xFFFFFF , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , shSkullEyes , darkena ( 0 , 0 , 0xFF ) ) ;
ShadowV ( V , shSkeletonBody ) ;
2016-01-02 10:09:13 +00:00
}
else {
2017-03-23 10:53:57 +00:00
ShadowV ( V , shPBody ) ;
otherbodyparts ( V , darkena ( 0xFFD500 , 0 , 0xFF ) , m , footphase ) ;
2016-01-02 10:09:13 +00:00
if ( m = = moFatGuard ) {
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shFatBody , darkena ( 0xC06000 , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
col = 0xFFFFFF ;
2017-05-28 22:16:17 +00:00
if ( ! where | | where - > hitpoints > = 3 )
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shKnightCloak , darkena ( 0xFFC0C0 , 1 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
else {
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shPBody , darkena ( 0xFFD500 , 0 , 0xFF ) ) ;
queuepoly ( VBODY , shKnightArmor , m = = moVizier ? 0xC000C0FF :
2016-01-02 10:09:13 +00:00
darkena ( 0x00C000 , 1 , 0xFF ) ) ;
2017-03-23 10:53:57 +00:00
if ( where & & where - > hitpoints > = 3 )
queuepoly ( VBODY , shKnightCloak , m = = moVizier ? 0x800080Ff :
2016-01-02 10:09:13 +00:00
darkena ( 0x00FF00 , 1 , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
queuepoly ( VHEAD , shTurban1 , darkena ( col , 1 , 0xFF ) ) ;
2017-05-28 22:16:17 +00:00
if ( ! where | | where - > hitpoints > = 2 )
2017-03-23 10:53:57 +00:00
queuepoly ( VHEAD , shTurban2 , darkena ( col , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
drawStunStars ( V , where ? where - > stuntime : 0 ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moCrystalSage ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , 0xFFFFFFFF , m , footphase ) ;
ShadowV ( V , shPBody ) ;
queuepoly ( VBODY , shPBody , 0xFFFFFFFF ) ;
queuepoly ( VHEAD , shPHead , 0xFFFFFFFF ) ;
queuepoly ( VHEAD , shPFace , 0xFFFFFFFF ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moHedge ) {
2017-03-23 10:53:57 +00:00
ShadowV ( V , shPBody ) ;
otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
queuepoly ( VBODY , shPBody , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBODY , shHedgehogBlade , 0xC0C0C0FF ) ;
queuepoly ( VHEAD , shPHead , 0x804000FF ) ;
queuepoly ( VHEAD , shPFace , 0xF09000FF ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moYeti | | m = = moMonkey ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0xC0 ) , m , footphase ) ;
ShadowV ( V , shPBody ) ;
queuepoly ( VBODY , shYeti , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD , shPHead , darkena ( col , 0 , 0xFF ) ) ;
}
else if ( m = = moResearcher ) {
otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shPBody ) ;
queuepoly ( VBODY , shPBody , darkena ( 0xFFFF00 , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD , shAztecHead , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , shAztecCap , darkena ( 0xC000C0 , 0 , 0xFF ) ) ;
}
else if ( m = = moFamiliar ) {
/* queuepoly(V, shFemaleBody, darkena(0xC0B070, 0, 0xFF));
queuepoly ( V , shPFace , darkena ( 0xC0B070 , 0 , 0XFF ) ) ;
queuepoly ( V , shWizardCape1 , 0x601000FF ) ;
queuepoly ( V , shWizardCape2 , 0x781800FF ) ;
queuepoly ( V , shWizardHat1 , 0x902000FF ) ;
queuepoly ( V , shWizardHat2 , 0xA82800FF ) ; */
// queuepoly(V, shCatBody, darkena(0x601000, 0, 0xFF));
// queuepoly(V, shGargoyleBody, darkena(0x903000, 0, 0xFF));
ShadowV ( V , shWolfBody ) ;
queuepoly ( VABODY , shWolfBody , darkena ( 0xA03000 , 0 , 0xFF ) ) ;
if ( mmspatial | | footphase )
animallegs ( VALEGS , moWolf , darkena ( 0xC04000 , 0 , 0xFF ) , footphase ) ;
else
queuepoly ( VALEGS , shWolfLegs , darkena ( 0xC04000 , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD , shFamiliarHead , darkena ( 0xC04000 , 0 , 0xFF ) ) ;
// queuepoly(V, shCatLegs, darkena(0x902000, 0, 0xFF));
if ( true ) {
queuepoly ( VAHEAD , shFamiliarEye , darkena ( 0xFFFF000 , 0 , 0xFF ) ) ;
queuepoly ( VAHEAD * Mirror , shFamiliarEye , darkena ( 0xFFFF000 , 0 , 0xFF ) ) ;
}
2016-01-02 10:09:13 +00:00
}
else if ( m = = moRanger ) {
2017-03-23 10:53:57 +00:00
ShadowV ( V , shPBody ) ;
otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
queuepoly ( VBODY , shPBody , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VBODY , shPSword , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , shArmor , darkena ( col , 1 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( m = = moGhost | | m = = moSeep | | m = = moFriendlyGhost ) {
2017-03-23 10:53:57 +00:00
if ( m = = moFriendlyGhost ) col = fghostcolor ( ticks , where ) ;
queuepoly ( VGHOST , shGhost , darkena ( col , 0 , m = = moFriendlyGhost ? 0xC0 : 0x80 ) ) ;
queuepoly ( VGHOST , shEyes , 0xFF ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moVineSpirit ) {
2017-03-23 10:53:57 +00:00
queuepoly ( VGHOST , shGhost , 0xD0D0D0C0 ) ;
queuepoly ( VGHOST , shEyes , 0xFF0000FF ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moFireFairy ) {
col = firecolor ( 0 ) ;
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shFemaleBody ) ;
queuepoly ( VBODY , shFemaleBody , darkena ( col , 0 , 0XC0 ) ) ;
queuepoly ( VHEAD , shWitchHair , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VHEAD , shPFace , darkena ( col , 0 , 0XFF ) ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moSlime ) {
2017-03-23 10:53:57 +00:00
queuepoly ( VFISH , shSlime , darkena ( col , 0 , 0x80 ) ) ;
queuepoly ( VSLIMEEYE , shEyes , 0xFF ) ;
}
else if ( m = = moKrakenH ) {
queuepoly ( VFISH , shKrakenHead , darkena ( col , 0 , 0xD0 ) ) ;
queuepoly ( VFISH , shKrakenEye , 0xFFFFFFC0 ) ;
queuepoly ( VFISH , shKrakenEye2 , 0xC0 ) ;
queuepoly ( VFISH * Mirror , shKrakenEye , 0xFFFFFFC0 ) ;
queuepoly ( VFISH * Mirror , shKrakenEye2 , 0xC0 ) ;
}
else if ( m = = moKrakenT ) {
queuepoly ( VFISH , shSeaTentacle , darkena ( col , 0 , 0xD0 ) ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moCultist | | m = = moPyroCultist | | m = = moCultistLeader ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shPBody ) ;
queuepoly ( VBODY , shPBody , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VBODY , shPSword , darkena ( col , 2 , 0xFF ) ) ;
queuepoly ( VHEAD , shHood , darkena ( col , 1 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moPirate ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shPBody ) ;
queuepoly ( VBODY , shPBody , darkena ( 0x404040 , 0 , 0xFF ) ) ;
queuepoly ( VBODY , shPirateHook , darkena ( 0xD0D0D0 , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , shPFace , darkena ( 0xFFFF80 , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , shEyepatch , darkena ( 0 , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD , shPirateHood , darkena ( col , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( m = = moRatling | | m = = moRatlingAvenger ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shYeti ) ;
2017-05-28 22:16:17 +00:00
queuepoly ( VLEG , shRatTail , darkena ( col , 0 , 0xFF ) ) ;
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shYeti , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VHEAD , shRatHead , darkena ( col , 0 , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
float t = sin ( ticks / 1000.0 + ( where ? where - > cpdist : 0 ) ) ;
2016-08-26 09:58:03 +00:00
int eyecol = t > 0.92 ? 0xFF0000 : 0 ;
2017-03-23 10:53:57 +00:00
queuepoly ( VHEAD , shWolf1 , darkena ( eyecol , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , shWolf2 , darkena ( eyecol , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , shWolf3 , darkena ( 0x202020 , 0 , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
if ( m = = moRatlingAvenger ) {
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shRatCape1 , 0x303030FF ) ;
queuepoly ( VHEAD , shRatCape2 , 0x484848FF ) ;
2016-08-26 09:58:03 +00:00
}
}
2016-01-02 10:09:13 +00:00
else if ( m = = moViking ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shPBody ) ;
queuepoly ( VBODY , shPBody , darkena ( 0xE00000 , 0 , 0xFF ) ) ;
queuepoly ( VBODY , shPSword , darkena ( 0xD0D0D0 , 0 , 0xFF ) ) ;
queuepoly ( VBODY , shKnightCloak , darkena ( 0x404040 , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , shVikingHelmet , darkena ( 0xC0C0C0 , 0 , 0XFF ) ) ;
queuepoly ( VHEAD , shPFace , darkena ( 0xFFFF80 , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( m = = moOutlaw ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shPBody ) ;
queuepoly ( VBODY , shPBody , darkena ( col , 0 , 0xFF ) ) ;
queuepoly ( VBODY , shKnightCloak , darkena ( col , 1 , 0xFF ) ) ;
queuepoly ( VHEAD , shWestHat1 , darkena ( col , 2 , 0XFF ) ) ;
queuepoly ( VHEAD , shWestHat2 , darkena ( col , 1 , 0XFF ) ) ;
queuepoly ( VHEAD , shPFace , darkena ( 0xFFFF80 , 0 , 0xFF ) ) ;
queuepoly ( VBODY , shGunInHand , darkena ( col , 1 , 0XFF ) ) ;
2016-08-26 09:58:03 +00:00
}
2016-01-02 10:09:13 +00:00
else if ( m = = moNecromancer ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shPBody ) ;
queuepoly ( VBODY , shPBody , 0xC00000C0 ) ;
queuepoly ( VHEAD , shHood , darkena ( col , 1 , 0xFF ) ) ;
}
else if ( m = = moDraugr ) {
otherbodyparts ( V , 0x483828D0 , m , footphase ) ;
queuepoly ( VBODY , shPBody , 0x483828D0 ) ;
queuepoly ( VBODY , shPSword , 0xFFFFD0A0 ) ;
queuepoly ( VHEAD , shPHead , 0x483828D0 ) ;
// queuepoly(V, shSkull, 0xC06020D0);
//queuepoly(V, shSkullEyes, 0x000000D0);
// queuepoly(V, shWightCloak, 0xC0A080A0);
2017-05-28 22:16:17 +00:00
int b = where ? where - > cpdist : 0 ;
2017-03-23 10:53:57 +00:00
b - - ;
if ( b < 0 ) b = 0 ;
if ( b > 6 ) b = 6 ;
queuepoly ( VHEAD , shWightCloak , 0x605040A0 + 0x10101000 * b ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moGoblin ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shYeti ) ;
queuepoly ( VBODY , shYeti , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD , shArmor , darkena ( col , 1 , 0XFF ) ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moLancer | | m = = moFlailer | | m = = moMiner ) {
transmatrix V2 = V ;
if ( m = = moLancer )
2017-03-23 10:53:57 +00:00
V2 = V * spin ( ( where & & where - > type = = 6 ) ? - M_PI / 3 : - M_PI / 2 ) ;
transmatrix Vh = mmscale ( V2 , geom3 : : HEAD ) ;
transmatrix Vb = mmscale ( V2 , geom3 : : BODY ) ;
otherbodyparts ( V2 , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
ShadowV ( V2 , shPBody ) ;
queuepoly ( Vb , shPBody , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( Vh , m = = moFlailer ? shArmor : shHood , darkena ( col , 1 , 0XFF ) ) ;
2016-01-02 10:09:13 +00:00
if ( m = = moMiner )
2017-03-23 10:53:57 +00:00
queuepoly ( Vb , shPickAxe , darkena ( 0xC0C0C0 , 0 , 0XFF ) ) ;
2016-01-02 10:09:13 +00:00
if ( m = = moLancer )
2017-03-23 10:53:57 +00:00
queuepoly ( Vb , shPike , darkena ( col , 0 , 0XFF ) ) ;
2016-01-02 10:09:13 +00:00
if ( m = = moFlailer ) {
2017-03-23 10:53:57 +00:00
queuepoly ( Vb , shFlailBall , darkena ( col , 0 , 0XFF ) ) ;
queuepoly ( Vb , shFlailChain , darkena ( col , 1 , 0XFF ) ) ;
queuepoly ( Vb , shFlailTrunk , darkena ( col , 0 , 0XFF ) ) ;
2015-08-08 13:57:52 +00:00
}
}
2016-01-02 10:09:13 +00:00
else if ( m = = moTroll ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shYeti ) ;
queuepoly ( VBODY , shYeti , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD , shPHead , darkena ( col , 1 , 0XFF ) ) ;
queuepoly ( VHEAD , shPFace , darkena ( col , 2 , 0XFF ) ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( m = = moFjordTroll | | m = = moForestTroll | | m = = moStormTroll ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shYeti ) ;
queuepoly ( VBODY , shYeti , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD , shPHead , darkena ( col , 1 , 0XFF ) ) ;
queuepoly ( VHEAD , shPFace , darkena ( col , 2 , 0XFF ) ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moDarkTroll ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shYeti ) ;
queuepoly ( VBODY , shYeti , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD , shPHead , darkena ( col , 1 , 0XFF ) ) ;
queuepoly ( VHEAD , shPFace , 0xFFFFFF80 ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moRedTroll ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shYeti ) ;
queuepoly ( VBODY , shYeti , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD , shPHead , darkena ( 0xFF8000 , 0 , 0XFF ) ) ;
queuepoly ( VHEAD , shPFace , 0xFFFFFF80 ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moEarthElemental ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shYeti ) ;
queuepoly ( VBODY , shYeti , darkena ( col , 0 , 0xC0 ) ) ;
queuepoly ( VHEAD , shPHead , darkena ( col , 0 , 0XFF ) ) ;
queuepoly ( VHEAD , shPFace , 0xF0000080 ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moWaterElemental ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , watercolor ( 50 ) , m , footphase ) ;
ShadowV ( V , shWaterElemental ) ;
queuepoly ( VBODY , shWaterElemental , watercolor ( 0 ) ) ;
queuepoly ( VHEAD , shFemaleHair , watercolor ( 100 ) ) ;
queuepoly ( VHEAD , shPFace , watercolor ( 200 ) ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moFireElemental ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( firecolor ( 50 ) , 0 , 0xFF ) , m , footphase ) ;
ShadowV ( V , shWaterElemental ) ;
queuepoly ( VBODY , shWaterElemental , darkena ( firecolor ( 0 ) , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , shFemaleHair , darkena ( firecolor ( 100 ) , 0 , 0xFF ) ) ;
queuepoly ( VHEAD , shPFace , darkena ( firecolor ( 200 ) , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
else if ( m = = moAirElemental ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0x40 ) , m , footphase ) ;
ShadowV ( V , shWaterElemental ) ;
queuepoly ( VBODY , shWaterElemental , darkena ( col , 0 , 0x80 ) ) ;
queuepoly ( VHEAD , shFemaleHair , darkena ( col , 0 , 0x80 ) ) ;
queuepoly ( VHEAD , shPFace , darkena ( col , 0 , 0x80 ) ) ;
2016-01-02 10:09:13 +00:00
}
2017-05-28 22:16:17 +00:00
else if ( ( xch = = ' d ' | | xch = = ' D ' ) & & m ! = moDragonHead & & m ! = moDragonTail ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 0 , 0xC0 ) , m , footphase ) ;
queuepoly ( VBODY , shPBody , darkena ( col , 1 , 0xC0 ) ) ;
ShadowV ( V , shPBody ) ;
2016-01-02 10:09:13 +00:00
int acol = col ;
if ( xch = = ' D ' ) acol = 0xD0D0D0 ;
2017-03-23 10:53:57 +00:00
queuepoly ( VHEAD , shDemon , darkena ( acol , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( isMetalBeast ( m ) ) {
2017-03-23 10:53:57 +00:00
ShadowV ( V , shTrylobite ) ;
if ( ! mmspatial )
queuepoly ( VABODY , shTrylobite , darkena ( col , 1 , 0xC0 ) ) ;
else {
queuepoly ( VABODY , shTrylobiteBody , darkena ( col , 1 , 0xFF ) ) ;
animallegs ( VALEGS , moMetalBeast , darkena ( col , 1 , 0xFF ) , footphase ) ;
}
2016-08-26 09:58:03 +00:00
int acol = col ;
2017-03-23 10:53:57 +00:00
queuepoly ( VAHEAD , shTrylobiteHead , darkena ( acol , 0 , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
}
2016-01-02 10:09:13 +00:00
else if ( m = = moEvilGolem ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 2 , 0xC0 ) , m , footphase ) ;
ShadowV ( V , shPBody ) ;
queuepoly ( VBODY , shPBody , darkena ( col , 0 , 0XC0 ) ) ;
queuepoly ( VHEAD , shGolemhead , darkena ( col , 1 , 0XFF ) ) ;
2016-01-02 10:09:13 +00:00
}
else if ( isWitch ( m ) ) {
2017-03-23 10:53:57 +00:00
otherbodyparts ( V , darkena ( col , 1 , 0xFF ) , m , footphase ) ;
2017-05-28 22:16:17 +00:00
int cc = 0xFF ;
if ( m = = moWitchGhost ) cc = 0x85 + 120 * sin ( ticks / 160.0 ) ;
if ( m = = moWitchWinter & & where ) drawWinter ( V , 0 ) ;
if ( m = = moWitchFlash & & where ) drawFlash ( V ) ;
if ( m = = moWitchSpeed & & where ) drawSpeed ( V ) ;
2016-01-02 10:09:13 +00:00
if ( m = = moWitchFire ) col = firecolor ( 0 ) ;
2017-03-23 10:53:57 +00:00
ShadowV ( V , shFemaleBody ) ;
2017-05-28 22:16:17 +00:00
queuepoly ( VBODY , shFemaleBody , darkena ( col , 0 , cc ) ) ;
2016-01-02 10:09:13 +00:00
// queuepoly(cV2, ct, shPSword, darkena(col, 0, 0XFF));
// queuepoly(V, shHood, darkena(col, 0, 0XC0));
if ( m = = moWitchFire ) col = firecolor ( 100 ) ;
2017-05-28 22:16:17 +00:00
queuepoly ( VHEAD , shWitchHair , darkena ( col , 1 , cc ) ) ;
2016-01-02 10:09:13 +00:00
if ( m = = moWitchFire ) col = firecolor ( 200 ) ;
2017-05-28 22:16:17 +00:00
queuepoly ( VHEAD , shPFace , darkena ( col , 0 , cc ) ) ;
2016-01-02 10:09:13 +00:00
if ( m = = moWitchFire ) col = firecolor ( 300 ) ;
2017-03-23 10:53:57 +00:00
queuepoly ( VBODY , shWitchDress , darkena ( col , 1 , 0XC0 ) ) ;
2016-01-02 10:09:13 +00:00
}
2017-05-28 22:16:17 +00:00
// just for the HUD glyphs...
else if ( isIvy ( m ) | | isMutantIvy ( m ) | | m = = moFriendlyIvy ) {
queuepoly ( V , shILeaf [ 0 ] , darkena ( col , 0 , 0xFF ) ) ;
}
else if ( m = = moWorm | | m = = moWormwait | | m = = moHexSnake ) {
queuepoly ( V , shWormHead , darkena ( col , 0 , 0xFF ) ) ;
queuepolyat ( V , shEyes , 0xFF , PPR_ONTENTACLE_EYES ) ;
}
else if ( m = = moDragonHead ) {
queuepoly ( V , shDragonHead , darkena ( col , 0 , 0xFF ) ) ;
queuepolyat ( V , shEyes , 0xFF , PPR_ONTENTACLE_EYES ) ;
int noscolor = 0xFF0000FF ;
queuepoly ( V , shDragonNostril , noscolor ) ;
queuepoly ( V * Mirror , shDragonNostril , noscolor ) ;
}
else if ( m = = moDragonTail ) {
queuepoly ( V , shDragonSegment , darkena ( col , 0 , 0xFF ) ) ;
}
else if ( m = = moTentacle | | m = = moTentaclewait | | m = = moTentacleEscaping ) {
queuepoly ( V , shTentHead , darkena ( col , 0 , 0xFF ) ) ;
ShadowV ( V , shTentHead , PPR_GIANTSHADOW ) ;
}
2016-01-02 10:09:13 +00:00
else return true ;
return false ;
}
2017-03-23 10:53:57 +00:00
bool drawMonsterTypeDH ( eMonster m , cell * where , const transmatrix & V , int col , bool dh , ld footphase ) {
2016-08-26 09:58:03 +00:00
if ( dh ) {
poly_outline = OUTLINE_DEAD ;
darken + + ;
}
2017-03-23 10:53:57 +00:00
bool b = drawMonsterType ( m , where , V , col , footphase ) ;
2016-08-26 09:58:03 +00:00
if ( dh ) {
poly_outline = OUTLINE_NONE ;
darken - - ;
}
return b ;
}
2017-03-23 10:53:57 +00:00
transmatrix playerV ;
bool applyAnimation ( cell * c , transmatrix & V , double & footphase , int layer ) {
if ( ! animations [ layer ] . count ( c ) ) return false ;
animation & a = animations [ layer ] [ c ] ;
int td = ticks - a . ltick ;
ld aspd = td / 1000.0 * exp ( vid . mspeed ) ;
ld R = hdist0 ( tC0 ( a . wherenow ) ) ;
aspd * = ( 1 + R + ( shmup : : on ? 1 : 0 ) ) ;
2017-05-27 19:40:40 +00:00
if ( R < aspd | | std : : isnan ( R ) | | std : : isnan ( aspd ) | | R > 10 ) {
2017-03-23 10:53:57 +00:00
animations [ layer ] . erase ( c ) ;
return false ;
}
else {
a . wherenow = a . wherenow * rspintox ( tC0 ( inverse ( a . wherenow ) ) ) ;
a . wherenow = a . wherenow * xpush ( aspd ) ;
fixmatrix ( a . wherenow ) ;
a . footphase + = aspd ;
footphase = a . footphase ;
V = V * a . wherenow ;
a . ltick = ticks ;
return true ;
}
}
double chainAngle ( cell * c , transmatrix & V , cell * c2 , double dft ) {
if ( ! gmatrix0 . count ( c2 ) ) return dft ;
hyperpoint h = C0 ;
if ( animations [ LAYER_BIG ] . count ( c2 ) ) h = animations [ LAYER_BIG ] [ c2 ] . wherenow * h ;
h = inverse ( V ) * gmatrix0 [ c2 ] * h ;
return atan2 ( h [ 1 ] , h [ 0 ] ) ;
}
// equivalent to V = V * spin(-chainAngle(c,V,c2,dft));
bool chainAnimation ( cell * c , transmatrix & V , cell * c2 , int i , int b ) {
if ( ! gmatrix0 . count ( c2 ) ) {
V = V * ddspin ( c , i , b ) ;
return false ;
}
hyperpoint h = C0 ;
if ( animations [ LAYER_BIG ] . count ( c2 ) ) h = animations [ LAYER_BIG ] [ c2 ] . wherenow * h ;
h = inverse ( V ) * gmatrix0 [ c2 ] * h ;
V = V * rspintox ( h ) ;
return true ;
}
// 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-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
int cellcolor ( cell * c ) {
if ( isPlayerOn ( c ) | | isFriendly ( c ) ) return OUTLINE_FRIEND ;
if ( noHighlight ( c - > monst ) ) return OUTLINE_NONE ;
if ( c - > monst ) return OUTLINE_ENEMY ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( c - > wall = = waMirror ) return c - > land = = laMirror ? OUTLINE_TREASURE : OUTLINE_ORB ;
if ( c - > item ) {
int k = itemclass ( c - > item ) ;
if ( k = = IC_TREASURE )
return OUTLINE_TREASURE ;
else if ( k = = IC_ORB )
return OUTLINE_ORB ;
else
return OUTLINE_OTHER ;
}
return OUTLINE_NONE ;
}
bool drawMonster ( const transmatrix & Vparam , int ct , cell * c , int col ) {
2016-08-26 09:58:03 +00:00
bool darkhistory = conformal : : includeHistory & & eq ( c - > aitmp , sval ) ;
2016-01-02 10:09:13 +00:00
if ( doHighlight ( ) )
poly_outline =
2017-03-23 10:53:57 +00:00
( isPlayerOn ( c ) | | isFriendly ( c ) ) ? OUTLINE_FRIEND :
noHighlight ( c - > monst ) ? OUTLINE_NONE :
OUTLINE_ENEMY ;
bool nospins = false , nospinb = false ;
double footphaseb = 0 , footphase = 0 ;
transmatrix Vs = Vparam ; nospins = applyAnimation ( c , Vs , footphase , LAYER_SMALL ) ;
transmatrix Vb = Vparam ; nospinb = applyAnimation ( c , Vb , footphaseb , LAYER_BIG ) ;
// nospin = true;
2016-01-02 10:09:13 +00:00
eMonster m = c - > monst ;
2017-03-23 10:53:57 +00:00
if ( isIvy ( c ) | | isWorm ( c ) | | isMutantIvy ( c ) | | c - > monst = = moFriendlyIvy ) {
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
if ( isDragon ( c - > monst ) & & c - > stuntime = = 0 ) col = 0xFF6000 ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
transmatrix Vb0 = Vb ;
2015-08-08 13:57:52 +00:00
if ( c - > mondir ! = NODIR ) {
2017-03-23 10:53:57 +00:00
if ( mmmon ) {
if ( nospinb )
chainAnimation ( c , Vb , c - > mov [ c - > mondir ] , c - > mondir , 0 ) ;
else
Vb = Vb * ddspin ( c , c - > mondir ) ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
# ifndef NOEDIT
if ( c = = mapeditor : : drawcell ) mapeditor : : drawtrans = Vb ;
2016-01-02 10:09:13 +00:00
# endif
2017-03-23 10:53:57 +00:00
if ( drawUserShape ( Vb , 1 , c - > monst , ( col < < 8 ) + 0xFF ) ) return false ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( isIvy ( c ) | | isMutantIvy ( c ) | | c - > monst = = moFriendlyIvy )
queuepoly ( Vb , shIBranch , ( col < < 8 ) + 0xFF ) ;
2015-08-08 13:57:52 +00:00
else if ( c - > monst < moTentacle ) {
2017-03-23 10:53:57 +00:00
ShadowV ( Vb , shTentacleX , PPR_GIANTSHADOW ) ;
queuepoly ( mmscale ( Vb , geom3 : : ABODY ) , shTentacleX , 0xFF ) ;
queuepoly ( mmscale ( Vb , geom3 : : ABODY ) , shTentacle , ( col < < 8 ) + 0xFF ) ;
2015-08-08 13:57:52 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( c - > monst = = moDragonHead | | c - > monst = = moDragonTail ) {
char part = dragon : : bodypart ( c , dragon : : findhead ( c ) ) ;
2017-03-23 10:53:57 +00:00
if ( part ! = ' 2 ' ) {
queuepoly ( mmscale ( Vb , geom3 : : ABODY ) , shDragonSegment , darkena ( col , 0 , 0xFF ) ) ;
ShadowV ( Vb , shDragonSegment , PPR_GIANTSHADOW ) ;
}
2016-08-26 09:58:03 +00:00
}
2015-08-08 13:57:52 +00:00
else {
2016-01-02 10:09:13 +00:00
if ( c - > monst = = moTentacleGhost ) {
2017-03-23 10:53:57 +00:00
hyperpoint V0 = conformal : : on ? tC0 ( Vs ) : inverse ( cwtV ) * tC0 ( Vs ) ;
2016-01-02 10:09:13 +00:00
hyperpoint V1 = spintox ( V0 ) * V0 ;
2017-03-23 10:53:57 +00:00
Vs = cwtV * rspintox ( V0 ) * rpushxto0 ( V1 ) * pispin ;
drawMonsterType ( moGhost , c , Vs , darkena ( col , 0 , 0xFF ) , footphase ) ;
2016-01-02 10:09:13 +00:00
col = minf [ moTentacletail ] . color ;
}
2017-03-23 10:53:57 +00:00
queuepoly ( mmscale ( Vb , geom3 : : ABODY ) , shTentacleX , 0xFFFFFFFF ) ;
queuepoly ( mmscale ( Vb , geom3 : : ABODY ) , shTentacle , ( col < < 8 ) + 0xFF ) ;
ShadowV ( Vb , shTentacleX , PPR_GIANTSHADOW ) ;
2015-08-08 13:57:52 +00:00
}
}
2017-03-23 10:53:57 +00:00
else {
int hdir = displaydir ( c , c - > mondir ) ;
int col = darkena ( 0x606020 , 0 , 0xFF ) ;
for ( int u = - 1 ; u < = 1 ; u + + )
queueline ( Vparam * ddi0 ( hdir + S21 , u * crossf / 5 ) , Vparam * ddi ( hdir , crossf ) * ddi0 ( hdir + S21 , u * crossf / 5 ) , col , 2 ) ;
}
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
if ( mmmon ) {
if ( isIvy ( c ) | | isMutantIvy ( c ) | | c - > monst = = moFriendlyIvy ) {
queuepoly ( mmscale ( Vb , geom3 : : ABODY ) , shILeaf [ K ( c ) ] , darkena ( col , 0 , 0xFF ) ) ;
ShadowV ( Vb , shILeaf [ K ( c ) ] , PPR_GIANTSHADOW ) ;
}
2016-01-02 10:09:13 +00:00
else if ( m = = moWorm | | m = = moWormwait | | m = = moHexSnake ) {
2017-03-23 10:53:57 +00:00
Vb = Vb * pispin ;
transmatrix Vbh = mmscale ( Vb , geom3 : : AHEAD ) ;
queuepoly ( Vbh , shWormHead , darkena ( col , 0 , 0xFF ) ) ;
queuepolyat ( Vbh , shEyes , 0xFF , PPR_ONTENTACLE_EYES ) ;
ShadowV ( Vb , shWormHead , PPR_GIANTSHADOW ) ;
2016-08-26 09:58:03 +00:00
}
else if ( m = = moDragonHead ) {
2017-03-23 10:53:57 +00:00
transmatrix Vbh = mmscale ( Vb , geom3 : : AHEAD ) ;
ShadowV ( Vb , shDragonHead , PPR_GIANTSHADOW ) ;
queuepoly ( Vbh , shDragonHead , darkena ( col , c - > hitpoints ? 0 : 1 , 0xFF ) ) ;
queuepolyat ( Vbh /* * pispin */ , shEyes , 0xFF , PPR_ONTENTACLE_EYES ) ;
2016-08-26 09:58:03 +00:00
int noscolor = ( c - > hitpoints = = 1 & & c - > stuntime = = 1 ) ? 0xFF0000FF : 0xFF ;
2017-03-23 10:53:57 +00:00
queuepoly ( Vbh , shDragonNostril , noscolor ) ;
queuepoly ( Vbh * Mirror , shDragonNostril , noscolor ) ;
}
else if ( m = = moTentacle | | m = = moTentaclewait | | m = = moTentacleEscaping ) {
Vb = Vb * pispin ;
transmatrix Vbh = mmscale ( Vb , geom3 : : AHEAD ) ;
queuepoly ( Vbh , shTentHead , darkena ( col , 0 , 0xFF ) ) ;
ShadowV ( Vb , shTentHead , PPR_GIANTSHADOW ) ;
2015-08-08 13:57:52 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( m = = moDragonTail ) {
cell * c2 = NULL ;
for ( int i = 0 ; i < c - > type ; i + + )
2017-03-23 10:53:57 +00:00
if ( c - > mov [ i ] & & isDragon ( c - > mov [ i ] - > monst ) & & c - > mov [ i ] - > mondir = = c - > spn ( i ) )
2016-08-26 09:58:03 +00:00
c2 = c - > mov [ i ] ;
int nd = neighborId ( c , c2 ) ;
char part = dragon : : bodypart ( c , dragon : : findhead ( c ) ) ;
if ( part = = ' t ' ) {
2017-03-23 10:53:57 +00:00
if ( nospinb ) {
chainAnimation ( c , Vb , c2 , nd , 0 ) ;
Vb = Vb * pispin ;
}
else {
Vb = Vb0 * ddspin ( c , nd , S42 ) ;
}
transmatrix Vbb = mmscale ( Vb , geom3 : : ABODY ) ;
queuepoly ( Vbb , shDragonTail , darkena ( col , c - > hitpoints ? 0 : 1 , 0xFF ) ) ;
ShadowV ( Vb , shDragonTail , PPR_GIANTSHADOW ) ;
2016-08-26 09:58:03 +00:00
}
else if ( true ) {
2017-03-23 10:53:57 +00:00
if ( nospinb ) {
chainAnimation ( c , Vb , c2 , nd , 0 ) ;
Vb = Vb * pispin ;
double ang = chainAngle ( c , Vb , c - > mov [ c - > mondir ] , ( displaydir ( c , c - > mondir ) - displaydir ( c , nd ) ) * M_PI / S42 ) ;
ang / = 2 ;
Vb = Vb * spin ( M_PI - ang ) ;
}
else {
int hdir0 = displaydir ( c , nd ) + S42 ;
int hdir1 = displaydir ( c , c - > mondir ) ;
while ( hdir1 > hdir0 + S42 ) hdir1 - = S84 ;
while ( hdir1 < hdir0 - S42 ) hdir1 + = S84 ;
Vb = Vb0 * spin ( ( hdir0 + hdir1 ) / 2 * M_PI / S42 + M_PI ) ;
}
transmatrix Vbb = mmscale ( Vb , geom3 : : ABODY ) ;
if ( part = = ' l ' | | part = = ' 2 ' ) {
queuepoly ( Vbb , shDragonLegs , darkena ( col , c - > hitpoints ? 0 : 1 , 0xFF ) ) ;
}
queuepoly ( Vbb , shDragonWings , darkena ( col , c - > hitpoints ? 0 : 1 , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
}
}
2017-03-23 10:53:57 +00:00
else if ( ! ( c - > mondir = = NODIR & & ( c - > monst = = moTentacletail | | ( c - > monst = = moWormtail & & wormpos ( c ) < WORMLENGTH ) ) ) )
queuepoly ( Vb , shJoint , darkena ( col , 0 , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
if ( ! mmmon ) return true ;
2015-08-08 13:57:52 +00:00
}
else if ( isMimic ( c ) ) {
2017-03-23 10:53:57 +00:00
if ( ! nospins )
Vs = Vs * ddspin ( c , c - > mondir , flipplayer ? S42 : 0 ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( c - > monst = = moMirror ) Vs = Vs * Mirror ;
multi : : cpid = c - > hitpoints ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( mmmon ) {
drawMonsterType ( c - > monst , c , Vs , col , footphase ) ;
drawPlayerEffects ( Vs , c , false ) ;
2016-08-26 09:58:03 +00:00
}
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( flipplayer ) Vs = Vs * pispin ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( ! outofmap ( mouseh ) & & ! nospins ) {
2016-01-02 10:09:13 +00:00
// transmatrix invxy = Id; invxy[0][0] = invxy[1][1] = -1;
2017-03-23 10:53:57 +00:00
hyperpoint P2 = Vs * inverse ( cwtV ) * mouseh ;
queuechr ( P2 , 10 , ' x ' , 0xFF00 ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
return ! mmmon ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else if ( c - > monst & & ! mmmon ) return true ;
2016-01-02 10:09:13 +00:00
// illusions face randomly
2015-08-08 13:57:52 +00:00
else if ( c - > monst = = moIllusion ) {
2017-03-23 10:53:57 +00:00
multi : : cpid = 0 ;
drawMonsterType ( c - > monst , c , Vs , col , footphase ) ;
drawPlayerEffects ( Vs , c , false ) ;
2015-08-08 13:57:52 +00:00
}
2016-01-02 10:09:13 +00:00
// wolves face the heat
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
else if ( c - > monst = = moWolf & & c - > cpdist > 1 ) {
2017-03-23 10:53:57 +00:00
if ( ! nospins ) {
int d = 0 ;
double bheat = - 999 ;
for ( int i = 0 ; i < c - > type ; i + + ) if ( c - > mov [ i ] & & HEAT ( c - > mov [ i ] ) > bheat ) {
bheat = HEAT ( c - > mov [ i ] ) ;
d = i ;
}
Vs = Vs * ddspin ( c , d ) ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
return drawMonsterTypeDH ( m , c , Vs , col , darkhistory , footphase ) ;
2016-08-26 09:58:03 +00:00
}
// golems, knights, and hyperbugs don't face the player (mondir-controlled)
// also whatever in the lineview mode
2017-03-23 10:53:57 +00:00
else if ( isFriendly ( c ) | | isBug ( c ) | | ( c - > monst & & conformal : : on ) | | c - > monst = = moKrakenH | | ( isBull ( c - > monst ) & & c - > mondir ! = NODIR ) | | c - > monst = = moButterfly ) {
if ( c - > monst = = moKrakenH ) Vs = Vb , nospins = nospinb ;
if ( ! nospins ) Vs = Vs * ddspin ( c , c - > mondir , S42 ) ;
if ( isFriendly ( c ) ) drawPlayerEffects ( Vs , c , false ) ;
return drawMonsterTypeDH ( m , c , Vs , col , darkhistory , footphase ) ;
}
else if ( c - > monst = = moKrakenT ) {
if ( c - > hitpoints = = 0 ) col = 0x404040 ;
if ( nospinb ) {
chainAnimation ( c , Vb , c - > mov [ c - > mondir ] , c - > mondir , 0 ) ;
Vb = Vb * pispin ;
}
else Vb = Vb * ddspin ( c , c - > mondir , S42 ) ;
if ( c - > type ! = 6 ) Vb = Vb * xpush ( hexhexdist - hcrossf ) ;
return drawMonsterTypeDH ( m , c , Vb , col , darkhistory , footphase ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( c - > monst ) {
2016-01-02 10:09:13 +00:00
// other monsters face the player
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( ! nospins ) {
hyperpoint V0 = inverse ( cwtV ) * tC0 ( Vs ) ;
2015-08-08 13:57:52 +00:00
hyperpoint V1 = spintox ( V0 ) * V0 ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
Vs = cwtV * rspintox ( V0 ) * rpushxto0 ( V1 ) * pispin ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
if ( c - > monst = = moShadow )
multi : : cpid = c - > hitpoints ;
return drawMonsterTypeDH ( m , c , Vs , col , darkhistory , footphase ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
for ( int i = 0 ; i < numplayers ( ) ; i + + ) if ( c = = playerpos ( i ) & & ! shmup : : on & & mapeditor : : drawplayer ) {
if ( ! nospins ) {
Vs = playerV ;
if ( multi : : players > 1 ? multi : : flipped [ i ] : flipplayer ) Vs = Vs * pispin ;
}
shmup : : cpid = i ;
drawPlayerEffects ( Vs , c , true ) ;
if ( ! mmmon ) return true ;
if ( isWorm ( m ) ) {
ld depth = geom3 : : factor_to_lev ( wormhead ( c ) = = c ? geom3 : : AHEAD : geom3 : : ABODY ) ;
footphase = 0 ;
int q = ptds . size ( ) ;
drawMonsterType ( moPlayer , c , Vs , col , footphase ) ;
pushdown ( c , q , Vs , - depth , true , false ) ;
}
else if ( mmmon )
drawMonsterType ( moPlayer , c , Vs , col , footphase ) ;
}
2015-08-08 13:57:52 +00:00
return false ;
}
2016-01-02 10:09:13 +00:00
bool showPirateX ;
cell * keycell , * pirateTreasureSeek , * pirateTreasureFound ;
2017-03-23 10:53:57 +00:00
hyperpoint pirateCoords ;
2016-01-02 10:09:13 +00:00
double downspin ;
cell * straightDownSeek ;
2015-08-08 13:57:52 +00:00
int keycelldist ;
2017-05-27 19:40:40 +00:00
# define AURA 180
int aurac [ AURA + 1 ] [ 4 ] ;
bool haveaura ( ) {
2017-05-28 22:16:17 +00:00
return pmodel = = mdDisk & & ! sphere & & ! euclid & & vid . aurastr > 0 & & ! svg : : in & & ( auraNOGL | | vid . usingGL ) ;
2017-05-27 19:40:40 +00:00
}
void clearaura ( ) {
if ( ! haveaura ( ) ) return ;
for ( int a = 0 ; a < AURA ; a + + ) for ( int b = 0 ; b < 4 ; b + + )
aurac [ a ] [ b ] = 0 ;
}
void addaura ( const hyperpoint & h , int col , int fd ) {
if ( ! haveaura ( ) ) return ;
int r = int ( 2 * AURA + atan2 ( h [ 0 ] , h [ 1 ] ) * AURA / 2 / M_PI ) % AURA ;
aurac [ r ] [ 3 ] + = ( ( 128 * 128 / vid . aurastr ) < < ( fd + darken ) ) ;
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 ] ;
}
void drawaura ( ) {
if ( ! haveaura ( ) ) return ;
for ( int v = 0 ; v < 4 ; v + + ) sumaura ( v ) ;
# ifndef NOSDL
if ( ! vid . usingGL ) {
SDL_LockSurface ( s ) ;
for ( int y = 0 ; y < vid . yres ; y + + )
for ( int x = 0 ; x < vid . xres ; x + + ) {
ld hx = ( x * 1. - vid . xcenter ) / vid . radius ;
ld hy = ( y * 1. - vid . ycenter ) / vid . radius ;
if ( vid . camera_angle ) camrotate ( hx , hy ) ;
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 ;
ld alpha = AURA * atan2 ( hx , hy ) / ( 2 * M_PI ) ;
if ( alpha < 0 ) alpha + = AURA ;
if ( alpha > = AURA ) alpha - = AURA ;
int rm = int ( alpha ) ;
double fr = alpha - rm ;
if ( rm < 0 | | rm > = AURA ) continue ;
int & p = qpixel ( s , x , y ) ;
for ( int c = 0 ; c < 3 ; c + + ) {
double c1 = aurac [ rm ] [ 2 - c ] / ( aurac [ rm ] [ 3 ] + .1 ) ;
double c2 = aurac [ rm + 1 ] [ 2 - c ] / ( aurac [ rm + 1 ] [ 3 ] + .1 ) ;
const ld one = 1 ;
part ( p , c ) = int ( 255 * min ( one , cmul * ( c1 + fr * ( c2 - c1 ) ) ) ) ;
}
}
SDL_UnlockSurface ( s ) ;
return ;
}
# endif
# ifdef GL
setcameraangle ( true ) ;
glEnableClientState ( GL_COLOR_ARRAY ) ;
float coltab [ 4 ] [ 4 ] ;
glColorPointer ( 4 , GL_FLOAT , 0 , coltab ) ;
activateGlcoords ( ) ;
float cx [ AURA + 1 ] [ 11 ] [ 5 ] ;
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 } ;
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 ;
for ( int r = 0 ; r < = AURA ; r + + ) for ( int z = 0 ; z < 11 ; z + + ) {
float rr = ( M_PI * 2 * r ) / AURA ;
float rad = vid . radius * facs [ z ] ;
int rm = r % AURA ;
cx [ r ] [ z ] [ 0 ] = rad * sin ( rr ) ;
cx [ r ] [ z ] [ 1 ] = rad * cos ( rr ) ;
cx [ r ] [ z ] [ 2 ] = cmul [ z ] * aurac [ rm ] [ 0 ] / ( aurac [ rm ] [ 3 ] + .1 ) ;
cx [ r ] [ z ] [ 3 ] = cmul [ z ] * aurac [ rm ] [ 1 ] / ( aurac [ rm ] [ 3 ] + .1 ) ;
cx [ r ] [ z ] [ 4 ] = cmul [ z ] * aurac [ rm ] [ 2 ] / ( aurac [ rm ] [ 3 ] + .1 ) ;
}
for ( int u = 0 ; u < 4 ; u + + ) glcoords [ u ] [ 2 ] = vid . scrdist ;
for ( int u = 0 ; u < 4 ; u + + ) coltab [ u ] [ 3 ] = 1 ;
for ( int r = 0 ; r < AURA ; r + + ) for ( int z = 0 ; z < 10 ; z + + ) {
for ( int c = 0 ; c < 4 ; c + + ) {
int br = ( c = = 1 | | c = = 2 ) ? r + 1 : r ;
int bz = ( c = = 3 | | c = = 2 ) ? z + 1 : z ;
glcoords [ c ] [ 0 ] = cx [ br ] [ bz ] [ 0 ] ;
glcoords [ c ] [ 1 ] = cx [ br ] [ bz ] [ 1 ] ;
coltab [ c ] [ 0 ] = cx [ br ] [ bz ] [ 2 ] ;
coltab [ c ] [ 1 ] = cx [ br ] [ bz ] [ 3 ] ;
coltab [ c ] [ 2 ] = cx [ br ] [ bz ] [ 4 ] ;
}
glDrawArrays ( GL_TRIANGLE_FAN , 0 , 4 ) ;
}
glDisableClientState ( GL_COLOR_ARRAY ) ;
setcameraangle ( false ) ;
# endif
}
2015-08-08 13:57:52 +00:00
void drawCircle ( int x , int y , int size , int color ) {
2017-03-23 10:53:57 +00:00
if ( size < 0 ) size = - size ;
2015-08-08 13:57:52 +00:00
# ifdef GL
if ( vid . usingGL ) {
qglcoords = 0 ;
2017-03-23 10:53:57 +00:00
glcolor2 ( color ) ;
2015-08-08 13:57:52 +00:00
x - = vid . xcenter ; y - = vid . ycenter ;
int pts = size * 4 ;
if ( pts > 1500 ) pts = 1500 ;
if ( ISMOBILE & & pts > 72 ) pts = 72 ;
for ( int r = 0 ; r < pts ; r + + ) {
float rr = ( M_PI * 2 * r ) / pts ;
glcoords [ r ] [ 0 ] = x + size * sin ( rr ) ;
glcoords [ r ] [ 1 ] = y + size * cos ( rr ) ;
glcoords [ r ] [ 2 ] = vid . scrdist ;
}
2017-03-23 10:53:57 +00:00
qglcoords = pts ;
activateGlcoords ( ) ;
2015-08-08 13:57:52 +00:00
glDrawArrays ( GL_LINE_LOOP , 0 , pts ) ;
return ;
}
# endif
# ifdef MOBILE
gdpush ( 4 ) ; gdpush ( color ) ; gdpush ( x ) ; gdpush ( y ) ; gdpush ( size ) ;
# else
2017-05-27 19:40:40 +00:00
# ifdef SDLGFX
2017-03-23 10:53:57 +00:00
( vid . usingAA ? aacircleColor : circleColor ) ( s , x , y , size , color ) ;
2015-08-08 13:57:52 +00:00
# else
2017-05-27 19:40:40 +00:00
# ifndef NOSDL
2015-08-08 13:57:52 +00:00
int pts = size * 4 ;
if ( pts > 1500 ) pts = 1500 ;
for ( int r = 0 ; r < pts ; r + + )
qpixel ( s , x + int ( size * sin ( r ) ) , y + int ( size * cos ( r ) ) ) = color ;
# endif
2017-05-27 19:40:40 +00:00
# endif
2015-08-08 13:57:52 +00:00
# endif
}
2016-01-02 10:09:13 +00:00
int fnt [ 100 ] [ 7 ] ;
2015-08-08 13:57:52 +00:00
bool bugsNearby ( cell * c , int dist = 2 ) {
2017-03-23 10:53:57 +00:00
if ( ! ( havewhat & HF_BUG ) ) return false ;
2015-08-08 13:57:52 +00:00
if ( isBug ( c ) ) return true ;
if ( dist ) for ( int t = 0 ; t < c - > type ; t + + ) if ( c - > mov [ t ] & & bugsNearby ( c - > mov [ t ] , dist - 1 ) ) return true ;
return false ;
}
2016-01-02 10:09:13 +00:00
int minecolors [ 8 ] = {
2016-08-26 09:58:03 +00:00
0xFFFFFF , 0xF0 , 0xF060 , 0xF00000 ,
2017-04-04 09:13:15 +00:00
0x60 , 0x600000 , 0x00C0C0 , 0x000000
} ;
int distcolors [ 8 ] = {
0xFFFFFF , 0xF0 , 0xF060 , 0xF00000 ,
0xA0A000 , 0xA000A0 , 0x00A0A0 , 0xFFD500
2016-01-02 10:09:13 +00:00
} ;
const char * minetexts [ 8 ] = {
" 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! "
} ;
int countMinesAround ( cell * c ) {
int mines = 0 ;
for ( int i = 0 ; i < c - > type ; i + + )
if ( c - > mov [ i ] & & c - > mov [ i ] - > wall = = waMineMine )
mines + + ;
return mines ;
}
transmatrix applyPatterndir ( cell * c , char patt = mapeditor : : whichPattern ) {
2017-03-23 10:53:57 +00:00
transmatrix V = ddspin ( c , mapeditor : : patterndir ( c , patt ) , S42 ) ;
2016-08-26 09:58:03 +00:00
if ( mapeditor : : reflectPatternAt ( c , patt ) )
2016-01-02 10:09:13 +00:00
return V * Mirror ;
return V ;
}
2016-08-26 09:58:03 +00:00
transmatrix applyDowndir ( cell * c , cellfunction * cf ) {
2017-03-23 10:53:57 +00:00
return ddspin ( c , mapeditor : : downdir ( c , cf ) , S42 ) ;
2016-08-26 09:58:03 +00:00
}
void drawTowerFloor ( const transmatrix & V , cell * c , int col , cellfunction * cf = coastvalEdge ) {
int j = - 1 ;
if ( euclid ) j = 10 ;
else if ( ( * cf ) ( c ) > 1 ) {
int i = towerval ( c , cf ) ;
if ( i = = 4 ) j = 0 ;
if ( i = = 5 ) j = 1 ;
if ( i = = 6 ) j = 2 ;
if ( i = = 8 ) j = 3 ;
if ( i = = 9 ) j = 4 ;
if ( i = = 10 ) j = 5 ;
if ( i = = 13 ) j = 6 ;
if ( purehepta ) {
if ( i = = 7 ) j = 7 ;
if ( i = = 11 ) j = 8 ;
if ( i = = 15 ) j = 9 ;
}
}
if ( j > = 0 )
2017-03-23 10:53:57 +00:00
qfloor ( c , V , applyDowndir ( c , cf ) , shTower [ j ] , col ) ;
2016-08-26 09:58:03 +00:00
else if ( c - > wall ! = waLadder )
2017-03-23 10:53:57 +00:00
qfloor ( c , V , shMFloor [ K ( c ) ] , col ) ;
2016-08-26 09:58:03 +00:00
}
void drawZebraFloor ( const transmatrix & V , cell * c , int col ) {
2017-03-23 10:53:57 +00:00
if ( euclid ) { qfloor ( c , V , shTower [ 10 ] , col ) ; return ; }
2016-08-26 09:58:03 +00:00
int i = zebra40 ( c ) ;
i & = ~ 3 ;
int j ;
if ( purehepta ) j = 4 ;
else if ( i > = 4 & & i < 16 ) j = 2 ;
else if ( i > = 16 & & i < 28 ) j = 1 ;
else if ( i > = 28 & & i < 40 ) j = 3 ;
else j = 0 ;
2017-03-23 10:53:57 +00:00
qfloor ( c , V , applyPatterndir ( c , ' z ' ) , shZebra [ j ] , col ) ;
2016-08-26 09:58:03 +00:00
}
2017-03-23 10:53:57 +00:00
void qplainfloor ( cell * c , bool warp , const transmatrix & V , int col ) ;
void drawReptileFloor ( const transmatrix & V , cell * c , int col , bool usefloor ) {
int i = zebra40 ( c ) ;
i & = ~ 3 ;
int j ;
if ( ! wmescher ) j = 4 ;
else if ( purehepta ) j = 0 ;
else if ( i < 4 ) j = 0 ;
else if ( i > = 4 & & i < 16 ) j = 1 ;
else if ( i > = 16 & & i < 28 ) j = 2 ;
else if ( i > = 28 & & i < 40 ) j = 3 ;
else j = 4 ;
transmatrix V2 = V * applyPatterndir ( c , ' z ' ) ;
if ( wmescher ) {
if ( usefloor )
qfloor ( c , V , applyPatterndir ( c , ' z ' ) , shReptile [ j ] [ 0 ] , darkena ( col , 0 , 0xFF ) ) ;
else
queuepoly ( V2 , shReptile [ j ] [ 0 ] , darkena ( col , 0 , 0xFF ) ) ;
}
else
qplainfloor ( c , isWarped ( c ) , V , darkena ( col , 0 , 0xFF ) ) ;
if ( usefloor & & chasmg = = 2 ) return ;
int dcol = 0 ;
int ecol = - 1 ;
if ( isReptile ( c - > wall ) ) {
unsigned char wp = c - > wparam ;
if ( wp = = 1 )
ecol = 0xFFFF00 ;
else if ( wp < = 5 )
ecol = 0xFF0000 ;
else
ecol = 0 ;
if ( ecol ) ecol = gradient ( 0 , ecol , - 1 , sin ( M_PI / 100 * ticks ) , 1 ) ;
}
if ( ecol = = - 1 | | ecol = = 0 ) dcol = darkena ( col , 1 , 0xFF ) ;
else dcol = darkena ( ecol , 0 , 0x80 ) ;
dynamicval < int > p ( poly_outline ,
doHighlight ( ) & & ecol ! = - 1 & & ecol ! = 0 ? OUTLINE_ENEMY : OUTLINE_NONE ) ;
if ( ! chasmg ) {
if ( wmescher )
queuepoly ( V2 , shReptile [ j ] [ 1 ] , dcol ) ;
else
queuepoly ( V2 , shMFloor [ c - > type ! = 6 ] , dcol ) ;
}
if ( ecol ! = - 1 ) {
queuepoly ( V2 , shReptile [ j ] [ 2 ] , ( ecol < < 8 ) + 0xFF ) ;
queuepoly ( V2 , shReptile [ j ] [ 3 ] , ( ecol < < 8 ) + 0xFF ) ;
}
}
# define ECT (euclid?2:ct6)
2016-08-26 09:58:03 +00:00
void drawEmeraldFloor ( const transmatrix & V , cell * c , int col ) {
int j = - 1 ;
if ( ! euclid & & ! purehepta ) {
int i = emeraldval ( c ) & ~ 3 ;
if ( i = = 8 ) j = 0 ;
else if ( i = = 12 ) j = 1 ;
else if ( i = = 16 ) j = 2 ;
else if ( i = = 20 ) j = 3 ;
else if ( i = = 28 ) j = 4 ;
else if ( i = = 36 ) j = 5 ;
}
if ( j > = 0 )
2017-03-23 10:53:57 +00:00
qfloor ( c , V , applyPatterndir ( c , ' f ' ) , shEmeraldFloor [ j ] , col ) ;
2016-08-26 09:58:03 +00:00
else
2017-03-23 10:53:57 +00:00
qfloor ( c , V , shCaveFloor [ euclid ? 2 : K ( c ) ] , col ) ;
2016-08-26 09:58:03 +00:00
}
double fanframe ;
void viewBuggyCells ( cell * c , transmatrix V ) {
for ( int i = 0 ; i < size ( buggycells ) ; i + + )
if ( c = = buggycells [ i ] ) {
queuepoly ( V , shPirateX , 0xC000C080 ) ;
return ;
}
for ( int i = 0 ; i < size ( buggycells ) ; i + + ) {
cell * c1 = buggycells [ i ] ;
cell * cf = cwt . c ;
while ( cf ! = c1 ) {
cf = pathTowards ( cf , c1 ) ;
if ( cf = = c ) {
queuepoly ( V , shMineMark [ 1 ] , 0xC000C0D0 ) ;
return ;
}
}
}
}
2017-03-23 10:53:57 +00:00
transmatrix pushone ( ) { return euclid ? eupush ( 1 , 0 ) : xpush ( sphere ? .5 : 1 ) ; }
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
void drawMovementArrows ( cell * c , transmatrix V ) {
2016-08-26 09:58:03 +00:00
2017-04-04 09:13:15 +00:00
if ( viewdists ) return ;
2017-03-23 10:53:57 +00:00
for ( int d = 0 ; d < 8 ; d + + ) {
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
movedir md = vectodir ( spin ( - d * M_PI / 4 ) * tC0 ( pushone ( ) ) ) ;
int u = md . d ;
cellwalker xc = cwt ; cwspin ( xc , u ) ; cwstep ( xc ) ;
if ( xc . c = = c ) {
transmatrix fixrot = rgpushxto0 ( tC0 ( V ) ) ;
// make it more transparent
int col = getcs ( ) . uicolor ;
col - = ( col & 0xFF ) > > 1 ;
poly_outline = OUTLINE_NONE ;
queuepoly ( fixrot * spin ( - d * M_PI / 4 + ( sphere & & vid . alpha > 1 ? M_PI : 0 ) ) /* * eupush(1,0)*/ , shArrow , col ) ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( c - > type ! = 6 & & ( isStunnable ( c - > monst ) | | c - > wall = = waThumperOn ) ) {
transmatrix Centered = rgpushxto0 ( tC0 ( cwtV ) ) ;
int sd = md . subdir ;
if ( sphere ) sd = - sd ;
queuepoly ( inverse ( Centered ) * rgpushxto0 ( Centered * tC0 ( V ) ) * rspintox ( Centered * tC0 ( V ) ) * spin ( - sd * M_PI / S7 ) * xpush ( 0.2 ) , shArrow , col ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else break ;
2015-08-08 13:57:52 +00:00
}
}
2017-03-23 10:53:57 +00:00
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
transmatrix screenpos ( ld x , ld y ) {
transmatrix V = Id ;
V [ 0 ] [ 2 ] + = ( x - vid . xcenter ) / vid . radius * ( 1 + vid . alphax ) ;
V [ 1 ] [ 2 ] + = ( y - vid . ycenter ) / vid . radius * ( 1 + vid . alphax ) ;
// V[2][0] -= (x - vid.xcenter) / vid.radius * (1+vid.alphax);
// V[2][1] -= (y - vid.ycenter) / vid.radius * (1+vid.alphax);
return V ;
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
# define SKIPFAC .4
void drawMobileArrow ( cell * c , transmatrix V ) {
// int col = getcs().uicolor;
// col -= (col & 0xFF) >> 1;
2016-01-02 10:09:13 +00:00
2017-03-31 19:41:09 +00:00
int dir = neighborId ( cwt . c , c ) ;
bool invalid = ! legalmoves [ dir ] ;
2017-03-23 10:53:57 +00:00
int col = cellcolor ( c ) ;
if ( col = = OUTLINE_NONE ) col = 0xC0C0C0FF ;
col - = ( col & 0xFF ) > > 1 ;
2017-03-31 19:41:09 +00:00
if ( invalid ) col - = ( col & 0xFF ) > > 1 ;
if ( invalid ) col - = ( col & 0xFF ) > > 1 ;
2017-03-23 10:53:57 +00:00
poly_outline = OUTLINE_NONE ;
transmatrix m2 = Id ;
ld scale = vid . mobilecompasssize / 15. ;
m2 [ 0 ] [ 0 ] = scale ; m2 [ 1 ] [ 1 ] = scale ; m2 [ 2 ] [ 2 ] = 1 ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
transmatrix Centered = rgpushxto0 ( tC0 ( cwtV ) ) ;
transmatrix t = inverse ( Centered ) * V ;
double alpha = atan2 ( tC0 ( t ) [ 1 ] , tC0 ( t ) [ 0 ] ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
using namespace shmupballs ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
double dx = xmove + rad * ( 1 + SKIPFAC - .2 ) / 2 * cos ( alpha ) ;
double dy = yb + rad * ( 1 + SKIPFAC - .2 ) / 2 * sin ( alpha ) ;
queuepoly (
screenpos ( dx , dy ) * spin ( - alpha ) * m2 , shArrow , col ) ;
/*
if ( c - > type ! = 6 & & ( isStunnable ( c - > monst ) | | c - > wall = = waThumperOn ) ) {
transmatrix Centered = rgpushxto0 ( tC0 ( cwtV ) ) ;
int sd = md . subdir ;
if ( sphere ) sd = - sd ;
queuepoly ( inverse ( Centered ) * rgpushxto0 ( Centered * tC0 ( V ) ) * rspintox ( Centered * tC0 ( V ) ) * spin ( - sd * M_PI / S7 ) * xpush ( 0.2 ) , shArrow , col ) ;
}
else break ;
} */
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
int celldistAltPlus ( cell * c ) { return 1000000 + celldistAlt ( c ) ; }
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
bool drawstaratvec ( double dx , double dy ) {
return dx * dx + dy * dy > .05 ;
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
int reptilecolor ( cell * c ) {
int i = zebra40 ( c ) ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( ! euclid ) {
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 ;
}
int fcoltab [ 4 ] = { 0xe3bb97 , 0xc2d1b0 , 0xebe5cb , 0xA0A0A0 } ;
return fcoltab [ i ] ;
}
ld wavefun ( ld x ) {
return sin ( x ) ;
/* x /= (2*M_PI);
x - = ( int ) x ;
if ( x > .5 ) return ( x - .5 ) * 2 ;
else return 0 ; */
}
2017-05-27 19:40:40 +00:00
void setcolors ( cell * c , int & wcol , int & fcol ) {
2017-03-23 10:53:57 +00:00
wcol = fcol = winf [ c - > wall ] . color ;
// floor colors for all the lands
if ( c - > land = = laKraken ) fcol = 0x20A020 ;
if ( c - > land = = laBurial ) fcol = linf [ laBurial ] . color ;
if ( c - > land = = laTrollheim ) fcol = linf [ c - > land ] . color ;
if ( c - > land = = laBarrier ) fcol = linf [ c - > land ] . color ;
if ( c - > land = = laOceanWall ) fcol = linf [ c - > land ] . color ;
if ( c - > land = = laAlchemist ) {
fcol = 0x202020 ;
if ( c - > item & & ! ( conformal : : includeHistory & & eq ( c - > aitmp , sval ) ) )
fcol = wcol = iinf [ c - > item ] . color ;
}
if ( c - > land = = laBull )
fcol = 0x800080 ;
if ( c - > land = = laCA )
fcol = 0x404040 ;
if ( c - > land = = laReptile ) {
fcol = reptilecolor ( c ) ;
}
if ( c - > land = = laCrossroads ) fcol = ( vid . goteyes2 ? 0xFF3030 : 0xFF0000 ) ;
if ( c - > land = = laCrossroads2 ) fcol = linf [ laCrossroads2 ] . color ;
if ( c - > land = = laCrossroads3 ) fcol = linf [ laCrossroads3 ] . color ;
if ( c - > land = = laCrossroads4 ) fcol = linf [ laCrossroads4 ] . color ;
if ( c - > land = = laCrossroads5 ) fcol = linf [ laCrossroads5 ] . color ;
if ( isElemental ( c - > land ) ) fcol = linf [ c - > land ] . color ;
if ( c - > land = = laDesert ) fcol = 0xEDC9AF ;
if ( c - > land = = laCaves ) fcol = 0x202020 ;
if ( c - > land = = laEmerald ) fcol = 0x202020 ;
if ( c - > land = = laDeadCaves ) fcol = 0x202020 ;
if ( c - > land = = laJungle ) fcol = ( vid . goteyes2 ? 0x408040 : 0x008000 ) ;
if ( c - > land = = laMountain ) {
if ( euclid | | c - > master - > alt )
fcol = celldistAlt ( c ) & 1 ? 0x604020 : 0x302010 ;
else fcol = 0 ;
if ( c - > wall = = waPlatform ) wcol = 0xF0F0A0 ;
}
if ( c - > land = = laWineyard ) fcol = 0x006000 ;
if ( c - > land = = laMirror ) fcol = 0x808080 ;
if ( c - > land = = laMotion ) fcol = 0xF0F000 ;
if ( c - > land = = laGraveyard ) fcol = 0x107010 ;
if ( c - > land = = laDryForest ) fcol = gradient ( 0x008000 , 0x800000 , 0 , c - > landparam , 10 ) ;
if ( c - > land = = laRlyeh ) fcol = ( vid . goteyes2 ? 0x4080C0 : 0x004080 ) ;
if ( c - > land = = laPower ) fcol = linf [ c - > land ] . color ;
if ( c - > land = = laHell ) fcol = ( vid . goteyes2 ? 0xC03030 : 0xC00000 ) ;
if ( c - > land = = laLivefjord ) fcol = 0x306030 ;
if ( c - > land = = laWildWest ) fcol = linf [ c - > land ] . color ;
if ( c - > land = = laHalloween ) fcol = linf [ c - > land ] . color ;
if ( c - > land = = laMinefield ) fcol = 0x80A080 ;
if ( c - > land = = laCaribbean ) fcol = 0x006000 ;
if ( c - > land = = laRose ) fcol = linf [ c - > land ] . color ;
if ( c - > land = = laCanvas ) fcol = c - > landparam ;
if ( c - > land = = laRedRock ) fcol = linf [ c - > land ] . color ;
if ( c - > land = = laDragon ) fcol = linf [ c - > land ] . color ;
if ( c - > land = = laStorms ) fcol = linf [ c - > land ] . color ;
if ( c - > land = = laPalace ) {
fcol = 0x806020 ;
if ( c - > wall = = waClosedGate | | c - > wall = = waOpenGate )
fcol = wcol ;
}
if ( c - > land = = laElementalWall )
fcol = ( linf [ c - > barleft ] . color > > 1 ) + ( linf [ c - > barright ] . color > > 1 ) ;
if ( c - > land = = laZebra ) {
fcol = 0xE0E0E0 ;
if ( c - > wall = = waTrapdoor ) fcol = 0x808080 ;
}
if ( c - > land = = laCaribbean & & ( c - > wall = = waCIsland | | c - > wall = = waCIsland2 ) )
fcol = wcol = winf [ c - > wall ] . color ;
if ( isHive ( c - > land ) ) {
fcol = linf [ c - > land ] . color ;
if ( c - > wall = = waWaxWall ) wcol = c - > landparam ;
if ( items [ itOrbInvis ] & & c - > wall = = waNone & & c - > landparam )
fcol = gradient ( fcol , 0xFF0000 , 0 , c - > landparam , 100 ) ;
if ( c - > bardir = = NOBARRIERS & & c - > barleft )
fcol = minf [ moBug0 + c - > barright ] . color ;
}
if ( isWarped ( c - > land ) ) {
fcol = pseudohept ( c ) ? 0x80C080 : 0xA06020 ;
if ( c - > wall = = waSmallTree ) wcol = 0x608000 ;
}
if ( c - > land = = laTortoise ) {
fcol = tortoise : : getMatchColor ( getBits ( c ) ) ;
if ( c - > wall = = waBigTree ) wcol = 0x709000 ;
else if ( c - > wall = = waSmallTree ) wcol = 0x905000 ;
}
if ( c - > land = = laOvergrown | | c - > land = = laClearing ) {
fcol = ( c - > land = = laOvergrown /* || (celldistAlt(c)&1)*/ ) ? 0x00C020 : 0x60E080 ;
if ( c - > wall = = waSmallTree ) wcol = 0x008060 ;
else if ( c - > wall = = waBigTree ) wcol = 0x0080C0 ;
}
if ( c - > land = = laTemple ) {
int d = showoff ? 0 : ( euclid | | c - > master - > alt ) ? celldistAlt ( c ) : 99 ;
if ( chaosmode )
fcol = 0x405090 ;
else if ( d % TEMPLE_EACH = = 0 )
fcol = gradient ( 0x304080 , winf [ waColumn ] . color , 0 , 0.5 , 1 ) ;
// else if(c->type == 7)
// wcol = 0x707070;
else if ( d % 2 = = - 1 )
fcol = 0x304080 ;
else
fcol = 0x405090 ;
}
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( isHaunted ( c - > land ) ) {
int itcolor = 0 ;
for ( int i = 0 ; i < c - > type ; i + + ) if ( c - > mov [ i ] & & c - > mov [ i ] - > item )
itcolor = 1 ;
if ( c - > item ) itcolor | = 2 ;
fcol = 0x609F60 + 0x202020 * itcolor ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
forCellEx ( c2 , c ) if ( c2 - > monst = = moFriendlyGhost )
fcol = gradient ( fcol , fghostcolor ( ticks , c2 ) , 0 , .25 , 1 ) ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( c - > monst = = moFriendlyGhost )
fcol = gradient ( fcol , fghostcolor ( ticks , c ) , 0 , .5 , 1 ) ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( c - > wall = = waSmallTree ) wcol = 0x004000 ;
else if ( c - > wall = = waBigTree ) wcol = 0x008000 ;
}
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( c - > land = = laCamelot ) {
int d = showoff ? 0 : ( ( euclid | | c - > master - > alt ) ? celldistAltRelative ( c ) : 0 ) ;
2017-04-08 15:18:29 +00:00
# ifdef TOUR
if ( ! tour : : on ) camelotcheat = false ;
if ( camelotcheat )
fcol = ( d & 1 ) ? 0xC0C0C0 : 0x606060 ;
else
# endif
if ( d < 0 ) {
2017-03-23 10:53:57 +00:00
fcol = 0xA0A0A0 ;
2017-04-08 15:18:29 +00:00
}
2017-03-23 10:53:57 +00:00
else {
// a nice floor pattern
int v = emeraldval ( c ) ;
int v0 = ( v & ~ 3 ) ;
bool sw = ( v & 1 ) ;
if ( v0 = = 8 | | v0 = = 12 | | v0 = = 20 | | v0 = = 40 | | v0 = = 36 | | v0 = = 24 )
sw = ! sw ;
if ( sw )
fcol = 0xC0C0C0 ;
else
fcol = 0xA0A0A0 ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
}
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( c - > land = = laPrairie ) {
/* if(isWateryOrBoat(c)) {
if ( prairie : : isriver ( c ) )
fcol = ( ( c - > LHU . fi . rval & 1 ) ? 0x000090 : 0x0000E0 )
+ int ( 16 * wavefun ( ticks / 200. + ( c - > wparam ) * 1.5 ) )
+ ( ( prairie : : next ( c ) ? 0 : 0xC00000 ) ) ;
else
fcol = 0x000080 ;
} */
if ( prairie : : isriver ( c ) ) {
fcol = ( ( c - > LHU . fi . rval & 1 ) ? 0x402000 : 0x503000 ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else {
fcol = 0x004000 + 0x001000 * c - > LHU . fi . walldist ;
fcol + = 0x10000 * ( 255 - 511 / ( 1 + max ( ( int ) c - > LHU . fi . flowerdist , 1 ) ) ) ;
// fcol += 0x1 * (511 / (1 + max((int) c->LHU.fi.walldist2, 1)));
}
}
else if ( isIcyLand ( c ) & & isIcyWall ( c ) ) {
float h = HEAT ( c ) ;
bool showcoc = c - > land = = laCocytus & & chaosmode & & ! wmescher ;
if ( h < - 0.4 )
wcol = gradient ( showcoc ? 0x4080FF : 0x4040FF , 0x0000FF , - 0.4 , h , - 1 ) ;
else if ( h < 0 )
wcol = gradient ( showcoc ? 0x80C0FF : 0x8080FF , showcoc ? 0x4080FF : 0x4040FF , 0 , h , - 0.4 ) ;
else if ( h < 0.2 )
wcol = gradient ( showcoc ? 0x80C0FF : 0x8080FF , 0xFFFFFF , 0 , h , 0.2 ) ;
// else if(h < 0.4)
// wcol = gradient(0xFFFFFF, 0xFFFF00, 0.2, h, 0.4);
else if ( h < 0.6 )
wcol = gradient ( 0xFFFFFF , 0xFF0000 , 0.2 , h , 0.6 ) ;
else if ( h < 0.8 )
wcol = gradient ( 0xFF0000 , 0xFFFF00 , 0.6 , h , 0.8 ) ;
else
wcol = 0xFFFF00 ;
if ( c - > wall = = waFrozenLake )
fcol = wcol ;
else
fcol = ( wcol & 0xFEFEFE ) > > 1 ;
if ( c - > wall = = waLake )
fcol = wcol = ( wcol & 0xFCFCFC ) > > 2 ;
}
else if ( isWateryOrBoat ( c ) | | c - > wall = = waReptileBridge ) {
if ( c - > land = = laOcean )
fcol = ( c - > landparam > 25 & & ! chaosmode ) ? 0x000090 :
0x1010C0 + int ( 32 * sin ( ticks / 500. + ( chaosmode ? c - > CHAOSPARAM : c - > landparam ) * 1.5 ) ) ;
else if ( c - > land = = laOceanWall )
fcol = 0x2020FF ;
else if ( c - > land = = laKraken ) {
fcol = 0x0000A0 ;
int mafcol = ( pseudohept ( c ) ? 64 : 8 ) ;
/* bool nearshore = false;
for ( int i = 0 ; i < c - > type ; i + + )
if ( c - > mov [ i ] - > wall ! = waSea & & c - > mov [ i ] - > wall ! = waBoat )
nearshore = true ;
if ( nearshore ) mafcol + = 30 ; */
fcol = fcol + mafcol * ( 4 + sin ( ticks / 500. + ( ( euclid | | c - > master - > alt ) ? celldistAlt ( c ) : 0 ) * 1.5 ) ) / 5 ;
}
else if ( c - > land = = laAlchemist )
fcol = 0x900090 ;
else if ( c - > land = = laWhirlpool )
fcol = 0x0000C0 + int ( 32 * sin ( ticks / 200. + ( ( euclid | | c - > master - > alt ) ? celldistAlt ( c ) : 0 ) * 1.5 ) ) ;
else if ( c - > land = = laLivefjord )
fcol = 0x000080 ;
else if ( isWarped ( c - > land ) )
fcol = 0x0000C0 + int ( ( pseudohept ( c ) ? 30 : - 30 ) * sin ( ticks / 600. ) ) ;
else
fcol = wcol ;
}
else if ( c - > land = = laOcean ) {
if ( chaosmode )
fcol = gradient ( 0xD0A090 , 0xD0D020 , 0 , c - > CHAOSPARAM , 30 ) ;
else
fcol = gradient ( 0xD0D090 , 0xD0D020 , - 1 , sin ( ( double ) c - > landparam ) , 1 ) ;
}
if ( c - > land = = laEmerald ) {
if ( c - > wall = = waCavefloor | | c - > wall = = waCavewall ) {
fcol = wcol = gradient ( winf [ waCavefloor ] . color , 0xFF00 , 0 , 0.5 , 1 ) ;
if ( c - > wall = = waCavewall ) wcol = 0xC0FFC0 ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
}
if ( c - > land = = laWhirlwind ) {
int wcol [ 4 ] = { 0x404040 , 0x404080 , 0x2050A0 , 0x5050C0 } ;
fcol = wcol [ whirlwind : : fzebra3 ( c ) ] ;
}
if ( c - > land = = laIvoryTower )
fcol = 0x10101 * ( 32 + ( c - > landparam & 1 ) * 32 ) - 0x000010 ;
if ( c - > land = = laDungeon ) {
int lp = c - > landparam % 5 ;
// xcol = (c->landparam&1) ? 0xD00000 : 0x00D000;
int lps [ 5 ] = { 0x402000 , 0x302000 , 0x202000 , 0x282000 , 0x382000 } ;
fcol = lps [ lp ] ;
if ( c - > wall = = waClosedGate )
fcol = wcol = 0xC0C0C0 ;
if ( c - > wall = = waOpenGate )
fcol = wcol = 0x404040 ;
if ( c - > wall = = waPlatform )
fcol = wcol = 0xDFB520 ;
}
if ( c - > land = = laEndorian ) {
int clev = cwt . c - > land = = laEndorian ? edgeDepth ( cwt . c ) : 0 ;
// xcol = (c->landparam&1) ? 0xD00000 : 0x00D000;
fcol = 0x10101 * ( 32 + ( c - > landparam & 1 ) * 32 ) - 0x000010 ;
fcol = gradient ( fcol , 0x0000D0 , clev - 10 , edgeDepth ( c ) , clev + 10 ) ;
if ( c - > wall = = waTrunk ) fcol = winf [ waTrunk ] . color ;
if ( c - > wall = = waCanopy | | c - > wall = = waSolidBranch | | c - > wall = = waWeakBranch ) {
fcol = winf [ waCanopy ] . color ;
if ( c - > landparam & 1 ) fcol = gradient ( 0 , fcol , 0 , .75 , 1 ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
}
// floors become fcol
if ( c - > wall = = waSulphur | | c - > wall = = waSulphurC | | isAlch ( c ) | | c - > wall = = waPlatform )
fcol = wcol ;
if ( c - > wall = = waDeadTroll2 | | c - > wall = = waPetrified ) {
eMonster m = eMonster ( c - > wparam ) ;
if ( c - > wall = = waPetrified )
wcol = gradient ( wcol , minf [ m ] . color , 0 , .2 , 1 ) ;
if ( c - > wall = = waPetrified | | isTroll ( m ) ) if ( ! ( m = = moForestTroll & & c - > land = = laOvergrown ) )
wcol = gradient ( wcol , minf [ m ] . color , 0 , .4 , 1 ) ;
}
if ( c - > land = = laNone & & c - > wall = = waNone )
wcol = fcol = 0x101010 ;
if ( isFire ( c ) )
fcol = wcol = c - > wall = = waEternalFire ? weakfirecolor ( 1500 ) : firecolor ( 100 ) ;
if ( c - > wall = = waBoat & & wmascii ) {
wcol = 0xC06000 ;
}
if ( mightBeMine ( c ) | | c - > wall = = waMineOpen ) {
fcol = wcol ;
if ( wmblack | | wmascii ) fcol > > = 1 , wcol > > = 1 ;
}
if ( c - > wall = = waAncientGrave | | c - > wall = = waFreshGrave | | c - > wall = = waThumperOn | | c - > wall = = waThumperOff | | c - > wall = = waBonfireOff )
fcol = wcol ;
if ( c - > land = = laMinefield & & c - > wall = = waMineMine & & ( cmode = = emMapEditor | | ! canmove ) )
fcol = wcol = 0xFF4040 ;
if ( mightBeMine ( c ) & & mineMarkedSafe ( c ) )
fcol = wcol = gradient ( wcol , 0x40FF40 , 0 , 0.2 , 1 ) ;
if ( mightBeMine ( c ) & & mineMarked ( c ) )
fcol = wcol = gradient ( wcol , 0xFF4040 , - 1 , sin ( ticks / 100.0 ) , 1 ) ;
int rd = rosedist ( c ) ;
if ( rd = = 1 )
wcol = gradient ( 0x804060 , wcol , 0 , 1 , 3 ) ,
fcol = gradient ( 0x804060 , fcol , 0 , 1 , 3 ) ;
if ( rd = = 2 )
wcol = gradient ( 0x804060 , wcol , 0 , 2 , 3 ) ,
fcol = gradient ( 0x804060 , fcol , 0 , 2 , 3 ) ;
if ( items [ itRevolver ] & & c - > pathdist > GUNRANGE & & ! shmup : : on )
fcol = gradient ( fcol , 0 , 0 , 25 , 100 ) ,
wcol = gradient ( wcol , 0 , 0 , 25 , 100 ) ;
if ( c - > wall = = waDeadfloor | | c - > wall = = waCavefloor ) fcol = wcol ;
if ( c - > wall = = waDeadwall ) fcol = winf [ waDeadfloor ] . color ;
if ( c - > wall = = waCavewall & & c - > land ! = laEmerald ) fcol = winf [ waCavefloor ] . color ;
if ( highwall ( c ) & & ! wmspatial )
fcol = wcol ;
if ( wmascii & & ( c - > wall = = waNone | | isWatery ( c ) ) ) wcol = fcol ;
if ( c - > wall = = waNone & & c - > land = = laHive ) wcol = fcol ;
if ( ! wmspatial & & snakelevel ( c ) & & ! realred ( c - > wall ) ) fcol = wcol ;
if ( c - > wall = = waGlass & & ! wmspatial ) fcol = wcol ;
if ( c - > wall = = waRoundTable ) fcol = wcol ;
}
bool noAdjacentChasms ( cell * c ) {
forCellEx ( c2 , c ) if ( c2 - > wall = = waChasm ) return false ;
return true ;
}
// -1 if away, 0 if not away
int away ( const transmatrix & V2 ) {
return intval ( C0 , V2 * xpush0 ( 1 ) ) > intval ( C0 , tC0 ( V2 ) ) ;
}
void floorShadow ( cell * c , const transmatrix & V , int col , bool warp ) {
if ( pmodel = = mdHyperboloid | | pmodel = = mdBall )
return ; // shadows break the depth testing
if ( shmup : : on | | purehepta ) warp = false ;
dynamicval < int > p ( poly_outline , OUTLINE_TRANS ) ;
if ( wmescher & & qfi . special ) {
queuepolyat ( V * qfi . spin * shadowmulmatrix , * qfi . shape , col , PPR_WALLSHADOW ) ;
}
else if ( warp ) {
if ( euclid ) {
if ( ishex1 ( c ) )
queuepolyat ( V * pispin * applyPatterndir ( c ) , shTriheptaEucShadow [ 0 ] , col , PPR_WALLSHADOW ) ;
else
queuepolyat ( V * applyPatterndir ( c ) , shTriheptaEucShadow [ ishept ( c ) ? 1 : 0 ] , col , PPR_WALLSHADOW ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else
queuepolyat ( V * applyPatterndir ( c ) , shTriheptaFloorShadow [ ishept ( c ) ? 1 : 0 ] , col , PPR_WALLSHADOW ) ;
}
else {
queuepolyat ( V , shFloorShadow [ c - > type = = 6 ? 0 : 1 ] , col , PPR_WALLSHADOW ) ;
}
}
void plainfloor ( cell * c , bool warp , const transmatrix & V , int col , int prio ) {
if ( warp ) {
if ( euclid ) {
if ( ishex1 ( c ) )
queuepolyat ( V * pispin * applyPatterndir ( c ) , shTriheptaEuc [ 0 ] , col , prio ) ;
2015-08-08 13:57:52 +00:00
else
2017-03-23 10:53:57 +00:00
queuepolyat ( V * applyPatterndir ( c ) , shTriheptaEuc [ ishept ( c ) ? 1 : 0 ] , col , prio ) ;
}
else
queuepolyat ( V * applyPatterndir ( c ) , shTriheptaFloor [ sphere ? 6 - c - > type : mapeditor : : nopattern ( c ) ] , col , prio ) ;
}
else {
queuepolyat ( V , shFloor [ c - > type = = 6 ? 0 : 1 ] , col , prio ) ;
}
}
void qplainfloor ( cell * c , bool warp , const transmatrix & V , int col ) {
if ( warp ) {
if ( euclid ) {
if ( ishex1 ( c ) )
qfloor ( c , V , pispin * applyPatterndir ( c ) , shTriheptaEuc [ 0 ] , col ) ;
2015-08-08 13:57:52 +00:00
else
2017-03-23 10:53:57 +00:00
qfloor ( c , V , applyPatterndir ( c ) , shTriheptaEuc [ ishept ( c ) ? 1 : 0 ] , col ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else
qfloor ( c , V , applyPatterndir ( c ) , shTriheptaFloor [ sphere ? 6 - c - > type : mapeditor : : nopattern ( c ) ] , col ) ;
}
else {
qfloor ( c , V , shFloor [ c - > type = = 6 ? 0 : 1 ] , col ) ;
}
}
void warpfloor ( cell * c , const transmatrix & V , int col , int prio , bool warp ) {
if ( shmup : : on | | purehepta ) warp = false ;
if ( wmescher & & qfi . special )
queuepolyat ( V * qfi . spin , * qfi . shape , col , prio ) ;
else plainfloor ( c , warp , V , col , prio ) ;
}
# define placeSidewallX(a,b,c,d,e,f,g) \
{ if ( ( wmescher & & qfi . special ) | | ! validsidepar [ c ] ) { \
escherSidewall ( a , c , d , g ) ; break ; } \
else placeSidewall ( a , b , c , d , e , f , g ) ; }
# define placeSidewallXB(a,b,c,d,e,f,g, Break) \
{ if ( ( wmescher & & qfi . shape ) | | ! validsidepar [ c ] ) { \
escherSidewall ( a , c , d , g ) ; Break ; break ; } \
else placeSidewall ( a , b , c , d , e , f , g ) ; }
/* double zgrad(double f1, double f2, int nom, int den) {
using namespace geom3 ;
ld fo1 = factor_to_lev ( f1 ) ;
ld fo2 = factor_to_lev ( f2 ) ;
return lev_to_factor ( fo1 + ( fo2 - fo1 ) * nom / den ) ;
} */
double zgrad0 ( double l1 , double l2 , int nom , int den ) {
using namespace geom3 ;
return lev_to_factor ( l1 + ( l2 - l1 ) * nom / den ) ;
}
void escherSidewall ( cell * c , int sidepar , const transmatrix & V , int col ) {
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 ) )
warpfloor ( c , mscale ( V , zgrad0 ( geom3 : : slev * sl , geom3 : : slev * ( sl + 1 ) , z , 4 ) ) , col , PPR_REDWALL - 4 + z + 4 * sl , false ) ;
}
else if ( sidepar = = SIDE_WALL ) {
const int layers = 2 < < detaillevel ;
for ( int z = 1 ; z < layers ; z + + )
warpfloor ( c , mscale ( V , zgrad0 ( 0 , geom3 : : wall_height , z , layers ) ) , col , PPR_WALL3 + z - layers , false ) ;
}
else if ( sidepar = = SIDE_LAKE ) {
const int layers = 1 < < ( detaillevel - 1 ) ;
if ( detaillevel ) for ( int z = 0 ; z < layers ; z + + )
warpfloor ( c , mscale ( V , zgrad0 ( - geom3 : : lake_top , 0 , z , layers ) ) , col , PPR_FLOOR + z - layers , false ) ;
}
else if ( sidepar = = SIDE_LTOB ) {
const int layers = 1 < < ( detaillevel - 1 ) ;
if ( detaillevel ) for ( int z = 0 ; z < layers ; z + + )
warpfloor ( c , mscale ( V , zgrad0 ( - geom3 : : lake_bottom , - geom3 : : lake_top , z , layers ) ) , col , PPR_INLAKEWALL + z - layers , false ) ;
}
else if ( sidepar = = SIDE_BTOI ) {
const int layers = 1 < < detaillevel ;
warpfloor ( c , mscale ( V , geom3 : : INFDEEP ) , col , PPR_MINUSINF , false ) ;
for ( int z = 1 ; z < layers ; z + + )
warpfloor ( c , mscale ( V , zgrad0 ( - geom3 : : lake_bottom , - geom3 : : lake_top , - z , 1 ) ) , col , PPR_LAKEBOTTOM + z - layers , false ) ;
}
}
void placeSidewall ( cell * c , int i , int sidepar , const transmatrix & V , bool warp , bool mirr , int col ) {
if ( shmup : : on | | purehepta ) warp = false ;
if ( warp & & ! ishept ( c ) & & ( ! c - > mov [ i ] | | ! ishept ( c - > mov [ i ] ) ) ) return ;
int prio ;
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 ;
else prio = PPR_REDWALL - 2 + 4 * ( sidepar - SIDE_SLEV ) ;
transmatrix V2 = V * ddspin ( c , i ) ;
int aw = away ( V2 ) ; prio + = aw ;
if ( ! detaillevel & & aw < 0 ) return ;
// prio += c->cpdist - c->mov[i]->cpdist;
queuepolyat ( V2 ,
( mirr ? shMFloorSide : warp ? shTriheptaSide : shFloorSide ) [ sidepar ] [ c - > type = = 6 ? 0 : 1 ] , col , prio ) ;
}
bool openorsafe ( cell * c ) {
return c - > wall = = waMineOpen | | mineMarkedSafe ( c ) ;
}
# define Dark(x) darkena(x,0,0xFF)
int gridcolor ( cell * c1 , cell * c2 ) {
if ( cmode = = emDraw ) return Dark ( 0xFFFFFF ) ;
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 ) ;
}
if ( chasmgraph ( c1 ) ! = chasmgraph ( c2 ) )
return Dark ( 0x808080 ) ;
if ( c1 - > land = = laAlchemist & & c2 - > land = = laAlchemist & & c1 - > wall ! = c2 - > wall )
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 ) ;
return Dark ( 0x202020 ) ;
}
void pushdown ( cell * c , int & q , const transmatrix & V , double down , bool rezoom , bool repriority ) {
// since we might be changing priorities, we have to make sure that we are sorting correctly
if ( down > 0 & & repriority ) {
int qq = q + 1 ;
while ( qq < size ( ptds ) )
if ( qq > q & & ptds [ qq ] . prio < ptds [ qq - 1 ] . prio ) {
swap ( ptds [ qq ] , ptds [ qq - 1 ] ) ;
qq - - ;
}
else qq + + ;
}
while ( q < size ( ptds ) ) {
polytodraw & ptd = ptds [ q + + ] ;
if ( ptd . kind = = pkPoly ) {
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
double z2 ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
double z = zlevel ( tC0 ( ptd . u . poly . V ) ) ;
double lev = geom3 : : factor_to_lev ( z ) ;
double nlev = lev - down ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
double xyscale = rezoom ? geom3 : : scale_at_lev ( lev ) / geom3 : : scale_at_lev ( nlev ) : 1 ;
z2 = geom3 : : lev_to_factor ( nlev ) ;
double zscale = z2 / z ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
// xyscale = xyscale + (zscale-xyscale) * (1+sin(ticks / 1000.0)) / 2;
ptd . u . poly . V = xyzscale ( V , xyscale * zscale , zscale )
* inverse ( V ) * ptd . u . poly . V ;
if ( ! repriority ) ;
else if ( nlev < - geom3 : : lake_bottom - 1e-3 ) {
ptd . prio = PPR_BELOWBOTTOM ;
if ( c - > wall ! = waChasm )
ptd . col = 0 ; // disappear!
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else if ( nlev < - geom3 : : lake_top - 1e-3 )
ptd . prio = PPR_INLAKEWALL ;
else if ( nlev < 0 )
ptd . prio = PPR_LAKEWALL ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
}
}
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
bool dodrawcell ( cell * c ) {
// todo: fix when scrolling
if ( ! buggyGeneration & & c - > land ! = laCanvas & & sightrange < 10 ) {
// not yet created
if ( c - > mpdist > 7 & & ! cheater ) return false ;
// in the Yendor Challenge, scrolling back is forbidden
if ( c - > cpdist > 7 & & ( yendor : : on & & ! cheater ) ) return false ;
// (incorrect comment) too far, no bugs nearby
if ( playermoved & & sightrange < = 7 & & c - > cpdist > sightrange ) return false ;
}
return true ;
}
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
// 1 : (floor, water); 2 : (water, bottom); 4 : (bottom, inf)
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
int shallow ( cell * c ) {
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 | |
c - > wall = = waFrozenLake )
return 5 ;
return 7 ;
}
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
bool viewdists = false ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
bool allemptynear ( cell * c ) {
if ( c - > wall ) return false ;
forCellEx ( c2 , c ) if ( c2 - > wall ) return false ;
return true ;
}
2016-08-26 09:58:03 +00:00
2017-05-27 19:40:40 +00:00
bool behindsphere ( const transmatrix & V ) {
if ( ! sphere ) return false ;
if ( vid . alpha > 1 ) {
if ( V [ 2 ] [ 2 ] > - 1 / vid . alpha ) return true ;
}
if ( vid . alpha < = 1 ) {
if ( V [ 2 ] [ 2 ] < - .8 ) return true ;
}
return false ;
}
2017-03-23 10:53:57 +00:00
void drawcell ( cell * c , transmatrix V , int spinv , bool mirrored ) {
qfi . shape = NULL ; qfi . special = false ;
ivoryz = isGravityLand ( c - > land ) ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
transmatrix & gm = gmatrix [ c ] ;
2017-04-04 09:13:15 +00:00
bool orig = ( gm [ 2 ] [ 2 ] = = 0 | | fabs ( gm [ 2 ] [ 2 ] - 1 ) > = fabs ( V [ 2 ] [ 2 ] - 1 ) - 1e-8 ) ;
2017-03-23 10:53:57 +00:00
if ( orig ) gm = V ;
2016-01-02 10:09:13 +00:00
2017-05-27 19:40:40 +00:00
if ( behindsphere ( V ) ) return ;
2017-03-23 10:53:57 +00:00
ld dist0 = hdist0 ( tC0 ( V ) ) - 1e-6 ;
if ( dist0 < geom3 : : highdetail ) detaillevel = 2 ;
else if ( dist0 < geom3 : : middetail ) detaillevel = 1 ;
else detaillevel = 0 ;
# ifdef BUILDZEBRA
if ( c - > type = = 6 & & c - > tmp > 0 ) {
int i = c - > tmp ;
zebra ( cellwalker ( c , i & 15 ) , 1 , i > > 4 , " " , 0 ) ;
}
c - > item = eItem ( c - > heat / 4 ) ;
buildAutomatonRule ( c ) ;
# endif
viewBuggyCells ( c , V ) ;
if ( conformal : : on | | inHighQual ) checkTide ( c ) ;
// save the player's view center
if ( isPlayerOn ( c ) & & ! shmup : : on ) {
playerfound = true ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
/* if(euclid)
return d * S84 / c - > type ;
else
return S42 - d * S84 / c - > type ;
cwtV = V * spin ( - cwt . spin * 2 * M_PI / c - > type ) * pispin ; */
if ( multi : : players > 1 ) {
for ( int i = 0 ; i < numplayers ( ) ; i + + )
if ( playerpos ( i ) = = c ) {
playerV = V * ddspin ( c , multi : : player [ i ] . spin ) ;
if ( multi : : player [ i ] . mirrored ) playerV = playerV * Mirror ;
if ( multi : : player [ i ] . mirrored = = mirrored )
multi : : whereis [ i ] = playerV ;
}
}
else {
playerV = V * ddspin ( c , cwt . spin ) ;
// playerV = V * spin(displaydir(c, cwt.spin) * M_PI/S42);
if ( cwt . mirrored ) playerV = playerV * Mirror ;
if ( orig ) cwtV = playerV ;
2016-08-26 09:58:03 +00:00
}
2017-03-23 10:53:57 +00:00
}
/* if(cwt.c->land == laEdge) {
if ( c = = chosenDown ( cwt . c , 1 , 0 ) )
playerfoundL = c , cwtVL = V ;
if ( c = = chosenDown ( cwt . c , - 1 , 0 ) )
playerfoundR = c , cwtVR = V ;
} */
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( 1 ) {
hyperpoint VC0 = tC0 ( V ) ;
if ( intval ( mouseh , VC0 ) < modist ) {
modist2 = modist ; mouseover2 = mouseover ;
modist = intval ( mouseh , VC0 ) ;
mouseover = c ;
2016-08-26 09:58:03 +00:00
}
2017-03-23 10:53:57 +00:00
else if ( intval ( mouseh , VC0 ) < modist2 ) {
modist2 = intval ( mouseh , VC0 ) ;
mouseover2 = c ;
}
double dfc = euclid ? intval ( VC0 , C0 ) : VC0 [ 2 ] ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( dfc < centdist ) {
centdist = dfc ;
centerover = c ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
int orbrange = ( items [ itRevolver ] ? 3 : 2 ) ;
if ( c - > cpdist < = orbrange ) if ( multi : : players > 1 | | multi : : alwaysuse )
for ( int i = 0 ; i < multi : : players ; i + + ) if ( multi : : playerActive ( i ) ) {
double dfc = intval ( VC0 , tC0 ( multi : : crosscenter [ i ] ) ) ;
if ( dfc < multi : : ccdist [ i ] & & celldistance ( playerpos ( i ) , c ) < = orbrange ) {
multi : : ccdist [ i ] = dfc ;
multi : : ccat [ i ] = c ;
}
2016-01-02 10:09:13 +00:00
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
// int col = 0xFFFFFF - 0x20 * c->maxdist - 0x2000 * c->cpdist;
if ( ! buggyGeneration & & c - > mpdist > 8 & & ! cheater ) return ; // not yet generated
if ( c - > land = = laNone & & cmode = = emMapEditor ) {
queuepoly ( V , shTriangle , 0xFF0000FF ) ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
char ch = winf [ c - > wall ] . glyph ;
int wcol , fcol , asciicol ;
setcolors ( c , wcol , fcol ) ;
2017-05-27 19:40:40 +00:00
// addaura(tC0(V), wcol);
int zcol = fcol ;
2017-04-04 09:13:15 +00:00
if ( viewdists ) {
int cd = celldistance ( c , cwt . c ) ;
string label = its ( cd ) ;
// string label = its(fieldpattern::getriverdistleft(c)) + its(fieldpattern::getriverdistright(c));
int dc = distcolors [ cd & 7 ] ;
wcol = gradient ( wcol , dc , 0 , .4 , 1 ) ;
fcol = gradient ( fcol , dc , 0 , .4 , 1 ) ;
/* queuepolyat(V, shFloor[ct6], darkena(gradient(0, distcolors[cd&7], 0, .25, 1), fd, 0xC0),
PPR_TEXT ) ; */
queuestr ( V , ( cd > 9 ? .6 : 1 ) * .2 , label , 0xFF000000 + distcolors [ cd & 7 ] , 1 ) ;
}
2017-03-23 10:53:57 +00:00
asciicol = wcol ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( c - > land = = laNone & & c - > wall = = waNone )
queuepoly ( V , shTriangle , 0xFFFF0000 ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( c - > wall = = waThumperOn ) {
int ds = ticks ;
for ( int u = 0 ; u < 5 ; u + + ) {
ld rad = hexf * ( .3 * u + ( ds % 1000 ) * .0003 ) ;
int tcol = darkena ( gradient ( 0xFFFFFF , 0 , 0 , rad , 1.5 * hexf ) , 0 , 0xFF ) ;
for ( int a = 0 ; a < S84 ; a + + )
queueline ( V * ddi0 ( a , rad ) , V * ddi0 ( a + 1 , rad ) , tcol , 0 ) ;
}
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
// bool dothept = false;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
/* if(pseudohept(c) && vid.darkhepta) {
col = gradient ( 0 , col , 0 , 0.75 , 1 ) ;
} */
2016-01-02 10:09:13 +00:00
eItem it = c - > item ;
bool hidden = itemHidden ( c ) ;
bool hiddens = itemHiddenFromSight ( c ) ;
2016-08-26 09:58:03 +00:00
if ( conformal : : includeHistory & & eq ( c - > aitmp , sval ) ) {
hidden = true ;
hiddens = false ;
}
2016-01-02 10:09:13 +00:00
if ( hiddens & & cmode ! = emMapEditor )
it = itNone ;
2017-03-23 10:53:57 +00:00
int icol = 0 , moncol = 0xFF00FF ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( it )
ch = iinf [ it ] . glyph , asciicol = icol = iinf [ it ] . color ;
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
if ( c - > monst ) {
2017-03-23 10:53:57 +00:00
ch = minf [ c - > monst ] . glyph , moncol = minf [ c - > monst ] . color ;
2016-08-26 09:58:03 +00:00
if ( c - > monst = = moMutant ) {
// root coloring
if ( c - > stuntime ! = mutantphase )
2017-03-23 10:53:57 +00:00
moncol =
gradient ( 0xC00030 , 0x008000 , 0 , ( c - > stuntime - mutantphase ) & 15 , 15 ) ;
2016-08-26 09:58:03 +00:00
}
if ( isMetalBeast ( c - > monst ) & & c - > stuntime )
2017-03-23 10:53:57 +00:00
moncol > > = 1 ;
if ( c - > monst = = moSlime ) {
moncol = winf [ c - > wall ] . color ;
moncol | = ( moncol > > 1 ) ;
}
asciicol = moncol ;
if ( isDragon ( c - > monst ) | | isKraken ( c - > monst ) ) if ( ! c - > hitpoints )
asciicol = 0x505050 ;
if ( c - > monst = = moTortoise )
asciicol = tortoise : : getMatchColor ( tortoise : : getb ( c ) ) ;
if ( c - > monst ! = moMutant ) for ( int k = 0 ; k < c - > stuntime ; k + + )
asciicol = ( ( asciicol & 0xFEFEFE ) > > 1 ) + 0x101010 ;
2016-08-26 09:58:03 +00:00
}
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
if ( c - > cpdist = = 0 & & mapeditor : : drawplayer ) {
ch = ' @ ' ;
2017-03-23 10:53:57 +00:00
if ( ! mmitem ) asciicol = moncol = cheater ? 0xFF3030 : 0xD0D0D0 ;
2015-08-08 13:57:52 +00:00
}
if ( c - > ligon ) {
int tim = ticks - lightat ;
if ( tim > 1000 ) tim = 800 ;
2016-08-26 09:58:03 +00:00
if ( elec : : havecharge & & tim > 400 ) tim = 400 ;
2017-03-23 10:53:57 +00:00
for ( int t = 0 ; t < c - > type ; t + + ) if ( c - > mov [ t ] & & c - > mov [ t ] - > ligon ) {
2015-08-08 13:57:52 +00:00
int hdir = displaydir ( c , t ) ;
2017-03-23 10:53:57 +00:00
int lcol = darkena ( gradient ( iinf [ itOrbLightning ] . color , 0 , 0 , tim , 1100 ) , 0 , 0xFF ) ;
queueline ( V * ddi0 ( ticks , hexf / 2 ) , V * ddi0 ( hdir , crossf ) , lcol , 2 ) ;
2015-08-08 13:57:52 +00:00
}
}
int ct = c - > type ;
2017-03-23 10:53:57 +00:00
int ct6 = K ( c ) ;
2015-08-08 13:57:52 +00:00
bool error = false ;
2017-03-23 10:53:57 +00:00
chasmg = chasmgraph ( c ) ;
int fd =
c - > land = = laRedRock ? 0 :
( c - > land = = laOcean | | c - > land = = laLivefjord | | c - > land = = laWhirlpool ) ? 1 :
c - > land = = laAlchemist | | c - > land = = laIce | | c - > land = = laGraveyard | |
c - > land = = laRlyeh | | c - > land = = laTemple | | c - > land = = laWineyard | |
c - > land = = laDeadCaves | | c - > land = = laPalace | | c - > land = = laCA ? 1 :
c - > land = = laCanvas ? 0 :
c - > land = = laKraken ? 1 :
c - > land = = laBurial ? 1 :
c - > land = = laIvoryTower ? 1 :
c - > land = = laDungeon ? 1 :
c - > land = = laMountain ? 1 :
c - > land = = laEndorian ? 1 :
c - > land = = laCaribbean ? 1 :
c - > land = = laWhirlwind ? 1 :
c - > land = = laRose ? 1 :
c - > land = = laWarpSea ? 1 :
c - > land = = laTortoise ? 1 :
c - > land = = laDragon ? 1 :
c - > land = = laHalloween ? 1 :
c - > land = = laTrollheim ? 2 :
c - > land = = laReptile ? 0 :
2 ;
poly_outline = OUTLINE_NONE ;
int sl = snakelevel ( c ) ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
transmatrix Vd0 , Vf0 , Vboat0 ;
const transmatrix * Vdp =
( ! wmspatial ) ? & V :
sl ? & ( Vd0 = mscale ( V , geom3 : : SLEV [ sl ] ) ) :
highwall ( c ) ? & ( Vd0 = mscale ( V , ( 1 + geom3 : : WALL ) / 2 ) ) :
( chasmg = = 1 ) ? & ( Vd0 = mscale ( V , geom3 : : LAKE ) ) :
& V ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
const transmatrix & Vf = ( chasmg & & wmspatial ) ? ( Vf0 = mscale ( V , geom3 : : BOTTOM ) ) : V ;
const transmatrix * Vboat = & ( * Vdp ) ;
if ( DOSHMUP ) {
ld zlev = - geom3 : : factor_to_lev ( zlevel ( tC0 ( ( * Vdp ) ) ) ) ;
shmup : : drawMonster ( V , c , Vboat , Vboat0 , zlev ) ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
poly_outline = ( backcolor < < 8 ) + 0xFF ;
if ( ! wmascii ) {
2015-08-08 13:57:52 +00:00
// floor
2017-03-23 10:53:57 +00:00
# ifndef NOEDIT
2016-01-02 10:09:13 +00:00
transmatrix Vpdir = V * applyPatterndir ( c ) ;
2016-08-26 09:58:03 +00:00
# endif
bool eoh = euclid | | purehepta ;
2017-03-23 10:53:57 +00:00
# ifndef NOEDIT
2016-01-02 10:09:13 +00:00
if ( c = = mapeditor : : drawcell & & c ! = cwt . c & & ! c - > monst & & ! c - > item ) {
mapeditor : : drawtrans = Vpdir ;
2015-08-08 13:57:52 +00:00
}
2016-01-02 10:09:13 +00:00
# endif
2017-03-23 10:53:57 +00:00
if ( c - > wall = = waChasm ) {
if ( c - > land = = laZebra ) fd + + ;
if ( c - > land = = laHalloween & & ! wmblack ) {
transmatrix Vdepth = mscale ( V , geom3 : : BOTTOM ) ;
queuepolyat ( Vdepth , shFloor [ ct6 ] , darkena ( firecolor ( ticks / 10 ) , 0 , 0xDF ) ,
PPR_LAKEBOTTOM ) ;
}
}
# ifndef NOEDIT
if ( drawUserShape ( Vpdir , mapeditor : : cellShapeGroup ( ) , mapeditor : : realpatternsh ( c ) ,
darkena ( fcol , fd , cmode = = emDraw ? 0xC0 : 0xFF ) ) ) ;
2016-01-02 10:09:13 +00:00
else if ( mapeditor : : whichShape = = ' 7 ' ) {
if ( ishept ( c ) )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , wmblack ? shBFloor [ ct6 ] :
2016-01-02 10:09:13 +00:00
euclid ? shBigHex :
2017-03-23 10:53:57 +00:00
shBigHepta , darkena ( fcol , fd , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( mapeditor : : whichShape = = ' 8 ' ) {
if ( euclid )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shTriheptaEuc [ ishept ( c ) ? 1 : ishex1 ( c ) ? 0 : 2 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
else
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shTriheptaFloor [ ishept ( c ) ? 1 : 0 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
}
2016-01-02 10:09:13 +00:00
else if ( mapeditor : : whichShape = = ' 6 ' ) {
if ( ! ishept ( c ) )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf ,
wmblack ? shBFloor [ ct6 ] :
2016-01-02 10:09:13 +00:00
euclid ? ( ishex1 ( c ) ? shBigHexTriangle : shBigHexTriangleRev ) :
2017-03-23 10:53:57 +00:00
shBigTriangle , darkena ( fcol , fd , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
# endif
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
else if ( c - > land = = laWineyard & & cellHalfvine ( c ) ) {
2015-08-08 13:57:52 +00:00
int i = - 1 ;
for ( int t = 0 ; t < 6 ; t + + ) if ( c - > mov [ t ] & & c - > mov [ t ] - > wall = = c - > wall )
i = t ;
2017-03-23 10:53:57 +00:00
qfi . spin = ddspin ( c , i , S14 ) ;
transmatrix V2 = V * qfi . spin ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( wmspatial & & wmescher ) {
qfi . shape = & shSemiFeatherFloor [ 0 ] ; qfi . special = true ;
int dk = 1 ;
int vcol = winf [ waVinePlant ] . color ;
warpfloor ( c , mscale ( V , geom3 : : WALL ) , darkena ( vcol , dk , 0xFF ) , PPR_WALL3A , false ) ;
escherSidewall ( c , SIDE_WALL , V , darkena ( gradient ( 0 , vcol , 0 , .8 , 1 ) , dk , 0xFF ) ) ;
qfloor ( c , V2 , shSemiFeatherFloor [ 1 ] , darkena ( fcol , dk , 0xFF ) ) ;
qfi . shape = & shFeatherFloor [ 0 ] ; qfi . special = true ;
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
else if ( wmspatial ) {
hpcshape * shar = wmplain ? shFloor : shFeatherFloor ;
int dk = 1 ;
qfloor ( c , V , shar [ 0 ] , darkena ( fcol , dk , 0xFF ) ) ;
int vcol = winf [ waVinePlant ] . color ;
int vcol2 = gradient ( 0 , vcol , 0 , .8 , 1 ) ;
transmatrix Vdepth = mscale ( V2 , geom3 : : WALL ) ;
queuepolyat ( Vdepth , shSemiFloor [ 0 ] , darkena ( vcol , dk , 0xFF ) , PPR_WALL3A ) ;
{ dynamicval < int > p ( poly_outline , OUTLINE_TRANS ) ; queuepolyat ( V2 * spin ( M_PI * 2 / 3 ) , shSemiFloorShadow , SHADOW_WALL , PPR_WALLSHADOW ) ; }
queuepolyat ( V2 , shSemiFloorSide [ SIDE_WALL ] , darkena ( vcol , dk , 0xFF ) , PPR_WALL3A - 2 + away ( V2 ) ) ;
if ( validsidepar [ SIDE_WALL ] ) forCellIdEx ( c2 , j , c ) {
int dis = i - j ;
dis % = 6 ;
if ( dis < 0 ) dis + = 6 ;
if ( dis ! = 1 & & dis ! = 5 ) continue ;
placeSidewall ( c , j , SIDE_WALL , V , false , false , darkena ( vcol2 , fd , 0xFF ) ) ;
}
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
else {
hpcshape * shar = shSemiFeatherFloor ;
if ( wmblack ) shar = shSemiBFloor ;
if ( wmplain ) shar = shSemiFloor ;
int dk = wmblack ? 0 : wmplain ? 1 : 1 ;
qfloor ( c , V2 , shar [ 0 ] , darkena ( winf [ waVinePlant ] . color , dk , 0xFF ) ) ;
qfloor ( c , V2 , shar [ 1 ] , darkena ( fcol , dk , 0xFF ) ) ;
}
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else if ( c - > land = = laReptile | | c - > wall = = waReptile )
drawReptileFloor ( Vf , c , fcol , true ) ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
else if ( wmblack = = 1 & & c - > wall = = waMineOpen & & vid . grid )
2016-01-02 10:09:13 +00:00
;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
else if ( wmblack ) {
qfloor ( c , Vf , shBFloor [ ct6 ] , darkena ( fcol , 0 , 0xFF ) ) ;
int rd = rosedist ( c ) ;
if ( rd = = 1 )
qfloor ( c , Vf , shHeptaMarker , darkena ( fcol , 0 , 0x80 ) ) ;
else if ( rd = = 2 )
qfloor ( c , Vf , shHeptaMarker , darkena ( fcol , 0 , 0x40 ) ) ;
}
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
else if ( isWarped ( c ) & & euclid )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shTriheptaEuc [ ishept ( c ) ? 1 : ishex1 ( c ) ? 0 : 2 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
else if ( isWarped ( c ) & & ! purehepta & & ! shmup : : on ) {
int np = mapeditor : : nopattern ( c ) ;
if ( c - > landparam = = 1337 ) np = 0 ; // for the achievement screenshot
if ( np < 11 )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , applyPatterndir ( c ) , shTriheptaFloor [ np ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
}
2017-03-23 10:53:57 +00:00
else if ( wmplain ) {
if ( wmspatial & & highwall ( c ) ) ;
else qfloor ( c , Vf , shFloor [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
}
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
else if ( randomPatternsMode & & c - > land ! = laBarrier & & ! isWarped ( c - > land ) ) {
int j = ( randompattern [ c - > land ] / 5 ) % 15 ;
2017-03-23 10:53:57 +00:00
int dfcol = darkena ( fcol , fd , 0xFF ) ;
2016-08-26 09:58:03 +00:00
int k = randompattern [ c - > land ] % RPV_MODULO ;
int k7 = randompattern [ c - > land ] % 7 ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( k = = RPV_ZEBRA & & k7 < 2 ) drawZebraFloor ( Vf , c , dfcol ) ;
else if ( k = = RPV_EMERALD & & k7 = = 0 ) drawEmeraldFloor ( Vf , c , dfcol ) ;
else if ( k = = RPV_CYCLE & & k7 < 4 ) drawTowerFloor ( Vf , c , dfcol , celldist ) ;
2016-08-26 09:58:03 +00:00
else switch ( j ) {
2017-03-23 10:53:57 +00:00
case 0 : qfloor ( c , Vf , shCloudFloor [ ct6 ] , dfcol ) ; break ;
case 1 : qfloor ( c , Vf , shFeatherFloor [ ECT ] , dfcol ) ; break ;
case 2 : qfloor ( c , Vf , shStarFloor [ ct6 ] , dfcol ) ; break ;
case 3 : qfloor ( c , Vf , shTriFloor [ ct6 ] , dfcol ) ; break ;
case 4 : qfloor ( c , Vf , shSStarFloor [ ct6 ] , dfcol ) ; break ;
case 5 : qfloor ( c , Vf , shOverFloor [ ECT ] , dfcol ) ; break ;
case 6 : qfloor ( c , Vf , shFeatherFloor [ ECT ] , dfcol ) ; break ;
case 7 : qfloor ( c , Vf , shDemonFloor [ ct6 ] , dfcol ) ; break ;
case 8 : qfloor ( c , Vf , shCrossFloor [ ct6 ] , dfcol ) ; break ;
case 9 : qfloor ( c , Vf , shMFloor [ ct6 ] , dfcol ) ; break ;
case 10 : qfloor ( c , Vf , shCaveFloor [ ECT ] , dfcol ) ; break ;
case 11 : qfloor ( c , Vf , shPowerFloor [ ct6 ] , dfcol ) ; break ;
case 12 : qfloor ( c , Vf , shDesertFloor [ ct6 ] , dfcol ) ; break ;
case 13 : qfloor ( c , Vf , purehepta ? shChargedFloor [ 3 ] : shChargedFloor [ ct6 ] , dfcol ) ; break ;
case 14 : qfloor ( c , Vf , ct = = 6 ? shChargedFloor [ 2 ] : shFloor [ 1 ] , dfcol ) ; break ;
2016-08-26 09:58:03 +00:00
}
}
2017-03-23 10:53:57 +00:00
// else if(c->land == laPrairie && !eoh && allemptynear(c) && fieldpattern::getflowerdist(c) <= 1)
// queuepoly(Vf, shLeafFloor[ct6], darkena(fcol, fd, 0xFF));
/* else if(c->land == laPrairie && prairie::isriver(c))
drawTowerFloor ( Vf , c , darkena ( fcol , fd , 0xFF ) ,
prairie : : isleft ( c ) ? river : : towerleft : river : : towerright ) ; */
else if ( c - > land = = laPrairie )
qfloor ( c , Vf , shCloudFloor [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
else if ( c - > land = = laWineyard ) {
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shFeatherFloor [ euclid ? 2 : ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( c - > land = = laZebra )
2017-03-23 10:53:57 +00:00
drawZebraFloor ( Vf , c , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
else if ( c - > wall = = waTrunk )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shFloor [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
else if ( c - > wall = = waCanopy | | c - > wall = = waSolidBranch | | c - > wall = = waWeakBranch )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shFeatherFloor [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
else if ( c - > land = = laMountain )
drawTowerFloor ( Vf , c , darkena ( fcol , fd , 0xFF ) ,
euclid ? celldist : c - > master - > alt ? celldistAltPlus : celldist ) ;
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
else if ( isGravityLand ( c - > land ) )
2017-03-23 10:53:57 +00:00
drawTowerFloor ( Vf , c , darkena ( fcol , fd , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
else if ( c - > land = = laEmerald )
2017-03-23 10:53:57 +00:00
drawEmeraldFloor ( Vf , c , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
else if ( c - > land = = laRlyeh )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , ( eoh ? shFloor : shTriFloor ) [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
else if ( c - > land = = laTemple )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , ( eoh ? shFloor : shTriFloor ) [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
else if ( c - > land = = laAlchemist )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shCloudFloor [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
else if ( c - > land = = laRose )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shRoseFloor [ purehepta ? 2 : ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
else if ( c - > land = = laTortoise )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shTurtleFloor [ purehepta ? 2 : ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
else if ( c - > land = = laDragon & & ! purehepta ) {
/* if(!wmspatial || noAdjacentChasms(c)) */
qfloor ( c , Vf , shDragonFloor [ euclid ? 2 : ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
/* if(wmspatial)
qfloor ( c , Vf , shFloor [ euclid ? 2 : ct6 ] , darkena ( fcol , fd , 0xFF ) ) ; */
}
2016-08-26 09:58:03 +00:00
else if ( ( isElemental ( c - > land ) | | c - > land = = laElementalWall ) & & ! eoh )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shNewFloor [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
else if ( c - > land = = laBurial )
qfloor ( c , Vf , shBarrowFloor [ euclid ? 0 : purehepta ? 2 : ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
else if ( c - > land = = laTrollheim & & ! eoh )
qfloor ( c , Vf , shTrollFloor [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
else if ( c - > land = = laTrollheim )
qfloor ( c , Vf , shCaveFloor [ euclid ? 2 : 1 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
else if ( c - > land = = laJungle )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shFeatherFloor [ euclid ? 2 : ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
else if ( c - > land = = laMountain )
qfloor ( c , Vf , shFeatherFloor [ euclid ? 2 : ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
else if ( c - > land = = laGraveyard )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , ( eoh ? shFloor : shCrossFloor ) [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
else if ( c - > land = = laDeadCaves ) {
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shCaveFloor [ euclid ? 2 : ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
}
else if ( c - > land = = laMotion )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shMFloor [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
else if ( c - > land = = laWhirlwind )
2017-03-23 10:53:57 +00:00
// drawZebraFloor(V, c, darkena(fcol, fd, 0xFF));
qfloor ( c , Vf , ( eoh ? shCloudFloor : shNewFloor ) [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
else if ( c - > land = = laHell )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , ( euclid ? shStarFloor : shDemonFloor ) [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
else if ( c - > land = = laIce )
2017-03-23 10:53:57 +00:00
// qfloor(c, V, shFloor[ct6], darkena(fcol, 2, 0xFF));
qfloor ( c , Vf , shStarFloor [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
else if ( c - > land = = laCocytus )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , ( eoh ? shCloudFloor : shDesertFloor ) [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
else if ( c - > land = = laStorms ) {
if ( euclid )
2017-03-23 10:53:57 +00:00
qfloor ( c , ishex1 ( c ) ? V * pispin : Vf ,
ishept ( c ) ? shFloor [ 0 ] : shChargedFloor [ 2 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
else
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , ( purehepta ? shChargedFloor [ 3 ] : ct = = 6 ? shChargedFloor [ 2 ] : shFloor [ 1 ] ) , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
}
else if ( c - > land = = laWildWest )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , ( eoh ? shCloudFloor : shSStarFloor ) [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
else if ( c - > land = = laPower )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , ( eoh ? shStarFloor : shPowerFloor ) [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
else if ( c - > land = = laHive & & c - > wall ! = waFloorB & & c - > wall ! = waFloorA & & c - > wall ! = waMirror & & c - > wall ! = waCloud ) {
qfloor ( c , Vf , shFloor [ ct6 ] , darkena ( fcol , 1 , 0xFF ) ) ;
if ( c - > wall ! = waMirror & & c - > wall ! = waCloud )
qfloor ( c , Vf , shMFloor [ ct6 ] , darkena ( fcol , 2 , 0xFF ) ) ;
if ( c - > wall ! = waMirror & & c - > wall ! = waCloud )
qfloor ( c , Vf , shMFloor2 [ ct6 ] , darkena ( fcol , fcol = = wcol ? 1 : 2 , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
}
else if ( c - > land = = laCaves )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shCaveFloor [ ECT ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
else if ( c - > land = = laDesert )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , ( eoh ? shCloudFloor : shDesertFloor ) [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
else if ( c - > land = = laOvergrown | | c - > land = = laClearing | | isHaunted ( c - > land ) )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shOverFloor [ ECT ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
else if ( c - > land = = laRose )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shOverFloor [ ECT ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
2017-04-14 18:12:23 +00:00
else if ( c - > land = = laBull )
qfloor ( c , Vf , ( eoh ? shFloor : shButterflyFloor ) [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
else if ( c - > land = = laDryForest )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , ( eoh ? shStarFloor : shDesertFloor ) [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
else if ( c - > land = = laCaribbean | | c - > land = = laOcean | | c - > land = = laOceanWall | | c - > land = = laWhirlpool )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shCloudFloor [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
else if ( c - > land = = laLivefjord )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shCaveFloor [ ECT ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
else if ( c - > land = = laRedRock )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , eoh ? shFloor [ ct6 ] : shDesertFloor [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
else if ( c - > land = = laPalace )
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , ( eoh ? shFloor : shPalaceFloor ) [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
else {
2017-03-23 10:53:57 +00:00
qfloor ( c , Vf , shFloor [ ct6 ] , darkena ( fcol , fd , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
2015-08-08 13:57:52 +00:00
// walls
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
# ifndef NOEDIT
2017-04-08 15:18:29 +00:00
if ( mapeditor : : displaycodes ) {
2016-01-02 10:09:13 +00:00
int labeli = mapeditor : : displaycodes = = 1 ? mapeditor : : realpattern ( c ) : mapeditor : : subpattern ( c ) ;
string label = its ( labeli ) ;
2017-03-23 10:53:57 +00:00
if ( svg : : in )
queuestr ( V , .5 , label , 0xFF000000 ) ;
else
queuestr ( V , .2 , label , 0xFFFFFFFF ) ;
2016-01-02 10:09:13 +00:00
/* transmatrix V2 = V * applyPatterndir(c);
2017-03-23 10:53:57 +00:00
qfloor ( c , V2 , shNecro , 0x80808080 ) ;
qfloor ( c , V2 , shStatue , 0x80808080 ) ; */
2016-01-02 10:09:13 +00:00
}
# endif
2017-03-23 10:53:57 +00:00
if ( cmode = = emNumber & & ( dialog : : editingDetail ( ) ) ) {
int col =
dist0 < geom3 : : highdetail ? 0xFF80FF80 :
dist0 > = geom3 : : middetail ? 0xFFFF8080 :
0XFFFFFF80 ;
# if 1
queuepoly ( V , shHeptaMarker , darkena ( col & 0xFFFFFF , 0 , 0xFF ) ) ;
# else
char buf [ 64 ] ;
sprintf ( buf , " %3.1f " , float ( dist0 ) ) ;
queuestr ( V , .6 , buf , col ) ;
# endif
}
2017-04-04 09:13:15 +00:00
2017-03-23 10:53:57 +00:00
if ( realred ( c - > wall ) & & ! wmspatial ) {
2016-01-02 10:09:13 +00:00
int s = snakelevel ( c ) ;
if ( s > = 1 )
2017-03-23 10:53:57 +00:00
qfloor ( c , V , shRedRockFloor [ 0 ] [ ct6 ] , darkena ( winf [ waRed1 ] . color , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
if ( s > = 2 )
2017-03-23 10:53:57 +00:00
queuepoly ( V , shRedRockFloor [ 1 ] [ ct6 ] , darkena ( winf [ waRed2 ] . color , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
if ( s > = 3 )
2017-03-23 10:53:57 +00:00
queuepoly ( V , shRedRockFloor [ 2 ] [ ct6 ] , darkena ( winf [ waRed3 ] . color , 0 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( c - > wall = = waTower & & ! wmspatial ) {
qfloor ( c , V , shMFloor [ ct6 ] , darkena ( 0xE8E8E8 , fd , 0xFF ) ) ;
}
if ( pseudohept ( c ) & & (
c - > land = = laRedRock | |
vid . darkhepta | |
( purehepta & & ( c - > land = = laClearing | | isWarped ( c ) ) ) ) ) {
queuepoly ( ( * Vdp ) , shHeptaMarker , wmblack ? 0x80808080 : 0x00000080 ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
if ( conformal : : includeHistory & & eq ( c - > aitmp , sval - 1 ) )
2017-03-23 10:53:57 +00:00
queuepoly ( ( * Vdp ) , shHeptaMarker , 0x000000C0 ) ;
2016-08-26 09:58:03 +00:00
2016-01-02 10:09:13 +00:00
char xch = winf [ c - > wall ] . glyph ;
2017-03-23 10:53:57 +00:00
if ( c - > wall = = waBigBush ) {
if ( detaillevel > = 2 )
queuepolyat ( mmscale ( V , zgrad0 ( 0 , geom3 : : slev , 1 , 2 ) ) , shHeptaMarker , darkena ( wcol , 0 , 0xFF ) , PPR_REDWALL ) ;
if ( detaillevel > = 1 )
queuepolyat ( mmscale ( V , geom3 : : SLEV [ 1 ] ) * pispin , shWeakBranch , darkena ( wcol , 0 , 0xFF ) , PPR_REDWALL + 1 ) ;
if ( detaillevel > = 2 )
queuepolyat ( mmscale ( V , zgrad0 ( 0 , geom3 : : slev , 3 , 2 ) ) , shHeptaMarker , darkena ( wcol , 0 , 0xFF ) , PPR_REDWALL + 2 ) ;
queuepolyat ( mmscale ( V , geom3 : : SLEV [ 2 ] ) , shSolidBranch , darkena ( wcol , 0 , 0xFF ) , PPR_REDWALL + 3 ) ;
}
else if ( c - > wall = = waSmallBush ) {
if ( detaillevel > = 2 )
queuepolyat ( mmscale ( V , zgrad0 ( 0 , geom3 : : slev , 1 , 2 ) ) , shHeptaMarker , darkena ( wcol , 0 , 0xFF ) , PPR_REDWALL ) ;
if ( detaillevel > = 1 )
queuepolyat ( mmscale ( V , geom3 : : SLEV [ 1 ] ) * pispin , shWeakBranch , darkena ( wcol , 0 , 0xFF ) , PPR_REDWALL + 1 ) ;
if ( detaillevel > = 2 )
queuepolyat ( mmscale ( V , zgrad0 ( 0 , geom3 : : slev , 3 , 2 ) ) , shHeptaMarker , darkena ( wcol , 0 , 0xFF ) , PPR_REDWALL + 2 ) ;
queuepolyat ( mmscale ( V , geom3 : : SLEV [ 2 ] ) , shWeakBranch , darkena ( wcol , 0 , 0xFF ) , PPR_REDWALL + 3 ) ;
}
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
else if ( c - > wall = = waSolidBranch ) {
queuepoly ( V , shSolidBranch , darkena ( wcol , 0 , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
}
else if ( c - > wall = = waWeakBranch ) {
2017-03-23 10:53:57 +00:00
queuepoly ( V , shWeakBranch , darkena ( wcol , 0 , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
}
else if ( c - > wall = = waLadder ) {
2016-01-02 10:09:13 +00:00
if ( euclid ) {
2017-03-23 10:53:57 +00:00
queuepoly ( V , shMFloor [ ct6 ] , 0x804000FF ) ;
queuepoly ( V , shMFloor2 [ ct6 ] , 0x000000FF ) ;
2016-01-02 10:09:13 +00:00
}
else {
2017-03-23 10:53:57 +00:00
queuepolyat ( V , shFloor [ ct6 ] , 0x804000FF , PPR_FLOOR + 1 ) ;
queuepolyat ( V , shMFloor [ ct6 ] , 0x000000FF , PPR_FLOOR + 2 ) ;
2016-01-02 10:09:13 +00:00
}
}
2017-03-23 10:53:57 +00:00
if ( c - > wall = = waReptileBridge ) {
Vboat = & ( Vboat0 = V ) ;
dynamicval < qfloorinfo > qfi2 ( qfi , qfi ) ;
int col = reptilecolor ( c ) ;
chasmg = 0 ;
drawReptileFloor ( V , c , col , true ) ;
forCellIdEx ( c2 , i , c ) if ( chasmgraph ( c2 ) )
placeSidewallX ( c , i , SIDE_LAKE , V , isWarped ( c ) , false , darkena ( gradient ( 0 , col , 0 , .8 , 1 ) , fd , 0xFF ) ) ;
chasmg = 1 ;
}
if ( c - > wall = = waBoat | | c - > wall = = waStrandedBoat ) {
double footphase ;
bool magical = items [ itOrbWater ] & & ( isPlayerOn ( c ) | | ( isFriendly ( c ) & & items [ itOrbEmpathy ] ) ) ;
int outcol = magical ? watercolor ( 0 ) : 0xC06000FF ;
int incol = magical ? 0x0060C0FF : 0x804000FF ;
bool nospin = false ;
Vboat = & ( Vboat0 = * Vboat ) ;
if ( wmspatial & & c - > wall = = waBoat ) {
nospin = c - > wall = = waBoat & & applyAnimation ( c , Vboat0 , footphase , LAYER_BOAT ) ;
if ( ! nospin ) Vboat0 = Vboat0 * ddspin ( c , c - > mondir , S42 ) ;
queuepolyat ( Vboat0 , shBoatOuter , outcol , PPR_BOATLEV ) ;
Vboat = & ( Vboat0 = V ) ;
}
if ( c - > wall = = waBoat ) {
nospin = applyAnimation ( c , Vboat0 , footphase , LAYER_BOAT ) ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
if ( ! nospin )
Vboat0 = Vboat0 * ddspin ( c , c - > mondir , S42 ) ;
2016-01-02 10:09:13 +00:00
else {
2017-03-23 10:53:57 +00:00
transmatrix Vx ;
if ( applyAnimation ( c , Vx , footphase , LAYER_SMALL ) )
animations [ LAYER_SMALL ] [ c ] . footphase = 0 ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
if ( wmspatial )
queuepolyat ( mscale ( Vboat0 , ( geom3 : : LAKE + 1 ) / 2 ) , shBoatOuter , outcol , PPR_BOATLEV2 ) ;
queuepoly ( Vboat0 , shBoatOuter , outcol ) ;
queuepoly ( Vboat0 , shBoatInner , incol ) ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
else if ( c - > wall = = waBigStatue ) {
transmatrix V2 = V ;
double footphase ;
applyAnimation ( c , V2 , footphase , LAYER_BOAT ) ;
queuepolyat ( V2 , shStatue ,
darkena ( winf [ c - > wall ] . color , 0 , 0xFF ) ,
PPR_BIGSTATUE
2015-08-08 13:57:52 +00:00
) ;
2017-03-23 10:53:57 +00:00
}
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
else if ( c - > wall = = waSulphurC ) {
2017-03-23 10:53:57 +00:00
if ( drawstar ( c ) ) {
2017-05-27 19:40:40 +00:00
zcol = wcol ;
2017-03-23 10:53:57 +00:00
if ( wmspatial )
queuepolyat ( mscale ( V , geom3 : : HELLSPIKE ) , shGiantStar [ ct6 ] , darkena ( wcol , 0 , 0x40 ) , PPR_HELLSPIKE ) ;
else
queuepoly ( V , shGiantStar [ ct6 ] , darkena ( wcol , 0 , 0xFF ) ) ;
}
2016-01-02 10:09:13 +00:00
}
else if ( c - > wall = = waClosePlate | | c - > wall = = waOpenPlate | | ( c - > wall = = waTrapdoor & & c - > land ! = laZebra ) ) {
transmatrix V2 = V ;
2017-03-23 10:53:57 +00:00
if ( ct ! = 6 & & wmescher ) V2 = V * pispin ;
queuepoly ( V2 , shMFloor [ ct6 ] , darkena ( winf [ c - > wall ] . color , 0 , 0xFF ) ) ;
queuepoly ( V2 , shMFloor2 [ ct6 ] , ( ! wmblack ) ? darkena ( fcol , 1 , 0xFF ) : darkena ( 0 , 1 , 0xFF ) ) ;
2016-01-02 10:09:13 +00:00
}
2015-08-08 13:57:52 +00:00
else if ( c - > wall = = waFrozenLake | | c - > wall = = waLake | | c - > wall = = waCamelotMoat | |
2017-03-23 10:53:57 +00:00
c - > wall = = waSea | | c - > wall = = waClosePlate | | c - > wall = = waOpenPlate | |
2016-01-02 10:09:13 +00:00
c - > wall = = waOpenGate | | c - > wall = = waTrapdoor )
2015-08-08 13:57:52 +00:00
;
2016-08-26 09:58:03 +00:00
else if ( c - > wall = = waRose ) {
2017-05-27 19:40:40 +00:00
zcol = wcol ;
2017-03-23 10:53:57 +00:00
wcol < < = 1 ;
2016-08-26 09:58:03 +00:00
if ( c - > cpdist > 5 )
2017-03-23 10:53:57 +00:00
wcol = 0xC0C0C0 ;
2016-08-26 09:58:03 +00:00
else if ( rosephase = = 7 )
2017-03-23 10:53:57 +00:00
wcol = 0xFF0000 ;
2016-08-26 09:58:03 +00:00
else
2017-03-23 10:53:57 +00:00
wcol = gradient ( wcol , 0xC00000 , 0 , rosephase , 6 ) ;
2016-08-26 09:58:03 +00:00
queuepoly ( V , shThorns , 0xC080C0FF ) ;
for ( int u = 0 ; u < 4 ; u + = 2 )
2017-03-23 10:53:57 +00:00
queuepoly ( V * spin ( 2 * M_PI / 3 / 4 * u ) , shRose , darkena ( wcol , 0 , 0xC0 ) ) ;
}
else if ( sl & & wmspatial ) {
bool w = isWarped ( c ) ;
warpfloor ( c , ( * Vdp ) , darkena ( wcol , fd , 0xFF ) , PPR_REDWALL - 4 + 4 * sl , w ) ;
floorShadow ( c , V , SHADOW_SL * sl , w ) ;
bool tower = c - > wall = = waTower ;
for ( int s = 0 ; s < sl ; s + + )
forCellIdEx ( c2 , i , c ) {
int sl2 = snakelevel ( c2 ) ;
if ( s > = sl2 )
placeSidewallX ( c , i , SIDE_SLEV + s , V , w , false ,
darkena ( tower ? 0xD0D0D0 - i * 0x101010 : s = = sl - 1 ? wcol : winf [ waRed1 + s ] . color , fd , 0xFF ) ) ;
}
}
else if ( c - > wall = = waRoundTable ) ;
else if ( c - > wall = = waGlass & & wmspatial ) {
int col = winf [ waGlass ] . color ;
int dcol = darkena ( col , 0 , 0x80 ) ;
transmatrix Vdepth = mscale ( ( * Vdp ) , geom3 : : WALL ) ;
queuepolyat ( Vdepth , shMFloor [ ct6 ] , dcol , PPR_GLASS ) ;
if ( validsidepar [ SIDE_WALL ] ) forCellIdEx ( c2 , i , c )
placeSidewall ( c , i , SIDE_WALL , ( * Vdp ) , false , true , dcol ) ;
2016-08-26 09:58:03 +00:00
}
2017-03-23 10:53:57 +00:00
else if ( c - > wall = = waGlass & & ! wmspatial ) ;
else if ( wmescher & & wmspatial & & c - > wall = = waBarrier & & c - > land = = laOceanWall ) {
const int layers = 2 < < detaillevel ;
dynamicval < const hpcshape * > ds ( qfi . shape , & shCircleFloor ) ;
dynamicval < bool > db ( qfi . special , true ) ;
for ( int z = 1 ; z < layers ; z + + ) {
double zg = zgrad0 ( - geom3 : : lake_top , geom3 : : wall_height , z , layers ) ;
warpfloor ( c , xyzscale ( V , zg * ( layers - z ) / layers , zg ) ,
darkena ( gradient ( 0 , wcol , - layers , z , layers ) , 0 , 0xFF ) , PPR_WALL3 + z - layers + 2 , isWarped ( c ) ) ;
}
}
else if ( highwall ( c ) ) {
2017-05-27 19:40:40 +00:00
zcol = wcol ;
2017-03-23 10:53:57 +00:00
int wcol0 = wcol ;
int starcol = wcol ;
if ( c - > wall = = waWarpGate ) starcol = 0 ;
if ( c - > wall = = waVinePlant ) starcol = 0x60C000 ;
int wcol2 = gradient ( 0 , wcol0 , 0 , .8 , 1 ) ;
if ( c - > wall = = waClosedGate ) {
int hdir = 0 ;
for ( int i = 0 ; i < c - > type ; i + + ) if ( c - > mov [ i ] - > wall = = waClosedGate )
hdir = i ;
transmatrix V2 = mscale ( V , wmspatial ? geom3 : : WALL : 1 ) * ddspin ( c , hdir , S42 ) ;
queuepolyat ( V2 , shPalaceGate , darkena ( wcol , 0 , 0xFF ) , wmspatial ? PPR_WALL3A : PPR_WALL ) ;
starcol = 0 ;
}
hpcshape & shThisWall = isGrave ( c - > wall ) ? shCross : shWall [ ct6 ] ;
if ( conegraph ( c ) ) {
const int layers = 2 < < detaillevel ;
for ( int z = 1 ; z < layers ; z + + ) {
double zg = zgrad0 ( 0 , geom3 : : wall_height , z , layers ) ;
warpfloor ( c , xyzscale ( V , zg * ( layers - z ) / layers , zg ) ,
darkena ( gradient ( 0 , wcol , - layers , z , layers ) , 0 , 0xFF ) , PPR_WALL3 + z - layers + 2 , isWarped ( c ) ) ;
}
floorShadow ( c , V , SHADOW_WALL , isWarped ( c ) ) ;
}
else if ( true ) {
if ( ! wmspatial ) {
if ( starcol ) queuepoly ( V , shThisWall , darkena ( starcol , 0 , 0xFF ) ) ;
}
else {
transmatrix Vdepth = mscale ( V , geom3 : : WALL ) ;
bool warp = isWarped ( c ) ;
if ( starcol & & ! ( wmescher & & c - > wall = = waPlatform ) )
queuepolyat ( Vdepth , shThisWall , darkena ( starcol , 0 , 0xFF ) , PPR_WALL3A ) ;
warpfloor ( c , Vdepth , darkena ( wcol0 , fd , 0xFF ) , PPR_WALL3 , warp ) ;
floorShadow ( c , V , SHADOW_WALL , warp ) ;
if ( c - > wall = = waCamelot ) {
forCellIdEx ( c2 , i , c ) {
placeSidewallX ( c , i , SIDE_SLEV , V , warp , false , darkena ( wcol2 , fd , 0xFF ) ) ;
}
forCellIdEx ( c2 , i , c ) {
placeSidewallX ( c , i , SIDE_SLEV + 1 , V , warp , false , darkena ( wcol2 , fd , 0xFF ) ) ;
}
forCellIdEx ( c2 , i , c ) {
placeSidewallX ( c , i , SIDE_SLEV + 2 , V , warp , false , darkena ( wcol2 , fd , 0xFF ) ) ;
}
forCellIdEx ( c2 , i , c ) {
placeSidewallX ( c , i , SIDE_WTS3 , V , warp , false , darkena ( wcol2 , fd , 0xFF ) ) ;
}
}
else forCellIdEx ( c2 , i , c ) {
if ( ! highwall ( c2 ) | | conegraph ( c2 ) )
{ placeSidewallX ( c , i , SIDE_WALL , V , warp , false , darkena ( wcol2 , fd , 0xFF ) ) ; }
}
}
}
2015-08-08 13:57:52 +00:00
}
2016-08-26 09:58:03 +00:00
else if ( c - > wall = = waFan ) {
2017-03-23 10:53:57 +00:00
queuepoly ( V * spin ( M_PI / 6 - fanframe * M_PI / 3 ) , shFan , darkena ( wcol , 0 , 0xFF ) ) ;
2016-08-26 09:58:03 +00:00
}
else if ( xch = = ' % ' ) {
if ( doHighlight ( ) )
poly_outline = ( c - > land = = laMirror ) ? OUTLINE_TREASURE : OUTLINE_ORB ;
2017-03-23 10:53:57 +00:00
if ( wmspatial ) {
int col = winf [ c - > wall ] . color ;
int dcol = darkena ( col , 0 , 0xC0 ) ;
transmatrix Vdepth = mscale ( ( * Vdp ) , geom3 : : WALL ) ;
queuepolyat ( Vdepth , shMFloor [ ct6 ] , dcol , PPR_GLASS ) ;
if ( validsidepar [ SIDE_WALL ] ) forCellIdEx ( c2 , i , c )
placeSidewall ( c , i , SIDE_WALL , ( * Vdp ) , false , true , dcol ) ;
}
else {
queuepoly ( V , shMirror , darkena ( wcol , 0 , 0xC0 ) ) ;
}
2016-08-26 09:58:03 +00:00
poly_outline = OUTLINE_NONE ;
}
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
else if ( isFire ( c ) | | isThumper ( c ) | | c - > wall = = waBonfireOff ) {
ld sp = 0 ;
if ( hasTimeout ( c ) ) sp = ticks / ( c - > land = = laPower ? 5000. : 500. ) ;
2017-03-23 10:53:57 +00:00
queuepoly ( V * spin ( sp ) , shStar , darkena ( wcol , 0 , 0xF0 ) ) ;
if ( isFire ( c ) & & rand ( ) % 300 < ticks - lastt )
drawParticle ( c , wcol , 75 ) ;
2015-08-08 13:57:52 +00:00
}
2017-05-27 19:40:40 +00:00
else if ( c - > wall = = waFreshGrave | | c - > wall = = waAncientGrave ) {
zcol = wcol ;
2017-03-23 10:53:57 +00:00
queuepoly ( V , shCross , darkena ( wcol , 0 , 0xFF ) ) ;
2017-05-27 19:40:40 +00:00
}
2016-01-02 10:09:13 +00:00
else if ( xch = = ' + ' & & c - > wall = = waGiantRug ) {
queuepoly ( V , shBigCarpet1 , darkena ( 0xC09F00 , 0 , 0xFF ) ) ;
queuepoly ( V , shBigCarpet2 , darkena ( 0x600000 , 0 , 0xFF ) ) ;
queuepoly ( V , shBigCarpet3 , darkena ( 0xC09F00 , 0 , 0xFF ) ) ;
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
else if ( xch ! = ' . ' & & xch ! = ' + ' & & xch ! = ' > ' & & xch ! = ' : ' & & xch ! = ' - ' & & xch ! = ' ; ' & & c - > wall ! = waSulphur & & xch ! = ' , ' )
2015-08-08 13:57:52 +00:00
error = true ;
}
2016-01-02 10:09:13 +00:00
else if ( ! ( it | | c - > monst | | c - > cpdist = = 0 ) ) error = true ;
2017-03-23 10:53:57 +00:00
int sha = shallow ( c ) ;
if ( wmspatial & & sha ) {
bool w = isWarped ( c ) ;
int col = ( highwall ( c ) | | c - > wall = = waTower ) ? wcol : fcol ;
if ( ! chasmg ) {
if ( sha & 1 ) {
forCellIdEx ( c2 , i , c ) if ( chasmgraph ( c2 ) )
placeSidewallX ( c , i , SIDE_LAKE , V , w , false , darkena ( gradient ( 0 , col , 0 , .8 , 1 ) , fd , 0xFF ) ) ;
}
if ( sha & 2 ) {
forCellIdEx ( c2 , i , c ) if ( chasmgraph ( c2 ) )
placeSidewallX ( c , i , SIDE_LTOB , V , w , false , darkena ( gradient ( 0 , col , 0 , .7 , 1 ) , fd , 0xFF ) ) ;
}
if ( sha & 4 ) {
bool dbot = true ;
forCellIdEx ( c2 , i , c ) if ( chasmgraph ( c2 ) = = 2 ) {
if ( dbot ) dbot = false ,
warpfloor ( c , mscale ( V , geom3 : : BOTTOM ) , 0x080808FF , PPR_LAKEBOTTOM , isWarped ( c ) ) ;
placeSidewallX ( c , i , SIDE_BTOI , V , w , false , darkena ( gradient ( 0 , col , 0 , .6 , 1 ) , fd , 0xFF ) ) ;
}
}
}
// wall between lake and chasm -- no Escher here
if ( chasmg = = 1 ) forCellIdEx ( c2 , i , c ) if ( chasmgraph ( c2 ) = = 2 ) {
placeSidewall ( c , i , SIDE_LAKE , V , w , false , 0x202030FF ) ;
placeSidewall ( c , i , SIDE_LTOB , V , w , false , 0x181820FF ) ;
placeSidewall ( c , i , SIDE_BTOI , V , w , false , 0x101010FF ) ;
}
}
if ( chasmg = = 1 & & wmspatial ) {
int fd0 = fd ? fd - 1 : 0 ;
warpfloor ( c , ( * Vdp ) , darkena ( fcol , fd0 , 0x80 ) , PPR_LAKELEV , isWarped ( c ) ) ;
}
if ( chasmg ) {
int q = size ( ptds ) ;
if ( fallanims . count ( c ) ) {
fallanim & fa = fallanims [ c ] ;
bool erase = true ;
if ( fa . t_floor ) {
int t = ( ticks - fa . t_floor ) ;
if ( t < = 1500 ) {
erase = false ;
if ( fa . walltype = = waNone )
warpfloor ( c , V , darkena ( fcol , fd , 0xFF ) , PPR_FLOOR , isWarped ( c ) ) ;
else {
int wcol2 , fcol2 ;
eWall w = c - > wall ; int p = c - > wparam ;
c - > wall = fa . walltype ; c - > wparam = fa . m ;
setcolors ( c , wcol2 , fcol2 ) ;
int starcol = c - > wall = = waVinePlant ? 0x60C000 : wcol2 ;
c - > wall = w ; c - > wparam = p ;
bool warp = isWarped ( c ) ;
warpfloor ( c , mscale ( V , geom3 : : WALL ) , darkena ( starcol , fd , 0xFF ) , PPR_WALL3 , warp ) ;
queuepolyat ( mscale ( V , geom3 : : WALL ) , shWall [ ct6 ] , darkena ( wcol2 , 0 , 0xFF ) , PPR_WALL3A ) ;
forCellIdEx ( c2 , i , c )
placeSidewallX ( c , i , SIDE_WALL , V , warp , false , darkena ( wcol2 , 1 , 0xFF ) ) ;
}
pushdown ( c , q , V , t * t / 1000000. + t / 1000. , true , true ) ;
}
}
if ( fa . t_mon ) {
int t = ( ticks - fa . t_mon ) ;
if ( t < = 1500 ) {
erase = false ;
c - > stuntime = 0 ;
transmatrix V2 = V ;
double footphase = t / 200.0 ;
applyAnimation ( c , V2 , footphase , LAYER_SMALL ) ;
drawMonsterType ( fa . m , c , V2 , minf [ fa . m ] . color , footphase ) ;
pushdown ( c , q , V2 , t * t / 1000000. + t / 1000. , true , true ) ;
}
}
if ( erase ) fallanims . erase ( c ) ;
}
}
2016-01-02 10:09:13 +00:00
if ( c - > wall = = waMineOpen ) {
int mines = countMinesAround ( c ) ;
2017-03-23 10:53:57 +00:00
if ( wmascii ) {
2016-01-02 10:09:13 +00:00
if ( ch = = ' . ' ) {
if ( mines = = 0 ) ch = ' ' ;
2017-03-23 10:53:57 +00:00
else ch = ' 0 ' + mines , asciicol = minecolors [ mines ] ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
else if ( ch = = ' @ ' ) asciicol = minecolors [ mines ] ;
2016-01-02 10:09:13 +00:00
}
else if ( mines > 0 )
2017-03-23 10:53:57 +00:00
queuepoly ( V , shMineMark [ ct6 ] , ( minecolors [ mines ] < < 8 ) | 0xFF ) ;
2016-01-02 10:09:13 +00:00
}
2015-08-08 13:57:52 +00:00
// treasure
2017-03-23 10:53:57 +00:00
if ( c - > land = = laWhirlwind & & c - > wall ! = waBoat ) {
double footphase = 0 ;
Vboat = & ( Vboat0 = * Vboat ) ;
applyAnimation ( c , Vboat0 , footphase , LAYER_BOAT ) ;
}
# ifndef NOEDIT
2016-01-02 10:09:13 +00:00
if ( c = = mapeditor : : drawcell & & mapeditor : : drawcellShapeGroup ( ) = = 2 )
mapeditor : : drawtrans = V ;
# endif
2017-05-27 19:40:40 +00:00
2017-05-28 22:16:17 +00:00
if ( it & & cellHalfvine ( c ) ) {
int i = - 1 ;
for ( int t = 0 ; t < 6 ; t + + ) if ( c - > mov [ t ] & & c - > mov [ t ] - > wall = = c - > wall )
i = t ;
Vboat = & ( Vboat0 = * Vboat * ddspin ( c , i ) * xpush ( - .13 ) ) ;
2016-01-02 10:09:13 +00:00
}
2017-05-28 22:16:17 +00:00
error | = drawItemType ( it , c , * Vboat , icol , ticks , hidden ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( true ) {
int q = ptds . size ( ) ;
error | = drawMonster ( V , ct , c , moncol ) ;
if ( Vboat ! = & V & & Vboat ! = & Vboat0 & & q ! = size ( ptds ) )
pushdown ( c , q , V , - geom3 : : factor_to_lev ( zlevel ( tC0 ( ( * Vboat ) ) ) ) ,
! isMultitile ( c - > monst ) , false ) ;
}
if ( ! shmup : : on & & sword : : at ( c ) ) {
queuepolyat ( V , shDisk , 0xC0404040 , PPR_SWORDMARK ) ;
2016-08-26 09:58:03 +00:00
}
2016-01-02 10:09:13 +00:00
2017-05-27 19:40:40 +00:00
if ( c - > wall = = waChasm ) zcol = 0 ;
addaura ( tC0 ( V ) , zcol , fd ) ;
2016-01-02 10:09:13 +00:00
int ad = airdist ( c ) ;
if ( ad = = 1 | | ad = = 2 ) {
for ( int i = 0 ; i < c - > type ; i + + ) {
2016-08-26 09:58:03 +00:00
cell * c2 = c - > mov [ i ] ;
2016-01-02 10:09:13 +00:00
if ( airdist ( c2 ) < airdist ( c ) ) {
2016-08-26 09:58:03 +00:00
calcAirdir ( c2 ) ; // printf("airdir = %d\n", airdir);
2017-03-23 10:53:57 +00:00
transmatrix V0 = ddspin ( c , i , S42 ) ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
double ph = ticks / ( purehepta ? 150 : 75.0 ) + airdir * M_PI / ( S21 + .0 ) ;
2016-01-02 10:09:13 +00:00
int aircol = 0x8080FF00 | int ( 32 + 32 * - cos ( ph ) ) ;
double ph0 = ph / 2 ;
ph0 - = floor ( ph0 / M_PI ) * M_PI ;
2017-03-23 10:53:57 +00:00
poly_outline = OUTLINE_TRANS ;
queuepoly ( ( * Vdp ) * V0 * xpush ( hexf * - cos ( ph0 ) ) , shDisk , aircol ) ;
2016-08-26 09:58:03 +00:00
poly_outline = OUTLINE_NONE ;
}
}
2017-03-23 10:53:57 +00:00
// queuepoly(V*ddi(rand() % S84, hexf*(rand()%100)/100), shDisk, aircolor(airdir));
2016-08-26 09:58:03 +00:00
}
/* int rd = rosedist(c);
if ( rd > 0 & & ( ( rd & 7 ) = = ( turncount & 7 ) ) ) {
for ( int i = 0 ; i < c - > type ; i + + ) {
cell * c2 = c - > mov [ i ] ;
if ( rosedist ( c2 ) = = rosedist ( c ) - 1 ) {
int hdir = displaydir ( c , i ) ;
2017-03-23 10:53:57 +00:00
transmatrix V0 = spin ( ( S42 + hdir ) * M_PI / S42 ) ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
double ph = ticks / 75.0 ; // + airdir * M_PI / (S21+.0);
2016-08-26 09:58:03 +00:00
int rosecol = 0x764e7c00 | int ( 32 + 32 * - cos ( ph ) ) ;
double ph0 = ph / 2 ;
ph0 - = floor ( ph0 / M_PI ) * M_PI ;
2017-03-23 10:53:57 +00:00
poly_outline = OUTLINE_TRANS ;
2016-08-26 09:58:03 +00:00
queuepoly ( V * V0 * ddi ( 0 , hexf * - cos ( ph0 ) ) , shDisk , rosecol ) ;
2017-03-23 10:53:57 +00:00
poly_outline = OUTLINE_NONE ;
2016-01-02 10:09:13 +00:00
}
}
2016-08-26 09:58:03 +00:00
} */
if ( c - > land = = laWhirlwind ) {
whirlwind : : calcdirs ( c ) ;
for ( int i = 0 ; i < whirlwind : : qdirs ; i + + ) {
2017-03-23 10:53:57 +00:00
int hdir0 = displaydir ( c , whirlwind : : dfrom [ i ] ) + S42 ;
int hdir1 = displaydir ( c , whirlwind : : dto [ i ] ) ;
double ph1 = fanframe ;
int aircol = 0xC0C0FF40 ;
ph1 - = floor ( ph1 ) ;
if ( hdir1 < hdir0 - S42 ) hdir1 + = S84 ;
if ( hdir1 > = hdir0 + S42 ) hdir1 - = S84 ;
int hdir = ( hdir1 * ph1 + hdir0 * ( 1 - ph1 ) ) ;
transmatrix V0 = spin ( ( hdir ) * M_PI / S42 ) ;
double ldist = purehepta ? crossf : c - > type = = 6 ? .2840 : 0.3399 ;
poly_outline = OUTLINE_TRANS ;
queuepoly ( ( * Vdp ) * V0 * xpush ( ldist * ( 2 * ph1 - 1 ) ) , shDisk , aircol ) ;
poly_outline = OUTLINE_NONE ;
}
2016-01-02 10:09:13 +00:00
}
2015-08-08 13:57:52 +00:00
if ( error ) {
2017-03-23 10:53:57 +00:00
queuechr ( V , 1 , ch , asciicol , 2 ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
if ( vid . grid ) {
// sphere: 0.3948
// sphere heptagonal: 0.5739
// sphere trihepta: 0.3467
// hyper trihepta: 0.2849
// hyper heptagonal: 0.6150
// hyper: 0.3798
if ( purehepta ) {
double x = sphere ? .645 : .6150 ;
for ( int t = 0 ; t < S7 ; t + + )
if ( c - > mov [ t ] & & c - > mov [ t ] < c )
queueline ( V * ddspin ( c , t , - 6 ) * xpush0 ( x ) ,
V * ddspin ( c , t , 6 ) * xpush0 ( x ) ,
gridcolor ( c , c - > mov [ t ] ) , 1 ) ;
}
else if ( isWarped ( c ) ) {
double x = sphere ? .3651 : euclid ? .2611 : .2849 ;
if ( ! ishept ( c ) ) for ( int t = 0 ; t < 6 ; t + + ) if ( c - > mov [ t ] & & ishept ( c - > mov [ t ] ) )
queueline ( V * ddspin ( c , t , - S14 ) * xpush0 ( x ) ,
V * ddspin ( c , t , + S14 ) * xpush0 ( x ) ,
gridcolor ( c , c - > mov [ t ] ) , 1 ) ;
}
else if ( ishept ( c ) & & ! euclid ) ;
else {
double x = sphere ? .401 : euclid ? .3 : .328 ;
for ( int t = 0 ; t < 6 ; t + + )
if ( euclid ? c - > mov [ t ] < c : ( ( ( t ^ 1 ) & 1 ) | | c - > mov [ t ] < c ) )
queueline ( V * ddspin ( c , t , - S7 ) * xpush0 ( x ) ,
V * ddspin ( c , t , + S7 ) * xpush0 ( x ) ,
gridcolor ( c , c - > mov [ t ] ) , 1 ) ;
2016-01-02 10:09:13 +00:00
}
}
2017-03-23 10:53:57 +00:00
2016-08-26 09:58:03 +00:00
if ( ! euclid & & ( ! pirateTreasureSeek | | compassDist ( c ) < compassDist ( pirateTreasureSeek ) ) )
2016-01-02 10:09:13 +00:00
pirateTreasureSeek = c ;
2016-08-26 09:58:03 +00:00
if ( ! euclid ) {
bool usethis = false ;
double spd = 1 ;
2017-03-23 10:53:57 +00:00
bool rev = false ;
2016-08-26 09:58:03 +00:00
if ( isGravityLand ( cwt . c - > land ) ) {
2017-03-23 10:53:57 +00:00
if ( cwt . c - > land = = laDungeon ) rev = true ;
2016-08-26 09:58:03 +00:00
if ( ! straightDownSeek | | edgeDepth ( c ) < edgeDepth ( straightDownSeek ) ) {
usethis = true ;
spd = cwt . c - > landparam / 10. ;
}
}
2017-03-23 10:53:57 +00:00
if ( c - > master - > alt & & cwt . c - > master - > alt & &
( cwt . c - > land = = laMountain | |
( pmodel & &
2016-08-26 09:58:03 +00:00
( cwt . c - > land = = laTemple | | cwt . c - > land = = laWhirlpool | |
( cheater & & ( cwt . c - > land = = laClearing | | cwt . c - > land = = laCaribbean | |
2017-03-23 10:53:57 +00:00
cwt . c - > land = = laCamelot | | cwt . c - > land = = laPalace ) ) )
) )
& & c - > land = = cwt . c - > land & & c - > master - > alt - > alt = = cwt . c - > master - > alt - > alt ) {
if ( ! straightDownSeek | | ! straightDownSeek - > master - > alt | | celldistAlt ( c ) < celldistAlt ( straightDownSeek ) ) {
usethis = true ;
spd = .5 ;
if ( cwt . c - > land = = laMountain ) rev = true ;
2016-08-26 09:58:03 +00:00
}
2017-03-23 10:53:57 +00:00
}
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( pmodel & & cwt . c - > land = = laOcean & & cwt . c - > landparam < 25 ) {
if ( ! straightDownSeek | | coastval ( c , laOcean ) < coastval ( straightDownSeek , laOcean ) ) {
usethis = true ;
spd = cwt . c - > landparam / 10 ;
2016-08-26 09:58:03 +00:00
}
2017-03-23 10:53:57 +00:00
2016-08-26 09:58:03 +00:00
}
if ( usethis ) {
straightDownSeek = c ;
2017-03-23 10:53:57 +00:00
downspin = atan2 ( VC0 [ 1 ] , VC0 [ 0 ] ) ;
downspin - = M_PI / 2 ;
if ( rev ) downspin + = M_PI ;
2016-08-26 09:58:03 +00:00
downspin + = M_PI / 2 * ( conformal : : rotation % 4 ) ;
while ( downspin < - M_PI ) downspin + = 2 * M_PI ;
while ( downspin > + M_PI ) downspin - = 2 * M_PI ;
downspin = downspin * min ( spd , ( double ) 1 ) ;
2016-01-02 10:09:13 +00:00
}
}
2017-03-23 10:53:57 +00:00
if ( ! inHighQual ) {
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
# ifndef NOEDIT
if ( cmode = = emMapEditor & & ! mapeditor : : subscreen & & lmouseover & & darken = = 0 & &
2016-01-02 10:09:13 +00:00
( mapeditor : : whichPattern ? mapeditor : : subpattern ( c ) = = mapeditor : : subpattern ( lmouseover ) : c = = lmouseover ) ) {
2017-03-23 10:53:57 +00:00
queuecircle ( V , .78 , 0x00FFFFFF ) ;
2015-08-08 13:57:52 +00:00
}
2016-01-02 10:09:13 +00:00
# endif
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
# ifndef NOEDIT
2016-01-02 10:09:13 +00:00
mapeditor : : drawGhosts ( c , V , ct ) ;
# endif
2016-08-26 09:58:03 +00:00
}
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
if ( c - > bardir ! = NODIR & & c - > bardir ! = NOBARRIERS & & c - > land ! = laHauntedWall & &
c - > barleft ! = NOWALLSEP_USED ) {
2017-03-23 10:53:57 +00:00
int col = darkena ( 0x505050 , 0 , 0xFF ) ;
queueline ( tC0 ( V ) , V * tC0 ( heptmove [ c - > bardir ] ) , col , 2 ) ;
queueline ( tC0 ( V ) , V * tC0 ( hexmove [ c - > bardir ] ) , col , 2 ) ;
2015-08-08 13:57:52 +00:00
}
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
# ifndef NOMODEL
2016-08-26 09:58:03 +00:00
netgen : : buildVertexInfo ( c , V ) ;
# endif
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
# ifdef LOCAL
extern void localdraw ( const transmatrix & V , cell * c ) ;
localdraw ( V , c ) ;
# endif
2015-08-08 13:57:52 +00:00
}
}
2017-03-23 10:53:57 +00:00
bool confusingGeometry ( ) {
return elliptic | | quotient = = 1 ;
}
struct flashdata {
int t ;
int size ;
cell * where ;
double angle ;
int spd ; // 0 for flashes, >0 for particles
int color ;
flashdata ( int _t , int _s , cell * _w , int col , int sped ) {
t = _t ; size = _s ; where = _w ; color = col ;
angle = rand ( ) % 1000 ; spd = sped ;
}
} ;
vector < flashdata > flashes ;
void drawFlash ( cell * c ) {
flashes . push_back ( flashdata ( ticks , 1000 , c , iinf [ itOrbFlash ] . color , 0 ) ) ;
}
void drawBigFlash ( cell * c ) {
flashes . push_back ( flashdata ( ticks , 2000 , c , 0xC0FF00 , 0 ) ) ;
}
void drawParticle ( cell * c , int col , int maxspeed ) {
if ( vid . particles & & ! confusingGeometry ( ) )
flashes . push_back ( flashdata ( ticks , rand ( ) % 16 , c , col , 1 + rand ( ) % maxspeed ) ) ;
}
void drawParticles ( cell * c , int col , int qty , int maxspeed ) {
if ( vid . particles )
while ( qty - - ) drawParticle ( c , col , maxspeed ) ;
}
void drawFireParticles ( cell * c , int qty , int maxspeed ) {
if ( vid . particles )
for ( int i = 0 ; i < qty ; i + + )
drawParticle ( c , firegradient ( i / ( qty - 1. ) ) , maxspeed ) ;
}
void fallingFloorAnimation ( cell * c , eWall w , eMonster m ) {
if ( ! wmspatial ) return ;
fallanim & fa = fallanims [ c ] ;
fa . t_floor = ticks ;
fa . walltype = w ; fa . m = m ;
// drawParticles(c, darkenedby(linf[c->land].color, 1), 4, 50);
}
void fallingMonsterAnimation ( cell * c , eMonster m ) {
if ( ! mmspatial ) return ;
fallanim & fa = fallanims [ c ] ;
fa . t_mon = ticks ;
fa . m = m ;
// drawParticles(c, darkenedby(linf[c->land].color, 1), 4, 50);
}
void queuecircleat ( cell * c , double rad , int col ) {
if ( ! c ) return ;
if ( ! gmatrix . count ( c ) ) return ;
queuecircle ( gmatrix [ c ] , rad , col ) ;
if ( ! wmspatial ) return ;
if ( highwall ( c ) )
queuecircle ( mscale ( gmatrix [ c ] , geom3 : : WALL ) , rad , col ) ;
int sl ;
if ( ( sl = snakelevel ( c ) ) ) {
queuecircle ( mscale ( gmatrix [ c ] , geom3 : : SLEV [ sl ] ) , rad , col ) ;
}
if ( chasmgraph ( c ) )
queuecircle ( mscale ( gmatrix [ c ] , geom3 : : LAKE ) , rad , col ) ;
}
# define G(x) x && gmatrix.count(x)
# define IG(x) if(G(x))
# define Gm(x) gmatrix[x]
# define Gm0(x) tC0(gmatrix[x])
# ifdef MOBILE
# define MOBON (clicked)
# else
# define MOBON true
# endif
void drawMarkers ( ) {
if ( darken | | cmode = = emNumber ) return ;
if ( ! inHighQual ) {
# ifdef PANDORA
bool ok = mousepressed ;
# else
bool ok = true ;
# endif
if ( G ( dragon : : target ) & & haveMount ( ) ) {
queuechr ( Gm0 ( dragon : : target ) , 2 * vid . fsize , ' X ' ,
gradient ( 0 , iinf [ itOrbDomination ] . color , - 1 , sin ( ticks / ( dragon : : whichturn = = turncount ? 75. : 150. ) ) , 1 ) ) ;
}
/* for(int i=0; i<12; i++) if(c->type == 5 && c->master == &dodecahedron[i])
queuechr ( xc , yc , sc , 4 * vid . fsize , ' A ' + i , iinf [ itOrbDomination ] . color ) ; */
IG ( keycell ) {
queuechr ( Gm0 ( keycell ) , 2 * vid . fsize , ' X ' , 0x10101 * int ( 128 + 100 * sin ( ticks / 150. ) ) ) ;
queuestr ( Gm0 ( keycell ) , vid . fsize , its ( keycelldist ) , 0x10101 * int ( 128 - 100 * sin ( ticks / 150. ) ) ) ;
}
IG ( pirateTreasureFound ) {
pirateCoords = Gm0 ( pirateTreasureFound ) ;
if ( showPirateX ) {
queuechr ( pirateCoords , 2 * vid . fsize , ' X ' , 0x10100 * int ( 128 + 100 * sin ( ticks / 150. ) ) ) ;
if ( numplayers ( ) = = 1 & & cwt . c - > master - > alt )
queuestr ( pirateCoords , vid . fsize , its ( - celldistAlt ( cwt . c ) ) , 0x10101 * int ( 128 - 100 * sin ( ticks / 150. ) ) ) ;
}
}
if ( lmouseover & & vid . drawmousecircle & & ok & & DEFAULTCONTROL & & MOBON ) {
queuecircleat ( lmouseover , .8 , darkena ( lmouseover - > cpdist > 1 ? 0x00FFFF : 0xFF0000 , 0 , 0xFF ) ) ;
}
if ( global_pushto & & vid . drawmousecircle & & ok & & DEFAULTCONTROL & & MOBON ) {
queuecircleat ( global_pushto , .6 , darkena ( 0xFFD500 , 0 , 0xFF ) ) ;
}
if ( joydir . d > = 0 )
queuecircleat ( cwt . c - > mov [ ( joydir . d + cwt . spin ) % cwt . c - > type ] , .78 - .02 * sin ( ticks / 199.0 ) ,
darkena ( 0x00FF00 , 0 , 0xFF ) ) ;
# ifndef NOMODEL
if ( centerover & & ! playermoved & & netgen : : mode = = 0 & & ! conformal : : on )
queuecircleat ( centerover , .70 - .06 * sin ( ticks / 200.0 ) ,
darkena ( int ( 175 + 25 * sin ( ticks / 200.0 ) ) , 0 , 0xFF ) ) ;
# endif
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 ) ;
queuecircleat ( ctgt , .40 - .06 * sin ( ticks / 200.0 + i * 2 * M_PI / numplayers ( ) ) , getcs ( ) . uicolor ) ;
}
// process mouse
# ifdef MOBILE
extern bool useRangedOrb ;
if ( canmove & & ! shmup : : on & & andmode = = 0 & & ! useRangedOrb & & vid . mobilecompasssize > 0 ) {
using namespace shmupballs ;
calc ( ) ;
queuecircle ( xmove , yb , rad , 0xFF0000FF ) ;
2017-03-31 19:41:09 +00:00
queuecircle ( xmove , yb , rad * SKIPFAC ,
legalmoves [ 7 ] ? 0xFF0000FF : 0xFF000080
) ;
2017-03-23 10:53:57 +00:00
forCellAll ( c2 , cwt . c ) IG ( c2 ) drawMobileArrow ( c2 , Gm ( c2 ) ) ;
}
# endif
if ( ( vid . axes = = 4 | | ( vid . axes = = 1 & & ! mousing ) ) & & ! shmup : : on ) {
if ( multi : : players = = 1 ) {
forCellAll ( c2 , cwt . c ) IG ( c2 ) drawMovementArrows ( c2 , Gm ( c2 ) ) ;
}
else if ( multi : : players > 1 ) for ( int p = 0 ; p < multi : : players ; p + + ) {
if ( multi : : playerActive ( p ) & & ( vid . axes = = 4 | | ! drawstaratvec ( multi : : mdx [ p ] , multi : : mdy [ p ] ) ) )
forCellAll ( c2 , multi : : player [ p ] . c ) IG ( c2 ) {
multi : : cpid = p ;
dynamicval < transmatrix > ttm ( cwtV , multi : : whereis [ p ] ) ;
dynamicval < cellwalker > tcw ( cwt , multi : : player [ p ] ) ;
drawMovementArrows ( c2 , Gm ( c2 ) ) ;
}
}
}
}
monsterToSummon = moNone ;
orbToTarget = itNone ;
if ( mouseover & & targetclick & & cmode = = emNormal ) {
shmup : : cpid = 0 ;
orbToTarget = targetRangedOrb ( mouseover , roCheck ) ;
if ( orbToTarget = = itOrbSummon ) {
monsterToSummon = summonedAt ( mouseover ) ;
queuechr ( mousex , mousey , 0 , vid . fsize , minf [ monsterToSummon ] . glyph , minf [ monsterToSummon ] . color ) ;
queuecircleat ( mouseover , 0.6 , darkena ( minf [ monsterToSummon ] . color , 0 , 0xFF ) ) ;
}
else if ( orbToTarget ) {
queuechr ( mousex , mousey , 0 , vid . fsize , ' @ ' , iinf [ orbToTarget ] . color ) ;
queuecircleat ( mouseover , 0.6 , darkena ( iinf [ orbToTarget ] . color , 0 , 0xFF ) ) ;
}
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 ) ;
}
}
}
}
void drawFlashes ( ) {
for ( int k = 0 ; k < size ( flashes ) ; k + + ) {
flashdata & f = flashes [ k ] ;
transmatrix V = gmatrix [ f . where ] ;
int tim = ticks - f . t ;
bool kill = tim > f . size ;
if ( f . spd ) {
kill = tim > 300 ;
int partcol = darkena ( f . color , 0 , max ( 255 - kill / 2 , 0 ) ) ;
poly_outline = OUTLINE_NONE ;
queuepoly ( V * spin ( f . angle ) * xpush ( f . spd * tim / 50000. ) , shParticle [ f . size ] , partcol ) ;
}
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 * = hexf ;
int flashcol = f . color ;
if ( u > 500 ) flashcol = gradient ( flashcol , 0 , 500 , u , 1100 ) ;
flashcol = darkena ( flashcol , 0 , 0xFF ) ;
for ( int a = 0 ; a < = S84 ; a + + ) curvepoint ( V * ddi0 ( a , rad ) ) ;
queuecurve ( flashcol , 0x8080808 , PPR_LINE ) ;
}
}
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 * = hexf ;
int flashcol = f . color ;
if ( u > 1000 ) flashcol = gradient ( flashcol , 0 , 1000 , u , 2200 ) ;
flashcol = darkena ( flashcol , 0 , 0xFF ) ;
for ( int a = 0 ; a < = S84 ; a + + ) curvepoint ( V * ddi0 ( a , rad ) ) ;
queuecurve ( flashcol , 0x8080808 , PPR_LINE ) ;
}
}
if ( kill ) {
f = flashes [ size ( flashes ) - 1 ] ;
flashes . pop_back ( ) ; k - - ;
}
}
}
2015-08-08 13:57:52 +00:00
string buildCredits ( ) ;
string buildHelpText ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " buildHelpText \n " ) ) ;
2017-05-27 19:40:40 +00:00
# ifdef ROGUEVIZ
if ( rogueviz : : on ) return rogueviz : : help ( ) ;
# endif
2015-08-08 13:57:52 +00:00
string h ;
h + = XLAT ( " Welcome to HyperRogue " ) ;
# ifdef ANDROID
h + = XLAT ( " for Android " ) ;
# endif
# ifdef IOS
h + = XLAT ( " for iOS " ) ;
# endif
h + = XLAT ( " ! (version %1) \n \n " , VER ) ;
h + = XLAT (
2016-01-02 10:09:13 +00:00
" You have been trapped in a strange, non-Euclidean world. Collect as much treasure as possible "
" before being caught by monsters. The more treasure you collect, the more "
" monsters come to hunt you, as long as you are in the same land type. The "
" Orbs of Yendor are the ultimate treasure; get at least one of them to win the game! "
2015-08-08 13:57:52 +00:00
) ;
h + = XLAT ( " (press ESC for some hints about it). " ) ;
h + = " \n \n " ;
h + = XLAT (
2016-01-02 10:09:13 +00:00
" You can fight most monsters by moving into their location. "
" The monster could also kill you by moving into your location, but the game "
" automatically cancels all moves which result in that. \n \n "
2015-08-08 13:57:52 +00:00
) ;
2017-03-23 10:53:57 +00:00
h + = XLAT (
" There are many lands in HyperRogue. Collect 10 treasure "
" in the given land type to complete it; this enables you to "
" find the magical Orbs of this land, and in some cases "
" get access to new lands. At 25 treasures "
" this type of Orbs starts appearing in other lands as well. Press 'o' to "
" get the details of all the Lands. \n \n " ) ;
h + = " \n \n " ;
2015-08-08 13:57:52 +00:00
# ifdef MOBILE
h + = XLAT (
2016-01-02 10:09:13 +00:00
" Usually, you move by touching somewhere on the map; you can also touch one "
" of the four buttons on the map corners to change this (to scroll the map "
" or get information about map objects). You can also touch the "
" numbers displayed to get their meanings. \n "
2015-08-08 13:57:52 +00:00
) ;
# else
h + = XLAT (
2016-01-02 10:09:13 +00:00
" Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Home/Space. "
2017-03-23 10:53:57 +00:00
" To save the game you need an Orb of Safety. Press 'v' for the main menu (configuration, special modes, etc.), ESC for the quest status. \n \n "
2015-08-08 13:57:52 +00:00
) ;
h + = XLAT (
" You can right click any element to get more information about it. \n \n "
) ;
2017-03-23 10:53:57 +00:00
h + = XLAT ( " (You can also use right Shift) \n \n " ) ;
2015-08-08 13:57:52 +00:00
# endif
h + = XLAT ( " See more on the website: " )
2017-03-31 19:41:09 +00:00
+ " http//roguetemple.com/z/hyper/ \n \n " ;
2017-04-08 15:18:29 +00:00
# ifdef TOUR
h + = XLAT ( " Try the Tutorial to help with understanding the "
" geometry of HyperRogue (menu -> special modes). \n \n " ) ;
# endif
2016-01-02 10:09:13 +00:00
h + = XLAT ( " Still confused? Read the FAQ on the HyperRogue website! \n \n " ) ;
2015-08-08 13:57:52 +00:00
return h ;
}
string buildCredits ( ) {
string h ;
h + = XLAT ( " game design, programming, texts and graphics by Zeno Rogue <zeno@attnam.com> \n \n " ) ;
if ( lang ( ) ! = 0 )
h + = XLAT ( " add credits for your translation here " ) ;
# ifndef NOLICENSE
h + = XLAT (
2016-01-02 10:09:13 +00:00
" released under GNU General Public License version 2 and thus "
" comes with absolutely no warranty; see COPYING for details \n \n "
2015-08-08 13:57:52 +00:00
) ;
# endif
h + = XLAT (
2016-01-02 10:09:13 +00:00
" special thanks to the following people for their bug reports, feature requests, porting, and other help: \n \n %1 \n \n " ,
" Konstantin Stupnik, ortoslon, chrysn, Adam Borowski, Damyan Ivanov, Ryan Farnsley, mcobit, Darren Grey, tricosahedron, Maciej Chojecki, Marek Čtrnáct, "
2017-03-23 10:53:57 +00:00
" wonderfullizardofoz, Piotr Migdał, tehora, Michael Heerdegen, Sprite Guard, zelda0x181e, Vipul, snowyowl0, Patashu, phenomist, Alan Malloy, Tom Fryers, Sinquetica, _monad, CtrlAltDestroy, jruderman "
2015-08-08 13:57:52 +00:00
) ;
# ifdef EXTRALICENSE
h + = EXTRALICENSE ;
# endif
2017-03-23 10:53:57 +00:00
# ifndef MOBILE
h + = XLAT (
" \n \n See sounds/credits.txt for credits for sound effects "
) ;
# endif
2015-08-08 13:57:52 +00:00
if ( musiclicense ! = " " ) h + = musiclicense ;
return h ;
}
2016-01-02 10:09:13 +00:00
string pushtext ( stringpar p ) {
string s = XLAT (
" \n \n Note: when pushing %the1 off a heptagonal cell, you can control the pushing direction "
" by clicking left or right half of the heptagon. " , p ) ;
# ifndef MOBILE
s + = XLAT ( " With the keyboard, you can rotate the view for a similar effect (Page Up/Down). " ) ;
# endif
return s ;
}
string princedesc ( ) {
2016-08-26 09:58:03 +00:00
if ( princessgender ( ) = = GEN_M )
2016-01-02 10:09:13 +00:00
return XLAT ( " Apparently a prince is kept locked somewhere, but you won't ever find him in this hyperbolic palace. " ) ;
else
return XLAT ( " Apparently a princess is kept locked somewhere, but you won't ever find her in this hyperbolic palace. " ) ;
}
2017-03-23 10:53:57 +00:00
string helptitle ( string s , int col ) {
return " @ " + its ( col ) + " \t " + s + " \n " ;
}
string princessReviveHelp ( ) {
string h = " \n \n " +
XLAT ( " Killed %1 can be revived with Orb of the Love, after you collect 20 more $$$. " , moPrincess ) ;
if ( princess : : reviveAt )
h + = " \n \n " +
XLAT ( " %The1 will be revivable at %2 $$$ " , moPrincess , its ( princess : : reviveAt ) ) ;
return h ;
}
2015-08-08 13:57:52 +00:00
string generateHelpForItem ( eItem it ) {
2017-03-23 10:53:57 +00:00
string help = helptitle ( XLATN ( iinf [ it ] . name ) , iinf [ it ] . color ) ;
help + = XLAT ( iinf [ it ] . help ) ;
if ( it = = itSavedPrincess | | it = = itOrbLove )
help + = princessReviveHelp ( ) ;
if ( it = = itTrollEgg )
help + = XLAT ( " \n \n After the Trolls leave, you have 750 turns to collect %the1, or it gets stolen. " , it ) ;
if ( it = = itIvory | | it = = itAmethyst | | it = = itLotus | | it = = itMutant ) {
help + = XLAT (
" \n \n Easy %1 might disappear when you collect more of its kind. " , it ) ;
if ( it ! = itMutant ) help + = XLAT (
" You need to go deep to collect lots of them. " ) ;
}
# ifdef MOBILE
2015-08-08 13:57:52 +00:00
if ( it = = itOrbSafety )
2017-03-23 10:53:57 +00:00
help + = XLAT ( " This might be very useful for devices with limited memory. " ) ;
2015-08-08 13:57:52 +00:00
# else
if ( it = = itOrbSafety )
help + = XLAT ( " Thus, it is potentially useful for extremely long games, which would eat all the memory on your system otherwise. \n " ) ;
2016-08-26 09:58:03 +00:00
# endif
2017-03-23 10:53:57 +00:00
if ( isRangedOrb ( it ) ) {
help + = XLAT ( " \n This is a ranged Orb. " ) ;
# ifdef ISMOBILE
if ( vid . shifttarget & 2 )
help + = XLAT ( " \n Ranged Orbs can be targeted by long touching the desired location. " ) ;
else
help + = XLAT ( " \n Ranged Orbs can be targeted by touching the desired location. " ) ;
# else
if ( vid . shifttarget & 1 )
help + = XLAT ( " \n Ranged Orbs can be targeted by shift-clicking the desired location. "
else
help + = XLAT ( " \n Ranged Orbs can be targeted by clicking the desired location. " ) ;
help + = " You can also scroll to the desired location and then press 't'. " ) ;
2016-08-26 09:58:03 +00:00
# endif
2017-03-23 10:53:57 +00:00
help + = XLAT ( " \n You can never target cells which are adjacent to the player character, or ones out of the sight range. " ) ;
}
2016-08-26 09:58:03 +00:00
# ifdef MOBILE
if ( it = = itGreenStone )
help + = XLAT ( " You can touch the Dead Orb in your inventory to drop it. " ) ;
# else
2015-08-08 13:57:52 +00:00
if ( it = = itGreenStone )
help + = XLAT ( " You can press 'g' or click them in the list to drop a Dead Orb. " ) ;
# endif
2017-03-23 10:53:57 +00:00
if ( it = = itOrbLightning | | it = = itOrbFlash )
help + = XLAT ( " \n \n This Orb is triggered on your first attack or illegal move. " ) ;
if ( it = = itOrbShield )
help + = XLAT ( " \n \n This Orb protects you from attacks, scents, and insulates you "
" from electricity. It does not let you go through deadly terrain, but "
" if you are attacked with fire, it lets you stay in place in it. " ) ;
2016-08-26 09:58:03 +00:00
if ( it = = itOrbEmpathy ) {
int cnt = 0 ;
for ( int i = 0 ; i < ittypes ; i + + ) {
eItem it2 = eItem ( i ) ;
if ( isEmpathyOrb ( it2 ) ) {
help + = XLAT ( cnt ? " , %1 " : " %1 " , it2 ) ;
cnt + + ;
}
}
}
2017-03-23 10:53:57 +00:00
if ( itemclass ( it ) = = IC_ORB | | it = = itGreenStone | | it = = itOrbYendor ) {
eOrbLandRelation olr = getOLR ( it , cwt . c - > land ) ;
for ( int i = 0 ; i < ORBLINES ; i + + ) {
orbinfo & oi ( orbinfos [ i ] ) ;
if ( oi . orb = = it ) {
eItem tr = treasureType ( oi . l ) ;
help + = " \n \n " + XLAT ( olrDescriptions [ olr ] , cwt . c - > land , tr , treasureType ( cwt . c - > land ) ) ;
int t = items [ tr ] * landMultiplier ( oi . l ) ;
if ( t > = 25 )
if ( olr = = olrPrize25 | | olr = = olrPrize3 | | olr = = olrGuest | | olr = = olrMonster | | olr = = olrAlways ) {
help + = XLAT ( " \n Spawn rate (as prize Orb): %1%/%2 \n " ,
its ( int ( .5 + 100 * orbprizefun ( t ) ) ) ,
its ( oi . gchance ) ) ;
}
if ( t > = 10 )
if ( olr = = olrHub ) {
help + = XLAT ( " \n Spawn rate (in Hubs): %1%/%2 \n " ,
its ( int ( .5 + 100 * orbcrossfun ( t ) ) ) ,
its ( oi . gchance ) ) ;
}
}
}
}
2015-08-08 13:57:52 +00:00
return help ;
}
2017-03-23 10:53:57 +00:00
void addMinefieldExplanation ( string & s ) {
s + = XLAT (
" \n \n Once you collect 10 Bomberbird Eggs, "
" stepping on a cell with no adjacent mines also reveals the adjacent cells. "
" Collecting even more Eggs will increase the radius. Additionally, collecting "
" 25 Bomberbird Eggs will reveal adjacent cells even in your future games. "
) ;
s + = " \n \n " ;
# ifdef MOBILE
s + = XLAT ( " Known mines may be marked by pressing 'm'. Your allies won't step on marked mines. " ) ;
# else
s + = XLAT ( " Known mines may be marked by touching while in drag mode. Your allies won't step on marked mines. " ) ;
# endif
}
2016-01-02 10:09:13 +00:00
string generateHelpForWall ( eWall w ) {
2017-03-23 10:53:57 +00:00
string s = helptitle ( XLATN ( winf [ w ] . name ) , winf [ w ] . color ) ;
s + = XLAT ( winf [ w ] . help ) ;
if ( w = = waMineMine | | w = = waMineUnknown | | w = = waMineOpen )
addMinefieldExplanation ( s ) ;
2016-01-02 10:09:13 +00:00
if ( isThumper ( w ) ) s + = pushtext ( w ) ;
2016-08-26 09:58:03 +00:00
if ( ( w = = waClosePlate | | w = = waOpenPlate ) & & purehepta )
s + = " \n \n (For the heptagonal mode, the radius has been reduced to 2 for closing plates.) " ;
2016-01-02 10:09:13 +00:00
return s ;
}
2017-03-23 10:53:57 +00:00
void buteol ( string & s , int current , int req ) {
int siz = size ( s ) ;
if ( s [ siz - 1 ] = = ' \n ' ) s . resize ( siz - 1 ) ;
char buf [ 100 ] ; sprintf ( buf , " (%d/%d) " , current , req ) ;
s + = buf ; s + = " \n " ;
}
2016-01-02 10:09:13 +00:00
string generateHelpForMonster ( eMonster m ) {
2017-03-23 10:53:57 +00:00
string s = helptitle ( XLATN ( minf [ m ] . name ) , minf [ m ] . color ) ;
2017-05-27 19:40:40 +00:00
if ( m = = moPlayer ) {
# ifdef TOUR
if ( tour : : on )
return s + XLAT (
" A tourist from another world. They mutter something about the 'tutorial', "
" and claim that they are here just to learn, and to leave without any treasures. "
" Do not kill them! "
) ;
# endif
s + = XLAT (
" This monster has come from another world, presumably to steal our treasures. "
" Not as fast as an Eagle, not as resilient as the guards from the Palace, "
" and not as huge as the Mutant Ivy from the Clearing; however, "
" they are very dangerous because of their intelligence, "
" and access to magical powers. \n \n " ) ;
if ( cheater )
s + = XLAT ( " Actually, their powers appear god-like... \n \n " ) ;
else if ( ! hardcore )
s + = XLAT (
" Rogues will never make moves which result in their immediate death. "
" Even when cornered, they are able to instantly teleport back to their "
" home world at any moment, taking the treasures forever... but "
" at least they will not steal anything further! \n \n "
) ;
if ( ! euclid )
s + = XLAT (
" Despite this intelligence, Rogues appear extremely surprised "
" by the most basic facts about geometry. They must come from "
" some really strange world. \n \n "
) ;
if ( shmup : : on )
s + = XLAT ( " In the Shoot'em Up mode, you are armed with thrown Knives. " ) ;
return s ;
}
2017-03-23 10:53:57 +00:00
s + = XLAT ( minf [ m ] . help ) ;
2016-01-02 10:09:13 +00:00
if ( m = = moPalace | | m = = moSkeleton )
s + = pushtext ( m ) ;
if ( m = = moTroll ) s + = XLAT ( trollhelp2 ) ;
2016-08-26 09:58:03 +00:00
if ( isMonsterPart ( m ) )
s + = XLAT ( " \n \n This is a part of a monster. It does not count for your total kills. " , m ) ;
if ( isFriendly ( m ) )
s + = XLAT ( " \n \n This is a friendly being. It does not count for your total kills. " , m ) ;
if ( m = = moTortoise )
s + = XLAT ( " \n \n Tortoises are not monsters! They are just annoyed. They do not count for your total kills. " , m ) ;
if ( isGhost ( m ) )
s + = XLAT ( " \n \n A Ghost never moves to a cell which is adjacent to another Ghost of the same kind. " , m ) ;
2017-03-23 10:53:57 +00:00
if ( m = = moBat | | m = = moEagle )
s + = XLAT ( " \n \n Fast flying creatures may attack or go against gravity only in their first move. " , m ) ;
2016-01-02 10:09:13 +00:00
return s ;
}
string generateHelpForLand ( eLand l ) {
2017-03-23 10:53:57 +00:00
string s = helptitle ( XLATN ( linf [ l ] . name ) , linf [ l ] . color ) ;
if ( l = = laPalace ) s + = princedesc ( ) ;
s + = XLAT ( linf [ l ] . help ) ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( l = = laMinefield ) addMinefieldExplanation ( s ) ;
2016-01-02 10:09:13 +00:00
s + = " \n \n " ;
if ( l = = laIce | | l = = laCaves | | l = = laDesert | | l = = laMotion | | l = = laJungle | |
2016-08-26 09:58:03 +00:00
l = = laCrossroads | | l = = laAlchemist )
2016-01-02 10:09:13 +00:00
s + = XLAT ( " Always available. \n " ) ;
2016-08-26 09:58:03 +00:00
# define ACCONLY(z) s += XLAT("Accessible only from %the1.\n", z);
# define ACCONLY2(z,x) s += XLAT("Accessible only from %the1 or %the2.\n", z, x);
# define ACCONLYF(z) s += XLAT("Accessible only from %the1 (until finished).\n", z);
2017-03-23 10:53:57 +00:00
# define TREQ(z) { s += XLAT("Treasure required: %1 $$$.\n", #z); buteol(s, gold(), z); }
# define TREQ2(z,x) { s += XLAT("Treasure required: %1 x %2.\n", #z, x); buteol(s, items[x], z); }
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
if ( l = = laMirror | | l = = laMinefield | | l = = laPalace | |
2017-03-23 10:53:57 +00:00
l = = laOcean | | l = = laLivefjord | | l = = laZebra | | l = = laWarpCoast | | l = = laWarpSea | |
l = = laReptile | | l = = laIvoryTower )
2016-08-26 09:58:03 +00:00
TREQ ( 30 )
2017-03-23 10:53:57 +00:00
if ( isCoastal ( l ) )
s + = XLAT ( " Coastal region -- connects inland and aquatic regions. \n " ) ;
if ( isPureSealand ( l ) )
s + = XLAT ( " Aquatic region -- accessible only from coastal regions and other aquatic regions. \n " ) ;
if ( l = = laWhirlpool ) ACCONLY ( laOcean )
2016-08-26 09:58:03 +00:00
if ( l = = laRlyeh ) ACCONLYF ( laOcean )
if ( l = = laTemple ) ACCONLY ( laRlyeh )
if ( l = = laClearing ) ACCONLY ( laOvergrown )
if ( l = = laHaunted ) ACCONLY ( laGraveyard )
if ( l = = laPrincessQuest ) ACCONLY ( laPalace )
2017-03-23 10:53:57 +00:00
if ( l = = laMountain ) ACCONLY ( laJungle )
2016-08-26 09:58:03 +00:00
if ( l = = laCamelot ) ACCONLY2 ( laCrossroads , laCrossroads3 )
2016-01-02 10:09:13 +00:00
if ( l = = laDryForest | | l = = laWineyard | | l = = laDeadCaves | | l = = laHive | | l = = laRedRock | |
2017-03-23 10:53:57 +00:00
l = = laOvergrown | | l = = laStorms | | l = = laWhirlwind | | l = = laRose | |
l = = laCrossroads2 | | l = = laRlyeh )
2016-08-26 09:58:03 +00:00
TREQ ( 60 )
2017-03-23 10:53:57 +00:00
if ( l = = laReptile ) TREQ2 ( 10 , itElixir )
if ( l = = laEndorian ) TREQ2 ( 10 , itIvory )
if ( l = = laKraken ) TREQ2 ( 10 , itFjord )
if ( l = = laBurial ) TREQ2 ( 10 , itKraken )
if ( l = = laDungeon ) TREQ2 ( 5 , itIvory )
if ( l = = laDungeon ) TREQ2 ( 5 , itPalace )
if ( l = = laMountain ) TREQ2 ( 5 , itIvory )
if ( l = = laMountain ) TREQ2 ( 5 , itRuby )
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( l = = laPrairie ) TREQ ( 90 )
if ( l = = laBull ) TREQ ( 90 )
2016-08-26 09:58:03 +00:00
if ( l = = laCrossroads4 ) TREQ ( 200 )
2017-03-23 10:53:57 +00:00
if ( l = = laCrossroads5 ) TREQ ( 300 )
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( l = = laGraveyard | | l = = laHive ) {
2016-01-02 10:09:13 +00:00
s + = XLAT ( " Kills required: %1. \n " , " 100 " ) ;
2017-03-23 10:53:57 +00:00
buteol ( s , tkills ( ) , 100 ) ;
}
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( l = = laDragon ) {
2016-08-26 09:58:03 +00:00
s + = XLAT ( " Different kills required: %1. \n " , " 20 " ) ;
2017-03-23 10:53:57 +00:00
buteol ( s , killtypes ( ) , 20 ) ;
}
2016-08-26 09:58:03 +00:00
if ( l = = laTortoise ) ACCONLY ( laDragon )
if ( l = = laTortoise ) s + = XLAT ( " Find a %1 in %the2. " , itBabyTortoise , laDragon ) ;
2017-03-23 10:53:57 +00:00
if ( l = = laHell | | l = = laCrossroads3 ) {
2016-01-02 10:09:13 +00:00
s + = XLAT ( " Finished lands required: %1 (collect 10 treasure) \n " , " 9 " ) ;
2017-03-23 10:53:57 +00:00
buteol ( s , orbsUnlocked ( ) , 9 ) ;
}
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
if ( l = = laCocytus | | l = = laPower ) TREQ2 ( 10 , itHell )
if ( l = = laRedRock ) TREQ2 ( 10 , itSpice )
if ( l = = laOvergrown ) TREQ2 ( 10 , itRuby )
if ( l = = laClearing ) TREQ2 ( 5 , itMutant )
if ( l = = laCocytus ) TREQ2 ( 10 , itDiamond )
if ( l = = laDeadCaves ) TREQ2 ( 10 , itGold )
if ( l = = laTemple ) TREQ2 ( 5 , itStatue )
if ( l = = laHaunted ) TREQ2 ( 10 , itBone )
if ( l = = laCamelot ) TREQ2 ( 5 , itEmerald )
2016-01-02 10:09:13 +00:00
if ( l = = laEmerald ) {
2016-08-26 09:58:03 +00:00
TREQ2 ( 5 , itFernFlower ) TREQ2 ( 5 , itGold )
2016-01-02 10:09:13 +00:00
s + = XLAT ( " Alternatively: kill a %1 in %the2. \n " , moVizier , laPalace ) ;
2017-03-23 10:53:57 +00:00
buteol ( s , kills [ moVizier ] , 1 ) ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
# define KILLREQ(who, where) { s += XLAT("Kills required: %1 (%2).\n", who, where); buteol(s, kills[who], 1); }
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( l = = laPrincessQuest )
KILLREQ ( moVizier , laPalace ) ;
2016-08-26 09:58:03 +00:00
if ( l = = laElementalWall ) {
2017-03-23 10:53:57 +00:00
KILLREQ ( moFireElemental , laDragon ) ;
KILLREQ ( moEarthElemental , laDeadCaves ) ;
KILLREQ ( moWaterElemental , laLivefjord ) ;
KILLREQ ( moAirElemental , laWhirlwind ) ;
}
if ( l = = laTrollheim ) {
KILLREQ ( moTroll , laCaves ) ;
KILLREQ ( moFjordTroll , laLivefjord ) ;
KILLREQ ( moDarkTroll , laDeadCaves ) ;
KILLREQ ( moStormTroll , laStorms ) ;
KILLREQ ( moForestTroll , laOvergrown ) ;
KILLREQ ( moRedTroll , laRedRock ) ;
2016-08-26 09:58:03 +00:00
}
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
if ( l = = laZebra ) TREQ2 ( 10 , itFeather )
2017-03-23 10:53:57 +00:00
if ( l = = laCamelot | | l = = laPrincessQuest )
s + = XLAT ( " Completing the quest in this land is not necessary for the Hyperstone Quest. " ) ;
int rl = isRandland ( l ) ;
if ( rl = = 2 )
s + = XLAT ( " Variants of %the1 are always available in the Random Pattern Mode. " , l ) ;
else if ( rl = = 1 )
s + = XLAT (
" Variants of %the1 are available in the Random Pattern Mode after "
" getting a highscore of at least 10 %2. " , l , treasureType ( l ) ) ;
if ( l = = laPrincessQuest ) {
s + = XLAT ( " Unavailable in the shmup mode. \n " ) ;
s + = XLAT ( " Unavailable in the multiplayer mode. \n " ) ;
}
if ( noChaos ( l ) )
s + = XLAT ( " Unavailable in the Chaos mode. \n " ) ;
if ( l = = laWildWest )
s + = XLAT ( " Bonus land, available only in some special modes. \n " ) ;
if ( l = = laWhirlpool )
s + = XLAT ( " Orbs of Safety always appear here, and may be used to escape. \n " ) ;
/* if(isHaunted(l) || l == laDungeon)
s + = XLAT ( " You may be unable to leave %the1 if you are not careful! \n " , l ) ; */
if ( l = = laStorms ) {
if ( elec : : lightningfast = = 0 ) s + = XLAT ( " \n Special conduct (still valid) \n " ) ;
else s + = XLAT ( " \n Special conduct failed: \n " ) ;
s + = XLAT (
" Avoid escaping from a discharge ( \" That was close \" ). " ) ;
}
if ( isHaunted ( l ) ) {
if ( survivalist ) s + = XLAT ( " \n Special conduct (still valid) \n " ) ;
else s + = XLAT ( " \n Special conduct failed: \n " ) ;
2016-08-26 09:58:03 +00:00
2016-01-02 10:09:13 +00:00
s + = XLAT (
2017-03-23 10:53:57 +00:00
" Avoid chopping trees, using Orbs, and non-graveyard monsters in the Haunted Woods. "
) ;
}
# ifndef ISMOBILE
if ( l = = laCA )
s + = XLAT ( " \n \n Hint: use 'm' to toggle cells quickly " ) ;
# endif
2016-01-02 10:09:13 +00:00
return s ;
}
2017-03-23 10:53:57 +00:00
bool instat ;
2017-05-27 19:40:40 +00:00
string turnstring ( int i ) {
if ( i = = 1 ) return XLAT ( " 1 turn " ) ;
else return XLAT ( " %1 turns " , its ( i ) ) ;
}
2015-08-08 13:57:52 +00:00
void describeMouseover ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " describeMouseover \n " ) ) ;
2015-08-08 13:57:52 +00:00
cell * c = mousing ? mouseover : playermoved ? NULL : centerover ;
string out = mouseovers ;
2017-03-23 10:53:57 +00:00
if ( ! c | | instat | | getcstat ) { }
2016-01-02 10:09:13 +00:00
else if ( cmode = = emNormal | | cmode = = emQuit | | cmode = = emMapEditor ) {
2015-08-08 13:57:52 +00:00
out = XLAT1 ( linf [ c - > land ] . name ) ;
2016-01-02 10:09:13 +00:00
help = generateHelpForLand ( c - > land ) ;
// Celsius
2015-08-08 13:57:52 +00:00
// if(c->land == laIce) out = "Icy Lands (" + fts(60 * (c->heat - .4)) + " C)";
2017-03-23 10:53:57 +00:00
2016-01-02 10:09:13 +00:00
if ( c - > land = = laIce | | c - > land = = laCocytus )
2016-08-26 09:58:03 +00:00
out + = " ( " + fts ( heat : : celsius ( c ) ) + " °C) " ;
2016-01-02 10:09:13 +00:00
if ( c - > land = = laDryForest & & c - > landparam )
out + = " ( " + its ( c - > landparam ) + " /10) " ;
2016-08-26 09:58:03 +00:00
if ( c - > land = = laOcean & & chaosmode )
out + = " ( " + its ( c - > CHAOSPARAM ) + " S " + its ( c - > SEADIST ) + " L " + its ( c - > LANDDIST ) + " ) " ;
2017-03-23 10:53:57 +00:00
else if ( c - > land = = laOcean & & c - > landparam < = 25 ) {
if ( shmup : : on )
out + = " ( " + its ( c - > landparam ) + " ) " ;
else {
bool b = c - > landparam > = tide [ ( turncount - 1 ) % tidalsize ] ;
int t = 1 ;
for ( ; t < 1000 & & b = = ( c - > landparam > = tide [ ( turncount + t - 1 ) % tidalsize ] ) ; t + + ) ;
if ( b )
2017-05-27 19:40:40 +00:00
out + = " ( " + turnstring ( t ) + XLAT ( " to surface " ) + " ) " ;
2017-03-23 10:53:57 +00:00
else
2017-05-27 19:40:40 +00:00
out + = " ( " + turnstring ( t ) + XLAT ( " to submerge " ) + " ) " ;
2017-03-23 10:53:57 +00:00
}
}
2016-08-26 09:58:03 +00:00
if ( c - > land = = laTortoise & & tortoise : : seek ( ) ) out + = " " + tortoise : : measure ( getBits ( c ) ) ;
/* if(c->land == laGraveyard || c->land == laHauntedBorder || c->land == laHaunted)
out + = " ( " + its ( c - > landparam ) + " ) " ; */
2016-01-02 10:09:13 +00:00
if ( buggyGeneration ) {
char buf [ 20 ] ; sprintf ( buf , " H=%d M=%d " , c - > landparam , c - > mpdist ) ; out + = buf ;
}
// if(c->land == laBarrier)
// out += "(" + string(linf[c->barleft].name) + " / " + string(linf[c->barright].name) + ")";
2016-08-26 09:58:03 +00:00
// out += "(" + its(c->bardir) + ":" + string(linf[c->barleft].name) + " / " + string(linf[c->barright].name) + ")";
2016-01-02 10:09:13 +00:00
// out += " MD"+its(c->mpdist);
2016-08-26 09:58:03 +00:00
// out += " WP:" + its(c->wparam);
// out += " rose:" + its(rosemap[c]/4) + "." + its(rosemap[c]%4);
// out += " MP:" + its(c->mpdist);
// out += " cda:" + its(celldistAlt(c));
/* out += " DP=" + its(celldistance(c, cwt.c));
out + = " DO= " + its ( celldist ( c ) ) ;
out + = " PD= " + its ( c - > pathdist ) ; */
2017-05-27 19:40:40 +00:00
if ( false ) {
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
out + = " LP: " + itsh ( c - > landparam ) + " / " + its ( turncount ) ;
2017-04-04 09:13:15 +00:00
out + = " CD: " + its ( celldist ( c ) ) ;
2017-03-23 10:53:57 +00:00
out + = " D: " + its ( c - > mpdist ) ;
2016-08-26 09:58:03 +00:00
char zz [ 64 ] ; sprintf ( zz , " P%p " , c ) ; out + = zz ;
// out += " rv" + its(rosedist(c));
// if(rosemap.count(c))
// out += " rv " + its(rosemap[c]/8) + "." + its(rosemap[c]%8);
// out += " ai" + its(c->aitmp);
if ( euclid ) {
for ( int i = 0 ; i < 4 ; i + + ) out + = " " + its ( getEuclidCdata ( c - > master ) - > val [ i ] ) ;
out + = " " + itsh ( getBits ( c ) ) ;
}
else {
for ( int i = 0 ; i < 4 ; i + + ) out + = " " + its ( getHeptagonCdata ( c - > master ) - > val [ i ] ) ;
// out += " " + itsh(getHeptagonCdata(c->master)->bits);
out + = " " + fts ( tortoise : : getScent ( getBits ( c ) ) ) ;
}
// itsh(getHeptagonCdata(c->master)->bits);
// out += " barleft: " + s0 + dnameof(c->barleft);
// out += " barright: " + s0 + dnameof(c->barright);
}
2016-01-02 10:09:13 +00:00
// char zz[64]; sprintf(zz, " P%p", c); out += zz;
2016-08-26 09:58:03 +00:00
/* whirlwind::calcdirs(c);
for ( int i = 0 ; i < whirlwind : : qdirs ; i + + )
out + = " " + its ( whirlwind : : dfrom [ i ] ) + " : " + its ( whirlwind : : dto [ i ] ) ; */
// out += " : " + its(whirlwinddir(c));
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
if ( randomPatternsMode )
out + = " " + describeRPM ( c - > land ) ;
if ( euclid & & cheater ) {
eucoord x , y ;
decodeMaster ( c - > master , x , y ) ;
out + = " ( " + its ( short ( x ) ) + " , " + its ( short ( y ) ) + " ) " ;
}
2016-01-02 10:09:13 +00:00
// char zz[64]; sprintf(zz, " P%d", princess::dist(c)); out += zz;
// out += " MD"+its(c->mpdist);
// out += " H "+its(c->heat);
2017-03-23 10:53:57 +00:00
// if(c->type != 6) out += " Z"+its(c->master->zebraval);
2016-01-02 10:09:13 +00:00
// out += " H"+its(c->heat);
2015-08-08 13:57:52 +00:00
/* // Hive debug
if ( c - > land = = laHive ) {
out + = " [ " + its ( c - > tmp ) + " H " + its ( int ( c - > heat ) ) ;
if ( c - > tmp > = 0 & & c - > tmp < size ( buginfo ) & & buginfo [ c - > tmp ] . where = = c ) {
buginfo_t b ( buginfo [ c - > tmp ] ) ;
for ( int k = 0 ; k < 3 ; k + + ) out + = " : " + its ( b . dist [ k ] ) ;
for ( int k = 0 ; k < 3 ; k + + )
for ( int i = 0 ; i < size ( bugqueue [ k ] ) ; i + + )
if ( bugqueue [ k ] [ i ] = = c - > tmp )
out + = " B " + its ( k ) + " : " + its ( i ) ;
}
out + = " ] " ;
} */
2016-01-02 10:09:13 +00:00
if ( c - > wall & &
2016-08-26 09:58:03 +00:00
! ( ( c - > wall = = waFloorA | | c - > wall = = waFloorB | | c - > wall = = waFloorC | | c - > wall = = waFloorD ) & & c - > item ) ) {
2015-08-08 13:57:52 +00:00
out + = " , " ; out + = XLAT1 ( winf [ c - > wall ] . name ) ;
2016-08-26 09:58:03 +00:00
if ( c - > wall = = waRose ) out + = " ( " + its ( 7 - rosephase ) + " ) " ;
if ( ( c - > wall = = waBigTree | | c - > wall = = waSmallTree ) & & c - > land ! = laDryForest )
help =
2017-03-23 10:53:57 +00:00
" Trees in this forest can be chopped down. Big trees take two turns to chop down. " ;
2016-08-26 09:58:03 +00:00
else if ( c - > wall ! = waSea & & c - > wall ! = waPalace )
2016-01-02 10:09:13 +00:00
if ( ! ( ( c - > wall = = waCavefloor | | c - > wall = = waCavewall ) & & c - > land = = laEmerald ) )
help = generateHelpForWall ( c - > wall ) ;
2015-08-08 13:57:52 +00:00
}
2016-01-02 10:09:13 +00:00
if ( isActivable ( c ) ) out + = XLAT ( " (touch to activate) " ) ;
2017-05-27 19:40:40 +00:00
if ( hasTimeout ( c ) ) out + = XLAT ( " [ " + turnstring ( c - > wparam ) + " ] " ) ;
2017-03-23 10:53:57 +00:00
if ( isReptile ( c - > wall ) )
2017-05-27 19:40:40 +00:00
out + = XLAT ( " [ " + turnstring ( ( unsigned char ) c - > wparam ) + " ] " ) ;
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
if ( c - > monst ) {
out + = " , " ; out + = XLAT1 ( minf [ c - > monst ] . name ) ;
if ( hasHitpoints ( c - > monst ) )
out + = " ( " + its ( c - > hitpoints ) + " HP) " ;
2016-08-26 09:58:03 +00:00
if ( isMutantIvy ( c ) )
out + = " ( " + its ( ( c - > stuntime - mutantphase ) & 15 ) + " *) " ;
else if ( c - > stuntime )
2016-01-02 10:09:13 +00:00
out + = " ( " + its ( c - > stuntime ) + " *) " ;
2016-08-26 09:58:03 +00:00
if ( c - > monst = = moTortoise & & tortoise : : seek ( ) )
out + = " " + tortoise : : measure ( tortoise : : getb ( c ) ) ;
2016-01-02 10:09:13 +00:00
help = generateHelpForMonster ( c - > monst ) ;
}
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
if ( c - > item & & ! itemHiddenFromSight ( c ) ) {
2015-08-08 13:57:52 +00:00
out + = " , " ;
out + = XLAT1 ( iinf [ c - > item ] . name ) ;
2017-03-23 10:53:57 +00:00
if ( c - > item = = itBarrow ) out + = " (x " + its ( c - > landparam ) + " ) " ;
2016-08-26 09:58:03 +00:00
if ( c - > item = = itBabyTortoise & & tortoise : : seek ( ) )
out + = " " + tortoise : : measure ( tortoise : : babymap [ c ] ) ;
2015-08-08 13:57:52 +00:00
if ( ! c - > monst ) help = generateHelpForItem ( c - > item ) ;
}
2017-05-27 19:40:40 +00:00
if ( isPlayerOn ( c ) & & ! shmup : : on ) out + = XLAT ( " , you " ) , help = generateHelpForMonster ( moPlayer ) ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( shmup : : mousetarget & & intval ( mouseh , tC0 ( shmup : : mousetarget - > pat ) ) < .1 ) {
out + = " , " ;
# ifdef ROGUEVIZ
if ( shmup : : mousetarget - > type = = moRogueviz ) {
help = XLAT ( minf [ shmup : : mousetarget - > type ] . help ) ;
out + = rogueviz : : describe ( shmup : : mousetarget ) ;
}
else
# endif
{
out + = XLAT1 ( minf [ shmup : : mousetarget - > type ] . name ) ;
2017-05-27 19:40:40 +00:00
help = generateHelpForMonster ( shmup : : mousetarget - > type ) ;
2017-03-23 10:53:57 +00:00
}
2016-01-02 10:09:13 +00:00
/* char buf[64];
sprintf ( buf , " %Lf " , intval ( mouseh , shmup : : mousetarget - > pat * C0 ) ) ;
mouseovers = mouseovers + " D: " + buf ;
printf ( " ms = %s \n " , mouseovers . c_str ( ) ) ; */
2016-08-26 09:58:03 +00:00
}
if ( rosedist ( c ) = = 1 )
out + = " , wave of scent (front) " ;
if ( rosedist ( c ) = = 2 )
out + = " , wave of scent (back) " ;
2017-03-23 10:53:57 +00:00
if ( sword : : at ( c ) ) out + = " , Energy Sword " ;
2016-08-26 09:58:03 +00:00
if ( rosedist ( c ) | | c - > land = = laRose | | c - > wall = = waRose )
help + = s0 + " \n \n " + rosedesc ;
if ( isWarped ( c ) & & ! isWarped ( c - > land ) )
out + = " , warped " ;
if ( isWarped ( c ) )
help + = s0 + " \n \n " + warpdesc ;
2016-01-02 10:09:13 +00:00
2015-08-08 13:57:52 +00:00
}
else if ( cmode = = emVisual1 ) {
if ( getcstat = = ' p ' ) {
out = XLAT ( " 0 = Klein model, 1 = Poincaré model " ) ;
if ( vid . alpha < - 0.5 )
out = XLAT ( " you are looking through it! " ) ;
2016-08-26 09:58:03 +00:00
if ( vid . alpha > 5 )
out = XLAT ( " (press 'i' to approach infinity (Gans model) " ) ;
2015-08-08 13:57:52 +00:00
}
else if ( getcstat = = ' r ' ) {
out = XLAT ( " simply resize the window to change resolution " ) ;
}
2017-03-23 10:53:57 +00:00
/* else if(getcstat == 'f') {
2015-08-08 13:57:52 +00:00
out = XLAT ( " [+] keep the window size, [-] use the screen resolution " ) ;
2017-03-23 10:53:57 +00:00
} */
else if ( getcstat = = ' a ' & & vid . sspeed > - 4.99 )
2015-08-08 13:57:52 +00:00
out = XLAT ( " +5 = center instantly, -5 = do not center the map " ) ;
else if ( getcstat = = ' a ' )
out = XLAT ( " press Space or Home to center on the PC " ) ;
else if ( getcstat = = ' w ' )
out = XLAT ( " also hold Alt during the game to toggle high contrast " ) ;
else if ( getcstat = = ' w ' | | getcstat = = ' m ' )
out = XLAT ( " You can choose one of the several modes " ) ;
else if ( getcstat = = ' c ' )
out = XLAT ( " The axes help with keyboard movement " ) ;
else if ( getcstat = = ' g ' )
out = XLAT ( " Affects looks and grammar " ) ;
# ifndef MOBILE
else if ( getcstat = = ' s ' )
out = XLAT ( " Config file: %1 " , conffile ) ;
# endif
else out = " " ;
}
else if ( cmode = = emVisual2 ) {
2016-01-02 10:09:13 +00:00
if ( getcstat = = ' p ' ) {
2015-08-08 13:57:52 +00:00
if ( autojoy )
out = XLAT ( " joystick mode: automatic (release the joystick to move) " ) ;
if ( ! autojoy )
out = XLAT ( " joystick mode: manual (press a button to move) " ) ;
}
else if ( getcstat = = ' e ' )
out = XLAT ( " You need special glasses to view the game in 3D " ) ;
else if ( getcstat = = ' f ' )
out = XLAT ( " Reduce the framerate limit to conserve CPU energy " ) ;
}
2016-01-02 10:09:13 +00:00
else if ( cmode = = emChangeMode ) {
if ( getcstat = = ' h ' )
out = XLAT ( " One wrong move and it is game over! " ) ;
}
2015-08-08 13:57:52 +00:00
mouseovers = out ;
2016-01-02 10:09:13 +00:00
int col = linf [ cwt . c - > land ] . color ;
if ( cwt . c - > land = = laRedRock ) col = 0xC00000 ;
2017-03-23 10:53:57 +00:00
# ifndef MOBILE
displayfr ( vid . xres / 2 , vid . fsize , 2 , vid . fsize , out , col , 8 ) ;
2016-08-26 09:58:03 +00:00
# endif
2017-03-23 10:53:57 +00:00
2015-08-08 13:57:52 +00:00
if ( mousey < vid . fsize * 3 / 2 ) getcstat = SDLK_F1 ;
2016-01-02 10:09:13 +00:00
if ( false & & shmup : : mousetarget ) {
char buf [ 64 ] ;
2017-03-23 10:53:57 +00:00
sprintf ( buf , " %Lf " , ( long double ) intval ( mouseh , tC0 ( shmup : : mousetarget - > pat ) ) ) ;
2016-01-02 10:09:13 +00:00
mouseovers = mouseovers + " D: " + buf ;
return ;
}
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
void drawrec ( const heptspin & hs , int lev , hstate s , const transmatrix & V ) {
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
// shmup::calc_relative_matrix(cwt.c, hs.h);
2016-08-26 09:58:03 +00:00
2015-08-08 13:57:52 +00:00
cell * c = hs . h - > c7 ;
2017-03-23 10:53:57 +00:00
transmatrix V10 ;
const transmatrix & V1 = hs . mirrored ? ( V10 = V * Mirror ) : V ;
if ( dodrawcell ( c ) ) {
reclevel = maxreclevel - lev ;
drawcell ( c , ( hs . spin | | purehepta ) ? V1 * spin ( hs . spin * 2 * M_PI / S7 + ( purehepta ? M_PI : 0 ) ) : V1 , hs . spin ,
hs . mirrored ) ;
}
2015-08-08 13:57:52 +00:00
if ( lev < = 0 ) return ;
2017-03-23 10:53:57 +00:00
if ( ! purehepta ) for ( int d = 0 ; d < S7 ; d + + ) {
2015-08-08 13:57:52 +00:00
int ds = fixrot ( hs . spin + d ) ;
2017-03-23 10:53:57 +00:00
reclevel = maxreclevel - lev + 1 ;
2015-08-08 13:57:52 +00:00
// createMov(c, ds);
2017-03-23 10:53:57 +00:00
if ( c - > mov [ ds ] & & c - > spn ( ds ) = = 0 & & dodrawcell ( c - > mov [ ds ] ) ) {
drawcell ( c - > mov [ ds ] , V1 * hexmove [ d ] , 0 , hs . mirrored ^ c - > mirror ( ds ) ) ;
}
2015-08-08 13:57:52 +00:00
}
if ( lev < = 1 ) return ;
2017-03-23 10:53:57 +00:00
for ( int d = 0 ; d < S7 ; d + + ) {
2015-08-08 13:57:52 +00:00
hstate s2 = transition ( s , d ) ;
if ( s2 = = hsError ) continue ;
heptspin hs2 = hsstep ( hsspin ( hs , d ) , 0 ) ;
drawrec ( hs2 , lev - 2 , s2 , V * heptmove [ d ] ) ;
}
}
int mindx = - 7 , mindy = - 7 , maxdx = 7 , maxdy = 7 ;
2017-03-23 10:53:57 +00:00
transmatrix eumove ( int x , int y ) {
transmatrix Mat = Id ;
Mat [ 2 ] [ 2 ] = 1 ;
Mat [ 0 ] [ 2 ] + = ( x + y * .5 ) * eurad ;
// Mat[2][0] += (x + y * .5) * eurad;
Mat [ 1 ] [ 2 ] + = y * q3 / 2 * eurad ;
// Mat[2][1] += y * q3 /2 * eurad;
while ( Mat [ 0 ] [ 2 ] < = - 16384 * eurad ) Mat [ 0 ] [ 2 ] + = 32768 * eurad ;
while ( Mat [ 0 ] [ 2 ] > = 16384 * eurad ) Mat [ 0 ] [ 2 ] - = 32768 * eurad ;
while ( Mat [ 1 ] [ 2 ] < = - 16384 * q3 * eurad ) Mat [ 1 ] [ 2 ] + = 32768 * q3 * eurad ;
while ( Mat [ 1 ] [ 2 ] > = 16384 * q3 * eurad ) Mat [ 1 ] [ 2 ] - = 32768 * q3 * eurad ;
return Mat ;
}
2015-08-08 13:57:52 +00:00
void drawEuclidean ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " drawEuclidean \n " ) ) ;
2015-08-08 13:57:52 +00:00
eucoord px , py ;
2017-03-23 10:53:57 +00:00
if ( ! centerover ) centerover = cwt . c ;
2016-01-02 10:09:13 +00:00
// printf("centerover = %p player = %p [%d,%d]-[%d,%d]\n", lcenterover, cwt.c,
// mindx, mindy, maxdx, maxdy);
2017-03-23 10:53:57 +00:00
decodeMaster ( centerover - > master , px , py ) ;
2015-08-08 13:57:52 +00:00
int minsx = mindx - 1 , maxsx = maxdx + 1 , minsy = mindy - 1 , maxsy = maxdy + 1 ;
mindx = maxdx = mindy = maxdy = 0 ;
for ( int dx = minsx ; dx < = maxsx ; dx + + )
for ( int dy = minsy ; dy < = maxsy ; dy + + ) {
eucoord x = dx + px ;
eucoord y = dy + py ;
2017-03-23 10:53:57 +00:00
reclevel = eudist ( dx , dy ) ;
2015-08-08 13:57:52 +00:00
cell * c = euclideanAt ( x , y ) ;
if ( ! c ) continue ;
2017-03-23 10:53:57 +00:00
transmatrix Mat = eumove ( x , y ) ;
2015-08-08 13:57:52 +00:00
Mat = View * Mat ;
// Mat[0][0] = -1;
// Mat[1][1] = -1;
// Mat[2][0] = x*x/10;
// Mat[2][1] = y*y/10;
// Mat = Mat * xpush(x-30) * ypush(y-30);
int cx , cy , shift ;
2017-03-23 10:53:57 +00:00
getcoord0 ( tC0 ( Mat ) , cx , cy , shift ) ;
2015-08-08 13:57:52 +00:00
if ( cx > = 0 & & cy > = 0 & & cx < vid . xres & & cy < vid . yres ) {
if ( dx < mindx ) mindx = dx ;
if ( dy < mindy ) mindy = dy ;
if ( dx > maxdx ) maxdx = dx ;
if ( dy > maxdy ) maxdy = dy ;
}
2017-03-23 10:53:57 +00:00
if ( dodrawcell ( c ) ) {
drawcell ( c , Mat , 0 , false ) ;
}
2015-08-08 13:57:52 +00:00
}
}
void drawthemap ( ) {
2017-03-23 10:53:57 +00:00
frameid + + ;
if ( ! cheater & & ! svg : : in & & ! inHighQual ) {
if ( sightrange > 7 ) sightrange = 7 ;
overgenerate = false ;
}
profile_frame ( ) ;
profile_start ( 0 ) ;
swap ( gmatrix0 , gmatrix ) ;
gmatrix . clear ( ) ;
wmspatial = vid . wallmode = = 4 | | vid . wallmode = = 5 ;
wmescher = vid . wallmode = = 3 | | vid . wallmode = = 5 ;
wmplain = vid . wallmode = = 2 | | vid . wallmode = = 4 ;
wmascii = vid . wallmode = = 0 ;
wmblack = vid . wallmode = = 1 ;
mmitem = vid . monmode > = 1 ;
mmmon = vid . monmode > = 2 ;
mmhigh = vid . monmode = = 3 | | vid . monmode = = 5 ;
mmspatial = vid . monmode = = 4 | | vid . monmode = = 5 ;
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " draw the map \n " ) ) ;
2017-03-23 10:53:57 +00:00
fanframe = ticks / ( purehepta ? 300 : 150.0 ) / M_PI ;
2016-08-26 09:58:03 +00:00
2016-01-02 10:09:13 +00:00
for ( int m = 0 ; m < motypes ; m + + ) if ( isPrincess ( eMonster ( m ) ) )
minf [ m ] . name = princessgender ( ) ? " Princess " : " Prince " ;
2016-08-26 09:58:03 +00:00
2016-01-02 10:09:13 +00:00
iinf [ itSavedPrincess ] . name = minf [ moPrincess ] . name ;
2016-08-26 09:58:03 +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 ;
}
2015-08-08 13:57:52 +00:00
keycell = NULL ;
2016-01-02 10:09:13 +00:00
pirateTreasureFound = pirateTreasureSeek ;
pirateTreasureSeek = NULL ;
straightDownSeek = NULL ; downspin = 0 ;
shmup : : mousetarget = NULL ;
2017-03-23 10:53:57 +00:00
showPirateX = false ;
for ( int i = 0 ; i < numplayers ( ) ; i + + ) if ( multi : : playerActive ( i ) )
if ( playerpos ( i ) - > item = = itCompass ) showPirateX = true ;
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
using namespace yendor ;
2015-08-08 13:57:52 +00:00
if ( yii < size ( yi ) ) {
2016-08-26 09:58:03 +00:00
if ( ! yi [ yii ] . found )
for ( int i = 0 ; i < YDIST ; i + + )
if ( yi [ yii ] . path [ i ] - > cpdist < = sightrange ) {
2015-08-08 13:57:52 +00:00
keycell = yi [ yii ] . path [ i ] ;
keycelldist = YDIST - i ;
2017-03-23 10:53:57 +00:00
}
2015-08-08 13:57:52 +00:00
}
2016-01-02 10:09:13 +00:00
modist = 1e20 ; mouseover = NULL ;
modist2 = 1e20 ; mouseover2 = NULL ;
mouseovers = XLAT ( " Press F1 or right click for help " ) ;
2017-03-31 19:41:09 +00:00
# ifdef ROGUEVIZ
if ( rogueviz : : on ) mouseovers = " " ;
2017-04-08 15:18:29 +00:00
# endif
# ifdef TOUR
if ( tour : : on ) mouseovers = tour : : tourhelp ;
2017-03-31 19:41:09 +00:00
# endif
2017-03-23 10:53:57 +00:00
centdist = 1e20 ; centerover = NULL ;
for ( int i = 0 ; i < multi : : players ; i + + ) {
multi : : ccdist [ i ] = 1e20 ; multi : : ccat [ i ] = NULL ;
}
2015-08-08 13:57:52 +00:00
# ifdef MOBILE
mouseovers = XLAT ( " No info about this... " ) ;
# endif
if ( outofmap ( mouseh ) )
modist = - 5 ;
playerfound = false ;
2016-01-02 10:09:13 +00:00
// playerfoundL = false;
// playerfoundR = false;
2017-03-23 10:53:57 +00:00
sphereflip = Id ;
profile_start ( 1 ) ;
2015-08-08 13:57:52 +00:00
if ( euclid )
drawEuclidean ( ) ;
2017-03-23 10:53:57 +00:00
else {
if ( sphere & & vid . alpha > 1 ) sphereflip [ 2 ] [ 2 ] = - 1 ;
maxreclevel =
2016-08-26 09:58:03 +00:00
conformal : : on ? sightrange + 2 :
2017-03-23 10:53:57 +00:00
( ! playermoved ) ? sightrange + 1 : sightrange + 4 ;
drawrec ( viewctr ,
maxreclevel ,
hsOrigin , ypush ( vid . yshift ) * sphereflip * View ) ;
}
2017-05-27 19:40:40 +00:00
linepatterns : : drawAll ( ) ;
2017-03-23 10:53:57 +00:00
# ifdef ROGUEVIZ
rogueviz : : drawExtra ( ) ;
# endif
2017-04-08 15:18:29 +00:00
# ifdef TOUR
2017-05-27 19:40:40 +00:00
if ( tour : : on ) tour : : presentation ( tour : : pmFrame ) ;
2017-04-08 15:18:29 +00:00
# endif
2017-03-23 10:53:57 +00:00
profile_stop ( 1 ) ;
profile_start ( 4 ) ;
drawMarkers ( ) ;
profile_stop ( 4 ) ;
drawFlashes ( ) ;
if ( multi : : players > 1 & & ! shmup : : on ) {
if ( shmup : : centerplayer ! = - 1 )
cwtV = multi : : whereis [ shmup : : centerplayer ] ;
else {
hyperpoint h ;
for ( int i = 0 ; i < 3 ; i + + ) h [ i ] = 0 ;
for ( int p = 0 ; p < multi : : players ; p + + ) if ( multi : : playerActive ( p ) ) {
hyperpoint h1 = tC0 ( multi : : whereis [ p ] ) ;
for ( int i = 0 ; i < 3 ; i + + ) h [ i ] + = h1 [ i ] ;
}
h = mid ( h , h ) ;
cwtV = rgpushxto0 ( h ) ;
}
}
2016-01-02 10:09:13 +00:00
if ( shmup : : on ) {
if ( shmup : : players = = 1 )
cwtV = shmup : : pc [ 0 ] - > pat ;
2016-08-26 09:58:03 +00:00
else if ( shmup : : centerplayer ! = - 1 )
cwtV = shmup : : pc [ shmup : : centerplayer ] - > pat ;
2017-03-23 10:53:57 +00:00
else {
hyperpoint h ;
for ( int i = 0 ; i < 3 ; i + + ) h [ i ] = 0 ;
for ( int p = 0 ; p < multi : : players ; p + + ) {
hyperpoint h1 = tC0 ( shmup : : pc [ p ] - > pat ) ;
for ( int i = 0 ; i < 3 ; i + + ) h [ i ] + = h1 [ i ] ;
}
h = mid ( h , h ) ;
cwtV = rgpushxto0 ( h ) ;
}
}
2017-05-27 19:40:40 +00:00
# ifndef NOSDL
2017-03-23 10:53:57 +00:00
Uint8 * keystate = SDL_GetKeyState ( NULL ) ;
lmouseover = mouseover ;
bool useRangedOrb = ( ! ( vid . shifttarget & 1 ) & & haveRangedOrb ( ) & & lmouseover & & lmouseover - > cpdist > 1 ) | | ( keystate [ SDLK_RSHIFT ] | keystate [ SDLK_LSHIFT ] ) ;
if ( ! useRangedOrb & & cmode ! = emMapEditor & & DEFAULTCONTROL & & ! outofmap ( mouseh ) ) {
void calcMousedest ( ) ;
calcMousedest ( ) ;
cellwalker cw = cwt ; bool f = flipplayer ;
items [ itWarning ] + = 2 ;
bool recorduse [ ittypes ] ;
for ( int i = 0 ; i < ittypes ; i + + ) recorduse [ i ] = orbused [ i ] ;
movepcto ( mousedest . d , mousedest . subdir , true ) ;
for ( int i = 0 ; i < ittypes ; i + + ) orbused [ i ] = recorduse [ i ] ;
items [ itWarning ] - = 2 ;
if ( multi : : players = = 1 & & cw . spin ! = cwt . spin ) mirror : : spin ( - mousedest . d ) ;
cwt = cw ; flipplayer = f ;
lmouseover = mousedest . d > = 0 ? cwt . c - > mov [ ( cwt . spin + mousedest . d ) % cwt . c - > type ] : cwt . c ;
}
2016-08-26 09:58:03 +00:00
# endif
2017-03-23 10:53:57 +00:00
profile_stop ( 0 ) ;
2016-01-02 10:09:13 +00:00
}
void spinEdge ( ld aspd ) {
if ( downspin > aspd ) downspin = aspd ;
if ( downspin < - aspd ) downspin = - aspd ;
View = spin ( downspin ) * View ;
2015-08-08 13:57:52 +00:00
}
void centerpc ( ld aspd ) {
2017-03-23 10:53:57 +00:00
if ( vid . sspeed > = 4.99 ) aspd = 1000 ;
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " center pc \n " ) ) ;
2017-03-23 10:53:57 +00:00
hyperpoint H = ypush ( - vid . yshift ) * sphereflip * tC0 ( cwtV ) ;
if ( H [ 0 ] = = 0 & & H [ 1 ] = = 0 ) return ; // either already centered or direction unknown
ld R = hdist0 ( H ) ; // = sqrt(H[0] * H[0] + H[1] * H[1]);
2015-08-08 13:57:52 +00:00
if ( R < 1e-9 ) {
2016-01-02 10:09:13 +00:00
/* if(playerfoundL && playerfoundR) {
} */
spinEdge ( aspd ) ;
2017-03-23 10:53:57 +00:00
fixmatrix ( View ) ;
2015-08-08 13:57:52 +00:00
return ;
}
if ( euclid ) {
// Euclidean
aspd * = ( 2 + 3 * R * R ) ;
if ( aspd > R ) aspd = R ;
View [ 0 ] [ 2 ] - = cwtV [ 0 ] [ 2 ] * aspd / R ;
View [ 1 ] [ 2 ] - = cwtV [ 1 ] [ 2 ] * aspd / R ;
}
else {
2016-01-02 10:09:13 +00:00
aspd * = ( 1 + R + ( shmup : : on ? 1 : 0 ) ) ;
2015-08-08 13:57:52 +00:00
if ( R < aspd ) {
View = gpushxto0 ( H ) * View ;
}
else
View = rspintox ( H ) * xpush ( - aspd ) * spintox ( H ) * View ;
2016-01-02 10:09:13 +00:00
fixmatrix ( View ) ;
spinEdge ( aspd ) ;
2015-08-08 13:57:52 +00:00
}
}
2017-03-23 10:53:57 +00:00
void drawmovestar ( double dx , double dy ) {
2015-08-08 13:57:52 +00:00
2017-04-04 09:13:15 +00:00
if ( viewdists ) return ;
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " draw movestar \n " ) ) ;
2015-08-08 13:57:52 +00:00
if ( ! playerfound ) return ;
2016-01-02 10:09:13 +00:00
if ( shmup : : on ) return ;
2017-03-23 10:53:57 +00:00
# ifndef NORUG
if ( rug : : rugged & & multi : : players = = 1 & & ! multi : : alwaysuse ) return ;
# endif
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
hyperpoint H = tC0 ( cwtV ) ;
2015-08-08 13:57:52 +00:00
ld R = sqrt ( H [ 0 ] * H [ 0 ] + H [ 1 ] * H [ 1 ] ) ;
transmatrix Centered = Id ;
if ( euclid )
Centered = eupush ( H [ 0 ] , H [ 1 ] ) ;
else if ( R > 1e-9 ) Centered = rgpushxto0 ( H ) ;
2017-03-23 10:53:57 +00:00
Centered = Centered * rgpushxto0 ( hpxy ( dx * 5 , dy * 5 ) ) ;
if ( multi : : cpid > = 0 ) multi : : crosscenter [ multi : : cpid ] = Centered ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
int rax = vid . axes ;
if ( rax = = 1 ) rax = drawstaratvec ( dx , dy ) ? 2 : 0 ;
if ( rax = = 0 | | vid . axes = = 4 ) return ;
int starcol = getcs ( ) . uicolor ;
if ( vid . axes = = 3 )
queuepoly ( Centered , shMovestar , starcol ) ;
2015-08-08 13:57:52 +00:00
else for ( int d = 0 ; d < 8 ; d + + ) {
int col = starcol ;
# ifdef PANDORA
2017-03-23 10:53:57 +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
// EUCLIDEAN
if ( euclid )
2017-03-23 10:53:57 +00:00
queueline ( tC0 ( Centered ) , Centered * ddi0 ( d * 10.5 , 0.5 ) , col , 0 ) ;
2015-08-08 13:57:52 +00:00
else
2017-03-23 10:53:57 +00:00
// queueline(tC0(Centered), Centered * spin(M_PI*d/4)* xpush(d==0?.7:d==2?.6:.5) * C0, col >> darken);
queueline ( tC0 ( Centered ) , Centered * xspinpush0 ( M_PI * d / 4 , d = = 0 ? .7 : d = = 2 ? .5 : .2 ) , col , 3 ) ;
2015-08-08 13:57:52 +00:00
}
}
void optimizeview ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " optimize view \n " ) ) ;
2015-08-08 13:57:52 +00:00
int turn = 0 ;
ld best = INF ;
2016-08-26 09:58:03 +00:00
transmatrix TB = Id ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
for ( int i = - 1 ; i < S7 ; i + + ) {
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
ld trot = - i * M_PI * 2 / ( S7 + .0 ) ;
transmatrix T = i < 0 ? Id : spin ( trot ) * xpush ( tessf ) * pispin ;
hyperpoint H = View * tC0 ( T ) ;
2015-08-08 13:57:52 +00:00
if ( H [ 2 ] < best ) best = H [ 2 ] , turn = i , TB = T ;
}
if ( turn > = 0 ) {
View = View * TB ;
fixmatrix ( View ) ;
viewctr = hsspin ( viewctr , turn ) ;
viewctr = hsstep ( viewctr , 0 ) ;
}
}
2016-01-02 10:09:13 +00:00
movedir vectodir ( const hyperpoint & P ) {
2017-03-23 10:53:57 +00:00
hyperpoint H = sphereflip * tC0 ( cwtV ) ;
2015-08-08 13:57:52 +00:00
ld R = sqrt ( H [ 0 ] * H [ 0 ] + H [ 1 ] * H [ 1 ] ) ;
2017-03-23 10:53:57 +00:00
transmatrix Centered = sphereflip * cwtV ;
2015-08-08 13:57:52 +00:00
if ( ! euclid )
2017-03-23 10:53:57 +00:00
Centered = gpushxto0 ( H ) * Centered ;
2015-08-08 13:57:52 +00:00
else if ( R > 1e-9 )
Centered = eupush ( - H [ 0 ] , - H [ 1 ] ) * Centered ;
ld binv = 99 ;
2016-01-02 10:09:13 +00:00
ld dirdist [ 7 ] ;
2017-03-23 10:53:57 +00:00
for ( int i = 0 ; i < cwt . c - > type ; i + + ) {
dirdist [ i ] = intval ( Centered * xspinpush0 ( - i * 2 * M_PI / cwt . c - > type , .5 ) , P ) ;
}
2016-01-02 10:09:13 +00:00
movedir res ;
res . d = - 1 ;
2015-08-08 13:57:52 +00:00
for ( int i = 0 ; i < cwt . c - > type ; i + + ) {
2016-01-02 10:09:13 +00:00
if ( dirdist [ i ] < binv ) {
binv = dirdist [ i ] ;
res . d = i ;
res . subdir = dirdist [ ( i + 1 ) % cwt . c - > type ] < dirdist [ ( i + cwt . c - > type - 1 ) % cwt . c - > type ] ? 1 : - 1 ;
2017-03-23 10:53:57 +00:00
if ( sphere ) res . subdir = - res . subdir ;
2016-01-02 10:09:13 +00:00
}
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
2015-08-08 13:57:52 +00:00
// if(euclid) bdir = (bdir + 3) % 6;
2016-01-02 10:09:13 +00:00
return res ;
2015-08-08 13:57:52 +00:00
}
void movepckeydir ( int d ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " movepckeydir \n " ) ) ;
2015-08-08 13:57:52 +00:00
// EUCLIDEAN
2017-03-23 10:53:57 +00:00
movedir md =
vectodir ( spin ( - d * M_PI / 4 ) * tC0 ( pushone ( ) ) ) ;
movepcto ( md ) ;
2015-08-08 13:57:52 +00:00
}
2016-01-02 10:09:13 +00:00
void calcMousedest ( ) {
if ( outofmap ( mouseh ) ) return ;
2016-08-26 09:58:03 +00:00
if ( revcontrol = = true ) { mouseh [ 0 ] = - mouseh [ 0 ] ; mouseh [ 1 ] = - mouseh [ 1 ] ; }
2017-03-23 10:53:57 +00:00
ld mousedist = intval ( mouseh , tC0 ( shmup : : ggmatrix ( cwt . c ) ) ) ;
2016-01-02 10:09:13 +00:00
mousedest . d = - 1 ;
2017-03-23 10:53:57 +00:00
cellwalker bcwt = cwt ;
2016-01-02 10:09:13 +00:00
ld dists [ 7 ] ;
2017-03-23 10:53:57 +00:00
for ( int i = 0 ; i < cwt . c - > type ; i + + )
dists [ i ] = intval ( mouseh , tC0 ( shmup : : ggmatrix ( cwt . c - > mov [ i ] ) ) ) ;
2016-01-02 10:09:13 +00:00
/* printf("curcell = %Lf\n", mousedist);
for ( int i = 0 ; i < cwt . c - > type ; i + + )
printf ( " d%d = %Lf \n " , i , dists [ i ] ) ; */
for ( int i = 0 ; i < cwt . c - > type ; i + + ) if ( dists [ i ] < mousedist ) {
mousedist = dists [ i ] ;
mousedest . d = fixdir ( i - cwt . spin , cwt . c ) ;
mousedest . subdir =
dists [ ( i + 1 ) % cwt . c - > type ] < dists [ ( i + cwt . c - > type - 1 ) % cwt . c - > type ] ? 1 : - 1 ;
2017-03-23 10:53:57 +00:00
if ( cwt . mirrored )
mousedest . d = fixdir ( - mousedest . d , cwt . c ) ,
mousedest . subdir = - mousedest . subdir ;
if ( sphere ) mousedest . subdir = - mousedest . subdir ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
if ( revcontrol = = true ) { mouseh [ 0 ] = - mouseh [ 0 ] ; mouseh [ 1 ] = - mouseh [ 1 ] ; }
cwt = bcwt ;
2016-01-02 10:09:13 +00:00
}
void mousemovement ( ) {
calcMousedest ( ) ;
movepcto ( mousedest ) ;
2017-03-23 10:53:57 +00:00
lmouseover = NULL ;
2016-01-02 10:09:13 +00:00
}
long double sqr ( long double x ) { return x * x ; }
2017-03-23 10:53:57 +00:00
// old style joystick control
2015-08-08 13:57:52 +00:00
void checkjoy ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " check joy \n " ) ) ;
2017-03-23 10:53:57 +00:00
if ( ! DEFAULTCONTROL ) return ;
2016-01-02 10:09:13 +00:00
ld joyvalue1 = sqr ( vid . joyvalue ) ;
ld joyvalue2 = sqr ( vid . joyvalue2 ) ;
2015-08-08 13:57:52 +00:00
ld jx = joyx ;
ld jy = joyy ;
ld sq = jx * jx + jy * jy ;
2017-03-23 10:53:57 +00:00
static int laststate = 0 ;
int curstate = sq < joyvalue1 ? 0 : sq < joyvalue2 ? 1 : 2 ;
if ( curstate ! = laststate ) flashMessages ( ) , laststate = curstate ;
2015-08-08 13:57:52 +00:00
if ( autojoy ) {
2016-01-02 10:09:13 +00:00
if ( sq < joyvalue1 ) { if ( joydir . d > = 0 ) movepcto ( joydir ) ; joydir . d = - 1 ; return ; }
if ( sq < joyvalue2 & & joydir . d = = - 1 ) return ;
2015-08-08 13:57:52 +00:00
}
else {
2016-01-02 10:09:13 +00:00
if ( sq < joyvalue1 ) { joydir . d = - 1 ; return ; }
2015-08-08 13:57:52 +00:00
}
joydir = vectodir ( hpxy ( jx , jy ) ) ;
}
void checkpanjoy ( double t ) {
2016-01-02 10:09:13 +00:00
if ( shmup : : on ) return ;
if ( vid . joypanspeed < 1e-7 ) return ;
if ( sqr ( panjoyx ) + sqr ( panjoyy ) < sqr ( vid . joypanthreshold ) )
2015-08-08 13:57:52 +00:00
return ;
ld jx = panjoyx * t * vid . joypanspeed ;
ld jy = panjoyy * t * vid . joypanspeed ;
playermoved = false ;
View = gpushxto0 ( hpxy ( jx , jy ) ) * View ;
}
2017-03-23 10:53:57 +00:00
int realradius ;
2017-04-04 09:13:15 +00:00
bool sidescreen ;
2017-05-27 19:40:40 +00:00
bool dronemode ;
2015-08-08 13:57:52 +00:00
void calcparam ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " calc param \n " ) ) ;
2015-08-08 13:57:52 +00:00
vid . xcenter = vid . xres / 2 ;
vid . ycenter = vid . yres / 2 ;
2017-03-23 10:53:57 +00:00
realradius = min ( vid . xcenter , vid . ycenter ) ;
2015-08-08 13:57:52 +00:00
vid . radius = int ( vid . scale * vid . ycenter ) - ( ISANDROID ? 2 : ISIOS ? 40 : 40 ) ;
2017-03-23 10:53:57 +00:00
realradius = min ( realradius , vid . radius ) ;
2017-04-04 09:13:15 +00:00
sidescreen = false ;
2015-08-08 13:57:52 +00:00
if ( vid . xres < vid . yres ) {
vid . radius = int ( vid . scale * vid . xcenter ) - ( ISIOS ? 10 : 2 ) ;
2017-03-23 10:53:57 +00:00
vid . ycenter = vid . yres - realradius - vid . fsize - ( ISIOS ? 10 : 0 ) ;
2015-08-08 13:57:52 +00:00
}
2017-04-04 09:13:15 +00:00
else {
2017-04-08 15:18:29 +00:00
if ( vid . xres > = vid . yres * 5 / 4 - 16 & & dialog : : sidedialog & & cmode = = emNumber )
2017-04-04 09:13:15 +00:00
sidescreen = true ;
2017-04-08 15:18:29 +00:00
if ( viewdists & & cmode = = emNormal & & vid . xres > vid . yres ) sidescreen = true ;
2017-04-04 09:13:15 +00:00
if ( sidescreen ) vid . xcenter = vid . yres / 2 ;
}
2017-05-27 19:40:40 +00:00
if ( dronemode ) { vid . ycenter - = vid . radius ; vid . ycenter + = vid . fsize / 2 ; vid . ycenter + = vid . fsize / 2 ; vid . radius * = 2 ; }
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
ld eye = vid . eye ; if ( pmodel | | rug : : rugged ) eye = 0 ;
vid . beta = 1 + vid . alpha + eye ;
vid . alphax = vid . alpha + eye ;
2015-08-08 13:57:52 +00:00
vid . goteyes = vid . eye > 0.001 | | vid . eye < - 0.001 ;
2016-08-26 09:58:03 +00:00
vid . goteyes2 = vid . goteyes ;
2015-08-08 13:57:52 +00:00
}
2016-01-02 10:09:13 +00:00
void displayButton ( int x , int y , const string & name , int key , int align , int rad ) {
2015-08-08 13:57:52 +00:00
if ( displayfr ( x , y , rad , vid . fsize , name , 0x808080 , align ) ) {
displayfr ( x , y , rad , vid . fsize , name , 0xFFFF00 , align ) ;
getcstat = key ;
}
}
2017-03-23 10:53:57 +00:00
bool displayButtonS ( int x , int y , const string & name , int col , int align , int size ) {
if ( displaystr ( x , y , 0 , size , name , col , align ) ) {
displaystr ( x , y , 0 , size , name , 0xFFFF00 , align ) ;
return true ;
}
else return false ;
}
2016-01-02 10:09:13 +00:00
void displayColorButton ( int x , int y , const string & name , int key , int align , int rad , int color , int color2 ) {
if ( displayfr ( x , y , rad , vid . fsize , name , color , align ) ) {
if ( color2 ) displayfr ( x , y , rad , vid . fsize , name , color2 , align ) ;
getcstat = key ;
}
}
2016-08-26 09:58:03 +00:00
# ifndef MOBILE
2015-08-08 13:57:52 +00:00
void quitOrAgain ( ) {
int y = vid . yres * ( 618 ) / 1000 ;
displayButton ( vid . xres / 2 , y + vid . fsize * 1 / 2 ,
( items [ itOrbSafety ] & & havesave ) ?
XLAT ( " Press Enter or F10 to save " ) :
XLAT ( " Press Enter or F10 to quit " ) ,
SDLK_RETURN , 8 , 2 ) ;
displayButton ( vid . xres / 2 , y + vid . fsize * 2 , XLAT ( " or 'r' or F5 to restart " ) , ' r ' , 8 , 2 ) ;
displayButton ( vid . xres / 2 , y + vid . fsize * 7 / 2 , XLAT ( " or 't' to see the top scores " ) , ' t ' , 8 , 2 ) ;
2016-08-26 09:58:03 +00:00
displayButton ( vid . xres / 2 , y + vid . fsize * 10 / 2 , XLAT ( " or 'v' to see the main menu " ) , ' v ' , 8 , 2 ) ;
2016-01-02 10:09:13 +00:00
displayButton ( vid . xres / 2 , y + vid . fsize * 13 / 2 , XLAT ( " or 'o' to see the world overview " ) , ' o ' , 8 , 2 ) ;
2015-08-08 13:57:52 +00:00
}
# endif
int calcfps ( ) {
# define CFPS 30
static int last [ CFPS ] , lidx = 0 ;
int ct = ticks ;
int ret = ct - last [ lidx ] ;
last [ lidx ] = ct ;
lidx + + ; lidx % = CFPS ;
if ( ret = = 0 ) return 0 ;
return ( 1000 * CFPS ) / ret ;
}
int msgscroll = 0 ;
string timeline ( ) {
2016-08-26 09:58:03 +00:00
int timespent = ( int ) ( savetime + ( timerstopped ? 0 : ( time ( NULL ) - timerstart ) ) ) ;
2015-08-08 13:57:52 +00:00
char buf [ 20 ] ;
sprintf ( buf , " %d:%02d " , timespent / 60 , timespent % 60 ) ;
2016-01-02 10:09:13 +00:00
return
shmup : : on ?
XLAT ( " %1 knives (%2) " , its ( turncount ) , buf )
:
XLAT ( " %1 turns (%2) " , its ( turncount ) , buf ) ;
}
2015-08-08 13:57:52 +00:00
void showGameover ( ) {
2017-03-23 10:53:57 +00:00
dialog : : init (
2017-04-08 15:18:29 +00:00
# ifdef TOUR
tour : : on ? ( canmove ? XLAT ( " Tutorial " ) : XLAT ( " GAME OVER " ) ) :
# endif
2015-08-08 13:57:52 +00:00
cheater ? XLAT ( " It is a shame to cheat! " ) :
showoff ? XLAT ( " Showoff mode " ) :
2016-01-02 10:09:13 +00:00
canmove & & princess : : challenge ? XLAT ( " %1 Challenge " , moPrincess ) :
2015-08-08 13:57:52 +00:00
canmove ? XLAT ( " Quest status " ) :
2017-03-23 10:53:57 +00:00
XLAT ( " GAME OVER " ) ,
0xC00000 , 200 , 100
2015-08-08 13:57:52 +00:00
) ;
2017-03-23 10:53:57 +00:00
dialog : : addInfo ( XLAT ( " Your score: %1 " , its ( gold ( ) ) ) ) ;
dialog : : addInfo ( XLAT ( " Enemies killed: %1 " , its ( tkills ( ) ) ) ) ;
2017-04-15 02:48:59 +00:00
# ifdef TOUR
if ( tour : : on ) ; else
# endif
if ( items [ itOrbYendor ] ) {
2017-03-23 10:53:57 +00:00
dialog : : addInfo ( XLAT ( " Orbs of Yendor found: %1 " , its ( items [ itOrbYendor ] ) ) , iinf [ itOrbYendor ] . color ) ;
dialog : : addInfo ( XLAT ( " CONGRATULATIONS! " ) , iinf [ itOrbYendor ] . color ) ;
2015-08-08 13:57:52 +00:00
}
else {
2017-03-23 10:53:57 +00:00
if ( princess : : challenge )
dialog : : addInfo ( XLAT ( " Follow the Mouse and escape with %the1! " , moPrincess ) ) ;
2016-01-02 10:09:13 +00:00
else if ( gold ( ) < 30 )
2017-03-23 10:53:57 +00:00
dialog : : addInfo ( XLAT ( " Collect 30 $$$ to access more worlds " ) ) ;
2015-08-08 13:57:52 +00:00
else if ( gold ( ) < 60 )
2017-03-23 10:53:57 +00:00
dialog : : addInfo ( XLAT ( " Collect 60 $$$ to access even more lands " ) ) ;
2015-08-08 13:57:52 +00:00
else if ( ! hellUnlocked ( ) )
2017-03-23 10:53:57 +00:00
dialog : : addInfo ( XLAT ( " Collect at least 10 treasures in each of 9 types to access Hell " ) ) ;
2015-08-08 13:57:52 +00:00
else if ( items [ itHell ] < 10 )
2017-03-23 10:53:57 +00:00
dialog : : addInfo ( XLAT ( " Collect at least 10 Demon Daisies to find the Orbs of Yendor " ) ) ;
2016-08-26 09:58:03 +00:00
else if ( size ( yendor : : yi ) = = 0 )
2017-03-23 10:53:57 +00:00
dialog : : addInfo ( XLAT ( " Look for the Orbs of Yendor in Hell or in the Crossroads! " ) ) ;
2015-08-08 13:57:52 +00:00
else
2017-03-23 10:53:57 +00:00
dialog : : addInfo ( XLAT ( " Unlock the Orb of Yendor! " ) ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
if ( ! timerstopped & & ! canmove ) {
savetime + = time ( NULL ) - timerstart ;
timerstopped = true ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
if ( canmove & & ! timerstart )
timerstart = time ( NULL ) ;
if ( princess : : challenge ) ;
2017-04-08 15:18:29 +00:00
# ifdef TOUR
else if ( tour : : on ) ;
# endif
2017-03-23 10:53:57 +00:00
else if ( tkills ( ) < 100 )
dialog : : addInfo ( XLAT ( " Defeat 100 enemies to access the Graveyard " ) ) ;
else if ( kills [ moVizier ] = = 0 & & ( items [ itFernFlower ] < 5 | | items [ itGold ] < 5 ) )
dialog : : addInfo ( XLAT ( " Kill a Vizier in the Palace to access Emerald Mine " ) ) ;
2016-01-02 10:09:13 +00:00
else if ( items [ itEmerald ] < 5 )
2017-03-23 10:53:57 +00:00
dialog : : addInfo ( XLAT ( " Collect 5 Emeralds to access Camelot " ) ) ;
else if ( hellUnlocked ( ) & & ! chaosmode ) {
2015-08-08 13:57:52 +00:00
bool b = true ;
2016-08-26 09:58:03 +00:00
for ( int i = 0 ; i < LAND_HYP ; i + + )
if ( b & & items [ treasureType ( land_hyp [ i ] ) ] < 10 ) {
2017-03-23 10:53:57 +00:00
dialog : : addInfo (
2016-08-26 09:58:03 +00:00
XLAT (
land_hyp [ i ] = = laTortoise ? " Hyperstone Quest: collect at least 10 points in %the2 " :
" Hyperstone Quest: collect at least 10 %1 in %the2 " ,
2017-03-23 10:53:57 +00:00
treasureType ( land_hyp [ i ] ) , land_hyp [ i ] ) ) ;
2015-08-08 13:57:52 +00:00
b = false ;
}
2017-03-23 10:53:57 +00:00
if ( b )
dialog : : addInfo ( XLAT ( " Hyperstone Quest completed! " ) , iinf [ itHyperstone ] . color ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else dialog : : addInfo ( XLAT ( " Some lands unlock at specific treasures or kills " ) ) ;
if ( cheater ) {
dialog : : addInfo ( XLAT ( " you have cheated %1 times " , its ( cheater ) ) , 0xFF2020 ) ;
2016-01-02 10:09:13 +00:00
}
2015-08-08 13:57:52 +00:00
if ( ! cheater ) {
2017-03-23 10:53:57 +00:00
dialog : : addInfo ( timeline ( ) , 0xC0C0C0 ) ;
2015-08-08 13:57:52 +00:00
}
msgs . clear ( ) ;
if ( msgscroll < 0 ) msgscroll = 0 ;
int gls = size ( gamelog ) - msgscroll ;
int mnum = 0 ;
for ( int i = gls - 5 ; i < gls ; i + + )
if ( i > = 0 ) {
msginfo m ;
m . spamtype = 0 ;
m . flashout = true ;
m . stamp = ticks - 128 * vid . flashtime - 128 * ( gls - i ) ;
2017-03-23 10:53:57 +00:00
m . msg = gamelog [ i ] . msg ;
m . quantity = gamelog [ i ] . quantity ;
2015-08-08 13:57:52 +00:00
mnum + + ,
msgs . push_back ( m ) ;
}
2017-03-23 10:53:57 +00:00
dialog : : addBreak ( 100 ) ;
2017-04-08 15:18:29 +00:00
bool intour = false ;
# ifdef TOUR
intour = tour : : on ;
# endif
if ( intour ) {
2017-05-27 19:40:40 +00:00
# ifdef TOUR
2017-04-08 15:18:29 +00:00
if ( canmove ) {
dialog : : addItem ( " spherical geometry " , ' 1 ' ) ;
dialog : : addItem ( " Euclidean geometry " , ' 2 ' ) ;
dialog : : addItem ( " more curved hyperbolic geometry " , ' 3 ' ) ;
}
2017-04-14 18:12:23 +00:00
if ( ! items [ itOrbTeleport ] )
dialog : : addItem ( " teleport away " , ' 4 ' ) ;
else if ( ! items [ itOrbAether ] )
dialog : : addItem ( " move through walls " , ' 4 ' ) ;
else
dialog : : addItem ( " flash " , ' 4 ' ) ;
2017-04-08 15:18:29 +00:00
if ( canmove ) {
2017-05-27 19:40:40 +00:00
if ( tour : : slidecommand ! = " " )
dialog : : addItem ( tour : : slidecommand , ' 5 ' ) ;
2017-04-08 15:18:29 +00:00
dialog : : addItem ( " static mode " , ' 6 ' ) ;
dialog : : addItem ( " enable/disable texts " , ' 7 ' ) ;
dialog : : addItem ( " next slide " , SDLK_RETURN ) ;
dialog : : addItem ( " previous slide " , SDLK_BACKSPACE ) ;
}
2017-04-14 18:12:23 +00:00
else
dialog : : addBreak ( 200 ) ;
2017-04-08 15:18:29 +00:00
dialog : : addItem ( " main menu " , ' v ' ) ;
2017-05-27 19:40:40 +00:00
# endif
2017-04-08 15:18:29 +00:00
}
else {
dialog : : addItem ( canmove ? " continue " : " see how it ended " , SDLK_ESCAPE ) ;
dialog : : addItem ( " main menu " , ' v ' ) ;
dialog : : addItem ( " restart " , SDLK_F5 ) ;
# ifndef MOBILE
dialog : : addItem ( quitsaves ( ) ? " save " : " quit " , SDLK_F10 ) ;
# endif
# ifdef ANDROIDSHARE
dialog : : addItem ( " SHARE " , ' s ' - 96 ) ;
# endif
}
2017-03-23 10:53:57 +00:00
dialog : : display ( ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( mnum )
displayfr ( vid . xres / 2 , vid . yres - vid . fsize * ( mnum + 1 ) , 2 , vid . fsize / 2 , XLAT ( " last messages: " ) , 0xC0C0C0 , 8 ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
# ifdef MOBILE
2015-08-08 13:57:52 +00:00
void displayabutton ( int px , int py , string s , int col ) {
// TMP
int siz = vid . yres > vid . xres ? vid . fsize * 2 : vid . fsize * 3 / 2 ;
2017-03-23 10:53:57 +00:00
int vrx = min ( vid . radius , vid . xres / 2 - 40 ) ;
int vry = min ( vid . radius , min ( vid . ycenter , vid . yres - vid . ycenter ) - 20 ) ;
int x = vid . xcenter + px * vrx ;
int y = vid . ycenter + py * ( vry - siz / 2 ) ;
int vrr = int ( hypot ( vrx , vry ) * sqrt ( 2. ) ) ;
2015-08-08 13:57:52 +00:00
if ( gtouched & & ! mouseover
2017-03-23 10:53:57 +00:00
& & abs ( mousex - vid . xcenter ) < vrr
& & abs ( mousey - vid . ycenter ) < vrr
& & hypot ( mousex - vid . xcenter , mousey - vid . ycenter ) > vrr
2015-08-08 13:57:52 +00:00
& & px = = ( mousex > vid . xcenter ? 1 : - 1 )
& & py = = ( mousey > vid . ycenter ? 1 : - 1 )
) col = 0xFF0000 ;
2016-08-26 09:58:03 +00:00
if ( displayfr ( x , y , 0 , siz , s , col , 8 + 8 * px ) )
buttonclicked = true ;
2015-08-08 13:57:52 +00:00
}
2016-08-26 09:58:03 +00:00
# endif
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
# ifndef NOSAVE
2015-08-08 13:57:52 +00:00
vector < score > scores ;
int scoresort = 2 ;
int scoredisplay = 1 ;
int scorefrom = 0 ;
2016-01-02 10:09:13 +00:00
int scoremode = 0 ;
2015-08-08 13:57:52 +00:00
bool scorerev = false ;
bool scorecompare ( const score & s1 , const score & s2 ) {
return s1 . box [ scoresort ] > s2 . box [ scoresort ] ;
}
bool fakescore ( ) {
return fakebox [ scoredisplay ] ;
}
string displayfor ( score * S ) {
// printf("S=%p, scoredisplay = %d\n", S, scoredisplay);
if ( S = = NULL ) {
return XLATN ( boxname [ scoredisplay ] ) ;
}
if ( scoredisplay = = 0 ) {
char buf [ 10 ] ;
snprintf ( buf , 10 , " %d:%02d " , S - > box [ 0 ] / 60 , S - > box [ 0 ] % 60 ) ;
return buf ;
}
if ( scoredisplay = = 1 ) {
time_t tim = S - > box [ 1 ] ;
char buf [ 128 ] ; strftime ( buf , 128 , " %c " , localtime ( & tim ) ) ;
return buf ;
}
return its ( S - > box [ scoredisplay ] ) ;
}
void loadScores ( ) {
scores . clear ( ) ;
FILE * f = fopen ( scorefile , " rt " ) ;
if ( ! f ) {
printf ( " Could not open the score file '%s'! \n " , scorefile ) ;
addMessage ( s0 + " Could not open the score file: " + scorefile ) ;
return ;
}
while ( ! feof ( f ) ) {
char buf [ 120 ] ;
if ( fgets ( buf , 120 , f ) = = NULL ) break ;
if ( buf [ 0 ] = = ' H ' & & buf [ 1 ] = = ' y ' ) {
score sc ; bool ok = true ;
2017-03-23 10:53:57 +00:00
{ if ( fscanf ( f , " %s " , buf ) < = 0 ) break ; } sc . ver = buf ;
2015-08-08 13:57:52 +00:00
for ( int i = 0 ; i < MAXBOX ; i + + ) {
if ( fscanf ( f , " %d " , & sc . box [ i ] ) < = 0 ) { boxid = i ; break ; }
}
for ( int i = boxid ; i < MAXBOX ; i + + ) sc . box [ i ] = 0 ;
if ( sc . ver > = " 4.4 " ) {
sc . box [ 0 ] = sc . box [ 65 ] ;
// the first executable on Steam included a corruption
if ( sc . box [ 65 ] > 1420000000 & & sc . box [ 65 ] < 1430000000 ) {
sc . box [ 0 ] = sc . box [ 65 ] - sc . box [ 1 ] ;
sc . box [ 65 ] = sc . box [ 0 ] ;
}
// do not include saves
if ( sc . box [ 65 + 4 + itOrbSafety - itOrbLightning ] ) ok = false ;
}
else
sc . box [ 0 ] = sc . box [ 1 ] - sc . box [ 0 ] ; // could not save then
if ( ok & & boxid > 20 ) scores . push_back ( sc ) ;
}
}
fclose ( f ) ;
addMessage ( its ( size ( scores ) ) + " games have been recorded in " + scorefile ) ;
cmode = emScores ;
2017-03-23 10:53:57 +00:00
boxid = 0 ; applyBoxes ( ) ;
2015-08-08 13:57:52 +00:00
scoresort = 2 ; reverse ( scores . begin ( ) , scores . end ( ) ) ;
2016-01-02 10:09:13 +00:00
scoremode = 0 ;
if ( shmup : : on ) scoremode = 1 ;
else if ( hardcore ) scoremode = 2 ;
2015-08-08 13:57:52 +00:00
scorefrom = 0 ;
stable_sort ( scores . begin ( ) , scores . end ( ) , scorecompare ) ;
2017-03-23 10:53:57 +00:00
# ifdef MOBILE
extern int andmode ;
andmode = 2 ;
# endif
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
vector < pair < string , int > > pickscore_options ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
bool notgl = false ;
# endif
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
void setAppropriateOverview ( ) {
clearMessages ( ) ;
if ( tactic : : on )
cmode = emTactic ;
else if ( yendor : : on )
cmode = emYendor ;
else if ( geometry ! = gNormal )
cmode = emPickEuclidean ;
else
cmode = emOverview ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
ld textscale ( ) {
return vid . fsize / ( vid . radius * crossf ) * ( 1 + vid . alphax ) * 2 ;
}
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
transmatrix xymatrix ( int x , int y , ld scale ) {
transmatrix V ;
{ for ( int i = 0 ; i < 3 ; i + + ) for ( int j = 0 ; j < 3 ; j + + ) V [ i ] [ j ] = i = = j ? 1 : 0 ; }
V [ 0 ] [ 2 ] = ( x - vid . xcenter + .0 ) / vid . radius * ( 1 + vid . alphax ) ;
V [ 1 ] [ 2 ] = ( y - vid . ycenter + .0 ) / vid . radius * ( 1 + vid . alphax ) ;
V [ 0 ] [ 0 ] = scale ;
V [ 1 ] [ 1 ] = scale ;
V [ 2 ] [ 2 ] = 0 ;
return V ;
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
int monsterclass ( eMonster m ) {
if ( isFriendly ( m ) | | m = = moTortoise ) return 1 ;
else if ( isMonsterPart ( m ) ) return 2 ;
else return 0 ;
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
int glyphclass ( int i ) {
if ( i < ittypes ) {
eItem it = eItem ( i ) ;
return itemclass ( it ) = = IC_TREASURE ? 0 : 1 ;
}
else {
eMonster m = eMonster ( i - ittypes ) ;
return monsterclass ( m ) = = 0 ? 2 : 3 ;
2015-08-08 13:57:52 +00:00
}
}
2017-03-23 10:53:57 +00:00
int subclass ( int i ) {
if ( i < ittypes )
return itemclass ( eItem ( i ) ) ;
else
return monsterclass ( eMonster ( i - ittypes ) ) ;
}
# define GLYPH_MARKTODO 1
# define GLYPH_MARKOVER 2
# define GLYPH_LOCAL 4
# define GLYPH_IMPORTANT 8
# define GLYPH_NONUMBER 16
# define GLYPH_DEMON 32
# define GLYPH_RUNOUT 64
# define GLYPH_INPORTRAIT 128
# define GLYPH_LOCAL2 256
# define GLYPH_TARGET 512
2017-05-28 22:16:17 +00:00
# define GLYPH_INSQUARE 1024
2017-03-23 10:53:57 +00:00
eGlyphsortorder glyphsortorder ;
int zero = 0 ;
int & ikmerge ( int i ) {
if ( i < ittypes ) return items [ i ] ;
else if ( i = = ittypes ) return zero ;
else return kills [ i - ittypes ] ;
}
const int glyphs = ittypes + motypes ;
int gfirsttime [ glyphs ] , glasttime [ glyphs ] , gcopy [ glyphs ] , ikland [ glyphs ] ;
int glyphorder [ glyphs ] ;
void updatesort ( ) {
for ( int i = 0 ; i < glyphs ; i + + ) {
if ( ikmerge ( i ) & & gfirsttime [ i ] = = 0 )
gfirsttime [ i ] = ticks ;
if ( ikmerge ( i ) ! = gcopy [ i ] )
gcopy [ i ] = items [ i ] , glasttime [ i ] = ticks ;
}
}
void preparesort ( ) {
for ( int i = 0 ; i < glyphs ; i + + ) glyphorder [ i ] = i ;
for ( int i = 0 ; i < LAND_OVERX ; i + + ) {
eLand l = land_over [ i ] ;
ikland [ treasureType ( l ) ] = i + 1 ;
for ( int mi = 0 ; mi < motypes ; mi + + )
if ( isNative ( l , eMonster ( mi ) ) )
ikland [ mi + ittypes ] = i + 1 ;
}
glyphsortorder = gsoLand ; updatesort ( ) ;
glyphsortorder = gsoFirstTop ;
}
int glyphsortkey = 0 ;
2017-05-28 22:16:17 +00:00
int glyphcorner ( int i ) {
if ( i < ittypes )
return itemclass ( eItem ( i ) ) = = IC_ORB ? 2 : 0 ;
else
return 1 ;
}
2017-03-23 10:53:57 +00:00
bool glyphsort ( int i , int j ) {
if ( subclass ( i ) ! = subclass ( j ) )
return subclass ( i ) < subclass ( j ) ;
if ( glyphsortorder = = gsoFirstTop )
return gfirsttime [ i ] < gfirsttime [ j ] ;
if ( glyphsortorder = = gsoFirstBottom )
return gfirsttime [ i ] > gfirsttime [ j ] ;
if ( glyphsortorder = = gsoLastTop )
return glasttime [ i ] > glasttime [ j ] ;
if ( glyphsortorder = = gsoLastBottom )
return glasttime [ i ] < glasttime [ j ] ;
if ( glyphsortorder = = gsoValue )
return ikmerge ( i ) > ikmerge ( j ) ;
if ( glyphsortorder = = gsoLand )
return ikland [ i ] < ikland [ j ] ;
return 0 ;
}
int glyphflags ( int gid ) {
int f = 0 ;
if ( gid < ittypes ) {
eItem i = eItem ( gid ) ;
if ( itemclass ( i ) = = IC_NAI ) f | = GLYPH_NONUMBER ;
if ( isElementalShard ( i ) ) {
2017-05-28 22:16:17 +00:00
f | = GLYPH_LOCAL | GLYPH_INSQUARE ;
2017-03-23 10:53:57 +00:00
if ( i = = localshardof ( cwt . c - > land ) ) f | = GLYPH_LOCAL2 ;
}
2017-05-28 22:16:17 +00:00
if ( i = = treasureType ( cwt . c - > land ) )
f | = GLYPH_LOCAL | GLYPH_LOCAL2 | GLYPH_IMPORTANT | GLYPH_INSQUARE ;
2017-03-23 10:53:57 +00:00
if ( i = = itHolyGrail ) {
if ( items [ i ] > = 3 ) f | = GLYPH_MARKOVER ;
}
else if ( itemclass ( i ) = = IC_TREASURE ) {
if ( items [ i ] > = 25 & & items [ i ] < 100 ) f | = GLYPH_MARKOVER ;
else if ( items [ i ] < 10 ) f | = GLYPH_MARKTODO ;
}
else {
2017-05-28 22:16:17 +00:00
f | = GLYPH_IMPORTANT | GLYPH_INSQUARE ;
2017-03-23 10:53:57 +00:00
if ( itemclass ( i ) = = IC_ORB & & items [ i ] < 10 ) f | = GLYPH_RUNOUT ;
}
if ( i = = orbToTarget ) f | = GLYPH_TARGET ;
f | = GLYPH_INPORTRAIT ;
}
2015-08-08 13:57:52 +00:00
else {
2017-03-23 10:53:57 +00:00
eMonster m = eMonster ( gid - ittypes ) ;
2017-05-28 22:16:17 +00:00
if ( m = = moLesser ) f | = GLYPH_IMPORTANT | GLYPH_DEMON | GLYPH_INPORTRAIT | GLYPH_INSQUARE ;
2017-03-23 10:53:57 +00:00
int isnat = isNative ( cwt . c - > land , m ) ;
2017-05-28 22:16:17 +00:00
if ( isnat ) f | = GLYPH_LOCAL | GLYPH_IMPORTANT | GLYPH_INPORTRAIT | GLYPH_INSQUARE ;
2017-03-23 10:53:57 +00:00
if ( isnat = = 2 ) f | = GLYPH_LOCAL2 ;
if ( m = = monsterToSummon ) f | = GLYPH_TARGET ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
return f ;
2015-08-08 13:57:52 +00:00
}
2017-05-28 22:16:17 +00:00
transmatrix atscreenpos ( ld x , ld y , ld size ) {
transmatrix V = Id ;
// V[0][2] += (x - vid.xcenter) / vid.radius * (1+vid.alphax);
// V[1][2] += (y - vid.ycenter) / vid.radius * (1+vid.alphax);
// V[2][2] = size / vid.radius * 5;
V [ 0 ] [ 2 ] + = ( x - vid . xcenter ) ;
V [ 1 ] [ 2 ] + = ( y - vid . ycenter ) ;
2017-05-29 09:22:11 +00:00
V [ 0 ] [ 0 ] = size * 2 * crossf / hcrossf ;
V [ 1 ] [ 1 ] = size * 2 * crossf / hcrossf ;
2017-05-28 22:16:17 +00:00
V [ 2 ] [ 2 ] = vid . scrdist ;
2017-05-29 09:22:11 +00:00
if ( euclid ) V [ 2 ] [ 2 ] / = EUCSCALE ;
2017-05-28 22:16:17 +00:00
return V ;
}
bool displayglyph ( int cx , int cy , int buttonsize , char glyph , int color , int qty , int flags , int id ) {
2017-03-23 10:53:57 +00:00
bool b =
mousex > = cx & & mousex < cx + buttonsize & & mousey > = cy - buttonsize / 2 & & mousey < = cy - buttonsize / 2 + buttonsize ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
int glsize = buttonsize ;
if ( glyph = = ' % ' | | glyph = = ' M ' | | glyph = = ' W ' ) glsize = glsize * 4 / 5 ;
2017-05-28 22:16:17 +00:00
if ( vid . graphglyph ) {
ptds . clear ( ) ;
poly_outline = OUTLINE_NONE ;
if ( id > = ittypes ) {
eMonster m = eMonster ( id - ittypes ) ;
int bsize = buttonsize ;
2017-05-29 09:22:11 +00:00
if ( m = = moKrakenH ) bsize / = 3 ;
if ( m = = moKrakenT | | m = = moDragonTail ) bsize / = 2 ;
2017-05-28 22:16:17 +00:00
if ( m = = moSlime ) bsize = ( 2 * bsize + 1 ) / 3 ;
transmatrix V = atscreenpos ( cx + buttonsize / 2 , cy , bsize ) ;
int mcol = color ;
mcol - = ( color & 0xFCFCFC ) > > 2 ;
drawMonsterType ( m , NULL , V , mcol , 0 ) ;
}
else {
eItem it = eItem ( id ) ;
int bsize = buttonsize ;
if ( glyph = = ' * ' ) bsize * = 2 ;
if ( glyph = = ' $ ' ) bsize = ( bsize * 5 + 2 ) / 3 ;
2017-05-29 09:22:11 +00:00
if ( glyph = = ' o ' ) bsize = ( bsize * 3 + 1 ) / 2 ;
2017-05-28 22:16:17 +00:00
if ( glyph = = ' t ' ) bsize = bsize * 5 / 2 ;
if ( it = = itWarning ) bsize * = 2 ;
if ( it = = itBombEgg | | it = = itTrollEgg | | it = = itDodeca ) bsize = bsize * 3 / 2 ;
transmatrix V = atscreenpos ( cx + buttonsize / 2 , cy , bsize ) ;
int icol = color ;
icol - = ( color & 0xFCFCFC ) > > 2 ;
int ic = itemclass ( it ) ;
2017-05-29 09:22:11 +00:00
drawItemType ( it , NULL , V , icol , ( ic = = IC_ORB | | ic = = IC_NAI ) ? ticks * 2 : ( ( glyph = = ' t ' & & qty % 5 ) | | it = = itOrbYendor ) ? ticks / 2 : 0 , false ) ;
2017-05-28 22:16:17 +00:00
}
quickqueue ( ) ;
}
else if ( glyph = = ' * ' )
2017-03-23 10:53:57 +00:00
displaychr ( cx + buttonsize / 2 , cy + buttonsize / 4 , 0 , glsize * 3 / 2 , glyph , darkenedby ( color , b ? 0 : 1 ) ) ;
else
displaychr ( cx + buttonsize / 2 , cy , 0 , glsize , glyph , darkenedby ( color , b ? 0 : 1 ) ) ;
2017-05-28 22:16:17 +00:00
2017-03-23 10:53:57 +00:00
string fl = " " ;
string str = its ( qty ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( flags & GLYPH_TARGET ) fl + = " ! " ;
if ( flags & GLYPH_LOCAL2 ) fl + = " + " ;
else if ( flags & GLYPH_LOCAL ) fl + = " - " ;
if ( flags & GLYPH_DEMON ) fl + = " X " ;
if ( flags & GLYPH_MARKOVER ) str + = " ! " ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( fl ! = " " )
displaystr ( cx + buttonsize , cy - buttonsize / 2 + buttonsize / 4 , 0 , buttonsize / 2 , fl , darkenedby ( color , 0 ) , 16 ) ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( flags & GLYPH_NONUMBER ) str = " " ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
int bsize =
( qty < 10 & & ( flags & ( GLYPH_MARKTODO | GLYPH_RUNOUT ) ) ) ? buttonsize * 3 / 4 :
qty < 100 ? buttonsize / 2 :
buttonsize / 3 ;
if ( str ! = " " )
displayfr ( cx + buttonsize , cy + buttonsize / 2 - bsize / 2 , 1 , bsize , str , color , 16 ) ;
return b ;
}
2017-05-28 22:16:17 +00:00
void displayglyph2 ( int cx , int cy , int buttonsize , int i ) {
char glyph = i < ittypes ? iinf [ i ] . glyph : minf [ i - ittypes ] . glyph ;
int color = i < ittypes ? iinf [ i ] . color : minf [ i - ittypes ] . color ;
int imp = glyphflags ( i ) ;
if ( displayglyph ( cx , cy , buttonsize , glyph , color , ikmerge ( i ) , imp , i ) ) {
instat = true ;
getcstat = SDLK_F1 ;
if ( i < ittypes ) {
eItem it = eItem ( i ) ;
int t = itemclass ( it ) ;
if ( t = = IC_TREASURE )
mouseovers = XLAT ( " treasure collected: %1 " , it ) ;
if ( t = = IC_OTHER )
mouseovers = XLAT ( " objects found: %1 " , it ) ;
if ( t = = IC_NAI )
mouseovers = XLAT ( " %1 " , it ) ;
if ( t = = IC_ORB )
mouseovers = XLAT ( " orb power: %1 " , eItem ( i ) ) ;
if ( it = = itGreenStone ) {
mouseovers + = XLAT ( " (click to drop) " ) ;
getcstat = ' g ' ;
}
if ( imp & GLYPH_LOCAL ) mouseovers + = XLAT ( " (local treasure) " ) ;
help = generateHelpForItem ( it ) ;
}
else {
eMonster m = eMonster ( i - ittypes ) ;
if ( isMonsterPart ( m ) )
mouseovers = s0 + XLAT ( " parts destroyed: %1 " , m ) ;
else if ( isFriendly ( m ) & & isNonliving ( m ) )
mouseovers = s0 + XLAT ( " friends destroyed: %1 " , m ) ;
else if ( isFriendly ( m ) )
mouseovers = s0 + XLAT ( " friends killed: %1 " , m ) ;
else if ( isNonliving ( m ) )
mouseovers = s0 + XLAT ( " monsters destroyed: %1 " , m ) ;
else if ( m = = moTortoise )
mouseovers = s0 + XLAT ( " animals killed: %1 " , m ) ;
else
mouseovers = s0 + XLAT ( " monsters killed: %1 " , m ) ;
if ( imp & GLYPH_LOCAL2 ) mouseovers + = XLAT ( " (killing increases treasure spawn) " ) ;
else if ( imp & GLYPH_LOCAL ) mouseovers + = XLAT ( " (appears here) " ) ;
help = generateHelpForMonster ( m ) ;
}
}
}
2017-03-23 10:53:57 +00:00
void drawStats ( ) {
# ifdef ROGUEVIZ
if ( rogueviz : : on ) return ;
# endif
2017-04-04 09:13:15 +00:00
if ( viewdists & & sidescreen ) {
dialog : : init ( " " ) ;
int qty [ 64 ] ;
vector < cell * > & ac = currentmap - > allcells ( ) ;
for ( int i = 0 ; i < 64 ; i + + ) qty [ i ] = 0 ;
for ( int i = 0 ; i < size ( ac ) ; i + + ) {
int d = celldistance ( ac [ i ] , cwt . c ) ;
if ( d > = 0 & & d < 64 ) qty [ d ] + + ;
}
if ( geometry = = gNormal )
for ( int i = purehepta ? 6 : 8 ; i < = 15 ; i + + )
qty [ i ] =
purehepta ?
3 * qty [ i - 1 ] - qty [ i - 2 ]
: qty [ i - 1 ] + qty [ i - 2 ] + qty [ i - 3 ] - qty [ i - 4 ] ;
if ( geometry = = gEuclid )
for ( int i = 8 ; i < = 15 ; i + + ) qty [ i ] = 6 * i ;
for ( int i = 0 ; i < 64 ; i + + ) if ( qty [ i ] )
dialog : : addInfo ( its ( qty [ i ] ) , distcolors [ i & 7 ] ) ;
if ( geometry = = gNormal & & ! purehepta ) {
dialog : : addBreak ( 200 ) ;
2017-04-08 15:18:29 +00:00
dialog : : addHelp ( " a(d+4) = a(d+3) + a(d+2) + a(d+1) - a(d) " ) ;
2017-04-04 09:13:15 +00:00
dialog : : addInfo ( " a(d) ~ 1.72208^d " , 0xFFFFFF ) ;
}
if ( geometry = = gNormal & & purehepta ) {
dialog : : addBreak ( 200 ) ;
2017-04-08 15:18:29 +00:00
dialog : : addHelp ( " a(d+2) = 3a(d+1) - a(d+2) " ) ;
2017-04-04 09:13:15 +00:00
dialog : : addInfo ( " a(d) ~ 2.61803^d " , 0xFFFFFF ) ;
}
if ( geometry = = gEuclid ) {
dialog : : addBreak ( 300 ) ;
dialog : : addInfo ( " a(n) = 6n " , 0xFFFFFF ) ;
}
dialog : : display ( ) ;
}
if ( sidescreen ) return ;
2017-05-28 22:16:17 +00:00
if ( vid . xres > vid . yres * 85 / 100 & & vid . yres > vid . xres * 85 / 100 ) {
int bycorner [ 4 ] ;
for ( int u = 0 ; u < 4 ; u + + ) bycorner [ u ] = 0 ;
for ( int i = 0 ; i < glyphs ; i + + ) if ( ikmerge ( i ) & & ( glyphflags ( i ) & GLYPH_INSQUARE ) )
bycorner [ glyphcorner ( i ) ] + + ;
updatesort ( ) ;
stable_sort ( glyphorder , glyphorder + glyphs , glyphsort ) ;
int rad = min ( vid . xres , vid . yres ) / 2 ;
for ( int cor = 0 ; cor < 3 ; cor + + ) {
for ( int a = 5 ; a < 41 ; a + + ) {
int s = min ( vid . xres , vid . yres ) / a ;
int spots = 0 ;
for ( int u = vid . fsize ; u < vid . xres / 2 - s ; u + = s )
for ( int v = vid . fsize ; v < vid . yres / 2 - s ; v + = s )
if ( hypot ( vid . xres / 2 - u - s , vid . yres / 2 - v - s ) > rad ) {
spots + + ;
}
if ( spots > = bycorner [ cor ] & & spots > = 3 ) {
int next = 0 ;
vector < int > glyphstoshow ;
for ( int i = 0 ; i < glyphs ; i + + ) {
int g = glyphorder [ i ] ;
if ( ikmerge ( g ) & & ( glyphflags ( g ) & GLYPH_INSQUARE ) & & glyphcorner ( g ) = = cor )
glyphstoshow . push_back ( g ) ;
}
for ( int u = vid . fsize ; u < vid . xres / 2 - s ; u + = s )
for ( int v = vid . fsize ; v < vid . yres / 2 - s ; v + = s )
if ( hypot ( vid . xres / 2 - u - s , vid . yres / 2 - v - s ) > rad ) {
if ( next > = size ( glyphstoshow ) ) break ;
int cx = u ;
int cy = v + s / 2 ;
if ( cor & 1 ) cx = vid . xres - 1 - s - cx ;
if ( cor & 2 ) cy = vid . yres - 1 - cy ;
displayglyph2 ( cx , cy , s , glyphstoshow [ next + + ] ) ;
}
break ;
}
}
}
return ;
}
2017-03-23 10:53:57 +00:00
instat = false ;
2016-08-26 09:58:03 +00:00
bool portrait = vid . xres < vid . yres ;
2017-03-23 10:53:57 +00:00
int colspace = portrait ? ( vid . yres - vid . xres - vid . fsize * 3 ) : ( vid . xres - vid . yres - 16 ) / 2 ;
int rowspace = portrait ? vid . xres - 16 : vid . yres - vid . fsize * 4 ;
int colid [ 4 ] , rowid [ 4 ] ;
int maxbyclass [ 4 ] ;
for ( int z = 0 ; z < 4 ; z + + ) maxbyclass [ z ] = 0 ;
for ( int i = 0 ; i < glyphs ; i + + ) if ( ikmerge ( i ) )
if ( ! portrait | | ( glyphflags ( i ) | GLYPH_INPORTRAIT ) )
maxbyclass [ glyphclass ( i ) ] + + ;
int buttonsize ;
int columns , rows ;
bool imponly = false ;
int minsize = vid . fsize * ( portrait ? 4 : 2 ) ;
rows = 0 ;
while ( ( buttonsize = minsize - vid . killreduction ) ) {
columns = colspace / buttonsize ;
rows = rowspace / buttonsize ;
int coltaken = 0 ;
for ( int z = 0 ; z < 4 ; z + + ) {
if ( z = = 2 & & ! portrait ) {
if ( coltaken > columns ) { vid . killreduction + + ; continue ; }
coltaken = 0 ;
}
colid [ z ] = coltaken , rowid [ z ] = 0 ,
coltaken + = ( maxbyclass [ z ] + rows - 1 ) / rows ;
}
if ( coltaken > columns ) { vid . killreduction + + ; continue ; }
break ;
2015-08-08 13:57:52 +00:00
}
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( buttonsize < = vid . fsize * 3 / 4 ) {
imponly = true ; buttonsize = minsize ;
rows = rowspace / buttonsize ; if ( ! rows ) return ;
colid [ 0 ] = 0 ; colid [ 2 ] = portrait ? 1 : 0 ;
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
updatesort ( ) ;
stable_sort ( glyphorder , glyphorder + glyphs , glyphsort ) ;
for ( int i0 = 0 ; i0 < glyphs ; i0 + + ) {
int i = glyphorder [ i0 ] ;
if ( ! ikmerge ( i ) ) continue ;
int z = glyphclass ( i ) ;
int imp = glyphflags ( i ) ;
if ( imponly ) { z & = ~ 1 ; if ( ! ( imp & GLYPH_IMPORTANT ) ) continue ; }
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
int cx , cy ;
if ( portrait )
cx = 8 + buttonsize * rowid [ z ] , cy = vid . fsize * 2 + buttonsize * ( colid [ z ] ) + buttonsize / 2 ;
else
cx = 8 + buttonsize * ( colid [ z ] ) , cy = vid . fsize * 3 + buttonsize * rowid [ z ] ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( ! portrait & & z < 2 ) cx = vid . xres - cx - buttonsize ;
rowid [ z ] + + ; if ( rowid [ z ] > = rows ) rowid [ z ] = 0 , colid [ z ] + + ;
2017-05-28 22:16:17 +00:00
displayglyph2 ( cx , cy , buttonsize , i ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
string s0 ;
if ( displayButtonS ( vid . xres - 8 , vid . fsize , " score: " + its ( gold ( ) ) , 0xFFFFFFF , 16 , vid . fsize ) ) {
mouseovers = XLAT ( " Your total wealth " ) ,
instat = true ,
getcstat = SDLK_F1 ,
help = helptitle ( XLAT ( " Your total wealth " ) , 0xFFD500 ) +
XLAT (
" The total value of the treasure you have collected. \n \n "
" Every world type contains a specific type of treasure, worth 1 $$$; "
" your goal is to collect as much treasure as possible, but every treasure you find "
" causes more enemies to hunt you in its native land. \n \n "
" Orbs of Yendor are worth 50 $$$ each. \n \n "
) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
if ( displayButtonS ( 8 , vid . fsize , " kills: " + its ( tkills ( ) ) , 0xFFFFFFF , 0 , vid . fsize ) ) {
instat = true ,
getcstat = SDLK_F1 ,
mouseovers = XLAT ( " Your total kills " ) + " : " + its ( tkills ( ) ) ,
help = helptitle ( XLAT ( " Your total kills " ) + " : " + its ( tkills ( ) ) , 0x404040 ) +
XLAT (
" In most lands, more treasures are generated with each enemy native to this land you kill. "
" Moreover, 100 kills is a requirement to enter the Graveyard and the Hive. \n \n "
" Friendly creatures and parts of monsters (such as the Ivy) do appear in the list, "
" but are not counted in the total kill count. " ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
if ( displayButtonS ( 4 , vid . yres - 4 - vid . fsize / 2 , s0 + VER + " fps: " + its ( calcfps ( ) ) , 0x202020 , 0 , vid . fsize / 2 ) ) {
2015-08-08 13:57:52 +00:00
mouseovers = XLAT ( " frames per second " ) ,
2017-03-23 10:53:57 +00:00
getcstat = SDLK_F1 ,
instat = true ,
2015-08-08 13:57:52 +00:00
help =
2017-03-23 10:53:57 +00:00
helptitle ( XLAT ( " frames per second " ) , 0xFF4040 ) +
2015-08-08 13:57:52 +00:00
XLAT (
2016-01-02 10:09:13 +00:00
" The higher the number, the smoother the animations in the game. "
" If you find that animations are not smooth enough, you can try "
" to change the options "
2015-08-08 13:57:52 +00:00
) +
# ifdef IOS
XLAT (
2016-01-02 10:09:13 +00:00
" (in the MENU). You can reduce the sight range, this should make "
" the animations smoother. " ) ;
2015-08-08 13:57:52 +00:00
# else
XLAT (
2016-01-02 10:09:13 +00:00
" (press v) and change the wall/monster mode to ASCII, or change "
" the resolution. " ) ;
2015-08-08 13:57:52 +00:00
# endif
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
achievement_display ( ) ;
2016-08-26 09:58:03 +00:00
# ifdef LOCAL
process_local_stats ( ) ;
# endif
2016-01-02 10:09:13 +00:00
}
2017-05-27 19:40:40 +00:00
# ifndef NOSDL
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
# ifndef NOPNG
void IMAGESAVE ( SDL_Surface * s , const char * fname ) {
SDL_Surface * s2 = SDL_PNGFormatAlpha ( s ) ;
SDL_SavePNG ( s2 , fname ) ;
SDL_FreeSurface ( s2 ) ;
}
# endif
2017-03-23 10:53:57 +00:00
int pngres = 2000 ;
2017-05-27 19:40:40 +00:00
int pngformat = 0 ;
2017-03-23 10:53:57 +00:00
2017-05-27 19:40:40 +00:00
void saveHighQualityShot ( const char * fname , const char * caption , int fade ) {
2016-01-02 10:09:13 +00:00
2017-05-27 19:40:40 +00:00
# ifndef SDLGFX
2016-01-02 10:09:13 +00:00
addMessage ( XLAT ( " High quality shots not available on this platform " ) ) ;
return ;
# endif
2017-03-23 10:53:57 +00:00
dynamicval < int > v3 ( sightrange , ( cheater & & sightrange < 10 ) ? 10 : sightrange ) ;
if ( cheater ) doOvergenerate ( ) ;
2016-01-02 10:09:13 +00:00
time_t timer ;
timer = time ( NULL ) ;
2017-03-23 10:53:57 +00:00
dynamicval < videopar > v ( vid , vid ) ;
dynamicval < bool > v2 ( inHighQual , true ) ;
dynamicval < int > v4 ( cheater , 0 ) ;
2017-05-28 22:16:17 +00:00
dynamicval < bool > v6 ( auraNOGL , fname ? true : false ) ;
2017-05-27 19:40:40 +00:00
2017-03-23 10:53:57 +00:00
vid . xres = vid . yres = pngres ;
2017-05-27 19:40:40 +00:00
if ( pngformat = = 1 ) vid . xres = vid . yres * 4 / 3 ;
if ( pngformat = = 2 ) vid . xres = vid . yres * 16 / 9 ;
if ( pngformat = = 3 ) {
vid . xres = vid . yres * 22 / 16 ;
while ( vid . xres & 15 ) vid . xres + + ;
}
printf ( " format = %d, %d x %d \n " , pngformat , vid . xres , vid . yres ) ;
2016-01-02 10:09:13 +00:00
vid . usingGL = false ;
2016-08-26 09:58:03 +00:00
// if(vid.pmodel == 0) vid.scale = 0.99;
2016-01-02 10:09:13 +00:00
calcparam ( ) ;
2017-03-23 10:53:57 +00:00
# ifdef ROGUEVIZ
rogueviz : : fixparam ( ) ;
# endif
2017-05-27 19:40:40 +00:00
printf ( " format = %d, %d x %d \n " , pngformat , vid . xres , vid . yres ) ;
2017-03-23 10:53:57 +00:00
dynamicval < SDL_Surface * > v5 ( s , SDL_CreateRGBSurface ( SDL_SWSURFACE , vid . xres , vid . yres , 32 , 0 , 0 , 0 , 0 ) ) ;
2016-01-02 10:09:13 +00:00
darken = 0 ;
2017-05-27 19:40:40 +00:00
int numi = ( fname ? 1 : 2 ) ;
2016-01-02 10:09:13 +00:00
2017-05-27 19:40:40 +00:00
for ( int i = 0 ; i < numi ; i + + ) {
SDL_FillRect ( s , NULL , numi = = 1 ? backcolor : i ? 0xFFFFFF : 0 ) ;
2016-08-26 09:58:03 +00:00
drawfullmap ( ) ;
2017-05-27 19:40:40 +00:00
if ( fade < 255 )
for ( int y = 0 ; y < vid . yres ; y + + )
for ( int x = 0 ; x < vid . xres ; x + + ) {
int & p = qpixel ( s , x , y ) ;
for ( int i = 0 ; i < 3 ; i + + ) {
part ( p , i ) = ( part ( p , i ) * fade + 127 ) / 255 ;
}
}
if ( caption )
displayfr ( vid . xres / 2 , vid . fsize + vid . fsize / 4 , 3 , vid . fsize * 2 , caption , 0xFFFFFF , 8 ) ;
2016-08-26 09:58:03 +00:00
char buf [ 128 ] ; strftime ( buf , 128 , " bigshota-%y%m%d-%H%M%S " IMAGEEXT , localtime ( & timer ) ) ;
2016-01-02 10:09:13 +00:00
buf [ 7 ] + = i ;
2017-03-23 10:53:57 +00:00
if ( ! fname ) fname = buf ;
IMAGESAVE ( s , fname ) ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( i = = 0 ) addMessage ( XLAT ( " Saved the high quality shot to %1 " , fname ) ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
SDL_FreeSurface ( s ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
# endif
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
void addball ( ld a , ld b , ld c ) {
hyperpoint h ;
ballmodel ( h , a , b , c ) ;
for ( int i = 0 ; i < 3 ; i + + ) h [ i ] * = vid . radius ;
curvepoint ( h ) ;
}
void ballgeometry ( ) {
queuereset ( vid . usingGL ? mdDisk : mdUnchanged , PPR_CIRCLE ) ;
for ( int i = 0 ; i < 60 ; i + + )
addball ( i * M_PI / 30 , 10 , 0 ) ;
for ( double d = 10 ; d > = - 10 ; d - = .2 )
addball ( 0 , d , 0 ) ;
for ( double d = - 10 ; d < = 10 ; d + = .2 )
addball ( 0 , d , geom3 : : depth ) ;
addball ( 0 , 0 , - geom3 : : camera ) ;
addball ( 0 , 0 , geom3 : : depth ) ;
addball ( 0 , 0 , - geom3 : : camera ) ;
addball ( 0 , - 10 , 0 ) ;
addball ( 0 , 0 , - geom3 : : camera ) ;
queuecurve ( darkena ( 0xFF , 0 , 0x80 ) , 0 , PPR_CIRCLE ) ;
queuereset ( pmodel , PPR_CIRCLE ) ;
}
2016-08-26 09:58:03 +00:00
void drawfullmap ( ) {
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " draw full map \n " ) ) ;
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
ptds . clear ( ) ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( ! vid . goteyes & & ! euclid & & ( pmodel = = mdDisk | | pmodel = = mdBall ) ) {
double rad = vid . radius ;
if ( sphere ) {
if ( ! vid . grid & & ! elliptic )
rad = 0 ;
else if ( vid . alphax < = 0 )
;
else if ( vid . alphax < = 1 & & ( vid . grid | | elliptic ) ) // mark the equator
rad = rad * 1 / vid . alphax ;
else if ( vid . grid ) // mark the edge
rad / = sqrt ( vid . alphax * vid . alphax - 1 ) ;
}
2017-05-27 19:40:40 +00:00
if ( ! haveaura ( ) ) queuecircle ( vid . xcenter , vid . ycenter , rad ,
2017-03-23 10:53:57 +00:00
svg : : in ? 0x808080FF : darkena ( 0xFF , 0 , 0xFF ) ,
vid . usingGL ? PPR_CIRCLE : PPR_OUTCIRCLE ) ;
if ( pmodel = = mdBall ) ballgeometry ( ) ;
2016-08-26 09:58:03 +00:00
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( pmodel = = mdHyperboloid ) {
int col = darkena ( 0x80 , 0 , 0x80 ) ;
queueline ( hpxyz ( 0 , 0 , 1 ) , hpxyz ( 0 , 0 , - vid . alpha ) , col , 0 , PPR_CIRCLE ) ;
queueline ( xpush ( + 4 ) * C0 , hpxyz ( 0 , 0 , 0 ) , col , 0 , PPR_CIRCLE ) ;
queueline ( xpush ( + 4 ) * C0 , hpxyz ( 0 , 0 , - vid . alpha ) , col , 0 , PPR_CIRCLE ) ;
queueline ( xpush ( - 4 ) * C0 , hpxyz ( 0 , 0 , 0 ) , col , 0 , PPR_CIRCLE ) ;
queueline ( xpush ( - 4 ) * C0 , hpxyz ( 0 , 0 , - vid . alpha ) , col , 0 , PPR_CIRCLE ) ;
queueline ( hpxyz ( - 1 , 0 , 0 ) , hpxyz ( 1 , 0 , 0 ) , col , 0 , PPR_CIRCLE ) ;
}
if ( pmodel = = mdPolygonal | | pmodel = = mdPolynomial )
polygonal : : drawBoundary ( darkena ( 0xFF , 0 , 0xFF ) ) ;
/* if(vid.wallmode < 2 && !euclid && !mapeditor::whichShape) {
2016-08-26 09:58:03 +00:00
int ls = size ( lines ) ;
if ( ISMOBILE ) ls / = 10 ;
2017-03-23 10:53:57 +00:00
for ( int t = 0 ; t < ls ; t + + ) queueline ( View * lines [ t ] . P1 , View * lines [ t ] . P2 , lines [ t ] . col > > ( darken + 1 ) ) ;
} */
2016-01-02 10:09:13 +00:00
2017-05-27 19:40:40 +00:00
clearaura ( ) ;
2016-08-26 09:58:03 +00:00
drawthemap ( ) ;
2017-03-23 10:53:57 +00:00
# ifndef NORUG
2016-08-26 09:58:03 +00:00
if ( ! inHighQual ) {
2017-03-23 10:53:57 +00:00
if ( cmode = = emNormal & & ! rug : : rugged ) {
if ( multi : : players > 1 ) {
transmatrix bcwtV = cwtV ;
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 ) ;
}
if ( rug : : rugged & & ! rug : : renderonce ) queueline ( C0 , mouseh , 0xFF00FFFF , 5 ) ;
2016-08-26 09:58:03 +00:00
mapeditor : : drawGrid ( ) ;
}
# endif
2017-03-23 10:53:57 +00:00
profile_start ( 2 ) ;
2017-05-27 19:40:40 +00:00
drawaura ( ) ;
2016-08-26 09:58:03 +00:00
drawqueue ( ) ;
2017-03-23 10:53:57 +00:00
profile_stop ( 2 ) ;
2016-01-02 10:09:13 +00:00
}
2016-08-26 09:58:03 +00:00
# include "menus.cpp"
2016-01-02 10:09:13 +00:00
2015-08-08 13:57:52 +00:00
void drawscreen ( ) {
2017-03-23 10:53:57 +00:00
if ( vid . xres = = 0 | | vid . yres = = 0 ) return ;
2016-08-26 09:58:03 +00:00
DEBB ( DF_GRAPH , ( debugfile , " drawscreen \n " ) ) ;
calcparam ( ) ;
2017-03-23 10:53:57 +00:00
# ifdef ROGUEVIZ
rogueviz : : fixparam ( ) ;
# endif
2015-08-08 13:57:52 +00:00
# ifdef GL
if ( vid . usingGL ) setGLProjection ( ) ;
# endif
if ( cmode ! = emHelp ) help = " @ " ;
2017-05-27 19:40:40 +00:00
# ifndef NOSDL
2015-08-08 13:57:52 +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-03-23 10:53:57 +00:00
if ( ! vid . usingGL ) SDL_FillRect ( s , NULL , backcolor ) ;
2015-08-08 13:57:52 +00:00
# endif
if ( ! canmove ) darken = 1 ;
if ( cmode ! = emNormal & & cmode ! = emDraw & & cmode ! = emCustomizeChar ) darken = 2 ;
if ( cmode = = emQuit & & ! canmove ) darken = 0 ;
2017-03-23 10:53:57 +00:00
if ( cmode = = emOverview ) darken = 16 ;
2017-04-04 09:13:15 +00:00
if ( sidescreen ) darken = 0 ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
# ifndef NOEDIT
2016-01-02 10:09:13 +00:00
if ( cmode = = emMapEditor & & ! mapeditor : : subscreen & & ! mapeditor : : choosefile ) darken = 0 ;
if ( cmode = = emDraw & & mapeditor : : choosefile ) darken = 2 ;
# endif
2017-03-23 10:53:57 +00:00
if ( hiliteclick & & darken = = 0 & & mmmon ) darken = 1 ;
2016-08-26 09:58:03 +00:00
if ( cmode = = emProgress ) darken = 0 ;
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
if ( conformal : : includeHistory & & cmode ! = emProgress ) conformal : : restore ( ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( darken > = 8 ) ;
# ifndef NORUG
else if ( rug : : rugged ) {
2016-08-26 09:58:03 +00:00
rug : : actDraw ( ) ;
}
2017-03-23 10:53:57 +00:00
# endif
2016-08-26 09:58:03 +00:00
else drawfullmap ( ) ;
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
if ( conformal : : includeHistory & & cmode ! = emProgress ) conformal : : restoreBack ( ) ;
2017-03-23 10:53:57 +00:00
getcstat = 0 ; inslider = false ;
2015-08-08 13:57:52 +00:00
if ( cmode = = emNormal | | cmode = = emQuit ) drawStats ( ) ;
# ifdef MOBILE
2016-08-26 09:58:03 +00:00
buttonclicked = false ;
2017-03-23 10:53:57 +00:00
if ( cmode = = ( canmove ? emNormal : emQuit ) ) {
if ( andmode = = 0 & & shmup : : on ) {
using namespace shmupballs ;
calc ( ) ;
drawCircle ( xmove , yb , rad , 0xFFFFFFFF ) ;
drawCircle ( xmove , yb , rad / 2 , 0xFFFFFFFF ) ;
drawCircle ( xfire , yb , rad , 0xFF0000FF ) ;
drawCircle ( xfire , yb , rad / 2 , 0xFF0000FF ) ;
}
else {
if ( andmode ! = 0 ) displayabutton ( - 1 , + 1 , XLAT ( " MOVE " ) , andmode = = 0 ? BTON : BTOFF ) ;
displayabutton ( + 1 , + 1 , XLAT ( andmode = = 1 ? " BACK " : " DRAG " ) , andmode = = 1 ? BTON : BTOFF ) ;
}
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
}
2016-01-02 10:09:13 +00:00
# endif
2015-08-08 13:57:52 +00:00
// displaynum(vx,100, 0, 24, 0xc0c0c0, celldist(cwt.c), ":");
darken = 0 ;
drawmessages ( ) ;
if ( cmode = = emNormal ) {
if ( ! canmove ) showGameover ( ) ;
}
2016-08-26 09:58:03 +00:00
if ( cmode = = emProgress ) mouseovers = " " ;
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
displayMenus ( ) ;
2015-08-08 13:57:52 +00:00
describeMouseover ( ) ;
2017-03-23 10:53:57 +00:00
if ( ( havewhat & HF_BUG ) & & darken = = 0 & & ( cmode = = emNormal | | cmode = = emQuit ) ) for ( int k = 0 ; k < 3 ; k + + )
2015-08-08 13:57:52 +00:00
displayfr ( vid . xres / 2 + vid . fsize * 5 * ( k - 1 ) , vid . fsize * 2 , 2 , vid . fsize ,
2016-08-26 09:58:03 +00:00
its ( hive : : bugcount [ k ] ) , minf [ moBug0 + k ] . color , 8 ) ;
2016-01-02 10:09:13 +00:00
bool minefieldNearby = false ;
2016-08-26 09:58:03 +00:00
int mines [ 4 ] , tmines = 0 ;
for ( int p = 0 ; p < numplayers ( ) ; p + + ) {
mines [ p ] = 0 ;
cell * c = playerpos ( p ) ;
2017-03-23 10:53:57 +00:00
if ( ! c ) continue ;
2016-08-26 09:58:03 +00:00
for ( int i = 0 ; i < c - > type ; i + + ) if ( c - > mov [ i ] ) {
if ( c - > mov [ i ] - > land = = laMinefield )
minefieldNearby = true ;
if ( c - > mov [ i ] - > wall = = waMineMine ) {
bool ep = false ;
if ( ! ep ) mines [ p ] + + , tmines + + ;
}
}
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
if ( ( minefieldNearby | | tmines ) & & canmove & & ! items [ itOrbAether ] & & darken = = 0 & & cmode = = emNormal ) {
2016-01-02 10:09:13 +00:00
string s ;
2016-08-26 09:58:03 +00:00
if ( tmines > 7 ) tmines = 7 ;
int col = minecolors [ tmines ] ;
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
if ( tmines = = 7 ) seenSevenMines = true ;
2017-03-23 10:53:57 +00:00
for ( int p = 0 ; p < numplayers ( ) ; p + + ) if ( multi : : playerActive ( p ) )
2016-08-26 09:58:03 +00:00
displayfr ( vid . xres * ( p + .5 ) / numplayers ( ) ,
vid . ycenter - vid . radius * 3 / 4 , 2 ,
vid . fsize ,
XLAT ( minetexts [ mines [ p ] ] ) , minecolors [ mines [ p ] ] , 8 ) ;
2016-01-02 10:09:13 +00:00
2016-08-26 09:58:03 +00:00
if ( minefieldNearby & & ! shmup : : on & & cwt . c - > land ! = laMinefield & & cwt . c - > mov [ cwt . spin ] - > land ! = laMinefield ) {
2016-01-02 10:09:13 +00:00
displayfr ( vid . xres / 2 , vid . ycenter - vid . radius * 3 / 4 - vid . fsize * 3 / 2 , 2 ,
vid . fsize ,
XLAT ( " WARNING: you are entering a minefield! " ) ,
col , 8 ) ;
}
}
2015-08-08 13:57:52 +00:00
# ifndef MOBILE
2017-04-08 15:18:29 +00:00
if ( cmode = = emNormal | | cmode = = emVisual1 | | cmode = = emVisual2 | | cmode = = emChangeMode ) {
2017-04-15 02:48:59 +00:00
# ifdef TOUR
2017-04-08 15:18:29 +00:00
if ( tour : : on )
displayButton ( vid . xres - 8 , vid . yres - vid . fsize , XLAT ( " (ESC) tour menu " ) , SDLK_ESCAPE , 16 ) ;
else
2017-04-15 02:48:59 +00:00
# endif
2017-04-08 15:18:29 +00:00
displayButton ( vid . xres - 8 , vid . yres - vid . fsize , XLAT ( " (v) menu " ) , ' v ' , 16 ) ;
}
2017-03-23 10:53:57 +00:00
# endif
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( cmode = = emQuit ) {
if ( canmove ) showGameover ( ) ;
2015-08-08 13:57:52 +00:00
}
// SDL_UnlockSurface(s);
2017-03-23 10:53:57 +00:00
DEBT ( " swapbuffers " ) ;
2017-05-27 19:40:40 +00:00
# ifndef NOSDL
2015-08-08 13:57:52 +00:00
# ifdef GL
if ( vid . usingGL ) SDL_GL_SwapBuffers ( ) ; else
# endif
SDL_UpdateRect ( s , 0 , 0 , vid . xres , vid . yres ) ;
2017-05-27 19:40:40 +00:00
# endif
2016-01-02 10:09:13 +00:00
//printf("\ec");
2015-08-08 13:57:52 +00:00
}
2017-05-27 19:40:40 +00:00
# ifndef NOSDL
2017-03-23 10:53:57 +00:00
bool setfsize = true ;
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
void setvideomode ( ) {
DEBB ( DF_INIT , ( debugfile , " setvideomode \n " ) ) ;
2015-08-08 13:57:52 +00:00
if ( ! vid . full ) {
if ( vid . xres > vid . xscr ) vid . xres = vid . xscr * 9 / 10 , setfsize = true ;
if ( vid . yres > vid . yscr ) vid . yres = vid . yscr * 9 / 10 , setfsize = true ;
}
if ( setfsize ) vid . fsize = min ( vid . yres / 32 , vid . xres / 48 ) , setfsize = false ;
int flags = 0 ;
# ifdef GL
if ( vid . usingGL ) {
flags = SDL_OPENGL | SDL_HWSURFACE | SDL_GL_DOUBLEBUFFER ;
SDL_GL_SetAttribute ( SDL_GL_STENCIL_SIZE , 1 ) ;
}
# endif
int sizeflag = ( vid . full ? SDL_FULLSCREEN : SDL_RESIZABLE ) ;
s = SDL_SetVideoMode ( vid . xres , vid . yres , 32 , flags | sizeflag ) ;
if ( vid . full & & ! s ) {
vid . xres = vid . xscr ;
vid . yres = vid . yscr ;
vid . fsize = min ( vid . yres / 32 , vid . xres / 48 ) ;
s = SDL_SetVideoMode ( vid . xres , vid . yres , 32 , flags | SDL_FULLSCREEN ) ;
}
if ( ! s ) {
addMessage ( " Failed to set the graphical mode: " + its ( vid . xres ) + " x " + its ( vid . yres ) + ( vid . full ? " fullscreen " : " windowed " ) ) ;
vid . xres = 640 ;
vid . yres = 480 ;
s = SDL_SetVideoMode ( vid . xres , vid . yres , 32 , flags | SDL_RESIZABLE ) ;
}
# ifdef GL
2016-08-26 09:58:03 +00:00
if ( vid . usingGL ) {
glViewport ( 0 , 0 , vid . xres , vid . yres ) ;
resetGL ( ) ;
}
2015-08-08 13:57:52 +00:00
# endif
}
# endif
void restartGraph ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_INIT , ( debugfile , " restartGraph \n " ) ) ;
2017-04-04 09:13:15 +00:00
2015-08-08 13:57:52 +00:00
View = Id ;
2017-05-27 19:40:40 +00:00
linepatterns : : clearAll ( ) ;
2017-04-04 09:13:15 +00:00
if ( currentmap ) {
if ( euclid ) {
centerover = euclideanAtCreate ( 0 , 0 ) ;
}
else {
viewctr . h = currentmap - > getOrigin ( ) ;
viewctr . spin = 0 ;
viewctr . mirrored = false ;
}
if ( sphere ) View = spin ( - M_PI / 2 ) ;
}
2017-03-23 10:53:57 +00:00
}
void resetview ( ) {
DEBB ( DF_GRAPH , ( debugfile , " reset view \n " ) ) ;
View = Id ;
// EUCLIDEAN
if ( ! euclid )
viewctr . h = cwt . c - > master ,
viewctr . spin = cwt . spin ;
else centerover = cwt . c ;
// SDL_LockSurface(s);
// SDL_UnlockSurface(s);
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
2016-08-26 09:58:03 +00:00
void initcs ( charstyle & cs ) {
cs . charid = 0 ;
cs . skincolor = 0xD0D0D0FF ;
cs . haircolor = 0x686868FF ;
cs . dresscolor = 0xC00000FF ;
cs . swordcolor = 0xD0D0D0FF ;
cs . dresscolor2 = 0x8080FFC0 ;
2017-03-23 10:53:57 +00:00
cs . uicolor = 0xFF0000FF ;
2016-08-26 09:58:03 +00:00
}
2017-03-23 10:53:57 +00:00
# ifndef NOCONFIG
void savecs ( FILE * f , charstyle & cs , int xvernum ) {
2016-08-26 09:58:03 +00:00
int gflags = cs . charid ;
if ( vid . samegender ) gflags | = 16 ;
fprintf ( f , " %d %d %08x %08x %08x %08x " ,
gflags , vid . language , cs . skincolor , cs . haircolor , cs . swordcolor , cs . dresscolor ) ;
if ( cs . charid = = 3 ) fprintf ( f , " %08x " , cs . dresscolor2 ) ;
2017-03-23 10:53:57 +00:00
if ( xvernum > = 8990 ) fprintf ( f , " %x " , cs . uicolor ) ;
2016-08-26 09:58:03 +00:00
fprintf ( f , " \n " ) ;
}
2017-03-23 10:53:57 +00:00
void loadcs ( FILE * f , charstyle & cs , int xvernum ) {
2016-08-26 09:58:03 +00:00
int gflags , err =
fscanf ( f , " %d%d%x%x%x%x " , & gflags , & vid . language , & cs . skincolor , & cs . haircolor , & cs . swordcolor , & cs . dresscolor ) ;
if ( err ) cs . charid = gflags & 15 ;
if ( err ) vid . samegender = ( gflags & 16 ) ? true : false ;
if ( cs . charid = = 3 ) if ( fscanf ( f , " %x " , & cs . dresscolor2 ) )
;
2017-03-23 10:53:57 +00:00
if ( xvernum > = 8990 ) if ( fscanf ( f , " %x " , & cs . uicolor ) )
;
2016-08-26 09:58:03 +00:00
}
2015-08-08 13:57:52 +00:00
void saveConfig ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_INIT , ( debugfile , " save config \n " ) ) ;
2015-08-08 13:57:52 +00:00
FILE * f = fopen ( conffile , " wt " ) ;
if ( ! f ) {
addMessage ( s0 + " Could not open the config file: " + conffile ) ;
return ;
}
fprintf ( f , " %d %d %d %d \n " , vid . xres , vid . yres , vid . full , vid . fsize ) ;
2017-03-23 10:53:57 +00:00
fprintf ( f , " %f %f %f %f \n " , float ( vid . scale ) , float ( vid . eye ) , float ( vid . alpha ) , float ( vid . sspeed ) ) ;
fprintf ( f , " %d %d %d %d %d %d %d \n " , vid . wallmode , vid . monmode , vid . axes , musicvolume , vid . framelimit , vid . usingGL , vid . usingAA ) ;
fprintf ( f , " %d %d %d %f %d %d \n " , vid . joyvalue , vid . joyvalue2 , vid . joypanthreshold , float ( vid . joypanspeed ) , autojoy , vid . flashtime ) ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
savecs ( f , vid . cs , 0 ) ;
2016-01-02 10:09:13 +00:00
2015-08-08 13:57:52 +00:00
fprintf ( f , " %d %d \n " , vid . darkhepta , vid . shifttarget ) ;
2016-01-02 10:09:13 +00:00
fprintf ( f , " %d %d %d %d \n " , euclid , euclidland , shmup : : on , hardcore ) ;
2016-08-26 09:58:03 +00:00
2016-01-02 10:09:13 +00:00
shmup : : saveConfig ( f ) ;
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
fprintf ( f , " %d %d %d %d %f %d %d \n " , rug : : renderonce , rug : : rendernogl , rug : : texturesize , purehepta , rug : : scale , vid . steamscore , chaosmode ) ;
2017-03-23 10:53:57 +00:00
fprintf ( f , " %d %d %f %d %d %f \n " ,
pmodel , polygonal : : SI , float ( polygonal : : STAR ) , polygonal : : deg ,
conformal : : includeHistory , float ( conformal : : lvspeed ) ) ;
2016-08-26 09:58:03 +00:00
fprintf ( f , " %d %d %d %d %d %d \n " ,
conformal : : bandhalf , conformal : : bandsegment ,
conformal : : rotation , conformal : : autoband , conformal : : autobandhistory ,
conformal : : dospiral ) ;
fprintf ( f , " %d " , polygonal : : maxcoef ) ;
for ( int i = 0 ; i < = polygonal : : maxcoef ; i + + ) fprintf ( f , " %lf %lf " ,
( double ) real ( polygonal : : coef [ i ] ) , ( double ) imag ( polygonal : : coef [ i ] ) ) ;
2017-03-23 10:53:57 +00:00
fprintf ( f , " \n %d %d %d %f %d %d \n " ,
revcontrol , vid . drawmousecircle , sightrange , float ( vid . mspeed ) , effvolume , vid . particles ) ;
{
int pt_depth = 0 , pt_camera = 0 , pt_alpha = 0 ;
using namespace geom3 ;
if ( tc_depth > tc_camera ) pt_depth + + ;
if ( tc_depth < tc_camera ) pt_camera + + ;
if ( tc_depth > tc_alpha ) pt_depth + + ;
if ( tc_depth < tc_alpha ) pt_alpha + + ;
if ( tc_alpha > tc_camera ) pt_alpha + + ;
if ( tc_alpha < tc_camera ) pt_camera + + ;
fprintf ( f , " %f %f %f %f %f %f %f %d %d %d %f %f %d \n " ,
float ( geom3 : : depth ) , float ( geom3 : : camera ) , float ( geom3 : : wall_height ) ,
float ( geom3 : : rock_wall_ratio ) ,
float ( geom3 : : human_wall_ratio ) ,
float ( geom3 : : lake_top ) ,
float ( geom3 : : lake_bottom ) ,
pt_depth , pt_camera , pt_alpha ,
float ( geom3 : : highdetail ) , float ( geom3 : : middetail ) ,
glyphsortorder ) ;
fprintf ( f , " %f %f %f %f \n " ,
float ( vid . yshift ) , float ( vid . camera_angle ) ,
float ( vid . ballangle ) , float ( vid . ballproj )
) ;
2017-05-28 22:16:17 +00:00
fprintf ( f , " %d %d %d %d \n " , vid . mobilecompasssize , vid . aurastr , vid . aurasmoothen , vid . graphglyph ) ;
2017-03-23 10:53:57 +00:00
}
2016-08-26 09:58:03 +00:00
fprintf ( f , " \n \n This is a configuration file for HyperRogue (version " VER " ) \n " ) ;
2015-08-08 13:57:52 +00:00
fprintf ( f , " \n \n The numbers are: \n " ) ;
fprintf ( f , " screen width & height, fullscreen mode (0=windowed, 1=fullscreen), font size \n " ) ;
2017-03-23 10:53:57 +00:00
fprintf ( f , " scale, eye distance, parameter, scrolling speed \n " ) ;
fprintf ( f , " wallmode, monster mode, cross mode, music volume, framerate limit, usingGL, usingAA \n " ) ;
2015-08-08 13:57:52 +00:00
fprintf ( f , " calibrate first joystick (threshold A, threshold B), calibrate second joystick (pan threshold, pan speed), joy mode \n " ) ;
2016-01-02 10:09:13 +00:00
fprintf ( f , " gender (1=female, 16=same gender prince), language, skin color, hair color, sword color, dress color \n " ) ;
2015-08-08 13:57:52 +00:00
fprintf ( f , " darken hepta, shift target \n " ) ;
2016-01-02 10:09:13 +00:00
fprintf ( f , " euclid, euclid land, shmup, hardcore \n " ) ;
2017-03-23 10:53:57 +00:00
fprintf ( f , " version number, shmup players, alwaysuse, shmup keyboard/joystick config \n " ) ;
2016-08-26 09:58:03 +00:00
fprintf ( f , " hypersian rug config: renderonce, rendernogl, texturesize; purehepta; rug scale; share score; chaosmode \n " ) ;
fprintf ( f , " conformal: model, sides, star, degree, includeHistory, speed \n " ) ;
fprintf ( f , " conformal: bandwidth, segment, rotation, autoband, autohistory, dospiral \n " ) ;
fprintf ( f , " conformal: degree, (degree+1) times {real, imag} \n " ) ;
2017-03-23 10:53:57 +00:00
fprintf ( f , " revcontrol, drawmousecircle, sight range, movement animation speed, sound effect volume, particle effects \n " ) ;
fprintf ( f , " 3D parameters, sort order \n " ) ;
fprintf ( f , " yhsift, camera angle, ball angle, ball projection \n " ) ;
2017-05-28 22:16:17 +00:00
fprintf ( f , " compass size, aura strength, aura smoothen factor, graphical glyphs \n " ) ;
2015-08-08 13:57:52 +00:00
fclose ( f ) ;
2016-08-26 09:58:03 +00:00
# ifndef MOBILE
2015-08-08 13:57:52 +00:00
addMessage ( s0 + " Configuration saved to: " + conffile ) ;
2016-08-26 09:58:03 +00:00
# else
addMessage ( s0 + " Configuration saved " ) ;
# endif
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
void readf ( FILE * f , ld & x ) {
double fl = x ;
if ( fscanf ( f , " %lf " , & fl ) )
;
x = fl ;
}
2015-08-08 13:57:52 +00:00
void loadConfig ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_INIT , ( debugfile , " load config \n " ) ) ;
2015-08-08 13:57:52 +00:00
vid . xres = 9999 ; vid . yres = 9999 ; vid . framelimit = 300 ;
FILE * f = fopen ( conffile , " rt " ) ;
if ( f ) {
2016-08-26 09:58:03 +00:00
int fs , gl = 1 , aa = 1 , bb = 1 , cc , dd , ee ;
2015-08-08 13:57:52 +00:00
int err ;
err = fscanf ( f , " %d%d%d%d " , & vid . xres , & vid . yres , & fs , & vid . fsize ) ;
vid . full = fs ;
float a , b , c , d ;
err = fscanf ( f , " %f%f%f%f \n " , & a , & b , & c , & d ) ;
if ( err = = 4 ) {
2017-03-23 10:53:57 +00:00
vid . scale = a ; vid . eye = b ; vid . alpha = c ; vid . sspeed = d ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
err = fscanf ( f , " %d%d%d%d%d%d%d " , & vid . wallmode , & vid . monmode , & vid . axes , & musicvolume , & vid . framelimit , & gl , & aa ) ;
2015-08-08 13:57:52 +00:00
vid . usingGL = gl ; vid . usingAA = aa ;
2017-03-23 10:53:57 +00:00
double jps = vid . joypanspeed ;
err = fscanf ( f , " %d%d%d%lf%d%d " , & vid . joyvalue , & vid . joyvalue2 , & vid . joypanthreshold , & jps , & aa , & vid . flashtime ) ;
vid . joypanspeed = jps ;
2015-08-08 13:57:52 +00:00
autojoy = aa ; aa = 0 ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
loadcs ( f , vid . cs , 0 ) ;
2016-08-26 09:58:03 +00:00
2015-08-08 13:57:52 +00:00
aa = 0 ; bb = 0 ;
err = fscanf ( f , " %d%d " , & aa , & bb ) ;
vid . darkhepta = aa ; vid . shifttarget = bb ;
2017-03-23 10:53:57 +00:00
aa = geometry ; bb = euclidland ; cc = shmup : : on ; dd = hardcore ;
2016-01-02 10:09:13 +00:00
err = fscanf ( f , " %d%d%d%d " , & aa , & bb , & cc , & dd ) ;
2017-03-23 10:53:57 +00:00
geometry = eGeometry ( aa ) ; euclidland = eLand ( bb ) ; shmup : : on = cc ; hardcore = dd ;
2016-01-02 10:09:13 +00:00
shmup : : loadConfig ( f ) ;
2016-08-26 09:58:03 +00:00
aa = rug : : renderonce ; bb = rug : : rendernogl ; cc = purehepta ; dd = chaosmode ; ee = vid . steamscore ;
2017-03-23 10:53:57 +00:00
double rs = rug : : scale ;
err = fscanf ( f , " %d%d%d%d%lf%d%d " , & aa , & bb , & rug : : texturesize , & cc , & rs , & ee , & dd ) ;
2016-08-26 09:58:03 +00:00
rug : : renderonce = aa ; rug : : rendernogl = bb ; purehepta = cc ; chaosmode = dd ; vid . steamscore = ee ;
2017-03-23 10:53:57 +00:00
rug : : scale = rs ;
2016-08-26 09:58:03 +00:00
aa = conformal : : includeHistory ;
2017-03-23 10:53:57 +00:00
double ps = polygonal : : STAR , lv = conformal : : lvspeed ;
int pmb = pmodel ;
2016-08-26 09:58:03 +00:00
err = fscanf ( f , " %d%d%lf%d%d%lf " ,
2017-03-23 10:53:57 +00:00
& pmb , & polygonal : : SI , & ps , & polygonal : : deg ,
& aa , & lv ) ;
pmodel = eModel ( pmb ) ;
conformal : : includeHistory = aa ; polygonal : : STAR = ps ; conformal : : lvspeed = lv ;
2016-08-26 09:58:03 +00:00
aa = conformal : : autoband ; bb = conformal : : autobandhistory ; cc = conformal : : dospiral ;
err = fscanf ( f , " %d%d%d%d%d%d " ,
& conformal : : bandhalf , & conformal : : bandsegment , & conformal : : rotation ,
& aa , & bb , & cc ) ;
conformal : : autoband = aa ; conformal : : autobandhistory = bb ; conformal : : dospiral = cc ;
2017-03-23 10:53:57 +00:00
2016-08-26 09:58:03 +00:00
err = fscanf ( f , " %d " , & polygonal : : maxcoef ) ;
if ( polygonal : : maxcoef < 0 ) polygonal : : maxcoef = 0 ;
if ( polygonal : : maxcoef > MSI ) polygonal : : maxcoef = MSI ;
for ( int i = 0 ; i < = polygonal : : maxcoef ; i + + ) {
double re = 0 , im = 0 ;
err = fscanf ( f , " %lf%lf " , & re , & im ) ;
polygonal : : coef [ i ] = polygonal : : cld ( re , im ) ;
}
2017-03-23 10:53:57 +00:00
aa = revcontrol ; bb = vid . drawmousecircle ;
d = vid . mspeed ;
err = fscanf ( f , " %d%d%d%f%d%d " , & aa , & bb , & sightrange , & d , & effvolume , & vid . particles ) ;
vid . mspeed = d ;
if ( sightrange < 4 ) sightrange = 4 ;
if ( sightrange > 7 ) sightrange = 7 ;
revcontrol = aa ; vid . drawmousecircle = bb ;
readf ( f , geom3 : : depth ) ; readf ( f , geom3 : : camera ) ; readf ( f , geom3 : : wall_height ) ;
readf ( f , geom3 : : rock_wall_ratio ) ; readf ( f , geom3 : : human_wall_ratio ) ;
readf ( f , geom3 : : lake_top ) ; readf ( f , geom3 : : lake_bottom ) ;
err = fscanf ( f , " %d %d %d " , & geom3 : : tc_depth , & geom3 : : tc_camera , & geom3 : : tc_alpha ) ;
readf ( f , geom3 : : highdetail ) ;
geom3 : : middetail = 200 ; readf ( f , geom3 : : middetail ) ;
if ( geom3 : : middetail = = 200 ) {
if ( ISMOBILE )
geom3 : : highdetail = 0 , geom3 : : middetail = 3 ;
else
geom3 : : highdetail = geom3 : : middetail = 5 ;
}
int gso = glyphsortorder ; err = fscanf ( f , " %d " , & gso ) ; glyphsortorder = eGlyphsortorder ( gso ) ;
readf ( f , vid . yshift ) ; readf ( f , vid . camera_angle ) ; readf ( f , vid . ballangle ) ; readf ( f , vid . ballproj ) ;
2017-05-28 22:16:17 +00:00
err = fscanf ( f , " %d%d%d%d \n " , & vid . mobilecompasssize , & vid . aurastr , & vid . aurasmoothen , & vid . graphglyph ) ;
2016-08-26 09:58:03 +00:00
2015-08-08 13:57:52 +00:00
fclose ( f ) ;
2016-08-26 09:58:03 +00:00
DEBB ( DF_INIT , ( debugfile , " Loaded configuration: %s \n " , conffile ) ) ;
2017-03-23 10:53:57 +00:00
if ( err )
;
2015-08-08 13:57:52 +00:00
}
2016-08-26 09:58:03 +00:00
precalc ( ) ;
2015-08-08 13:57:52 +00:00
}
# endif
2017-05-27 19:40:40 +00:00
# ifndef NOSDL
2016-01-02 10:09:13 +00:00
void initJoysticks ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_INIT , ( debugfile , " init joysticks \n " ) ) ;
2016-01-02 10:09:13 +00:00
numsticks = SDL_NumJoysticks ( ) ;
if ( numsticks > 8 ) numsticks = 8 ;
for ( int i = 0 ; i < numsticks ; i + + ) {
sticks [ i ] = SDL_JoystickOpen ( i ) ;
/* printf("axes = %d, balls = %d, buttons = %d, hats = %d\n",
SDL_JoystickNumAxes ( sticks [ i ] ) ,
SDL_JoystickNumBalls ( sticks [ i ] ) ,
SDL_JoystickNumButtons ( sticks [ i ] ) ,
SDL_JoystickNumHats ( sticks [ i ] )
) ; */
}
}
void closeJoysticks ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_INIT , ( debugfile , " close joysticks \n " ) ) ;
2016-01-02 10:09:13 +00:00
for ( int i = 0 ; i < numsticks ; i + + ) {
SDL_JoystickClose ( sticks [ i ] ) , sticks [ i ] = NULL ;
}
numsticks = 0 ;
}
# endif
2017-05-27 19:40:40 +00:00
bool noGUI = false ;
2015-08-08 13:57:52 +00:00
void initgraph ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_INIT , ( debugfile , " initgraph \n " ) ) ;
2015-08-08 13:57:52 +00:00
vid . usingGL = true ;
vid . usingAA = true ;
vid . flashtime = 8 ;
vid . scale = 1 ;
vid . alpha = 1 ;
2017-03-23 10:53:57 +00:00
vid . sspeed = 0 ;
vid . mspeed = 1 ;
2015-08-08 13:57:52 +00:00
vid . eye = 0 ;
vid . full = false ;
2017-03-23 10:53:57 +00:00
vid . ballangle = 20 ;
vid . yshift = 0 ;
vid . camera_angle = 0 ;
vid . ballproj = 1 ;
2017-05-27 19:40:40 +00:00
vid . aurastr = 128 ;
vid . aurasmoothen = 5 ;
2017-05-28 22:16:17 +00:00
vid . graphglyph = 1 ;
2017-03-23 10:53:57 +00:00
# ifdef ANDROID
vid . monmode = 2 ;
2015-08-08 13:57:52 +00:00
vid . wallmode = 3 ;
2017-03-25 01:10:15 +00:00
# else
# ifdef PANDORA
vid . monmode = 2 ;
vid . wallmode = 3 ;
2017-03-23 10:53:57 +00:00
# else
vid . monmode = 4 ;
vid . wallmode = 5 ;
2017-03-25 01:10:15 +00:00
# endif
2017-03-23 10:53:57 +00:00
# endif
vid . particles = 1 ;
vid . mobilecompasssize = 30 ;
2015-08-08 13:57:52 +00:00
vid . joyvalue = 4800 ;
vid . joyvalue2 = 5600 ;
vid . joypanthreshold = 2500 ;
2016-01-02 10:09:13 +00:00
# ifdef PANDORA
2015-08-08 13:57:52 +00:00
vid . joypanspeed = 0.0001 ;
2016-01-02 10:09:13 +00:00
# else
vid . joypanspeed = 0 ;
# endif
2015-08-08 13:57:52 +00:00
vid . framelimit = 75 ;
vid . axes = 1 ;
2017-03-23 10:53:57 +00:00
vid . shifttarget = 2 ;
vid . steamscore = 1 ;
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
initcs ( vid . cs ) ;
2015-08-08 13:57:52 +00:00
vid . killreduction = 0 ;
2016-01-02 10:09:13 +00:00
vid . samegender = false ;
2015-08-08 13:57:52 +00:00
vid . language = - 1 ;
2016-01-02 10:09:13 +00:00
joyx = joyy = 0 ; joydir . d = - 1 ;
2017-03-23 10:53:57 +00:00
vid . drawmousecircle = false ;
revcontrol = false ;
# ifdef MOBILE
vid . drawmousecircle = true ;
# endif
# ifdef PANDORA
vid . drawmousecircle = true ;
# endif
2016-01-02 10:09:13 +00:00
shmup : : initConfig ( ) ;
2015-08-08 13:57:52 +00:00
restartGraph ( ) ;
initgeo ( ) ;
buildpolys ( ) ;
2017-05-27 19:40:40 +00:00
if ( noGUI ) {
# ifdef USE_COMMANDLINE
arg : : read ( 2 ) ;
# endif
return ;
}
2015-08-08 13:57:52 +00:00
2017-05-27 19:40:40 +00:00
# ifndef NOSDL
2015-08-08 13:57:52 +00:00
if ( SDL_Init ( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) = = - 1 )
{
printf ( " Failed to initialize video. \n " ) ;
exit ( 2 ) ;
}
2017-03-23 10:53:57 +00:00
# ifdef WEB
vid . xscr = vid . xres = 1200 ;
vid . yscr = vid . yres = 900 ;
# else
2015-08-08 13:57:52 +00:00
const SDL_VideoInfo * inf = SDL_GetVideoInfo ( ) ;
vid . xscr = vid . xres = inf - > current_w ;
vid . yscr = vid . yres = inf - > current_h ;
2017-03-23 10:53:57 +00:00
# endif
2015-08-08 13:57:52 +00:00
2016-08-26 09:58:03 +00:00
SDL_WM_SetCaption ( " HyperRogue " VER , " HyperRogue " VER ) ;
2017-03-23 10:53:57 +00:00
# endif
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
preparesort ( ) ;
# ifndef NOCONFIG
2015-08-08 13:57:52 +00:00
loadConfig ( ) ;
2017-03-23 10:53:57 +00:00
# endif
# ifdef USE_COMMANDLINE
arg : : read ( 2 ) ;
# endif
2015-08-08 13:57:52 +00:00
2017-05-27 19:40:40 +00:00
# ifndef NOSDL
2015-08-08 13:57:52 +00:00
setvideomode ( ) ;
if ( ! s ) {
printf ( " Failed to initialize graphics. \n " ) ;
exit ( 2 ) ;
}
SDL_EnableKeyRepeat ( SDL_DEFAULT_REPEAT_DELAY , SDL_DEFAULT_REPEAT_INTERVAL ) ;
SDL_EnableUNICODE ( 1 ) ;
2017-05-27 19:40:40 +00:00
# ifndef NOTTF
2015-08-08 13:57:52 +00:00
if ( TTF_Init ( ) ! = 0 ) {
printf ( " Failed to initialize TTF. \n " ) ;
exit ( 2 ) ;
}
2017-05-27 19:40:40 +00:00
# endif
2015-08-08 13:57:52 +00:00
2016-01-02 10:09:13 +00:00
initJoysticks ( ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
# ifdef SDLAUDIO
initAudio ( ) ;
# endif
# endif
}
int frames ;
bool outoffocus = false ;
void panning ( hyperpoint hf , hyperpoint ht ) {
View =
rgpushxto0 ( hf ) * rgpushxto0 ( gpushxto0 ( hf ) * ht ) * gpushxto0 ( hf ) * View ;
playermoved = false ;
}
# ifdef LOCAL
# include "local.cpp"
# endif
bool needConfirmation ( ) {
return canmove & & ( gold ( ) > = 30 | | tkills ( ) > = 50 ) & & ! cheater & & ! quitsaves ( ) ;
}
void fullcenter ( ) {
if ( playerfound & & false ) centerpc ( INF ) ;
else {
bfs ( ) ;
resetview ( ) ;
drawthemap ( ) ;
centerpc ( INF ) ;
}
playermoved = true ;
}
bool didsomething ;
bool quitmainloop = false ;
2017-05-27 19:40:40 +00:00
bool doexiton ( int sym , int uni ) {
if ( sym = = SDLK_ESCAPE ) return true ;
if ( sym = = SDLK_F10 ) return true ;
if ( uni ! = 0 ) return true ;
return false ;
}
2017-03-23 10:53:57 +00:00
void handleKeyQuit ( int sym , int uni ) {
dialog : : handleNavigation ( sym , uni ) ;
// ignore the camera movement keys
# ifndef NORUG
if ( rug : : rugged & & ( sym = = SDLK_UP | | sym = = SDLK_DOWN | | sym = = SDLK_PAGEUP | | sym = = SDLK_PAGEDOWN | |
sym = = SDLK_RIGHT | | sym = = SDLK_LEFT ) )
sym = 0 ;
# endif
2017-05-27 19:40:40 +00:00
if ( sym = = SDLK_RETURN | | sym = = SDLK_KP_ENTER | | sym = = SDLK_F10 ) quitmainloop = true ;
2017-03-23 10:53:57 +00:00
else if ( uni = = ' r ' | | sym = = SDLK_F5 ) {
restartGame ( ) , cmode = emNormal ;
msgs . clear ( ) ;
}
else if ( sym = = SDLK_UP | | sym = = SDLK_KP8 ) msgscroll + + ;
else if ( sym = = SDLK_DOWN | | sym = = SDLK_KP2 ) msgscroll - - ;
else if ( sym = = SDLK_PAGEUP | | sym = = SDLK_KP9 ) msgscroll + = 5 ;
else if ( sym = = SDLK_PAGEDOWN | | sym = = SDLK_KP3 ) msgscroll - = 5 ;
else if ( uni = = ' v ' ) cmode = emMenu ;
else if ( sym = = SDLK_HOME | | sym = = SDLK_F3 | | ( sym = = ' ' & & DEFAULTCONTROL ) )
fullcenter ( ) ;
else if ( uni = = ' o ' ) setAppropriateOverview ( ) ;
# ifndef NOSAVE
else if ( uni = = ' t ' ) {
if ( ! canmove ) restartGame ( ) ;
loadScores ( ) ;
msgs . clear ( ) ;
}
# endif
2017-05-27 19:40:40 +00:00
else if ( doexiton ( sym , uni ) & & ! didsomething ) {
2017-03-23 10:53:57 +00:00
cmode = emNormal ;
msgscroll = 0 ;
msgs . clear ( ) ;
}
}
# ifdef MOBILE
# define extra int
# else
# define extra SDL_Event
# endif
void handleKeyNormal ( int sym , int uni , extra & ev ) {
if ( cheater ) {
if ( applyCheat ( uni , mouseover ) )
sym = 0 ;
}
if ( ! ( uni > = ' A ' & & uni < = ' Z ' ) & & DEFAULTCONTROL ) {
if ( sym = = ' l ' | | sym = = ' d ' | | sym = = SDLK_KP6 ) movepckeydir ( 0 ) ;
if ( sym = = ' n ' | | sym = = ' c ' | | sym = = SDLK_KP3 ) movepckeydir ( 1 ) ;
if ( sym = = ' j ' | | sym = = ' x ' | | sym = = SDLK_KP2 ) movepckeydir ( 2 ) ;
if ( sym = = ' b ' | | sym = = ' z ' | | sym = = SDLK_KP1 ) movepckeydir ( 3 ) ;
if ( sym = = ' h ' | | sym = = ' a ' | | sym = = SDLK_KP4 ) movepckeydir ( 4 ) ;
if ( sym = = ' y ' | | sym = = ' q ' | | sym = = SDLK_KP7 ) movepckeydir ( 5 ) ;
if ( sym = = ' k ' | | sym = = ' w ' | | sym = = SDLK_KP8 ) movepckeydir ( 6 ) ;
if ( sym = = ' u ' | | sym = = ' e ' | | sym = = SDLK_KP9 ) movepckeydir ( 7 ) ;
}
# ifdef PANDORA
if ( DEFAULTCONTROL ) {
if ( sym = = SDLK_RIGHT ) movepckeydir ( 0 ) ;
if ( sym = = SDLK_LEFT ) movepckeydir ( 4 ) ;
if ( sym = = SDLK_DOWN ) movepckeydir ( 2 + ( leftclick ? 1 : 0 ) - ( rightclick ? 1 : 0 ) ) ;
if ( sym = = SDLK_UP ) movepckeydir ( 6 - ( leftclick ? 1 : 0 ) + ( rightclick ? 1 : 0 ) ) ;
}
# endif
if ( DEFAULTCONTROL ) {
if ( sym = = ' . ' | | sym = = ' s ' ) movepcto ( - 1 , 1 ) ;
if ( uni = = ' % ' & & sym = = ' 5 ' ) {
if ( vid . wallmode = = 0 ) vid . wallmode = 6 ;
vid . wallmode - - ;
}
if ( uni = = sym ) {
if ( uni = = ' 1 ' ) {
vid . alpha = 999 ; vid . scale = 998 ;
}
if ( uni = = ' 2 ' ) {
vid . alpha = 1 ; vid . scale = 0.4 ;
}
if ( uni = = ' 3 ' ) {
vid . alpha = 1 ; vid . scale = 1 ;
}
if ( uni = = ' 4 ' ) {
vid . alpha = 0 ; vid . scale = 1 ;
}
if ( uni = = ' 5 ' ) {
vid . wallmode + + ;
if ( vid . wallmode = = 6 ) vid . wallmode = 0 ;
}
if ( uni = = ' 6 ' ) {
vid . grid = ! vid . grid ;
}
if ( uni = = ' 7 ' ) {
vid . darkhepta = ! vid . darkhepta ;
}
if ( uni = = ' 8 ' ) {
backcolor = backcolor ^ 0xFFFFFF ;
printf ( " back = %x \n " , backcolor ) ;
}
if ( uni = = ' 9 ' ) {
pmodel = eModel ( 8 - pmodel ) ;
// vid.yshift = 1 - vid.yshift;
// vid.drawmousecircle = true;
}
}
if ( ( sym = = SDLK_DELETE | | sym = = SDLK_KP_PERIOD | | sym = = ' g ' ) & & uni ! = ' G ' & & uni ! = ' G ' - 64 )
movepcto ( MD_DROP , 1 ) ;
if ( sym = = ' m ' & & canmove & & cmode = = emNormal & & ( centerover = = cwt . c ? mouseover : centerover ) )
performMarkCommand ( mouseover ) ;
if ( sym = = ' t ' & & uni ! = ' T ' & & uni ! = ' T ' - 64 & & canmove & & cmode = = emNormal ) {
if ( playermoved & & items [ itStrongWind ] ) {
cell * c = whirlwind : : jumpDestination ( cwt . c ) ;
if ( c ) centerover = c ;
}
targetRangedOrb ( centerover , roKeyboard ) ;
sym = 0 ; uni = 0 ;
}
}
if ( sym = = SDLK_KP5 & & DEFAULTCONTROL ) movepcto ( - 1 , 1 ) ;
// if(sym == SDLK_F4) restartGameSwitchEuclid();
if ( sym = = SDLK_F5 ) {
if ( needConfirmation ( ) ) cmode = emQuit ;
else restartGame ( ) ;
}
if ( sym = = SDLK_ESCAPE ) {
cmode = emQuit ;
achievement_final ( false ) ;
if ( ! canmove ) {
addMessage ( XLAT ( " GAME OVER " ) ) ;
addMessage ( timeline ( ) ) ;
}
msgscroll = 0 ;
}
if ( sym = = SDLK_F10 ) {
if ( needConfirmation ( ) ) cmode = emQuit ;
else quitmainloop = true ;
}
if ( ! canmove ) {
2017-05-27 19:40:40 +00:00
if ( sym = = SDLK_RETURN | | sym = = SDLK_KP_ENTER ) quitmainloop = true ;
2017-03-23 10:53:57 +00:00
else if ( uni = = ' r ' ) restartGame ( ) ;
# ifndef NOSAVE
else if ( uni = = ' t ' ) {
restartGame ( ) ;
loadScores ( ) ;
}
# endif
# ifndef NORUG
else if ( rug : : rugged ) ;
# endif
else if ( sym = = SDLK_UP | | sym = = SDLK_KP8 ) msgscroll + + ;
else if ( sym = = SDLK_DOWN | | sym = = SDLK_KP2 ) msgscroll - - ;
else if ( sym = = SDLK_PAGEUP | | sym = = SDLK_KP9 ) msgscroll + = 5 ;
else if ( sym = = SDLK_PAGEDOWN | | sym = = SDLK_KP3 ) msgscroll - = 5 ;
}
if ( uni = = ' o ' ) setAppropriateOverview ( ) ;
if ( sym = = SDLK_HOME | | sym = = SDLK_F3 | | ( sym = = ' ' & & DEFAULTCONTROL ) )
fullcenter ( ) ;
/* if(sym == SDLK_F6) {
View = spin ( M_PI / 2 ) * inverse ( cwtV ) * View ;
if ( flipplayer ) View = pispin * View ;
cmode = emDraw ;
} */
if ( sym = = ' v ' ) {
cmode = emMenu ;
}
if ( sym = = SDLK_F2 ) {
cmode = emVisual1 ;
}
2015-08-08 13:57:52 +00:00
2017-05-27 19:40:40 +00:00
# ifndef NOSDL
2017-03-23 10:53:57 +00:00
# ifdef PANDORA
if ( ev . type = = SDL_MOUSEBUTTONUP & & sym = = 0 & & ! rightclick )
# else
if ( ev . type = = SDL_MOUSEBUTTONDOWN & & sym = = 0 & & ! rightclick )
2015-08-08 13:57:52 +00:00
# endif
2017-03-23 10:53:57 +00:00
if ( canmove & & getcstat ! = ' v ' & & getcstat ! = ' g ' & & getcstat ! = SDLK_F1 )
{
actonrelease = false ;
shmup : : cpid = 0 ;
if ( mouseover & &
targetclick & & ( ! shmup : : on | | numplayers ( ) = = 1 ) & & targetRangedOrb ( mouseover , forcetarget ? roMouseForce : roMouse ) ) {
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else if ( forcetarget )
;
else if ( ! DEFAULTCONTROL ) {
if ( ! shmup : : on )
multi : : mousemovement ( mouseover ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else mousemovement ( ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
# endif
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( sym = = SDLK_F1 ) {
lastmode = cmode ;
cmode = emHelp ;
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
# ifdef ROGUEVIZ
rogueviz : : processKey ( sym , uni ) ;
# endif
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
# ifdef LOCAL
process_local0 ( sym ) ;
# endif
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
void handlekey ( int sym , int uni , extra & ev ) {
2015-08-08 13:57:52 +00:00
2017-04-08 15:18:29 +00:00
# ifdef TOUR
if ( tour : : on & & tour : : handleKeyTour ( sym , uni ) ) return ;
# endif
2017-05-27 19:40:40 +00:00
if ( ( ( cmode = = emNormal & & canmove ) | | ( cmode = = emQuit & & ! canmove ) | | cmode = = emDraw | | ( cmode = = emMapEditor & & ! mapeditor : : subscreen ) ) & & DEFAULTCONTROL & & ! rug : : rugged ) {
2017-03-23 10:53:57 +00:00
# ifndef PANDORA
2017-04-14 18:12:23 +00:00
if ( sym = = SDLK_RIGHT ) {
if ( conformal : : on )
conformal : : lvspeed + = 0.1 * shiftmul ;
else
View = xpush ( - 0.2 * shiftmul ) * View , playermoved = false , didsomething = true ;
}
if ( sym = = SDLK_LEFT ) {
if ( conformal : : on )
conformal : : lvspeed - = 0.1 * shiftmul ;
else
View = xpush ( + 0.2 * shiftmul ) * View , playermoved = false , didsomething = true ;
}
if ( sym = = SDLK_UP ) {
if ( conformal : : on )
conformal : : lvspeed + = 0.1 * shiftmul ;
else
View = ypush ( + 0.2 * shiftmul ) * View , playermoved = false , didsomething = true ;
}
if ( sym = = SDLK_DOWN ) {
if ( conformal : : on )
conformal : : lvspeed - = 0.1 * shiftmul ;
else
View = ypush ( - 0.2 * shiftmul ) * View , playermoved = false , didsomething = true ;
}
2016-08-26 09:58:03 +00:00
# endif
2017-03-23 10:53:57 +00:00
if ( sym = = SDLK_PAGEUP ) {
2017-04-14 18:12:23 +00:00
if ( conformal : : on )
conformal : : rotation + + ;
else
View = spin ( M_PI / S21 * shiftmul ) * View , didsomething = true ;
}
if ( sym = = SDLK_PAGEDOWN ) {
if ( conformal : : on )
conformal : : rotation + + ;
else
View = spin ( - M_PI / S21 * shiftmul ) * View , didsomething = true ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
if ( sym = = SDLK_PAGEUP | | sym = = SDLK_PAGEDOWN )
if ( isGravityLand ( cwt . c - > land ) ) playermoved = false ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
2017-05-27 19:40:40 +00:00
# ifndef NOSDL
2017-03-23 10:53:57 +00:00
if ( sym = = SDLK_F7 & & ! vid . usingGL ) {
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
time_t timer ;
timer = time ( NULL ) ;
char buf [ 128 ] ; strftime ( buf , 128 , " shot-%y%m%d-%H%M%S " IMAGEEXT , localtime ( & timer ) ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
IMAGESAVE ( s , buf ) ;
addMessage ( XLAT ( " Screenshot saved to %1 " , buf ) ) ;
2015-08-08 13:57:52 +00:00
}
# endif
2017-03-23 10:53:57 +00:00
# ifdef DEMO
if ( cmode = = emOverview | | cmode = = emMenu ) handleDemoKey ( sym , uni ) ; else
# endif
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( cmode = = emNormal ) handleKeyNormal ( sym , uni , ev ) ;
else if ( cmode = = emMenu ) handleMenuKey ( sym , uni ) ;
else if ( cmode = = emCheatMenu ) handleCheatMenu ( sym , uni ) ;
else if ( cmode = = emVisual1 ) handleVisual1 ( sym , uni ) ;
else if ( cmode = = emJoyConfig ) handleJoystickConfig ( sym , uni ) ;
else if ( cmode = = emCustomizeChar ) handleCustomizeChar ( sym , uni ) ;
else if ( cmode = = emVisual2 ) handleVisual2 ( sym , uni ) ;
else if ( cmode = = emChangeMode ) handleChangeMode ( sym , uni ) ;
else if ( cmode = = emShmupConfig ) shmup : : handleConfig ( sym , uni ) ;
# ifndef NOMODEL
else if ( cmode = = emNetgen ) netgen : : handleKey ( sym , uni ) ;
# endif
# ifndef NORUG
else if ( cmode = = emRugConfig ) rug : : handleKey ( sym , uni ) ;
# endif
# ifndef NOEDIT
else if ( cmode = = emMapEditor ) mapeditor : : handleKey ( sym , uni ) ;
else if ( cmode = = emDraw ) mapeditor : : drawHandleKey ( sym , uni ) ;
# endif
# ifndef NOSAVE
# ifndef MOBILE
2017-05-27 19:40:40 +00:00
else if ( cmode = = emScores ) handleScoreKeys ( sym , uni ) ;
2017-03-23 10:53:57 +00:00
# endif
2017-05-27 19:40:40 +00:00
else if ( cmode = = emPickScores ) handlePickScoreKeys ( sym , uni ) ;
2017-03-23 10:53:57 +00:00
# endif
else if ( cmode = = emConformal ) conformal : : handleKey ( sym , uni ) ;
else if ( cmode = = emYendor ) yendor : : handleKey ( sym , uni ) ;
else if ( cmode = = emTactic ) tactic : : handleKey ( sym , uni ) ;
else if ( cmode = = emOverview ) handleOverview ( sym , uni ) ;
else if ( cmode = = emPickEuclidean ) handleEuclidean ( sym , uni ) ;
# ifdef MOBILE
2017-03-23 13:09:36 +00:00
# ifdef HAVE_ACHIEVEMENTS
2017-03-23 10:53:57 +00:00
else if ( cmode = = emLeader ) leader : : handleKey ( sym , uni ) ;
2017-03-23 13:09:36 +00:00
# endif
2017-03-23 10:53:57 +00:00
# endif
else if ( cmode = = emColor ) dialog : : handleColor ( sym , uni ) ;
else if ( cmode = = emNumber ) dialog : : handleNumber ( sym , uni ) ;
else if ( cmode = = emHelp ) handleHelp ( sym , uni ) ;
else if ( cmode = = em3D ) handle3D ( sym , uni ) ;
else if ( cmode = = emQuit ) handleKeyQuit ( sym , uni ) ;
# ifdef ROGUEVIZ
else if ( cmode = = emRogueviz ) rogueviz : : handleMenu ( sym , uni ) ;
2015-08-08 13:57:52 +00:00
# endif
2017-05-27 19:40:40 +00:00
else if ( cmode = = emLinepattern ) linepatterns : : handleMenu ( sym , uni ) ;
2016-01-02 10:09:13 +00:00
}
2017-05-27 19:40:40 +00:00
# ifdef NOSDL
void mainloopiter ( ) { printf ( " (compiled without SDL -- no action) \n " ) ; quitmainloop = true ; }
# else
2015-08-08 13:57:52 +00:00
// Warning: a very long function! todo: refactor
2017-03-23 10:53:57 +00:00
void mainloopiter ( ) {
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
DEBB ( DF_GRAPH , ( debugfile , " main loop \n " ) ) ;
# ifndef GFX
# ifndef GL
vid . wallmode = 0 ;
vid . monmode = 0 ;
# endif
# endif
2016-08-26 09:58:03 +00:00
# ifdef LOCAL
2017-03-23 10:53:57 +00:00
process_local_extra ( ) ;
2016-08-26 09:58:03 +00:00
# endif
2017-03-23 10:53:57 +00:00
optimizeview ( ) ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
if ( conformal : : on ) conformal : : apply ( ) ;
ticks = SDL_GetTicks ( ) ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
int cframelimit = vid . framelimit ;
if ( ( cmode = = emVisual1 | | cmode = = emVisual2 | | cmode = = emHelp | | cmode = = emQuit | |
cmode = = emCustomizeChar | | cmode = = emMenu | | cmode = = emPickEuclidean | |
cmode = = emScores | | cmode = = emPickScores ) & & cframelimit > 15 )
cframelimit = 15 ;
if ( outoffocus & & cframelimit > 10 ) cframelimit = 10 ;
int timetowait = lastt + 1000 / cframelimit - ticks ;
if ( DOSHMUP & & cmode = = emNormal )
timetowait = 0 , shmup : : turn ( ticks - lastt ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( ! DOSHMUP & & ( multi : : alwaysuse | | multi : : players > 1 ) & & cmode = = emNormal )
timetowait = 0 , multi : : handleMulti ( ticks - lastt ) ;
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( vid . sspeed > = 5 & & gmatrix . count ( cwt . c ) & & ! elliptic ) {
cwtV = gmatrix [ cwt . c ] * ddspin ( cwt . c , cwt . spin ) ;
if ( cwt . mirrored ) playerV = playerV * Mirror ;
}
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
# ifdef WEB
if ( playermoved & & vid . sspeed > - 4.99 & & ! outoffocus ) {
centerpc ( ( ticks - lastt ) / 1000.0 * exp ( vid . sspeed ) ) ;
}
if ( ! outoffocus ) drawscreen ( ) ;
# else
if ( timetowait > 0 )
SDL_Delay ( timetowait ) ;
else {
if ( cmode ! = emOverview ) {
if ( playermoved & & vid . sspeed > - 4.99 & & ! outoffocus )
centerpc ( ( ticks - lastt ) / 1000.0 * exp ( vid . sspeed ) ) ;
2016-01-02 10:09:13 +00:00
if ( panjoyx | | panjoyy )
2015-08-08 13:57:52 +00:00
checkpanjoy ( ( ticks - lastt ) / 1000.0 ) ;
}
2017-03-23 10:53:57 +00:00
tortoise : : updateVals ( ticks - lastt ) ;
frames + + ;
if ( ! outoffocus ) {
drawscreen ( ) ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
lastt = ticks ;
}
2015-08-08 13:57:52 +00:00
# endif
2017-03-23 10:53:57 +00:00
Uint8 * keystate = SDL_GetKeyState ( NULL ) ;
rightclick = keystate [ SDLK_RCTRL ] ;
leftclick = keystate [ SDLK_RSHIFT ] ;
lctrlclick = keystate [ SDLK_LCTRL ] ;
lshiftclick = keystate [ SDLK_LSHIFT ] ;
forcetarget = ( keystate [ SDLK_RSHIFT ] | keystate [ SDLK_LSHIFT ] ) ;
hiliteclick = keystate [ SDLK_LALT ] | keystate [ SDLK_RALT ] ;
anyshiftclick = keystate [ SDLK_LSHIFT ] | keystate [ SDLK_RSHIFT ] ;
wheelclick = false ;
getcshift = 1 ;
if ( keystate [ SDLK_LSHIFT ] | | keystate [ SDLK_RSHIFT ] ) getcshift = - 1 ;
if ( keystate [ SDLK_LCTRL ] | | keystate [ SDLK_RCTRL ] ) getcshift / = 10 ;
if ( keystate [ SDLK_LALT ] | | keystate [ SDLK_RALT ] ) getcshift * = 10 ;
didsomething = false ;
if ( vid . shifttarget & 1 ) {
leftclick = false ;
targetclick = keystate [ SDLK_RSHIFT ] | keystate [ SDLK_LSHIFT ] ;
}
else {
leftclick = keystate [ SDLK_RSHIFT ] ;
targetclick = true ;
}
# ifdef SDLAUDIO
if ( audio ) handlemusic ( ) ;
# endif
SDL_Event ev ;
DEBB ( DF_GRAPH , ( debugfile , " polling for events \n " ) ) ;
achievement_pump ( ) ;
while ( SDL_PollEvent ( & ev ) ) {
DEBB ( DF_GRAPH , ( debugfile , " got event type #%d \n " , ev . type ) ) ;
int sym = 0 ;
int uni = 0 ;
shiftmul = 1 ;
2016-08-26 09:58:03 +00:00
/* if(ev.type == SDL_JOYDEVICEADDED || ev.type == SDL_JOYDEVICEREMOVED) {
2017-03-23 10:53:57 +00:00
joyx = joyy = 0 ;
panjoyx = panjoyy = 0 ;
closeJoysticks ( ) ;
initJoysticks ( ) ;
} */
if ( ev . type = = SDL_ACTIVEEVENT ) {
if ( ev . active . state & SDL_APPINPUTFOCUS ) {
if ( ev . active . gain ) {
outoffocus = false ;
}
else {
outoffocus = true ;
2015-08-08 13:57:52 +00:00
}
}
2017-03-23 10:53:57 +00:00
}
if ( ev . type = = SDL_VIDEORESIZE ) {
vid . xres = ev . resize . w ;
vid . yres = ev . resize . h ;
vid . killreduction = 0 ;
extern bool setfsize ;
setfsize = true ;
setvideomode ( ) ;
2015-08-08 13:57:52 +00:00
# ifdef GL
2017-03-23 10:53:57 +00:00
if ( vid . usingGL ) glViewport ( 0 , 0 , vid . xres , vid . yres ) ;
2015-08-08 13:57:52 +00:00
# endif
2017-03-23 10:53:57 +00:00
}
if ( ev . type = = SDL_VIDEOEXPOSE ) {
drawscreen ( ) ;
}
if ( ev . type = = SDL_JOYAXISMOTION ) {
if ( ev . jaxis . which = = 0 ) {
if ( ev . jaxis . axis = = 0 )
joyx = ev . jaxis . value ;
else if ( ev . jaxis . axis = = 1 )
joyy = ev . jaxis . value ;
else if ( ev . jaxis . axis = = 3 )
panjoyx = ev . jaxis . value ;
else if ( ev . jaxis . axis = = 4 )
panjoyy = ev . jaxis . value ;
checkjoy ( ) ;
// printf("panjoy = %d,%d\n", panjoyx, panjoyy);
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else {
if ( ev . jaxis . axis = = 0 )
panjoyx = ev . jaxis . value ;
else
panjoyy = ev . jaxis . value ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( ev . type = = SDL_JOYBUTTONDOWN & & cmode = = emShmupConfig & & vid . scfg . setwhat ) {
int joyid = ev . jbutton . which ;
int button = ev . jbutton . button ;
if ( joyid < 8 & & button < 32 )
vid . scfg . joyaction [ joyid ] [ button ] = vid . scfg . setwhat ;
vid . scfg . setwhat = 0 ;
}
else if ( ev . type = = SDL_JOYHATMOTION & & cmode = = emShmupConfig & & vid . scfg . setwhat ) {
int joyid = ev . jhat . which ;
int hat = ev . jhat . hat ;
int dir = 4 ;
if ( ev . jhat . value = = SDL_HAT_UP ) dir = 0 ;
if ( ev . jhat . value = = SDL_HAT_RIGHT ) dir = 1 ;
if ( ev . jhat . value = = SDL_HAT_DOWN ) dir = 2 ;
if ( ev . jhat . value = = SDL_HAT_LEFT ) dir = 3 ;
if ( joyid < 8 & & hat < 4 & & dir < 4 ) {
vid . scfg . hataction [ joyid ] [ hat ] [ dir ] = vid . scfg . setwhat ;
2016-01-02 10:09:13 +00:00
vid . scfg . setwhat = 0 ;
}
2017-03-23 10:53:57 +00:00
}
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
else if ( ev . type = = SDL_JOYBUTTONDOWN & & DEFAULTCONTROL ) {
flashMessages ( ) ;
movepcto ( joydir ) ;
checkjoy ( ) ;
}
2016-01-02 10:09:13 +00:00
2017-03-23 10:53:57 +00:00
if ( ev . type = = SDL_KEYDOWN ) {
flashMessages ( ) ;
mousing = false ;
sym = ev . key . keysym . sym ;
uni = ev . key . keysym . unicode ;
if ( ev . key . keysym . mod & ( KMOD_LSHIFT | KMOD_RSHIFT ) ) shiftmul = - 1 ;
if ( ev . key . keysym . mod & ( KMOD_LCTRL | KMOD_RCTRL ) ) shiftmul / = 10 ;
2017-05-27 19:40:40 +00:00
if ( sym = = SDLK_RETURN & & ( ev . key . keysym . mod & ( KMOD_LALT | KMOD_RALT ) ) ) {
sym = 0 ; uni = 0 ;
switchFullscreen ( ) ;
}
2017-03-23 10:53:57 +00:00
}
dialog : : handleZooming ( ev ) ;
if ( sym = = SDLK_F1 & & cmode = = emNormal & & playermoved )
help = " @ " ;
bool rollchange =
cmode = = emOverview & & getcstat > = 2000 & & cheater ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( ev . type = = SDL_MOUSEBUTTONDOWN ) {
flashMessages ( ) ;
mousepressed = true ;
mousing = true ;
actonrelease = true ;
if ( ev . button . button = = SDL_BUTTON_WHEELUP & & ( ( cmode = = emQuit ) ^ ! canmove ) ) {
}
else if ( ev . button . button = = SDL_BUTTON_WHEELDOWN ) {
if ( cmode = = ( canmove ? emQuit : emNormal ) ) {
2016-01-02 10:09:13 +00:00
sym = 1 ; msgscroll - - ; didsomething = true ;
}
2017-03-23 10:53:57 +00:00
else
if ( cmode = = emTactic | | cmode = = emYendor | | cmode = = emPickEuclidean | |
cmode = = emLeader | | cmode = = emScores | | cmode = = emOverview )
if ( ! rollchange )
sym = uni = PSEUDOKEY_WHEELDOWN ;
}
if ( ev . button . button = = SDL_BUTTON_WHEELUP ) {
if ( cmode = = ( canmove ? emQuit : emNormal ) ) {
sym = 1 ; msgscroll + + ; didsomething = true ;
}
else if ( cmode = = ( canmove ? emNormal : emQuit ) | | cmode = = emMapEditor | | cmode = = emDraw ) {
2015-08-08 13:57:52 +00:00
ld jx = ( mousex - vid . xcenter - .0 ) / vid . radius / 10 ;
ld jy = ( mousey - vid . ycenter - .0 ) / vid . radius / 10 ;
playermoved = false ;
View = gpushxto0 ( hpxy ( jx , jy ) ) * View ;
sym = 1 ;
}
2017-03-23 10:53:57 +00:00
else
if ( cmode = = emTactic | | cmode = = emYendor | | cmode = = emPickEuclidean | |
cmode = = emLeader | | cmode = = emScores | | cmode = = emOverview )
if ( getcstat < 2000 | | ! cheater )
sym = uni = PSEUDOKEY_WHEELUP ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else if ( ev . button . button = = SDL_BUTTON_RIGHT ) {
sym = 1 ; didsomething = true ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else if ( ev . button . button = = SDL_BUTTON_MIDDLE ) {
sym = 2 ; didsomething = true ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( ev . type = = SDL_MOUSEBUTTONUP ) {
mousepressed = false ;
mousing = true ;
if ( ev . button . button = = SDL_BUTTON_RIGHT | | leftclick )
sym = SDLK_F1 ;
else if ( ev . button . button = = SDL_BUTTON_MIDDLE | | rightclick )
sym = 1 , didsomething = true ;
else if ( ev . button . button = = SDL_BUTTON_LEFT & & actonrelease ) {
sym = getcstat , uni = getcstat , shiftmul = getcshift ;
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
else if ( ev . button . button = = SDL_BUTTON_WHEELUP & & rollchange ) {
sym = getcstat , uni = getcstat , shiftmul = getcshift , wheelclick = true ;
}
else if ( ev . button . button = = SDL_BUTTON_WHEELDOWN & & rollchange ) {
sym = getcstat , uni = getcstat , shiftmul = - getcshift , wheelclick = true ;
}
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( ev . type = = SDL_MOUSEMOTION ) {
hyperpoint mouseoh = mouseh ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
mousing = true ;
mousemoved = true ;
mousex = ev . motion . x ;
mousey = ev . motion . y ;
# ifndef NORUG
if ( rug : : rugged )
mouseh = rug : : gethyper ( mousex , mousey ) ;
else
2015-08-08 13:57:52 +00:00
# endif
2017-03-23 10:53:57 +00:00
mouseh = gethyper ( mousex , mousey ) ;
if ( ( rightclick | | ( SDL_GetMouseState ( NULL , NULL ) & SDL_BUTTON_MMASK ) ) & &
! outofmap ( mouseh ) & & ! outofmap ( mouseoh ) & &
mouseh [ 2 ] < 50 & & mouseoh [ 2 ] < 50 ) {
panning ( mouseoh , mouseh ) ;
}
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
# ifdef SIMULATE_JOYSTICK
// pretend that both joysticks are present
stick = panstick = ( SDL_Joystick * ) ( & vid ) ;
panjoyx = 20 * ( mousex - vid . xcenter ) ;
panjoyy = 20 * ( mousey - vid . ycenter ) ;
checkjoy ( ) ;
2015-08-08 13:57:52 +00:00
# endif
2017-03-23 10:53:57 +00:00
if ( mousepressed & & inslider ) {
sym = getcstat , uni = getcstat , shiftmul = getcshift ;
2015-08-08 13:57:52 +00:00
}
}
2017-03-23 10:53:57 +00:00
handlekey ( sym , uni , ev ) ;
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
if ( ev . type = = SDL_QUIT ) {
if ( needConfirmation ( ) & & cmode ! = emQuit ) cmode = emQuit ;
else quitmainloop = true ;
}
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
}
2017-05-27 19:40:40 +00:00
# endif
2017-03-23 10:53:57 +00:00
void mainloop ( ) {
lastt = 0 ;
# ifdef WEB
initweb ( ) ;
emscripten_set_main_loop ( mainloopiter , 0 , true ) ;
# else
while ( ! quitmainloop ) mainloopiter ( ) ;
# endif
2015-08-08 13:57:52 +00:00
}
void cleargraph ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_INIT , ( debugfile , " clear graph \n " ) ) ;
2017-05-27 19:40:40 +00:00
# ifndef NOTTF
2015-08-08 13:57:52 +00:00
for ( int i = 0 ; i < 256 ; i + + ) if ( font [ i ] ) TTF_CloseFont ( font [ i ] ) ;
2017-05-27 19:40:40 +00:00
# endif
# ifndef EXTERNALFONT
2015-08-08 13:57:52 +00:00
for ( int i = 0 ; i < 128 ; i + + ) if ( glfont [ i ] ) delete glfont [ i ] ;
2017-05-27 19:40:40 +00:00
# endif
# ifndef NOSDL
2015-08-08 13:57:52 +00:00
# ifndef SIMULATE_JOYSTICK
2016-01-02 10:09:13 +00:00
closeJoysticks ( ) ;
2015-08-08 13:57:52 +00:00
# endif
SDL_Quit ( ) ;
# endif
2017-05-27 19:40:40 +00:00
}
2015-08-08 13:57:52 +00:00
void cleargraphmemory ( ) {
2016-08-26 09:58:03 +00:00
DEBB ( DF_INIT , ( debugfile , " clear graph memory \n " ) ) ;
2015-08-08 13:57:52 +00:00
mouseover = centerover = lmouseover = NULL ;
2017-03-23 10:53:57 +00:00
# ifndef NOEDIT
2016-01-02 10:09:13 +00:00
if ( mapeditor : : painttype = = 4 )
mapeditor : : painttype = 0 , mapeditor : : paintwhat = 0 ,
mapeditor : : paintwhat_str = " clear monster " ;
mapeditor : : copywhat = NULL ;
mapeditor : : undo . clear ( ) ;
if ( ! cheater ) mapeditor : : displaycodes = 0 ;
if ( ! cheater ) mapeditor : : whichShape = 0 ;
# endif
2017-03-23 10:53:57 +00:00
for ( int i = 0 ; i < ANIMLAYERS ; i + + ) animations [ i ] . clear ( ) ;
gmatrix . clear ( ) ; gmatrix0 . clear ( ) ;
2015-08-08 13:57:52 +00:00
}
2016-01-02 10:09:13 +00:00
void showMissionScreen ( ) {
cmode = emQuit ;
2016-08-26 09:58:03 +00:00
msgscroll = 0 ;
2016-01-02 10:09:13 +00:00
}
2017-03-23 10:53:57 +00:00
void resetGeometry ( ) {
precalc ( ) ;
fp43 . analyze ( ) ;
resetGL ( ) ;
}
//=== animation
map < cell * , animation > animations [ ANIMLAYERS ] ;
unordered_map < cell * , transmatrix > gmatrix , gmatrix0 ;
void animateMovement ( cell * src , cell * tgt , int layer ) {
if ( vid . mspeed > = 5 ) return ; // no animations!
if ( confusingGeometry ( ) ) return ;
if ( gmatrix . count ( src ) & & gmatrix . count ( tgt ) ) {
animation & a = animations [ layer ] [ tgt ] ;
if ( animations [ layer ] . count ( src ) ) {
a = animations [ layer ] [ src ] ;
a . wherenow = inverse ( gmatrix [ tgt ] ) * gmatrix [ src ] * a . wherenow ;
animations [ layer ] . erase ( src ) ;
}
else {
a . ltick = ticks ;
a . wherenow = inverse ( gmatrix [ tgt ] ) * gmatrix [ src ] ;
a . footphase = 0 ;
}
}
}
vector < pair < cell * , animation > > animstack ;
void indAnimateMovement ( cell * src , cell * tgt , int layer ) {
if ( vid . mspeed > = 5 ) return ; // no animations!
if ( confusingGeometry ( ) ) return ;
if ( animations [ layer ] . count ( tgt ) ) {
animation res = animations [ layer ] [ tgt ] ;
animations [ layer ] . erase ( tgt ) ;
animateMovement ( src , tgt , layer ) ;
if ( animations [ layer ] . count ( tgt ) )
animstack . push_back ( make_pair ( tgt , animations [ layer ] [ tgt ] ) ) ;
animations [ layer ] [ tgt ] = res ;
}
else {
animateMovement ( src , tgt , layer ) ;
if ( animations [ layer ] . count ( tgt ) ) {
animstack . push_back ( make_pair ( tgt , animations [ layer ] [ tgt ] ) ) ;
animations [ layer ] . erase ( tgt ) ;
}
}
}
void commitAnimations ( int layer ) {
for ( int i = 0 ; i < size ( animstack ) ; i + + )
animations [ layer ] [ animstack [ i ] . first ] = animstack [ i ] . second ;
animstack . clear ( ) ;
}
void animateReplacement ( cell * a , cell * b , int layer ) {
if ( vid . mspeed > = 5 ) return ; // no animations!
static cell c1 ;
gmatrix [ & c1 ] = gmatrix [ b ] ;
if ( animations [ layer ] . count ( b ) ) animations [ layer ] [ & c1 ] = animations [ layer ] [ b ] ;
animateMovement ( a , b , layer ) ;
animateMovement ( & c1 , a , layer ) ;
}